【博文推荐】如何获得C语言函数起始地址和返回地址

 本博文出自博客gmxydm 博主,有任何问题请进入博主页面互动讨论!
博文地址:http://5412097.blog./5402097/1641374
 

在反外挂系统中,经常会检测函数的返回地址,确认函数的返回地址在规定的范围之内,从而保证,游戏程序中的函数,不被外挂所调用。这种检查方式就涉及到一个基本的技术问题,如何获得函数的返回地址?

10年积累的成都做网站、网站建设经验,可以快速应对客户对网站的新想法和需求。提供各种问题对应的解决方案。让选择我们的客户得到更好、更有力的网络服务。我虽然不认识你,你也不认识我。但先网站策划后付款的网站建设流程,更有茂名免费网站建设让你可以放心的选择与我们合作。

例如下面的***段代码:

 
 
  1. #include 
  2. int main() 
  3. getchar(); 
  4. return 0; 

非常简单的一段程序,那么我们如何获得该函数的起始地址和返回地址呢?起始地址获取非常容易,如下:

 
 
  1. #include 
  2. int main() 
  3. printf("%0x\n",main); 
  4. getchar(); 
  5. return 0; 

那么如何获得函数的返回地址呢?这个就相对来说比较困难。我们先看***段代码反汇编后的结果:

 
 
  1. #include 
  2. intmain() 
  3. 009919E0 push ebp 
  4. 009919E1 mov ebp,esp 
  5. 009919E3 sub esp,0C0h 
  6. 009919E9 push ebx 
  7. 009919EA push esi 
  8. 009919EB push edi 
  9. 009919EC lea edi,[ebp-0C0h] 
  10. 009919F2 mov ecx,30h 
  11. 009919F7 mov eax,0CCCCCCCCh 
  12. 009919FC rep stos dword ptr es:[edi] 
  13. getchar(); 
  14. 009919FE mov esi,esp 
  15. 00991A00 call dword ptr [__imp__getchar (9982B0h)] 
  16. 00991A06 cmp esi,esp 
  17. 00991A08 call @ILT+295(__RTC_CheckEsp) (99112Ch) 
  18. return 0; 
  19. 00991A0D xor eax,eax 
  20. 00991A0F pop edi 
  21. 00991A10 pop esi 
  22. 00991A11 pop ebx 
  23. 00991A12 add esp,0C0h 
  24. 00991A18 cmp ebp,esp 
  25. 00991A1A call @ILT+295(__RTC_CheckEsp) (99112Ch) 
  26. 00991A1F mov esp,ebp 
  27. 00991A21 pop ebp 
  28. 00991A22 ret

代码开始部分,先保存ebp的内容,然后将ESP的内容写入EBP:

 
 
  1. 009919E0 push ebp 
  2.  
  3. 009919E1 mov ebp,esp 

汇编指令call会做两件事情,其一,将call指令后面的一条指令的地址压入栈中,无条件跳转到call指令的调用地指处,开始执行子程序。

和call指令对应的ret指令,则开始执行call指令后面的一条指令。

那么,ret指令如何知道call指令后面一条指令的地址呢?因为call指令已经将这条指令压入到了栈中,所以ret指令可以找到call指令后的一条指令的地址。

既然ret指令可以找到call的返回地址,也就是call的下一条指令的地址,那么我们也可以找到!!!

main函数在执行前以及执行过程中,栈的分布如下:

通过以上几张图,我们可以清楚的看到,main函数的返回地址在[EBP+4]处。所以,获得main函数的返回地址的代码如下:

 
 
  1. #include 
  2. int main() 
  3. int re_addr; 
  4. __asm 
  5. mov eax,dword ptr [ebp+4] 
  6. mov re_addr,eax 
  7. printf("%0X\n",re_addr); 
  8. getchar(); 
  9. return 0; 

其中__tmainCRTStartup()函数调用了main函数,调用的汇编代码如下:

mainret = main(argc, argv, envp);

00B81926  mov        eax,dword ptr [envp (0B87140h)] 

00B8192B  push       eax 

00B8192C  mov        ecx,dword ptr [argv (0B87144h)] 

00B81932  push       ecx 

00B81933  mov        edx,dword ptr [argc (0B8713Ch)] 

00B81939  push       edx 

00B8193A call        @ILT+300(_main)(0B81131h) 

00B8193F  add        esp,0Ch 

00B81942  mov        dword ptr [mainret (0B87154h)],eax

可以看出,call main指令后的一条指令的地址为:00B8193F,而我们获得的main的返回地址如下:

B8193F

说明我们获得的结果正确。

对于其他函数的情况类似,下面笔者就把获得某个函数的返回值得功能,做成一个函数,提供给大家,如下:

 
 
  1. #include 
  2.  
  3. int Get_return_addr() 
  4. int re_addr; 
  5. __asm 
  6. mov eax,dword ptr [ebp] 
  7. mov ebx,dword ptr [eax+4] 
  8. mov re_addr,ebx 
  9. returnre_addr; 
  10.  
  11.  
  12. int main() 
  13. intre_addr=Get_return_addr(); 
  14. printf("%0X\n",re_addr); 
  15. getchar(); 
  16. return 0; 

Get_return_add函数中,为什么会多几条汇编指令呢?大家可以自行思考。

分享标题:【博文推荐】如何获得C语言函数起始地址和返回地址
文章URL:http://www.shufengxianlan.com/qtweb/news15/156215.html

网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联