C/C++知识点之如何获得C语言函数起始地址和返回地址
小标 2018-11-13 来源 : 阅读 2548 评论 0

摘要:本文主要向大家介绍了C/C++知识点之如何获得C语言函数起始地址和返回地址,通过具体的内容向大家展示,希望对大家学习C/C++知识点有所帮助。

本文主要向大家介绍了C/C++知识点之如何获得C语言函数起始地址和返回地址,通过具体的内容向大家展示,希望对大家学习C/C++知识点有所帮助。

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

int main()
{
   getchar();
   return 0;
}     非常简单的一段程序,那么我们如何获得该函数的起始地址和返回地址呢?起始地址获取非常容易,如下:#include
int main()
{
   printf("%0x\n",main);
   getchar();
   return 0;
}那么如何获得函数的返回地址呢?这个就相对来说比较困难。我们先看第一段代码反汇编后的结果: #include
intmain()
{
009919E0  push       ebp  
009919E1  mov        ebp,esp  
009919E3  sub        esp,0C0h  
009919E9  push       ebx  
009919EA  push       esi  
009919EB  push       edi  
009919EC  lea        edi,[ebp-0C0h]  
009919F2  mov        ecx,30h  
009919F7  mov        eax,0CCCCCCCCh  
009919FC  rep stos   dword ptr es:[edi]  
   getchar();
009919FE  mov        esi,esp  
00991A00  call       dword ptr [__imp__getchar (9982B0h)] 
00991A06  cmp        esi,esp  
00991A08  call       @ILT+295(__RTC_CheckEsp) (99112Ch) 
   return 0;
00991A0D  xor        eax,eax  
}
00991A0F  pop        edi  
00991A10  pop        esi  
00991A11  pop        ebx  
00991A12  add        esp,0C0h  
00991A18  cmp        ebp,esp  
00991A1A  call       @ILT+295(__RTC_CheckEsp) (99112Ch) 
00991A1F  mov         esp,ebp 
00991A21  pop        ebp  
00991A22  ret  代码开始部分,先保存ebp的内容,然后将ESP的内容写入EBP:009919E0  push       ebp009919E1  mov        ebp,esp 汇编指令call会做两件事情,其一,将call指令后面的一条指令的地址压入栈中,无条件跳转到call指令的调用地指处,开始执行子程序。 和call指令对应的ret指令,则开始执行call指令后面的一条指令。 那么,ret指令如何知道call指令后面一条指令的地址呢?因为call指令已经将这条指令压入到了栈中,所以ret指令可以找到call指令后的一条指令的地址。 既然ret指令可以找到call的返回地址,也就是call的下一条指令的地址,那么我们也可以找到!!! main函数在执行前以及执行过程中,栈的分布如下:  通过以上几张图,我们可以清楚的看到,main函数的返回地址在[EBP+4]处。所以,获得main函数的返回地址的代码如下: #include
int main()
{
   int re_addr;
   __asm
   {
      mov eax,dword ptr [ebp+4]
      mov re_addr,eax
   }
   printf("%0X\n",re_addr);
   getchar();
   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 说明我们获得的结果正确。 对于其他函数的情况类似,下面笔者就把获得某个函数的返回值得功能,做成一个函数,提供给大家,如下: #include
 
int Get_return_addr()
{
   int re_addr;
   __asm
   {
      mov eax,dword ptr [ebp]
      mov ebx,dword ptr [eax+4]
      mov re_addr,ebx
   }
   returnre_addr;
 
}
 
int main()
{
   intre_addr=Get_return_addr();
   printf("%0X\n",re_addr);
   getchar();
   return 0;
} Get_return_add函数中,为什么会多几条汇编指令呢?大家可以自行思考。

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标编程语言C/C+频道!

本文由 @小标 发布于职坐标。未经许可,禁止转载。
喜欢 | 1 不喜欢 | 0
看完这篇文章有何感觉?已经有1人表态,100%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程