代码逆向一寻找main函数入口.docx
- 文档编号:27799512
- 上传时间:2023-07-05
- 格式:DOCX
- 页数:11
- 大小:17.95KB
代码逆向一寻找main函数入口.docx
《代码逆向一寻找main函数入口.docx》由会员分享,可在线阅读,更多相关《代码逆向一寻找main函数入口.docx(11页珍藏版)》请在冰豆网上搜索。
代码逆向一寻找main函数入口
逆向的第一步是什么?
这要问你学习C语言的第一步是什么,很自然的,逆向的第一步当然也是大名鼎鼎“HelloWorld!
”了。
但是也不要因此就误认为这一节会很简单,如果你是第一次接触逆向的话,那么这一节还是有些难度的。
好的,让我们先写一个世界上最出名的程序:
int_tmain(intargc,_TCHAR*argv[]){printf("HelloWorld!
\r\n");
return0;}不错!
很好的开始!
然后用VS2008以Debug方式编译下,再用OllyDbg打开看看:
>JMPTest_
0.004117B0
DJMPTest_
0.00412CC0
JMP 90D._lock> JMP 32.GetProcAddress> CJMPTest_ 0. JMPTest_ 0. JMP 90D.? terminate@@YAXXZ> BJMP 90D._exit> 004110A0JMP 32.GetCurrentThreadId> 004110A5JMP 90D._initterm> 看看我们的程序停在了什么鬼地方,如果各位初学读者试图从这里就开始分析的话那真的很恐怖,相信30分钟内你的自信心将被打击到零„„ 我们都知道其实编译器在编译我们的程序前会做很多准备工作,而这些准备工作由于涉及的东西较多且每个由此编译器生成的程序都一样,因此我们不必深究,只需快速且准确的找到main函数即可。 但是这对于初学逆向的朋友来说也是最难的,下面我就教各位读者怎样突破这个障碍。 想要找到main函数,那么我们就要从C语言本身讲起,在刚刚开始学习C语言的时候我们就被不幸的告知,我们的程序中必须要包含一个名字叫做main的函数,不管你多讨厌它都必须如此,后来便成了习惯„„ 后来查查C99标准,发现“intmain(intargc,char*argv[])”与“intmain(void)”都是被接受的,然后又查查MSDN,可以清晰看到一句话“Themainandmainfunctionscantakethefollowingthreeoptionalarguments”,也就是告诉了我们main函数其实是有3个参数的,其后面的例子更是证明了这句话确实是微软写上去的: main(intargc,char*argv[],char*envp[]) 嗯,他们又在标准上较劲了,但是考虑到我们大部分程序都是用vs编译的(而且Borland的C++的参数也是如此),因此我们还是做墙头草,随大流吧„„ 004113E7MOVESP,EBP 004113E9POPEBP 004113EARETN 我们单击选择函数入口后,可以看到CPU窗格下面的信息窗格中显示如下信息: 跳转来自F 我们单击选择此信息后,点击鼠标右键,并选择【转到JMP来自F】后即可来到上层调用函数(以后我们将之称为“返回到调用”): AJMP 32.DebugBreak> FJMPTest_ 0.004113A0;我们停到这里 JMPTest_ 0.004124E0 遇到这种情况直接在返回到调用,此时来到真正调用main函数的地方: FMOVEAX,DWORDPTRDS: [417148] PUSHEAX MOVECX,DWORDPTRDS: [41714C] BPUSHECX CMOVEDX,DWORDPTRDS: [417144] PUSHEDX CALLTest_ 0.F;我们停到这里 ADDESP,0C BMOVDWORDPTRDS: [41715C],EAX CMPDWORDPTRDS: [417150],0 JNZSHORTTest_ 0. MOVEAX,DWORDPTRDS: [41715C] EPUSHEAX;/status=>0 FCALLDWORDPTRDS: [<&MSVCR 90D.exit>];\exit 通过上面的代码我们便看到了main函数的典型特征,临近exit,且有三个参数。 接下来我们要做的就是不断地重复上面的步骤,一直到找到程序入口点为止。 最后你要做的就是针对不同的版本不同城上的编译器重复上面的步骤,直到收集到你认为足够丰富的信息后结束,从此你就再也不用怕为找不到main函数而苦恼了。 1.1. 2、栈回溯法 栈回溯的方法是先找到main函数中的那个“HelloWorld”,下断点并按【F9】键运行后查看堆栈情况,我这里的堆栈情况如下: 0012FE9C7C930208ntdll.7C930208;我们停在这里 0012FEA0FFFF 0012FEA47FFDE000 0012FEA8CCCC ………… 0012FF64CCCC 0012FF68/0012FFB8 0012FF6C|返回到Test_ 0.来自Test_ 0.F 0012FF70|00001 0012FF74|003D2C60 0012FF78|003D2D40 0012FF7C|0A641DBC 0012FF80|7C930208ntdll.7C930208 0012FF84|FFFF 0012FF88|7FFDE000 0012FF8C|00369E99 0012FF90|0000 0012FF94|0000 0012FF98|001300ASCII"Actx" 0012FF9C|0000 0012FFA0|0012FF7C 0012FFA4|00020 0012FFA8|0012FFE0指向下一个SEH记录的指针 0012FFAC|DSE处理程序 0012FFB0|0A3788D4 0012FFB4|0000 0012FFB8]0012FFC0 0012FFBC|004117BF返回到Test_ 0.004117BF来自Test_ 0.004117D0 0012FFC0\0012FFF0 0012FFC47C817077返回到kernel 32.7C817077 对于这些信息我们只需要关注注释前面有“返回到”三个字的,离我们最近是: 0012FF6C|返回到Test_ 0.来自Test_ 0.F 鼠标单击选择该项后,按【Enter】键即可来到返回地址处: F.A1MOVEAX,DWORDPTRDS: [417148] .50PUSHEAX .8B0D4C714100MOVECX,DWORDPTRDS: [41714C] B.51PUSHECX C.8B15MOVEDX,DWORDPTRDS: [417144] .52PUSHEDX .E897F6FFCALLTest_ 0.F .83C40CADDESP,0C;我们停在这里 B.A35C714100MOVDWORDPTRDS: [41715C],EAX .833D>CMPDWORDPTRDS: [417150],0 .750CJNZSHORTTest_ 0. .A15C714100MOVEAX,DWORDPTRDS: [41715C] E.50PUSHEAX;/status=>0 F.FF15CALLDWORDPTRDS: [<&MSVCR 90D.exit>];\exit此时我们又来到了这个熟悉的地方,接下来的事情就要各位读者自己发挥了(重复上面的步骤)。 1.1. 3、逐步分析法 以上讲的两种方法都是在学习与知识储备时用的,不可能收到什么实战效果。 假如我们现在碰到了一个现在就需要我们分析的软件,而且它的编译环境我们以前没碰到过,这就要求我们纯手工分析并找到main函数了。 之所以将之称为逐步分析法,是因为我们不需要阅读它代码的具体含义,而是只需要以JMP与CALL为单位逐个跟进,从而根据main函数的特征判定main函数的所在位置。 其实这种方法有点类似于文件搜索,先搜索根目录、在逐层加深搜索其子目录,直到找到我们需要的东西。 那我们的程序为例,我们的OEP处就是一个JMP,因此其“根目录”也就是第一层代码里是不可能有我们的main函数了,当我们跟进这个JMP后会发现如下代码: 004117B0>\8BFFMOVEDI,EDI 004117B2/.55PUSHEBP 004117B3|.8BECMOVEBP,ESP 004117B5|.E896F8FFCALLTest_ 0. 004117BA|.E811000CALLTest_ 0.004117D0 004117BF|.5DPOPEBP 004117C0\.C3RETN 我们发现第二层代码里也没有我们的main函数,但是有两个CALL。 因此我们跟进第一个CALL中,为了节省篇幅,我在这里就不贴出代码了,我在这里并没有发现main函数,但是发现了数个JMP与CALL。 不过需要注意的是,我们一定要注意采用逐层搜索的思想,因此这里的CALL与JMP就不要再继续跟下去了,我们现在要住的是返回上一层,看看第二个CALL里是什么: 004117D0MOVEDI,EDI 004117D2PUSHEBP 004117D3MOVEBP,ESP 004117D5PUSH-2 ………… CALLTest_ 0.004110FF ………… CALLDWORDPTRDS: [<&KERNEL 32.Interlocke>;kernel 32.InterlockedCompareExchange ………… EJMPSHORTTest_ 0.D PUSH3E8;/Timeout= 1000.msCALLDWORDPTRDS: [<&KERNEL 32.Sleep>];\Sleep BJMPSHORTTest_ 0. ………… 004118EBPUSHTest_ 0.004157C8;_ 004118F0PUSH0 004118F2PUSH1F4 004118F7PUSHTest_ 0.;f 004118FCPUSH2 004118FECALLDWORDPTRDS: [<&MSVCR 90D._CrtDbgRep>;MSVCR 90D._CrtDbgReportWADDESP,14 ………… PUSH0;/NewValue=0 PUSHTest_ 0.C;|pTarget=Test_ 0.CACALLDWORDPTRDS: [<&KERNEL 32.Interlocke>;\InterlockedExchange ………… PUSHTest_ 0. ECALLTest_ 0. ADDESP,4 ………… APUSH0 CPUSH2 EPUSH0 CALLDWORDPTRDS: [417590];注意这里,虽然这个CALL也有三个参数,但是仔细分析一下我们就会发现 ;这并不是main函数,因为main函数的后两个参数是指针,这里的0与2显然 ;不符合要求。 其次他也并非是临近exit的。 PUSH1 CALLDWORDPTRDS: [<&MSVCR 90D._CrtSetChe>; FMOVEAX,DWORDPTRDS: [417148] PUSHEAX MOVECX,DWORDPTRDS: [41714C] BPUSHECX CMOVEDX,DWORDPTRDS: [417144] PUSHEDX CALLTest_ 0.F;终于来到我们熟悉的main函数里了! ADDESP,0C ………… EPUSHEAX;/status=>0 FCALLDWORDPTRDS: [<&MSVCR 90D.exit>];\exit ………… ECALLDWORDPTRDS: [<&MSVCR 90D._cexit>] ………… 004119ABJMPSHORTTest_ 0.004119FF ………… 004119B7MOVECX,DWORDPTRSS: [EBP-14] 004119BAPUSHECX 004119BBMOVEDX,DWORDPTRSS: [EBP-28] 004119BEPUSHEDX 004119BFCALLTest_ 0. 004119C4ADDESP,8 004119C7RETN;MSVCR 90D._cexit
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 代码 逆向 寻找 main 函数 入口