用指针来"爬栈"
转自:http://dododododo.blog.sohu.com/4627612.html
指针是个好东西,她能在内存中随意的游走.下面来介绍一个有趣的应用--爬栈.
爬栈就是用指针,从子函数开始,顺着堆栈向下找母函数的过程.
先给出一段代码:
/////////////////////////////////////////
int papa(int a)
{
int i = 2;
int *ptr ;
int EBP;
i = a;
ptr = &i;
EBP = *(ptr+1);
return 1;
}
int main(int argc, char* argv[])
{
int ret = 0;
int e = 3;
ret = papa(e);
return ret;
}
/////////////////////////////////////////
运行起来,跟到papa()里面,单步运行,ebp = 0x12ff20 看堆栈:
/////////////////////////////////////////
0x12ff1c:02 00 00 00 //变量i
0x12ff20:80 ff 12 00 //main()的EBP;
0x12ff24:df 84 40 00 //main()中下一条指令地址
0x12ff28:03 00 00 00 //传递给papa()的参数e
.....................
/////////////////////////////////////////
我们用"ptr = &i" 来得到变量i的地址,也就是0x12ff1c,然后ptr+1就可以得到papa()的EBP值,也就是0x12ff20;然后mian()的EBP就是存放在0x12ff20里面的值;然后存放在0x12ff28中的就是main()函数中下一条指令的地址.简单吧.......
然后,顺着EBP看:
/////////////////////////////////////////
0x12ff80:c0 ff 12 00 //mainCRTStartup 的 EBP
49 11 40 00
.....................
0x12ffc0:f0 ff 12 00 //这里就没有了,新进程吗,与主进程(比如explorer.exe)没关系了
4f 6d 81 7c //顺着这个再向上找
.....................
0x12fff0:00 00 00 00
00 00 00 00
.....................
/////////////////////////////////////////
顺着0x7c816d4f向上找的话,你会进入到kernel32.dll,哈哈,好,我们来看看这段代码:
////////////////////////////////////////
7C816D2A 90 NOP
7C816D2B 90 NOP
7C816D2C 6A 0C PUSH 0C
7C816D2E 68 586D817C PUSH kernel32.7C816D58
7C816D33 E8 93B7FEFF CALL kernel32.7C8024CB
7C816D38 8365 FC 00 AND DWORD PTR SS:[EBP-4],0
7C816D3C 6A 04 PUSH 4
7C816D3E 8D45 08 LEA EAX,DWORD PTR SS:[EBP+8]
7C816D41 50 PUSH EAX
7C816D42 6A 09 PUSH 9
7C816D44 6A FE PUSH -2
7C816D46 FF15 A013807C CALL DWORD PTR DS:[<&ntdll.NtSetInformat>; ntdll.ZwSetInformationThread
7C816D4C FF55 08 CALL DWORD PTR SS:[EBP+8] //喂,在这里!!
7C816D4F 50 PUSH EAX
7C816D50 E8 545FFFFF CALL kernel32.ExitThread
7C816D55 90 NOP
7C816D56 90 NOP
7C816D57 90 NOP
///////////////////////////////////////
再向上走的话,你会发现,一个你很熟悉的函数CreateRemoteThread,最后是CreateThread!;
它由运行该exe的父进程调用!.
以上这些意味着,我用子函数的指针就可以对母函数的数据进行任意操作,如改改父函数的局部变量,从父函数偷点子函数不能获得的数据,甚至直接跳到父函数去执行都是可以的......