摘要:本文主要向大家介绍了C/C++知识点之如何获得C语言函数起始地址和返回地址,通过具体的内容向大家展示,希望对大家学习C/C++知识点有所帮助。
本文主要向大家介绍了C/C++知识点之如何获得C语言函数起始地址和返回地址,通过具体的内容向大家展示,希望对大家学习C/C++知识点有所帮助。
在反外挂系统中,经常会检测函数的返回地址,确认函数的返回地址在规定的范围之内,从而保证,游戏程序中的函数,不被外挂所调用。这种检查方式就涉及到一个基本的技术问题,如何获得函数的返回地址?例如下面的第一段代码:#include
{
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+频道!
您输入的评论内容中包含违禁敏感词
我知道了
请输入正确的手机号码
请输入正确的验证码
您今天的短信下发次数太多了,明天再试试吧!
我们会在第一时间安排职业规划师联系您!
您也可以联系我们的职业规划师咨询:
版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
沪公网安备 31011502005948号