逆向脱壳分析基础学习笔记八 反汇编分析C语言
2021/8/7 11:35:56
本文主要是介绍逆向脱壳分析基础学习笔记八 反汇编分析C语言,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
本文为本人在大神论坛破解脱壳学习笔记之一,为本人对以往所学的回顾和总结,可能会有谬误之处,欢迎大家指出。
陆续将不断有笔记放出,希望能对想要入门的萌新有所帮助,一起进步
反汇编分析C语言
环境:VC6.0
为什么不使用Visual Studio?
Visual Studio的反汇编代码更复杂一些,如下为VS2019的空函数反汇编代码
可以看到有CheckForDebuggerJustMyCode
等一些额外的函数
为了便于理解和学习,便采用VC6.0来进行学习
空函数反汇编
#include "stdafx.h" //空函数 void function(){ } int main(int argc, char* argv[]) { //调用空函数 function(); return 0; }
我们通过反汇编来分析这段空函数
函数外部
12: function(); 00401048 call @ILT+5(function) (0040100a) 13: return 0; 0040104D xor eax,eax 14: } 0040104F pop edi 00401050 pop esi 00401051 pop ebx 00401052 add esp,40h 00401055 cmp ebp,esp 00401057 call __chkesp (004010e0) 0040105C mov esp,ebp 0040105E pop ebp 0040105F ret
函数内部
6: void function(){ 00401010 push ebp 00401011 mov ebp,esp 00401013 sub esp,40h 00401016 push ebx 00401017 push esi 00401018 push edi 00401019 lea edi,[ebp-40h] 0040101C mov ecx,10h 00401021 mov eax,0CCCCCCCCh 00401026 rep stos dword ptr [edi] 7: 8: } 00401028 pop edi 00401029 pop esi 0040102A pop ebx 0040102B mov esp,ebp 0040102D pop ebp 0040102E ret
分析函数
函数调用
00401048 call @ILT+5(function) (0040100a)
首先就是通过call来调用我们的function函数
函数内部
接着进到函数的内部
有了之前画堆栈图的经验,我们不难看出,尽管我们的函数是个空函数,但其汇编代码依然完成了以下流程:
- 提升堆栈
- 保护现场
- 初始化提升的堆栈
- 恢复现场
- 返回
提升堆栈
00401010 push ebp 00401011 mov ebp,esp 00401013 sub esp,40h
保护现场
00401016 push ebx 00401017 push esi 00401018 push edi
PS:前面的push ebp也是保护现场
初始化提升的堆栈
00401019 lea edi,[ebp-40h] 0040101C mov ecx,10h 00401021 mov eax,0CCCCCCCCh 00401026 rep stos dword ptr [edi]
恢复现场
00401028 pop edi 00401029 pop esi 0040102A pop ebx 0040102B mov esp,ebp 0040102D pop ebp
PS:这里的mov esp,ebp就是降低堆栈,与前面的提升堆栈相对应,所以也属于恢复现场的一部分
返回
0040102E ret
函数返回后
函数返回后不出意料地返回到了调用CALL地下一行语句,我们接着看
0040104D xor eax,eax
这里是将eax清零,注意到我们的语句为return 0 这里就是将eax作为返回值来传递
一般来说eax都是作为函数的返回值,但不绝对,有的函数返回值是存在内存里或其它情况,要具体情况具体分析
接着看下面的代码:
0040104F pop edi 00401050 pop esi 00401051 pop ebx
很明显,这里是在还原现场,别忘了我们的主程序main本身也是个函数,这是在还原调用main前保护的现场
接着往下走
00401052 add esp,40h 00401055 cmp ebp,esp 00401057 call __chkesp (004010e0)
这里首先是将esp减少了40h,然后比较ebp和esp,最后再调用一个chkesp函数
从名称就不难看出chkesp = check esp ,检查esp,这个函数就是用来检查堆栈是否平衡的
继续
0040105C mov esp,ebp 0040105E pop ebp
依旧是恢复现场
最后就是返回
0040105F ret
总结空函数分析
我们可以看到,即便一个空函数什么都没有做,但调用一个空函数所产生的汇编代码却不少
保护现场、恢复现场以及堆栈平衡的检查等等都没少,可谓麻雀虽小五脏俱全
简单加法函数反汇编
有了前面分析空函数的经验,我们再来分析分析一个简单的加法函数
#include "stdafx.h" int Plus(int x,int y){ return x+y; } int main(int argc, char* argv[]) { //调用加法函数 Plus(1,2); return 0; }
函数外部
16: Plus(1,2); 004010A8 push 2 004010AA push 1 004010AC call @ILT+0(Plus) (00401005) 004010B1 add esp,8 17: return 0; 004010B4 xor eax,eax 18: } 004010B6 pop edi 004010B7 pop esi 004010B8 pop ebx 004010B9 add esp,40h 004010BC cmp ebp,esp 004010BE call __chkesp (004010e0) 004010C3 mov esp,ebp 004010C5 pop ebp 004010C6 ret
函数内部
10: int Plus(int x,int y){ 00401060 push ebp 00401061 mov ebp,esp 00401063 sub esp,40h 00401066 push ebx 00401067 push esi 00401068 push edi 00401069 lea edi,[ebp-40h] 0040106C mov ecx,10h 00401071 mov eax,0CCCCCCCCh 00401076 rep stos dword ptr [edi] 11: return x+y; 00401078 mov eax,dword ptr [ebp+8] 0040107B add eax,dword ptr [ebp+0Ch] 12: } 0040107E pop edi 0040107F pop esi 00401080 pop ebx 00401081 mov esp,ebp 00401083 pop ebp 00401084 ret
分析函数
函数调用
004010A8 push 2 004010AA push 1 004010AC call @ILT+0(Plus) (00401005)
结合前面的空函数分析,我们可以明显发现这里的函数调用环节,多了两个push
就是将函数所需的参数压入堆栈,这里的参数为 2 和 1,注意压入的顺序是反着的(由调用协定决定,下篇笔记会详细说明)
函数内部
提升堆栈保护现场初始化
提升堆栈、保护现场、初始化部分和空函数如出一辙,这里就不再赘述
00401060 push ebp 00401061 mov ebp,esp 00401063 sub esp,40h 00401066 push ebx 00401067 push esi 00401068 push edi 00401069 lea edi,[ebp-40h] 0040106C mov ecx,10h 00401071 mov eax,0CCCCCCCCh 00401076 rep stos dword ptr [edi]
实际执行
00401078 mov eax,dword ptr [ebp+8] 0040107B add eax,dword ptr [ebp+0Ch]
里的[ebp+8]就是我们前面压入的参数1,[ebp+c]就是前面压入的参数2
于是这两条语句其实就是
00401078 mov eax,1 0040107B add eax,2
将1+2的结果保存到eax中(此时eax又作为函数返回值的载体)
恢复现场和返回
接下来的内容就和空函数一样了,恢复现场和返回,也不再赘述
0040107E pop edi 0040107F pop esi 00401080 pop ebx 00401081 mov esp,ebp 00401083 pop ebp 00401084 ret
函数返回后
004010B1 add esp,8 17: return 0; 004010B4 xor eax,eax 18: } 004010B6 pop edi 004010B7 pop esi 004010B8 pop ebx 004010B9 add esp,40h 004010BC cmp ebp,esp 004010BE call __chkesp (004010e0) 004010C3 mov esp,ebp 004010C5 pop ebp 004010C6 ret
函数返回后我们会发现与先前的空函数相比多了这一行代码:
004010B1 add esp,8
这里是对应我们前面压入的两个参数1和2,压入参数后esp减少了8,这里我们函数调用结束后,就不再需要之前压入的两个参数了,于是将esp恢复到压入参数前,这其实也算在恢复现场里,用来平衡堆栈
我们可以发现,这条语句是在我们call调用完毕返回后执行的平衡堆栈操作,所以这种操作也被称为堆栈外平衡
与之相对就是堆栈内平衡:即在call里面就把堆栈平衡好了
之后的代码就和空函数无异了,也不再赘述,简单的加法函数分析到这也就告一段落了
本系列逆向脱壳基础学习都在下方链接中,欢迎下载并交流沟通
逆向脱壳分析基础学习笔记八 反汇编分析C语言 - 『学习资料区』 - 大神论坛 |脱壳破解|易语言|病毒分析
版权声明:本文由 lyl610abc 原创,欢迎分享本文,转载请保留出处
这篇关于逆向脱壳分析基础学习笔记八 反汇编分析C语言的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23增量更新怎么做?-icode9专业技术文章分享
- 2024-11-23压缩包加密方案有哪些?-icode9专业技术文章分享
- 2024-11-23用shell怎么写一个开机时自动同步远程仓库的代码?-icode9专业技术文章分享
- 2024-11-23webman可以同步自己的仓库吗?-icode9专业技术文章分享
- 2024-11-23在 Webman 中怎么判断是否有某命令进程正在运行?-icode9专业技术文章分享
- 2024-11-23如何重置new Swiper?-icode9专业技术文章分享
- 2024-11-23oss直传有什么好处?-icode9专业技术文章分享
- 2024-11-23如何将oss直传封装成一个组件在其他页面调用时都可以使用?-icode9专业技术文章分享
- 2024-11-23怎么使用laravel 11在代码里获取路由列表?-icode9专业技术文章分享
- 2024-11-22怎么实现ansible playbook 备份代码中命名包含时间戳功能?-icode9专业技术文章分享