2016-02-04 5 views
1
#include <stdio.h> 

void interrupt(); 

int main() { 
int n = 8; 
char c = 'Z'; 
interrupt(); 
printf("%d%c\n", n, c); 
} 

void interrupt() { 
printf("Run normally\n"); 
//ADD CODE... 
} 

Как бы то ни было, эта функция выдаст «8Z» независимо от того, что делает метод interrupt(). Я пытаюсь изменить его так, чтобы он печатал «3Y», ничего не меняя в исходной основной функции, и только с использованием функции interrupt() (не разрешается передавать аргументы!). Мне разрешено использовать переменные в функции interrupt(), но я смущен тем, как вы получаете адреса «n» и «c», не создавая глобальную переменную, которая могла бы победить цель этого вопроса. Поскольку адрес стека изменяется каждый раз, когда это выполняется, похоже, нет способа сделать арифметику указателя (это то, что мне нужно сделать), и поэтому я немного запутался и застрял.Используйте арифметику указателя, чтобы изменить значение переменной в другой функции.

+0

Это настоящий вопрос программирования? где ты это нашел? –

+0

Да, это вопрос программирования. Я полагаю, что пункт назначения состоял в том, чтобы вы изменили то, что main() печатает с использованием арифметики указателя в другой функции, но мой вопрос заключается в том, как вы можете получить доступ к этой информации, не используя глобальную переменную или параметры передачи. Если это невозможно. – Senescence

+2

Для этого нет твердого кросс-платформенного решения. Но, зная специфику компилятора и систему ABI, вы можете рассчитать смещения стека и тем самым изменить стек вызывающей функции (учитывая, что его локальные переменные фактически распределены по стеку, а не в регистрах). –

ответ

2

Предупреждение: Не пытайтесь использовать это в коде производства

Я воспринял это как головоломки и начал ее решить. Вы сказали, что вам не разрешено изменять main. Я позволил слегка изменить main - напечатать адреса n и c.

int main() 
{ 
    int n = 8; 
    char c = 'Z'; 

    printf("%p %p\n", &n, &c); 

    interrupt(); 
    printf("%d%c\n", n, c); 
} 

Я также изменил interrupt немного, и напечатать значения адреса.

void interrupt() { 
    int i = 10; 
    char* np = (char*)&i; 
    char* cp = (char*)&i; 

    printf("%p %p\n", np, cp); 
    printf("%p\n", &i); 
} 

Когда я запускал программу, я получил следующий вывод:

0x22cb0c 0x22cb0b 
0x22cabc 0x22cabc 
0x22cabc 
8Z 

С выхода, я могу вычислить смещение между &n в main и &i в interrupt, а смещение между &c в main и &i в interrupt. Теперь я могу манипулировать смещением, чтобы сделать np и cp в interrupt, чтобы указать на n и c в main.

void interrupt() { 
    int i = 10; 
    char* np = (char*)&i; 
    char* cp = (char*)&i; 

    np += (0x22cb0c - 0x22cabc); 
    cp += (0x22cb0b - 0x22cabc); 

    *(int*)np = 3; 
    *cp = 'Y'; 

    printf("%p %p\n", np, cp); 
    printf("%p\n", &i); 
} 

С изменениями в interrupt, я получаю следующий результат:

0x22cb0c 0x22cb0b 
0x22cb0c 0x22cb0b 
0x22cabc 
3Y 

Миссия выполнена путем изменения main немного. Если вам вообще не разрешено изменять его, вам придется использовать другую программу для вычисления смещений.

1

По словам @Alex Skalozub, вы можете получить смещение стека и изменить локальные переменные в вызывающей функции.

Вы можете: 1. Изучите руководство для компилятора и операционной системы для расчета смещения стека.

or 2. Напишите небольшую функцию, чтобы получить ее во время выполнения. Как показано ниже.

int get_stack_offset(void) 
{ 
    long dummy1; 
    return dummy_call(&dummy1) + sizeof(dummy1); 
} 

int dummy_call(int address) 
{ 
    long dummy2; 
    return &dummy2 - address; 
} 

Тогда вы можете просто

void interrupt() { 
    printf("Run normally\n"); 
    int stack_offset = get_stack_offset(); 
    char* c_address = (char*) (&stack_offset - stack_offset); 
    int* n_address = (int*) (c_address - sizeof(char)); 

    // Then, modify them 
    *c_address = 'Y'; 
    *n_address = 3; 

    // Other 
    // ... 
} 

* Предполагая, что стек растет. Когда он уменьшается, вам нужно перевернуть оператор +/-.

* Я не думаю о выравнивании, которое, возможно, вам нужно.

* И вот отличное объяснение, на которое вы можете ссылаться. Does stack grow upward or downward?

+0

Вспомогательная функция может быть не совсем корректной, поскольку различные функции компилятора (например, защитник стека и т. Д.) Могут отображать разные макеты стека в 'main' и' interrupt', поэтому будет дополнительное смещение. –

+0

@Alex Skalozub Конечно. Это всего лишь образец. Если вы хотите применить к реальному коду, нам нужно рассмотреть гораздо больше. – Holsety

Смежные вопросы