Присвойте значение определенному адресу - PullRequest
4 голосов
/ 23 марта 2011

Это вопрос собеседования, с которым я столкнулся в книге для собеседований, а позже во время собеседования.

Вопрос:

Как присвоить значение (скажем, 0) по адресу (скажем, 0x12345678).

Моя лучшая попытка ответить на этот вопрос (после длительного времени после собеседования) -

Адресчисло, которое может быть сохранено в указателе, и мы можем присвоить значение адресу с помощью указателя, значением которого является адрес, например:

         int* p = 0x12345678;
         *p = 0;

Однако,это невозможно в системе с управлением памятью, потому что программа не имеет прав доступа к определенному адресу.

По моему опыту, единственная операция в этом случае была экспериментом на 8086.чип без какой-либо операционной системы, и язык, который я использовал в тот раз, был ассемблером.

Пожалуйста, помогите мне исправить, улучшить и дополнить мой ответ.Спасибо.

Ответы [ 4 ]

3 голосов
/ 17 мая 2011

Ваш код верен, но может произойти сбой во время выполнения, если ОС определяет 0x12345678 только для чтения.

В то время как «обычные» ОС делают это, «легкие» - нет.

Вы хотите написать хакерскую программу для ядра.

Я решил это для Linux, если вы хотите посмотреть:


1) построить этот модуль (example.ko):

#include <linux/module.h>
#include <linux/fs.h>       /* for file_operations  */
#include <linux/uaccess.h>  /* copy_from & copy_to  */

char*   g_value=0;
size_t  size =0; 

int driver_open(struct inode *inode, struct file *filp)
{
    printk("open driver");
    return 0;
}

int driver_write(struct file*,          /*ignored*/
                const char __user *umem,/*source in user-space's address*/
                size_t size,            /*max size to be writen*/
                loff_t*)                /*offset - ignored*/
{
    unsigned long ret = 0;

    g_value = (char*) kmalloc(size, GFP_KERNEL);

    if (!g_value)
    {
        printk("ERROR:allocation failure\n");
        return -ENOMEM;
    }

    ret = copy_from_user(g_value,   /*destination*/
                        umem,       /*source*/
                        size);      /*size*/

    if (ret<0)
    {
        printk("ERROR:copy failure\n");
        return -EACCES;
    }

    return g_size = size;;
}

int driver_read(struct file*,       /*ignored*/
                 char __user *umem, /*destination in user-space's address*/
                 size_t size,       /*max size to be read*/
                 loff_t*)           /*offset - ignored*/
{

    /*  don't use copy_to_user(umem,    &value, size)!!
        we want to do exectly what it is made to protect from */

    int i = ((g_size>size)?size:g_size)-1; /*MIN(g_size,size)-1*/
    for (; i>=0; --i)
    {
        umem[i]=g_value[i]; /*can be done more effectively, thats not the point*/
    }

    return size;
}

int driver_close(struct inode *inode, struct file *filp)
{
    if (g_value)
        free(g_value);
    g_value = 0;
    printk("close driver");
    return 0;
}

/***interface***/

struct file_operations driver_ops = {
    open: driver_open,
    write: driver_write,
    read:  driver_read,
    release: driver_close
};

/***implementation***/

static int g_driver_fd = 0;

static void driver_cleanup(void) 
{
    printk("ERROR:driver exit\n");
    unregister_chrdev(g_driver_fd, "driver");
}

static int driver_init(void)
{

    printk("driver init\n");
    g_driver_fd =  register_chrdev(0,"ROM-bypass", &driver_ops);
    if (g_driver_fd<0)
    {
        printk("ERROR:failed to register char driver\n");
        return -1;
    }
    return 0;
}

module_init(driver_init);
module_exit(driver_cleanup);

/***documentation***/

MODULE_DESCRIPTION("write on OS's \"read only\" segment");
MODULE_AUTHOR("Elkana Bronstein");
MODULE_LICENSE("GPL");

2) добавить его в модули ядра:

$insmod example.ko

3) найдите «основной» модуль в списке:

$cat /proc/devices

4) сделать узел, связанный с устройством:

$mknod /dev/rom_bypass  c <major> <minor>

'c' для символьного устройства, а 'minor' может быть любым из 0-255

5) использовать устройство в вашем коде как файл:

int main()
{

    int fd;
    int value = 0;

    fd = open("/dev/rom_bypass",O_RDWR);    
    if (fd<0)
    {
        fprintf(stderr,"open failed");
        return -1;
    }

    /*write the desirable value into the device's buffer*/
    write(fd,&value,sizeof(value));
    /*read the device's buffer into the desirable object - without checking*/
    read(fd,0x12345678,sizeof(value));

    close(fd);
}
1 голос
/ 04 июня 2013

(почти) невозможно узнать, в какие ячейки памяти можно записывать.

Вы можете попросить ОС предоставить вам доступный адрес с помощью функции malloc (), а затем освободить это местоположение с помощью free ().

Другой способ - использовать стековую память. Просто определите переменную int * p = 0; & p даст вам адрес этого места.

Если вы попытаетесь присвоить значения тем местоположениям, которые недоступны, у вас могут возникнуть ошибки ошибки сегментации.

Надеюсь, это поможет!

0 голосов
/ 24 марта 2011

Подобные вещи наиболее определенно возможны даже в системах с управлением памятью, если указатель находится вне доступного пространства для текущего процесса, он выйдет из строя, но это то, что должно произойти. Если нет, значение устанавливается и вы идете. Кроме этого, ваш пример мне подходит.

0 голосов
/ 23 марта 2011

Возможно, ответ заключается в том, что ответа нет, потому что это невозможно в системе с управлением памятью.

В системе без управления памятью я бы попытался напрямую использовать код сборки.

Надеюсь, это поможет

...