原文:Hack the virtual memory Archives - Holberton

翻譯:RobotCode俱樂部

Hack the stack!

現在我們知道了在堆棧上哪裡可以找到返回地址,如果要修改這個值呢?我們能改變程序的流程並使func1返回到其他地方嗎?讓我們在程序中添加一個名為bye的新函數:(譯者註:原作者實驗環境為64位系統,譯者為32位系統。這裡也會給出在譯者的32位系統下的實驗結果

#include <stdio.h>
#include <stdlib.h>

void bye(void)
{
printf("[x] I am in the function bye!
");
exit(98);
}

void func1(void)
{
int a;
int b;
int c;
register long rsp asm ("rsp");
register long rbp asm ("rbp");

a = 98;
b = 972;
c = a + b;
printf("a = %d, b = %d, c = %d
", a, b, c);
printf("func1, rpb = %lx
", rbp);
printf("func1, rsp = %lx
", rsp);
printf("func1, a = %d
", *(int *)(((char *)rbp) - 0xc) );
printf("func1, b = %d
", *(int *)(((char *)rbp) - 0x8) );
printf("func1, c = %d
", *(int *)(((char *)rbp) - 0x4) );
printf("func1, previous rbp value = %lx
", *(unsigned long int *)rbp );
printf("func1, return address value = %lx
", *(unsigned long int *)((char *)rbp + 8) );
}

void func2(void)
{
int a;
int b;
int c;
register long rsp asm ("rsp");
register long rbp asm ("rbp");

printf("func2, a = %d, b = %d, c = %d
", a, b, c);
printf("func2, rpb = %lx
", rbp);
printf("func2, rsp = %lx
", rsp);
}

int main(void)
{
register long rsp asm ("rsp");
register long rbp asm ("rbp");

printf("main, rpb = %lx
", rbp);
printf("main, rsp = %lx
", rsp);
func1();
func2();
return (0);
}

讓我們看看這個函數的代碼從哪個地址開始:

00000000004005bd <bye>:
4005bd: 55 push rbp
4005be: 48 89 e5 mov rbp,rsp
4005c1: bf d8 07 40 00 mov edi,0x4007d8
4005c6: e8 b5 fe ff ff call 400480 <puts@plt>
4005cb: bf 62 00 00 00 mov edi,0x62
4005d0: e8 eb fe ff ff call 4004c0 <exit@plt>

現在讓我們將func1函數在堆棧上的返回地址替換為函數開頭的地址bye, 4005bd:

#include <stdio.h>
#include <stdlib.h>

void bye(void)
{
printf("[x] I am in the function bye!
");
exit(98);
}

void func1(void)
{
int a;
int b;
int c;
register long rsp asm ("rsp");
register long rbp asm ("rbp");

a = 98;
b = 972;
c = a + b;
printf("a = %d, b = %d, c = %d
", a, b, c);
printf("func1, rpb = %lx
", rbp);
printf("func1, rsp = %lx
", rsp);
printf("func1, a = %d
", *(int *)(((char *)rbp) - 0xc) );
printf("func1, b = %d
", *(int *)(((char *)rbp) - 0x8) );
printf("func1, c = %d
", *(int *)(((char *)rbp) - 0x4) );
printf("func1, previous rbp value = %lx
", *(unsigned long int *)rbp );
printf("func1, return address value = %lx
", *(unsigned long int *)((char *)rbp + 8) );
/* hack the stack! */
*(unsigned long int *)((char *)rbp + 8) = 0x4005bd;
}

void func2(void)
{
int a;
int b;
int c;
register long rsp asm ("rsp");
register long rbp asm ("rbp");

printf("func2, a = %d, b = %d, c = %d
", a, b, c);
printf("func2, rpb = %lx
", rbp);
printf("func2, rsp = %lx
", rsp);
}

int main(void)
{
register long rsp asm ("rsp");
register long rbp asm ("rbp");

printf("main, rpb = %lx
", rbp);
printf("main, rsp = %lx
", rsp);
func1();
func2();
return (0);
}

執行輸出如下:

holberton$ gcc 4-main.c && ./a.out
main, rpb = 7fff62ef1b60
main, rsp = 7fff62ef1b60
a = 98, b = 972, c = 1070
func1, rpb = 7fff62ef1b50
func1, rsp = 7fff62ef1b40
func1, a = 98
func1, b = 972
func1, c = 1070
func1, previous rbp value = 7fff62ef1b60
func1, return address value = 40074d
[x] I am in the function bye!
holberton$ echo $?
98
holberton$

我們已經成功執行了函數bye,但是並不是通過顯式調用它的方式!!

32位環境下long int 與int 類型都為4個位元組,64位環境下,long int 為8個位元組,int為4個位元組,所以譯者的32位測試環境下,程序需要做如下修改:

32位測試環境下需要修改的地方

bye函數地址

編譯運行結果如下:成功Hack!

至此,函數堆棧篇全部更新完了。應該能對虛擬內存中的Heap與Stack區域有個大概的認識。

由於本人水平有限,翻譯必然有很多不妥的地方,歡迎指正。

同時,歡迎關注下方微信公眾號,一起交流學習:)

推薦閱讀:

相关文章