求教:通过栈溢出来调用某个函数

pcliuguangtao 2012-04-22 10:03:44

#include "stdafx.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>

void DoSomething() {
printf("Enter the DoSomething() function:Hello.\n");
int i=0;
for (i=0; i<20; ++i)
printf("%d\n", i);
printf("Leave the DoSomething() function:Bye.\n");
}

void foo() {
int c;
int *p = (int*)&DoSomething;
void (*pfun)()=foo;
printf("sizeof(void*)=%d\n", sizeof(void*));
printf("pfun=0x%x\n", pfun);
printf("foo() function address=0x%x\n", foo);
printf("DoSomething() function address=0x%x\n",DoSomething);
memset(&c,(int)DoSomething, sizeof(void*)*10);
}

int _tmain(int argc, _TCHAR* argv[])
{
foo();
getchar();
return 0;
}

我想通过: memset(&c,(int)DoSomething, sizeof(void*)*10);
来实现栈溢出,从而调用DoSomething()函数?我在使用visual studio 2010调试的时候,vs显示的地址和我使用printf打印的地址为什么不一样?
打印地址为:
sizeof(void*)=4
pfun=0xdd11e5
foo() function address=0xdd11e5
DoSomething() function address=0xdd11ea

使用vs断点查看时:
foo()的地址是:0x00dd3540
DoSomethinf()的地址是:0x00dd2f10

对应的汇编代码如下:

00DD34EE CC int 3
00DD34EF CC int 3
--- d:\myprograms\commontest\commontest\commontest.cpp -------------------------
27:
28: int _tmain(int argc, _TCHAR* argv[])
29: {
00DD34F0 55 push ebp
00DD34F1 8B EC mov ebp,esp
00DD34F3 81 EC C0 00 00 00 sub esp,0C0h
00DD34F9 53 push ebx
00DD34FA 56 push esi
00DD34FB 57 push edi
00DD34FC 8D BD 40 FF FF FF lea edi,[ebp-0C0h]
00DD3502 B9 30 00 00 00 mov ecx,30h
00DD3507 B8 CC CC CC CC mov eax,0CCCCCCCCh
00DD350C F3 AB rep stos dword ptr es:[edi]
30: foo();
00DD350E E8 D2 DC FF FF call foo (0DD11E5h)
31: getchar();
00DD3513 8B F4 mov esi,esp
00DD3515 FF 15 B4 82 DD 00 call dword ptr [MSVCR100D_NULL_THUNK_DATA (0DD82B4h)]
00DD351B 3B F4 cmp esi,esp
00DD351D E8 14 DC FF FF call @ILT+305(__RTC_CheckEsp) (0DD1136h)
32: return 0;
00DD3522 33 C0 xor eax,eax
33: }
00DD3524 5F pop edi
00DD3525 5E pop esi
00DD3526 5B pop ebx
00DD3527 81 C4 C0 00 00 00 add esp,0C0h
00DD352D 3B EC cmp ebp,esp
00DD352F E8 02 DC FF FF call @ILT+305(__RTC_CheckEsp) (0DD1136h)
00DD3534 8B E5 mov esp,ebp
00DD3536 5D pop ebp
00DD3537 C3 ret
--- No source file -------------------------------------------------------------
00DD3538 CC int 3
00DD3539 CC int 3
00DD353A CC int 3
00DD353B CC int 3
00DD353C CC int 3
00DD353D CC int 3
00DD353E CC int 3
00DD353F CC int 3
--- d:\myprograms\commontest\commontest\commontest.cpp -------------------------
16:
17: void foo() {
00DD3540 55 push ebp
00DD3541 8B EC mov ebp,esp
00DD3543 81 EC E4 00 00 00 sub esp,0E4h
00DD3549 53 push ebx
00DD354A 56 push esi
00DD354B 57 push edi
00DD354C 8D BD 1C FF FF FF lea edi,[ebp-0E4h]
00DD3552 B9 39 00 00 00 mov ecx,39h
00DD3557 B8 CC CC CC CC mov eax,0CCCCCCCCh
00DD355C F3 AB rep stos dword ptr es:[edi]
18: int c;
19: int *p = (int*)&DoSomething;
00DD355E C7 45 EC EA 11 DD 00 mov dword ptr [p],offset DoSomething (0DD11EAh)
20: void (*pfun)()=foo;
00DD3565 C7 45 E0 E5 11 DD 00 mov dword ptr [pfun],offset foo (0DD11E5h)
21: printf("sizeof(void*)=%d\n", sizeof(void*));
00DD356C 8B F4 mov esi,esp
00DD356E 6A 04 push 4
00DD3570 68 B0 57 DD 00 push offset string "sizeof(void*)=%d\n" (0DD57B0h)
00DD3575 FF 15 B0 82 DD 00 call dword ptr [__imp__printf (0DD82B0h)]
00DD357B 83 C4 08 add esp,8
00DD357E 3B F4 cmp esi,esp
00DD3580 E8 B1 DB FF FF call @ILT+305(__RTC_CheckEsp) (0DD1136h)
22: printf("pfun=0x%x\n", pfun);
00DD3585 8B F4 mov esi,esp
00DD3587 8B 45 E0 mov eax,dword ptr [pfun]
00DD358A 50 push eax
00DD358B 68 3C 57 DD 00 push offset string "a.txt" (0DD573Ch)
00DD3590 FF 15 B0 82 DD 00 call dword ptr [__imp__printf (0DD82B0h)]
00DD3596 83 C4 08 add esp,8
00DD3599 3B F4 cmp esi,esp
00DD359B E8 96 DB FF FF call @ILT+305(__RTC_CheckEsp) (0DD1136h)
23: printf("foo() function address=0x%x\n", foo);
00DD35A0 8B F4 mov esi,esp
00DD35A2 68 E5 11 DD 00 push offset foo (0DD11E5h)
00DD35A7 68 E8 5B DD 00 push offset string "foo() function address=0x%x\n" (0DD5BE8h)
00DD35AC FF 15 B0 82 DD 00 call dword ptr [__imp__printf (0DD82B0h)]
00DD35B2 83 C4 08 add esp,8
00DD35B5 3B F4 cmp esi,esp
00DD35B7 E8 7A DB FF FF call @ILT+305(__RTC_CheckEsp) (0DD1136h)
24: printf("DoSomething() function address=0x%x\n",DoSomething);
00DD35BC 8B F4 mov esi,esp
00DD35BE 68 EA 11 DD 00 push offset DoSomething (0DD11EAh)
00DD35C3 68 74 62 DD 00 push offset string "DoSomething() function address=0"... (0DD6274h)
00DD35C8 FF 15 B0 82 DD 00 call dword ptr [__imp__printf (0DD82B0h)]
00DD35CE 83 C4 08 add esp,8
00DD35D1 3B F4 cmp esi,esp
00DD35D3 E8 5E DB FF FF call @ILT+305(__RTC_CheckEsp) (0DD1136h)
25: memset(&c,(int)DoSomething, sizeof(void*)*10);
00DD35D8 6A 28 push 28h
00DD35DA 68 EA 11 DD 00 push offset DoSomething (0DD11EAh)
00DD35DF 8D 45 F8 lea eax,[c]
00DD35E2 50 push eax
00DD35E3 E8 E9 DB FF FF call @ILT+460(_memset) (0DD11D1h)
00DD35E8 83 C4 0C add esp,0Ch
26: }
00DD35EB 52 push edx
00DD35EC 8B CD mov ecx,ebp
00DD35EE 50 push eax
00DD35EF 8D 15 10 36 DD 00 lea edx,[ (0DD3610h)]
00DD35F5 E8 88 DA FF FF call @ILT+125(@_RTC_CheckStackVars@8) (0DD1082h)
00DD35FA 58 pop eax
00DD35FB 5A pop edx
00DD35FC 5F pop edi
00DD35FD 5E pop esi
00DD35FE 5B pop ebx
00DD35FF 81 C4 E4 00 00 00 add esp,0E4h
00DD3605 3B EC cmp ebp,esp
00DD3607 E8 2A DB FF FF call @ILT+305(__RTC_CheckEsp) (0DD1136h)
00DD360C 8B E5 mov esp,ebp
00DD360E 5D pop ebp
00DD360F C3 ret
00DD3610 01 db 01h
00DD3611 00 db 00h
00DD3612 00 db 00h
00DD3613 00 db 00h
00DD3614 18 db 18h
00DD3615 36 db 36h
00DD3616 DD db ddh
00DD3617 00 db 00h
00DD3618 F8 db f8h
00DD3619 ?? db ffh
00DD361A ?? db ffh
00DD361B FF db ffh
00DD361C 04 db 04h
00DD361D 00 db 00h
00DD361E 00 db 00h
00DD361F 00 db 00h
00DD3620 24 db 24h
00DD3621 36 db 36h
00DD3622 DD db ddh
00DD3623 00 db 00h
00DD3624 63 db 63h
00DD3625 00 db 00h
--- No source file -------------------------------------------------------------
00DD3626 CC int 3
00DD3627 CC int 3
00DD3628 CC int 3
00DD3629 CC int 3
00DD362A CC int 3
00DD362B CC int 3
00DD362C CC int 3
00DD362D CC int 3
00DD362E CC int 3


...全文
401 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
Coder_Y_Jao 2012-08-06
  • 打赏
  • 举报
回复
关于EIP和10楼程序,说明下(环境还是VS2008 debug):
看下面反汇编,如果是C[2] =(int)DoSomething则会覆盖ebp处,C[3]则覆盖ebp+4处。

c[3] = (int)DoSomething; //到时会跳转至DoSomething
00AD158E mov dword ptr [ebp+4],offset DoSomething (0AD104Bh)
}


而如下代码也恰好使用了ebp+4

_asm
{
mov int ptr [_ebp], ebp;
}
retaddr_foo = (int)*(int**)(_ebp + 4);//实际上是函数退出时的最终eip


再来看下ebp+4到底是个什么东西,
首先,进入函数时会将esp保存在ebp中

013F14E0 push ebp
013F14E1 mov ebp,esp
013F14E3 sub esp,0F0h

在退出函数(平衡堆栈)前,ebp保持不变
在退出函数时,(如下代码)会将esp还原,也就是中途保存的ebp,然后将ebp出栈,
出栈后esp = esp + 4, 现在esp也就是中途的 ebp+4,
最后一句ret,实际上这里就是返回地址的赋值,将esp中的值付给eip


c[3] = (int)DoSomething; //到时会跳转至DoSomething
00E1158E mov dword ptr [ebp+4],offset DoSomething (0E1104Bh)
}
00E11595 push edx
00E11596 mov ecx,ebp
00E11598 push eax
00E11599 lea edx,[ (0E115BCh)]
00E1159F call @ILT+140(@_RTC_CheckStackVars@8) (0E11091h)
00E115A4 pop eax
00E115A5 pop edx
00E115A6 pop edi
00E115A7 pop esi
00E115A8 pop ebx
00E115A9 add esp,0F0h
00E115AF cmp ebp,esp
00E115B1 call @ILT+330(__RTC_CheckEsp) (0E1114Fh)
00E115B6 mov esp,ebp ;还原
00E115B8 pop ebp ;ebp出栈, esp自加4
00E115B9 ret ;eip = [esp]


所以结合10楼程序可以知道:
其中的(int*)(_ebp + 4)就是pop ebp之后的esp,也就是最终存放eip的地址,而
其中的(int)*(int**)(_ebp + 4)也就是函数退出时的最终eip
pcliuguangtao 2012-08-02
  • 打赏
  • 举报
回复
其实,我是想实现缓冲区溢出攻击~~
机智的呆呆 2012-08-02
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 的回复:]
你这个地方memset设置c上面栈中的内容为DoSomething的地址,会覆盖ebp的值吧,执行时会出错误的提示吧。
其实只要覆盖栈上foo返回时eip指令计数器的值为DoSomething的地址应该就可以了。这个我试了下,找不到eip存在具体什么位置。所以继续关注下。
[/Quote]
eip 里存的是一个相对位置 不是一个绝对位置~~~
Coder_Y_Jao 2012-08-02
  • 打赏
  • 举报
回复
修改下你的代码,做了个测试的,VS2008 debug环境

#include "stdafx.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>

int retaddr_foo = 0;

void DoSomething() {
printf("Enter the DoSomething() function:Hello.\n");
int i=0;
for (i=0; i<20; ++i)
printf("%d\n", i);
printf("Leave the DoSomething() function:Bye.\n");
int _ebp= 0;
_asm
{
mov int ptr [_ebp], ebp;
}
int* retaddr_addr = (int*)(_ebp + 4); //函数返回地址的地址
*retaddr_addr = retaddr_foo; //重置函数的返回地址为foo的返回地址,否则程序执行混乱
}

void foo() {
int c[1];
int _ebp = 0;
_asm
{
mov int ptr [_ebp], ebp;
}
retaddr_foo = (int)*(int**)(_ebp + 4);
int *p = (int*)&DoSomething;
void (*pfun)()=foo;
printf("sizeof(void*)=%d\n", sizeof(void*));
printf("pfun=0x%x\n", pfun);
printf("foo() function address=0x%x\n", foo);
printf("DoSomething() function address=0x%x\n",DoSomething);
//memset(&c,(int)DoSomething, sizeof(void*)*10);
c[3] = (int)DoSomething; //到时会跳转至DoSomething
}

int _tmain(int argc, _TCHAR* argv[])
{
foo();
getchar();
return 0;
}
pcliuguangtao 2012-04-26
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 的回复:]

你这个地方memset设置c上面栈中的内容为DoSomething的地址,会覆盖ebp的值吧,执行时会出错误的提示吧。
其实只要覆盖栈上foo返回时eip指令计数器的值为DoSomething的地址应该就可以了。这个我试了下,找不到eip存在具体什么位置。所以继续关注下。
[/Quote]
memset(&c,(int)DoSomething, sizeof(void*)*10);
我是修改后面的10,倍数,一点一点的尝试的结果也没有成功,继续关注
cattycat 2012-04-25
  • 打赏
  • 举报
回复
你这个地方memset设置c上面栈中的内容为DoSomething的地址,会覆盖ebp的值吧,执行时会出错误的提示吧。
其实只要覆盖栈上foo返回时eip指令计数器的值为DoSomething的地址应该就可以了。这个我试了下,找不到eip存在具体什么位置。所以继续关注下。
pcliuguangtao 2012-04-23
  • 打赏
  • 举报
回复
汇编代码里面都有函数跳转,没看出来啊
evencoming 2012-04-22
  • 打赏
  • 举报
回复
19: int *p = (int*)&DoSomething;
00DD355E C7 45 EC EA 11 DD 00 mov dword ptr [p],offset DoSomething (0DD11EAh)

也看看这里.
0DD11EAh什么的怀疑是有一些跳转,为了方便debug模式下 调试用的
evencoming 2012-04-22
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 的回复:]

00DD350E E8 D2 DC FF FF call foo (0DD11E5h)
[/Quote]
你跳转到 dd11e5看看
evencoming 2012-04-22
  • 打赏
  • 举报
回复
00DD350E E8 D2 DC FF FF call foo (0DD11E5h)
西山小月 2012-04-22
  • 打赏
  • 举报
回复
你声明一个函数指针,调用指针就行了

69,382

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧