2017-02-05 9 views
-2

Я делаю знаменитый учебник «Разбить стек», и я застрял. В основном я манипулирую указателем, указывающим на адрес возврата в стеке. А затем манипулируйте обратным адресом. Поэтому моя цель - перепрыгнуть инструкцию x = 1;C Управление указателем

Пожалуйста, проверьте мой код, в моем opionen он должен работать. Я даже выключил ASLR ... но никакого эффекта

Но в конце концов я все еще не печатает «1» ... Не могу сказать, почему :-(

код из учебника:

void function(int a, int b, int c) { 
    char buffer1[5]; 
    char buffer2[10]; 
    int *ret; 

    ret = buffer1 + 12; 
    (*ret) += 8; 
} 

void main() { 
    int x; 

    x = 0; 
    function(1,2,3); 
    x = 1; 
    printf("%d\n",x); 
} 

мой код (первый попробовать):

void function(int a, int b, int c) { 

    // Dont really know if initiated arrays have a different address than non initiated... 
    char buffer1[5] = {1,2,3,4,5}; 
    char buffer2[10]; 
    int *ret; 

    ret = buffer1; 

    int i; 
    for(i=0;i<64;i++){ 
    printf("Added: %d, Address: %016x\n",i,(*ret)); 
    ret += i; 
    //Found out that adding 5 points to the return address on the stack 
    if(i == 5) break; 

    } 

    printf("stack address of ret: %p\n", ret); 
    printf("unchanged ret address: %016x\n", (*ret)); 

    //Just counted the bytes to pass the x = 1; movl $0x1,-0x4(%rbp) 
    (*ret) += 7; 
    printf("changed ret address: %016x\n", (*ret)); 
} 

void main() { 
    int x; 

    x = 0; 
    function(1,2,3); 
    x = 1; 
    printf("print x: %d\n",x); 
} 

Update:. Мой код теперь работает (он пропускает х = 1) я выложу этот код, если кто-то заинтересован. ..

Greetz!

+0

это будет, конечно, печать 1 только –

+0

так, где моя ошибка? – int80

+0

и скомпилировать с -fno-stack-protector – int80

ответ

0

Это работает:

#include<stdio.h> 

void function(int a, int b, int c) { 
char buffer1[5] = {1,2,3,4,5}; 
char buffer2[10]; 
char *ret; 

ret = buffer1; 

ret += 0x18; 

printf("stack address of ret: %p\n", ret); 
printf("unchanged ret address: 0x%x%02x%x\n",ret[2],ret[1],ret[0]); 
printf("unchanged ret address: %p\n", *(void **)ret); 
printf("unchanged ret address: 0x%06x\n", *(unsigned int *)ret &  0x00FFFFFF); 
printf("unchanged ret address: 0x%03x\n", *(unsigned int *)ret); 

//Just counted the bytes to pass the x = 1; movl $0x1,-0x4(%rbp) 
(*ret) += 7; 
//printf("changed ret address: %p\n",(*ret)); 
printf("changed ret address: 0x%03x\n", *(unsigned int *)ret); 
} 

void main() { 
int x; 

x = 0; 
function(1,2,3); 
x = 1; 
printf("print x: %d\n",x); 
} 
0

У вашего кода есть ряд проблем - я не думаю, что вы понимаете, что вы пытаетесь сделать. Вернитесь назад и спросите себя, как выглядит стек?

Предполагая 64-битный ЦП, ваши указатели составляют 8 байтов (64 бит), а ваши ints позволяют считать 4 байта (32 бита) каждый, тогда у вас есть 5 символов по одному байту плюс еще 10 символов, а также другой указатель (8 байтов), плюс переменная i. Таким образом, ваш стек выглядит следующим образом:

<return address>  <8 bytes> 
<function parameters> <12 bytes> 
<buffer1>    <5 bytes> 
<buffer2>    <10 bytes> 
<ret>     <8 bytes> 
<i> 

Ваш указатель указывает на buffer1, чтобы получить обратный адрес вам нужно сделать резервную копию 20 байт и читать 8. Так как ваш делают это, чтобы узнать, не буду дать вам ответ, но вот подсказка:

//Chars are 1 byte, ints are 4, char != int 
char buffer1[5] = {'a', 'b', 'c', 'd', 'e'}; 
char* currentAddress = &buffer1; 

printf("Value: %c, Address: %016x\n",(*currentAddress), currentAddress); 

//move 1 byte forward 
currentAddress++; 

//print a char 
printf("Value: %c, Address: %016x\n",(*currentAddress), currentAddress); 

//move back 
currentAddress--; 

//print a char 
printf("Value: %c, Address: %016x\n",(*currentAddress), currentAddress);  

//back up one int - safer than just saying back up 4 bytes 
currentAddress -= sizeof(int); 
//Print an int, notice the cast. 
printf("Value: %d, Address: %016x\n",(*(int*)currentAddress), currentAddress); 
+0

ну, я получил его работу. ваше объяснение имеет несколько ошибок. стек выглядит иначе, чем вы показали (его параметры не являются его EBP). И локальные переменные действительно имеют размер слов ... – int80