配色: 字号:
Yoda's Crypter 1.2的脱壳学习文档
2012-06-14 | 阅:  转:  |  分享 
  
Yoda''sCrypter1.2的脱壳学习文档

用PEiD查一下,是yoda''s?cryptor?1.2壳,下面OD载入,开始分析。首先是壳引导部分,功能是解密壳主体部分代码,解密完成后就将控制权交给主体代码。0040D060?Y>??60????????????????pushad???????????????????????????????????;?程序入口,载入时停在此处0040D061?????E8?00000000???????call?Yoda''s_C.0040D0660040D066?????5D????????????????pop?ebp??????????????????????????????????;?这两行是壳代码自定位0040D067?????81ED?F31D4000?????sub?ebp,Yoda''s_C.00401DF3????????????????;?计算偏移量,用于取加壳时保存的信息的重定位0040D06D?????B9?7B090000???????mov?ecx,97B??????????????????????????????;?要解密代码的字节数为97Bh0040D072?????8DBD?3B1E4000?????lea?edi,dword?ptr?ss:[ebp+401E3B]????????;?被解密代码的起始位置,解密完成全就被执行0040D078?????8BF7??????????????mov?esi,edi0040D07A??/??AC????????????????lods?byte?ptr?ds:[esi]???????????????????;?逐字节取出进行解密,以下就是解密代码0040D07B??|??2AC1??????????????sub?al,cl0040D07D??|??EB?01?????????????jmp?short?Yoda''s_C.0040D0800040D07F??|??C2?348F???????????retn?8F34????????;?C2花指令,可将C2改为90(nop)。以下几处同此。0040D080??|??34?8F?????????????xor?al,8F0040D082??|??F9????????????????stc0040D083??|??02C1??????????????add?al,cl0040D085??|??F8????????????????clc0040D086??|??34?AE?????????????xor?al,0AE0040D088??|??2C?E9?????????????sub?al,0E90040D08A??|??FEC8??????????????dec?al0040D08C??|??02C1??????????????add?al,cl0040D08E??|??FEC8??????????????dec?al0040D090??|??04?CD?????????????add?al,0CD0040D092??|??90????????????????nop0040D093??|??EB?01?????????????jmp?short?Yoda''s_C.0040D0960040D095??|??C2?2AC1???????????retn?0C12A????????;?又是C2花指令0040D096??|??2AC1??????????????sub?al,cl0040D098??|??C0C8?5E???????????ror?al,5E

0040D09B??|??FEC8??????????????dec?al0040D09D??|??2AC1??????????????sub?al,cl0040D09F??|??04?7D?????????????add?al,7D0040D0A1??|??EB?01?????????????jmp?short?Yoda''s_C.0040D0A40040D0A3??|??C2?2AC1???????????retn?0C12A????????;?依然是C2花指令0040D0A4??|??2AC1??????????????sub?al,cl0040D0A6??|??34?58?????????????xor?al,580040D0A8??|??C0C0?B1???????????rol?al,0B10040D0AB??|??AA????????????????stos?byte?ptr?es:[edi]0040D0AC??\^?E2?CC?????????????loopd?short?Yoda''s_C.0040D07A因为有代码自解密,所以会给静态调试带来干扰,但分析上面所有解密方法,可以看出都是对al进行运算,另两个参数就是cl(剩余字节数的)和edi(代码地址),如果用IDA来调试的话,也很容易能写出脚本函数来解密这段代码。解密完成后,我们在数据窗口看到被解密的末尾赫然出现了“IsDebuggerPresent”,这里埋下伏笔。以下就是解密后的代码,位置是紧接上面的代码之后,解密完成后就开始执行之。0040D0AE?????8B4424?20????????????????mov?eax,dword?ptr?ss:[esp+20]????????;?kernel32.7C8170770040D0B2?????40???????????????????????inc?eax??????????????????????????????;?程序出口点--kernel32.ExitThread0040D0B3?????78?0A????????????????????js?short?Yoda''s_C.0040D0BF0040D0B5?????C785?78254000?01000000???mov?dword?ptr?ss:[ebp+402578],1??????;?设置标志,后面会用到。0040D0BF?????8D85?ED1D4000????????????lea?eax,dword?ptr?ss:[ebp+401DED]????;?地址=0040D060,程序入口点0040D0C5?????B9?2A060000??????????????mov?ecx,62A??????????????????????????;?自校验的代码字节数0040D0CA?????E8?41020000??????????????call?Yoda''s_C.0040D310???????????????;?壳代码自校验??{??0040D310?????8BF8?????????????????????mov?edi,eax??????????????????;?从入口点0040D060起62Ah字节纳入校验??0040D312?????33C0?????????????????????xor?eax,eax??0040D314?????33DB?????????????????????xor?ebx,ebx??0040D316?????33D2?????????????????????xor?edx,edx??0040D318?????8A07?????????????????????mov?al,byte?ptr?ds:[edi]

0040D31A?????F7E2?????????????????????mul?edx??0040D31C?????03D8?????????????????????add?ebx,eax??0040D31E?????42???????????????????????inc?edx??0040D31F?????47???????????????????????inc?edi??0040D320???^?E2?F6????????????????????loopd?short?Yoda''s_C.0040D318??}这个函数校验从壳入口起62A字节,实际上第1字节不影响结果,因这它乘0还是=0。0040D0CF?????8985?74254000????????????mov?dword?ptr?ss:[ebp+402574],eax????;?保存校验和(0002494C),后面会用到。我们可以看到[ebp+402574]上下是一张信息表,其中存放了加壳前原程序的一些数据信息,如[0040D7DB]处就是存放的原程序OEP--004010CC,以及[0040D7DB]处的00400000,加壳后的程序运行时用这些数据进行一系列处理。0040D0D5?????8B85?6C254000????????????mov?eax,dword?ptr?ss:[ebp+40256C]????;?ss:[0040D7DF]=0000003C0040D0DB?????83E0?01??????????????????and?eax,10040D0DE?????74?40????????????????????je?short?Yoda''s_C.0040D120???????????;?偶数,跳0040D120?????8B85?64254000????????????mov?eax,dword?ptr?ss:[ebp+402564]????;?取ImageBaseAddress0040D126?????0340?3C??????????????????add?eax,dword?ptr?ds:[eax+3C]????????;?定位PE?Header0040D129?????05?80000000??????????????add?eax,80???????????????????????????;?取输入表数据目录0040D12E?????8B08?????????????????????mov?ecx,dword?ptr?ds:[eax]???????????;?取输入表RVA(加壳时已经被改指向壳中的新位置)0040D130?????038D?64254000????????????add?ecx,dword?ptr?ss:[ebp+402564]????;?+ImageBaseAddress定位输入表(位于壳中,只有1个IID)0040D136?????83C1?10??????????????????add?ecx,10???????????????????????????;?FirstThunk0040D139?????8B01?????????????????????mov?eax,dword?ptr?ds:[ecx]???????????;?0040D13B?????0385?64254000????????????add?eax,dword?ptr?ss:[ebp+402564]????;?函数指针0040D141?????8B18?????????????????????mov?ebx,dword?ptr?ds:[eax]???????????;?函数kernel32.LoadLibraryA地址0040D143?????899D?F0264000????????????mov?dword?ptr?ss:[ebp+4026F0],ebx????;?保存LoadLibraryA函数地址

0040D149?????83C0?04??????????????????add?eax,4????????????????????????????;?下一个函数0040D14C?????8B18?????????????????????mov?ebx,dword?ptr?ds:[eax]???????????;?kernel32.GetProcAddress0040D14E?????899D?F4264000????????????mov?dword?ptr?ss:[ebp+4026F4],ebx????;?保存GetProcAddress函数地址0040D154?????8D85?F8264000????????????lea?eax,dword?ptr?ss:[ebp+4026F8]????;?ASCII?"Kernel32.dll"0040D15A?????50???????????????????????push?eax0040D15B?????FF95?F0264000????????????call?dword?ptr?ss:[ebp+4026F0]???????;?动态调入Kernel32.dll0040D161?????8BF0?????????????????????mov?esi,eax??????????????????????????;?Kernel32.dll句柄0040D163?????8985?05274000????????????mov?dword?ptr?ss:[ebp+402705],eax????;?保存句柄0040D169?????8D85?09274000????????????lea?eax,dword?ptr?ss:[ebp+402709]????;?ASCII?"GetModuleHandleA"0040D16F?????E8?96000000??????????????call?Yoda''s_C.0040D20A???????????????;?简单封装的GetProcAddress函数。获取kernel32.GetModuleHandleA地址??{??0040D20A?????50???????????????????????push?eax??0040D20B?????56???????????????????????push?esi??0040D20C?????FF95?F4264000????????????call?dword?ptr?ss:[ebp+4026F4]?;?kernel32.GetProcAddress??}0040D174?????8985?1A274000????????????mov?dword?ptr?ss:[ebp+40271A],eax????;?保存函数地址0040D17A?????8D85?1E274000????????????lea?eax,dword?ptr?ss:[ebp+40271E]????;?ASCII?"VirtualProtect"0040D180?????E8?85000000??????????????call?Yoda''s_C.0040D20A???????????????;?获取kernel32.VirtualProtect地址0040D185?????8985?2D274000????????????mov?dword?ptr?ss:[ebp+40272D],eax????;?保存函数地址0040D18B?????8D85?31274000????????????lea?eax,dword?ptr?ss:[ebp+402731]0040D191?????E8?74000000??????????????call?Yoda''s_C.0040D20A???????????????;?获取kernel32.GetModuleFileNameA地址0040D196?????8985?44274000????????????mov?dword?ptr?ss:[ebp+402744],eax????;?保存函数地址0040D19C?????8D85?48274000????????????lea?eax,dword?ptr?ss:[ebp+402748]0040D1A2?????E8?63000000??????????????call?Yoda''s_C.0040D20A???????????????;?获取kernel32.CreateFileA地址0040D1A7?????8985?54274000????????????mov?dword?ptr?ss:[ebp+402754],eax????;?保存函数地址0040D1AD?????8D85?58274000????????????lea?eax,dword?ptr?ss:[ebp+402758]0040D1B3?????E8?52000000??????????????call?Yoda''s_C.0040D20A???????????????;?获取kernel32.GlobalAlloc地址0040D1B8?????8985?64274000????????????mov?dword?ptr?ss:[ebp+402764],eax????;?保存函数地址0040D1BE?????8D85?68274000????????????lea?eax,dword?ptr?ss:[ebp+402768]0040D1C4?????E8?41000000??????????????call?Yoda''s_C.0040D20A???????????????;?获取kernel32.GlobalFree地址0040D1C9?????8985?73274000????????????mov?dword?ptr?ss:[ebp+402773],eax????;?保存函数地址0040D1CF?????8D85?77274000????????????lea?eax,dword?ptr?ss:[ebp+402777]0040D1D5?????E8?30000000??????????????call?Yoda''s_C.0040D20A???????????????;?获取kernel32.ReadFile地址0040D1DA?????8985?80274000????????????mov?dword?ptr?ss:[ebp+402780],eax????;?保存函数地址0040D1E0?????8D85?84274000????????????lea?eax,dword?ptr?ss:[ebp+402784]0040D1E6?????E8?1F000000??????????????call?Yoda''s_C.0040D20A???????????????;?获取kernel32.GetFileSize地址0040D1EB?????8985?90274000????????????mov?dword?ptr?ss:[ebp+402790],eax????;?保存函数地址0040D1F1?????8D85?94274000????????????lea?eax,dword?ptr?ss:[ebp+402794]0040D1F7?????E8?0E000000??????????????call?Yoda''s_C.0040D20A???????????????;?获取kernel32.CloseHandle地址0040D1FC?????8985?A0274000????????????mov?dword?ptr?ss:[ebp+4027A0],eax????;?保存函数地址0040D202?????8D85?A01F4000????????????lea?eax,dword?ptr?ss:[ebp+401FA0]????;?取上面执行过的子函数之后的代码的地址(0040D213)。0040D208?????50???????????????????????push?eax0040D209?????C3???????????????????????retn?????????????????????????????????;?用push+retn的形式跳转-------------------------------------------------0040D20A?????50???????????????????????push?eax0040D20B?????56???????????????????????push?esi0040D20C?????FF95?F4264000????????????call?dword?ptr?ss:[ebp+4026F4]?????;?kernel32.GetProcAddress-------------------------------------------------上面3行就是上面执行过的子函数,这种将子函数嵌入主程序代码中并用push+retn的形式跳转的做法,下面还有几处,我不再把子函数再一一列出了,看到用push+retn的形式跳转的形式就明白下面是还有一段已调用过的子函数的。用push+retn的形式跳转到了这里:0040D213?????F785?6C254000?10000000???test?dword?ptr?ss:[ebp+40256C],10?????;?3C0040D21D?????74?37????????????????????je?short?Yoda''s_C.0040D256????????????;?不跳0040D21F?????64:FF35?30000000?????????push?dword?ptr?fs:[30]????????????????;?push+pop获得PEB首地址0040D226?????58???????????????????????pop?eax0040D227?????85C0?????????????????????test?eax,eax0040D229?????78?0F????????????????????js?short?Yoda''s_C.0040D23A????????????;?如果是windows9x就跳,NT则不跳0040D22B?????8B40?0C??????????????????mov?eax,dword?ptr?ds:[eax+C]??????????;?进程PEB的双向链表(PEB_LDR_DATA)0040D22E?????8B40?0C??????????????????mov?eax,dword?ptr?ds:[eax+C]??????????;?InLoadOrderModuleList0040D231?????C740?20?00100000?????????mov?dword?ptr?ds:[eax+20],1000????????;?修改InLoadOrderLinks.SizeOfImage大小,原为0F000,做点小手脚反脱壳0040D238?????EB?1C????????????????????jmp?short?Yoda''s_C.0040D256???????????;?跳0040D23A?????6A?00????????????????????push?00040D23C?????FF95?1A274000????????????call?dword?ptr?ss:[ebp+40271A]0040D242?????85D2?????????????????????test?edx,edx0040D244?????79?10????????????????????jns?short?Yoda''s_C.0040D2560040D246?????837A?08?FF???????????????cmp?dword?ptr?ds:[edx+8],-10040D24A?????75?0A????????????????????jnz?short?Yoda''s_C.0040D2560040D24C?????8B52?04??????????????????mov?edx,dword?ptr?ds:[edx+4]0040D24F?????C742?50?00100000?????????mov?dword?ptr?ds:[edx+50],1000

0040D256?????8BBD?64254000????????????mov?edi,dword?ptr?ss:[ebp+402564]?????;?跳到这里。ImageBaseAddress0040D25C?????037F?3C??????????????????add?edi,dword?ptr?ds:[edi+3C]?????????;?定位PE头0040D25F?????8BB5?64254000????????????mov?esi,dword?ptr?ss:[ebp+402564]?????;?ImageBaseAddress0040D265?????8B4F?54??????????????????mov?ecx,dword?ptr?ds:[edi+54]?????????;?SizeOfHeaders0040D268?????8D85?D2274000????????????lea?eax,dword?ptr?ss:[ebp+4027D2]?????;?地址=0040DA45,文件末尾的空白处。这个壳把文件末尾的空白区域作为缓冲区(暂且称为buffer吧),保存一些临时数据。0040D26E?????50???????????????????????push?eax??????????????????????????????;?lpflOldProtect0040D26F?????6A?04????????????????????push?40040D271?????51???????????????????????push?ecx??????????????????????????????;?size=10000040D272?????FFB5?64254000????????????push?dword?ptr?ss:[ebp+402564]????????;?lpAddress=004000000040D278?????FF95?2D274000????????????call?dword?ptr?ss:[ebp+40272D]????????;?kernel32.VirtualProtect。文件头内存页的只读属性改为可读写0040D27E?????F785?6C254000?08000000???test?dword?ptr?ss:[ebp+40256C],8??????;?3C0040D288?????0F84?A7000000????????????je?Yoda''s_C.0040D3350040D28E?????68?04010000??????????????push?1040040D293?????8DBD?D2274000????????????lea?edi,dword?ptr?ss:[ebp+4027D2]?????;?buffer0040D299?????57???????????????????????push?edi0040D29A?????6A?00????????????????????push?00040D29C?????FF95?44274000????????????call?dword?ptr?ss:[ebp+402744]????????;?GetModuleFileNameA。获取文件名0040D2A2?????6A?00????????????????????push?0????????????????????????????????;?hTemplateFile0040D2A4?????68?80000000??????????????push?80???????????????????????????????;?dwFlagsAndAttributes0040D2A9?????6A?03????????????????????push?3????????????????????????????????;?dwCreationDisposition

0040D2AB?????6A?00????????????????????push?0????????????????????????????????;?lpSecurityAttributes0040D2AD?????6A?01????????????????????push?1????????????????????????????????;?dwShareMode0040D2AF?????68?00000080??????????????push?80000000?????????????????????????;?dwDesiredAccess0040D2B4?????57???????????????????????push?edi??????????????????????????????;?lpFileName0040D2B5?????FF95?54274000????????????call?dword?ptr?ss:[ebp+402754]????????;?kernel32.CreateFileA,打开磁盘文件并获取文件句柄。0040D2BB?????83F8?FF??????????????????cmp?eax,-10040D2BE?????75?04????????????????????jnz?short?Yoda''s_C.0040D2C4???????????;?成功则跳0040D2C0?????33C0?????????????????????xor?eax,eax0040D2C2?????EB?71????????????????????jmp?short?Yoda''s_C.0040D3350040D2C4?????8BF8?????????????????????mov?edi,eax???????????????????????????;?打开的文件句柄0040D2C6?????6A?00????????????????????push?00040D2C8?????57???????????????????????push?edi0040D2C9?????FF95?90274000????????????call?dword?ptr?ss:[ebp+402790]????????;?GetFileSize获取文件大小0040D2CF?????83E8?05??????????????????sub?eax,5?????????????????????????????;?文件大小DA46-5=DA41字节。后面我们可以知道,DA41之后的5个字节是DA41字节的校验和(4字节)及00040D2D2?????96???????????????????????xchg?eax,esi0040D2D3?????56???????????????????????push?esi0040D2D4?????6A?40????????????????????push?400040D2D6?????FF95?64274000????????????call?dword?ptr?ss:[ebp+402764]????????;?GlobalAlloc申请一个比原文件小5字节的内存空间0040D2DC?????0BC0?????????????????????or?eax,eax

0040D2DE?????75?02????????????????????jnz?short?Yoda''s_C.0040D2E2???????????;?成功则跳0040D2E0?????EB?4A????????????????????jmp?short?Yoda''s_C.0040D32C0040D2E2?????93???????????????????????xchg?eax,ebx0040D2E3?????6A?00????????????????????push?0????????????????????????????????;?lpOverlapped0040D2E5?????8D85?D2274000????????????lea?eax,dword?ptr?ss:[ebp+4027D2]?????;?buffer,现用来存放从文件读取的字节数0040D2EB?????50???????????????????????push?eax??????????????????????????????;?lpNumberOfBytesRead0040D2EC?????56???????????????????????push?esi??????????????????????????????;?nNumberOfBytesToRead0040D2ED?????53???????????????????????push?ebx??????????????????????????????;?lpBuffer0040D2EE?????57???????????????????????push?edi??????????????????????????????;?hFile0040D2EF?????FF95?80274000????????????call?dword?ptr?ss:[ebp+402780]????????;?ReadFile读取文件0040D2F5?????8BC3?????????????????????mov?eax,ebx???????????????????????????;?lpBuffer0040D2F7?????8BCE?????????????????????mov?ecx,esi???????????????????????????;?nNumberOfBytesToRead0040D2F9?????53???????????????????????push?ebx0040D2FA?????57???????????????????????push?edi0040D2FB?????E8?10000000??????????????call?Yoda''s_C.0040D310????????????????;?读入的文件内容校验和,同前面壳代码自校验是同一函数。??{??0040D310?????8BF8?????????????????????mov?edi,eax???????????????????;?lpBuffer(共DA41字节)??0040D312?????33C0?????????????????????xor?eax,eax

0040D314?????33DB?????????????????????xor?ebx,ebx??0040D316?????33D2?????????????????????xor?edx,edx??0040D318?????8A07?????????????????????mov?al,byte?ptr?ds:[edi]??0040D31A?????F7E2?????????????????????mul?edx???????????????????????;?同样是第1个字节不影响结果??0040D31C?????03D8?????????????????????add?ebx,eax??0040D31E?????42???????????????????????inc?edx??0040D31F?????47???????????????????????inc?edi??0040D320???^?E2?F6????????????????????loopd?short?Yoda''s_C.0040D318??0040D322?????93???????????????????????xchg?eax,ebx??0040D323?????C3???????????????????????retn??}0040D300?????8985?70254000????????????mov?dword?ptr?ss:[ebp+402570],eax?????;?保存文件校验和(00504875)0040D306?????5F???????????????????????pop?edi0040D307?????5B???????????????????????pop?ebx0040D308?????8D85?B1204000????????????lea?eax,dword?ptr?ss:[ebp+4020B1]?????;?修改地址跳过上面已执行的子函数代码0040D30E?????50???????????????????????push?eax0040D30F?????C3???????????????????????retn??????????????????????????????????;?用push+retn的形式跳转跳到了这里:0040D324?????53???????????????????????push?ebx??0040D325?????FF95?73274000????????????call?dword?ptr?ss:[ebp+402773]????????;?释放内存0040D32B?????96???????????????????????xchg?eax,esi0040D32C?????50???????????????????????push?eax0040D32D?????57???????????????????????push?edi0040D32E?????FF95?A0274000????????????call?dword?ptr?ss:[ebp+4027A0]????????;?关闭打开的文件

0040D334?????58???????????????????????pop?eax0040D335?????8B85?64254000????????????mov?eax,dword?ptr?ss:[ebp+402564]?????;?ImageBaseAddress0040D33B?????BB?01000000??????????????mov?ebx,1?????????????????????????????;?区段计数器0040D340?????E8?08000000??????????????call?Yoda''s_C.0040D34D????????????????;?解密区段数据??{??0040D34D?????8BF8?????????????????????mov?edi,eax??0040D34F?????037F?3C??????????????????add?edi,dword?ptr?ds:[edi+3C]?????????;?定位PE头??0040D352?????8BF7?????????????????????mov?esi,edi??0040D354?????81C6?F8000000????????????add?esi,0F8???????????????????????????;?定位区段表??0040D35A?????33D2?????????????????????xor?edx,edx??0040D35C?????813E?72737263????????????cmp?dword?ptr?ds:[esi],63727372???????;?区段名前4个字符是否''rsrc'',是则跳过该区段,否则继续判断??0040D362?????75?05????????????????????jnz?short?Yoda''s_C.0040D369??0040D364?????E9?9E000000??????????????jmp?Yoda''s_C.0040D407??0040D369?????813E?2E727372????????????cmp?dword?ptr?ds:[esi],7273722E???????;?是否''.rsr'',是则跳过该区段,否则继续判断??0040D36F?????75?05????????????????????jnz?short?Yoda''s_C.0040D376??0040D371?????E9?91000000??????????????jmp?Yoda''s_C.0040D407??0040D376?????813E?72656C6F????????????cmp?dword?ptr?ds:[esi],6F6C6572???????;?是否''relo'',是则跳过该区段,否则继续判断??0040D37C?????75?05????????????????????jnz?short?Yoda''s_C.0040D383??0040D37E?????E9?84000000??????????????jmp?Yoda''s_C.0040D407??0040D383?????813E?2E72656C????????????cmp?dword?ptr?ds:[esi],6C65722E???????;?是否''.rel'',是则跳过该区段,否则继续判断??0040D389?????75?02????????????????????jnz?short?Yoda''s_C.0040D38D??0040D38B?????EB?7A????????????????????jmp?short?Yoda''s_C.0040D407

0040D38D?????813E?79430000????????????cmp?dword?ptr?ds:[esi],4379???????????;?是否''yC'',即yada加壳的段名标志,是则跳过该区段,否则继续判断??0040D393?????75?02????????????????????jnz?short?Yoda''s_C.0040D397??0040D395?????EB?70????????????????????jmp?short?Yoda''s_C.0040D407??0040D397?????813E?2E656461????????????cmp?dword?ptr?ds:[esi],6164652E???????;?是否''.eda'',是则跳过该区段,否则继续判断??0040D39D?????75?02????????????????????jnz?short?Yoda''s_C.0040D3A1??0040D39F?????EB?66????????????????????jmp?short?Yoda''s_C.0040D407??0040D3A1?????837E?14?00???????????????cmp?dword?ptr?ds:[esi+14],0???????????;?该区段在文件中的偏移量否为0,是则跳过该区段,否则继续判断??0040D3A5?????74?06????????????????????je?short?Yoda''s_C.0040D3AD??0040D3A7?????837E?10?00???????????????cmp?dword?ptr?ds:[esi+10],0???????????;?该区段大小是否为0,是则跳过该区段,否则解密该段??0040D3AB?????75?02????????????????????jnz?short?Yoda''s_C.0040D3AF??0040D3AD?????EB?58????????????????????jmp?short?Yoda''s_C.0040D407??0040D3AF?????60???????????????????????pushad????????????????????????????????;?保护环境,开始解密该段??0040D3B0?????8B4E?10??????????????????mov?ecx,dword?ptr?ds:[esi+10]?????????;?区段大小??0040D3B3?????0BDB?????????????????????or?ebx,ebx??0040D3B5????/75?0C????????????????????jnz?short?Yoda''s_C.0040D3C3???????????;?计数器不为0则跳??0040D3B7????|8B76?14??????????????????mov?esi,dword?ptr?ds:[esi+14]??0040D3BA????|03F0?????????????????????add?esi,eax??0040D3BC????|E8?8BF9FFFF??????????????call?Yoda''s_C.0040CD4C??0040D3C1????|EB?0A????????????????????jmp?short?Yoda''s_C.0040D3CD??0040D3C3????\8B76?0C??????????????????mov?esi,dword?ptr?ds:[esi+C]??????????;?取区段的RVA地址

?0040D3C6?????03F0?????????????????????add?esi,eax???????????????????????????;?区段的地址??0040D3C8?????E8?02000000??????????????call?Yoda''s_C.0040D3CF????????????????;?解密????{????0040D3CF?????8BFE?????????????????????mov?edi,esi???????????????????;?段起始地址????0040D3D1?????AC???????????????????????lods?byte?ptr?ds:[esi]????????;?取一个字节进行解密????0040D3D2?????90???????????????????????nop????0040D3D3?????EB?01????????????????????jmp?short?Yoda''s_C.0040D3D6????0040D3D5?????C2?348F??????????????????retn?8F34?????????????????????;?又是可恶的C2,后面的这种代码我就不列出来了????0040D3D6?????34?8F????????????????????xor?al,8F????0040D3D8?????F9???????????????????????stc????0040D3D9?????02C1?????????????????????add?al,cl????0040D3DB?????F8???????????????????????clc????0040D3DC?????34?AE????????????????????xor?al,0AE????0040D3DE?????2C?E9????????????????????sub?al,0E9????0040D3E0?????FEC8?????????????????????dec?al????0040D3E2?????02C1?????????????????????add?al,cl????0040D3E4?????FEC8?????????????????????dec?al????0040D3E6?????04?CD????????????????????add?al,0CD????0040D3E8?????90???????????????????????nop????0040D3E9?????EB?01????????????????????jmp?short?Yoda''s_C.0040D3EC????0040D3EC?????2AC1?????????????????????sub?al,cl????0040D3EE?????C0C8?5E??????????????????ror?al,5E

0040D3F1?????FEC8?????????????????????dec?al????0040D3F3?????2AC1?????????????????????sub?al,cl????0040D3F5?????04?7D????????????????????add?al,7D????0040D3F7?????EB?01????????????????????jmp?short?Yoda''s_C.0040D3FA????0040D3FA?????2AC1?????????????????????sub?al,cl????0040D3FC?????34?58????????????????????xor?al,58????0040D3FE?????C0C0?B1??????????????????rol?al,0B1????0040D401?????90???????????????????????nop????0040D402?????AA???????????????????????stos?byte?ptr?es:[edi]???????;?回写解密后的字节????0040D403???^?E2?CC????????????????????loopd?short?Yoda''s_C.0040D3D1????0040D405?????C3???????????????????????retn????}????我们可以看到,这个解密方法与壳引导代码中解密壳代码的方法是完全相同的,只不过这里封装成了函数。??0040D3CD?????EB?37????????????????????jmp?short?Yoda''s_C.0040D406??0040D406?????61???????????????????????popad?????????????????????????;?恢复环境??0040D407?????83C6?28??????????????????add?esi,28????????????????????;?处理下一区段??0040D40A?????42???????????????????????inc?edx???????????????????????;?区段计数器+1??0040D40B?????66:3B57?06???????????????cmp?dx,word?ptr?ds:[edi+6]????;?区段是否处理完毕??0040D40F???^?0F85?47FFFFFF????????????jnz?Yoda''s_C.0040D35C?????????;?否则循环处理??0040D415?????C3???????????????????????retn??}0040D345?????8D85?A3214000????????????lea?eax,dword?ptr?ss:[ebp+4021A3]?????;?取上面执行过的子函数之后的代码的地址(0040D416)。0040D34B?????50???????????????????????push?eax??????????????????????????????;?压入地址

0040D34C?????C3???????????????????????retn??????????????????????????????????;?用retn的形式跳转跳到了这里:0040D416?????8B9D?64254000????????????mov?ebx,dword?ptr?ss:[ebp+402564]?????;?信息表中取ImageBaseAddress0040D41C?????039D?68254000????????????add?ebx,dword?ptr?ss:[ebp+402568]?????;?00400000+000010CC=004010CC(OEP,这里先假装不知,因为碰到不熟悉的带壳程序时,就只能猜它可能是,它正好落在程序的代码段,到后面根据情况再确定是不是)0040D422?????C1CB?07??????????????????ror?ebx,7?????????????????????????????;?这里要做什么!注意,004010CC被加密成了98008021,更值得怀疑是OEP!先留下一个悬念0040D425?????895C24?10????????????????mov?dword?ptr?ss:[esp+10],ebx?????????;?保存在堆栈0012FFB4中,这个地址的下一个地址的内容是ntdll.KiFastSystemCallRet,这些特殊地址都要收起注意0040D429?????8D9D?99244000????????????lea?ebx,dword?ptr?ss:[ebp+402499]?????;?信息表中取什么地址?0040D70C,再留下一个悬念0040D42F?????895C24?1C????????????????mov?dword?ptr?ss:[esp+1C],ebx?????????;?保存在0012FFC0,这个地址的下一个内容是“返回到kernel32.7C817077”0040D433?????8BBD?64254000????????????mov?edi,dword?ptr?ss:[ebp+402564]?????;?信息表中取ImageBaseAddress0040D439?????037F?3C??????????????????add?edi,dword?ptr?ds:[edi+3C]?????????;?定位PE头0040D43C?????8B9F?C0000000????????????mov?ebx,dword?ptr?ds:[edi+C0]?????????;?取线程本地存储器(TLS)这又是要做什么?这几行代码令人生疑!0040D442?????83FB?00??????????????????cmp?ebx,0?????????????????????????????;?本例为0。如果非0,则指向一个IMAGE_TLS_DIRECTORY结构,TLS是程序最先开始执行的地方,比EP更早执行0040D445?????74?0F????????????????????je?short?Yoda''s_C.0040D4560040D447?????039D?64254000????????????add?ebx,dword?ptr?ss:[ebp+402564]0040D44D?????8B43?08??????????????????mov?eax,dword?ptr?ds:[ebx+8]0040D450?????C700?00000000????????????mov?dword?ptr?ds:[eax],0??????????????;?将TLS索引清0。本例中未执行到这里,因为本就是00040D456?????8B85?70254000????????????mov?eax,dword?ptr?ss:[ebp+402570]?????;?取出之前保存的文件校验和(文件大小-5字节的,00504875),晕S,隔这么远的地方来检验!0040D45C?????0BC0?????????????????????or?eax,eax0040D45E?????74?0D????????????????????je?short?Yoda''s_C.0040D46D0040D460?????3B85?CE274000????????????cmp?eax,dword?ptr?ss:[ebp+4027CE]?????;?ss:[0040DA41]=00504875,这是加壳时保存的文件校验和,在此验证文件是否被改动过0040D466?????74?05????????????????????je?short?Yoda''s_C.0040D46D0040D468?????E9?AF010000??????????????jmp?Yoda''s_C.0040D61C?????????????????;?如果改动了就game?over了下面开始处理输入表了:0040D46D?????8DB5?7C254000????????????lea?esi,dword?ptr?ss:[ebp+40257C]?????;?地址=0040D7EF,这又是什么地址?从后面的处理可以看出,这个esi处是一个变形了的输入表结构,每个结构对应一个dll,并且每个结构压缩成3个成员:第一个是成员Name,第二个FirstThunk,第三个是OriginalFirstThunk。加壳时,对Name指向的dll名称都加了密,FirstThunk指向的函数地址都被篡改。0040D473?????F785?6C254000?20000000???test?dword?ptr?ss:[ebp+40256C],20?????;?3C0040D47D?????74?49????????????????????je?short?Yoda''s_C.0040D4C80040D47F?????56???????????????????????push?esi0040D480?????8DBD?D2274000????????????lea?edi,dword?ptr?ss:[ebp+4027D2]?????;?buffer0040D486?????33C9?????????????????????xor?ecx,ecx0040D488????/EB?17????????????????????jmp?short?Yoda''s_C.0040D4A1???????????;?这个循环象是在计算API个数0040D48A????|8B56?04??????????????????mov?edx,dword?ptr?ds:[esi+4]??????????;?ds:[0040D7F3]=000063F0,这是什么地址?IAT?0040D48D????|0395?64254000????????????add?edx,dword?ptr?ss:[ebp+402564]?????;?偏移地址+ImageBaseAddress0040D493????|EB?04????????????????????jmp?short?Yoda''s_C.0040D4990040D495????|41???????????????????????inc?ecx???????????????????????????????;?计数器+10040D496????|83C2?04??????????????????add?edx,40040D499????|833A?00??????????????????cmp?dword?ptr?ds:[edx],00040D49C???^|75?F7????????????????????jnz?short?Yoda''s_C.0040D495???????????;?象是在遍历IAT0040D49E????|83C6?0C??????????????????add?esi,0C0040D4A1????\837E?04?00???????????????cmp?dword?ptr?ds:[esi+4],00040D4A5???^?75?E3????????????????????jnz?short?Yoda''s_C.0040D48A???????????;?下一个DLL?0040D4A7?????33D2?????????????????????xor?edx,edx0040D4A9?????B8?05000000??????????????mov?eax,50040D4AE?????F7E1?????????????????????mul?ecx0040D4B0?????50???????????????????????push?eax??????????????????????????????;?8Ah5=2B2h,为何要5?后面揭秘0040D4B1?????6A?00????????????????????push?00040D4B3?????FF95?64274000????????????call?dword?ptr?ss:[ebp+402764]????????;?GlobalAlloc申请内存(堆),大小为2B2h字节0040D4B9?????0BC0?????????????????????or?eax,eax????????????????????????????;?我这里申请到的堆地址=001431E00040D4BB?????75?05????????????????????jnz?short?Yoda''s_C.0040D4C2???????????;?成功则跳,失败则退出0040D4BD?????83C4?04??????????????????add?esp,40040D4C0?????61???????????????????????popad0040D4C1?????C3???????????????????????retn0040D4C2?????8907?????????????????????mov?dword?ptr?ds:[edi],eax????????????;?[edi]=[0040DA45],即保存堆地址到buffer0040D4C4?????8947?04??????????????????mov?dword?ptr?ds:[edi+4],eax??????????;?连续保存2份0040D4C7?????5E???????????????????????pop?esi???????????????????????????????;?0040D7EF,弹出变形的输入表首地址0040D4C8?????E9?42010000??????????????jmp?Yoda''s_C.0040D60F?????????????????;?跳到循环条件判断处,之间为循环体0040D4CD??/??8B1E?????????????????????mov?ebx,dword?ptr?ds:[esi]????????????;?刚刚遍历的地址,通过一轮循环后知道这是IAT的RVA0040D4CF??|??039D?64254000????????????add?ebx,dword?ptr?ss:[ebp+402564]?????;?+ImageBaseAddress,定位到IAT0040D4D5??|??8BC3?????????????????????mov?eax,ebx0040D4D7??|??E8?08000000??????????????call?Yoda''s_C.0040D4E4????????????????;?字符串解密函数。这里是将dll文件名解密??{0040D4E4?????56???????????????????????push?esi??0040D4E5?????57???????????????????????push?edi??0040D4E6?????8BF0?????????????????????mov?esi,eax??0040D4E8?????8BF8?????????????????????mov?edi,eax???????????????????;?将源地址与目标地址指向同一地址,即直接解密后覆盖??0040D4EA?????AC???????????????????????lods?byte?ptr?ds:[esi]????????;?ds:[esi]=[0040658A],注意,这个地址是在.idata段,不是在壳中??0040D4EB?????C0C8?04??????????????????ror?al,4??????????????????????;?简单地将每字节循环右移4位解密??0040D4EE?????AA???????????????????????stos?byte?ptr?es:[edi]????????;?果然与解密输入表有关,首先解密出了"SHELL32.DLL"字符串(IID的NAME成员),并回写??0040D4EF?????803F?00??????????????????cmp?byte?ptr?ds:[edi],0??0040D4F2???^?75?F6????????????????????jnz?short?Yoda''s_C.0040D4EA??0040D4F4?????5F???????????????????????pop?edi??0040D4F5?????5E???????????????????????pop?esi??0040D4F6?????C3???????????????????????retn??}0040D4DC??|??8D85?84224000????????????lea?eax,dword?ptr?ss:[ebp+402284]?????;?取上面执行过的子函数之后的代码的地址(0040D4F7)。0040D4E2??|??50???????????????????????push?eax??????????????????????????????;?压入地址0040D4E3??|??C3???????????????????????retn??????????????????????????????????;?用push+retn的形式跳转跳到了这里:0040D4F7??|??53???????????????????????push?ebx??????????????????????????????;?ASCII?"SHELL32.dll"0040D4F8??|??FF95?F0264000????????????call?dword?ptr?ss:[ebp+4026F0]????????;?LoadLibraryA调入动态库SHELL32.dll0040D4FE??|??85C0?????????????????????test?eax,eax0040D500??|??0F84?16010000????????????je?Yoda''s_C.0040D61C??????????????????;?调入失败则game?over0040D506??|??50???????????????????????push?eax0040D507??|??F785?6C254000?04000000???test?dword?ptr?ss:[ebp+40256C],4??????;?3C,若=4则不清除shell32.dll字符串,否则清除0040D511??|??74?0E????????????????????je?short?Yoda''s_C.0040D5210040D513??|??8D85?AE224000????????????lea?eax,dword?ptr?ss:[ebp+4022AE]?????;?地址=0040D5210040D519??|??50???????????????????????push?eax??????????????????????????????;?这里用push+jmp的形式调用子函数0040D51A??|??8BC3?????????????????????mov?eax,ebx???????????????????????????;?ebx=0040658A,?ASCII?"SHELL32.dll"0040D51C??|??E9?48020000??????????????jmp?Yoda''s_C.0040D769?????????????????;?跳入子函数。功能是将eax处的字符串(这里是dll文件名)擦除??{??0040D769????/EB?04????????????????????jmp?short?Yoda''s_C.0040D76F??0040D76B????|C600?00??????????????????mov?byte?ptr?ds:[eax],0??0040D76E????|40???????????????????????inc?eax??0040D76F????\8038?00??????????????????cmp?byte?ptr?ds:[eax],0???????;?把刚刚解密出来的shell32.dll字符串擦除了??0040D772???^?75?F7????????????????????jnz?short?Yoda''s_C.0040D76B??0040D774?????C3???????????????????????retn??}0040D521??|??5B???????????????????????pop?ebx???????????????????????????????;?弹出dll句柄0040D522??|??8B4E?08??????????????????mov?ecx,dword?ptr?ds:[esi+8]??????????;?从后面可以看出,这是变形输入表的OriginalFirstThunk0040D525??|??0BC9?????????????????????or?ecx,ecx0040D527??|??75?03????????????????????jnz?short?Yoda''s_C.0040D52C???????????;?不为0则进行处理,为0则找FirstThunk。本例非00040D529??|??8B4E?04??????????????????mov?ecx,dword?ptr?ds:[esi+4]??????????;?从后面可以看出,这是变形输入表的FirstThunk0040D52C??|??038D?64254000????????????add?ecx,dword?ptr?ss:[ebp+402564]?????;?RVA+ImageBaseAddress定位OriginalFirstThunk0040D532??|??8B56?04??????????????????mov?edx,dword?ptr?ds:[esi+4]??????????;?FirstThunk0040D535?????0395?64254000????????????add?edx,dword?ptr?ss:[ebp+402564]?????;?RVA+ImageBaseAddress定位0040D53B??|?/E9?C3000000??????????????jmp?Yoda''s_C.0040D603?????????????????;?这里是一个大循环0040D540??|?|F701?00000080????????????test?dword?ptr?ds:[ecx],80000000??????;?从这个特征值几乎可以确定[ecx]就是一个IMAGE_THUNK_DATA了,判断是by_NAME还是by_INDEX0040D546??|?|75?4B????????????????????jnz?short?Yoda''s_C.0040D593???????????;?若IMAGE_ORDINAL_FLAG32则转向by_Index方式处理0040D548??|?|8B01?????????????????????mov?eax,dword?ptr?ds:[ecx]????????????;?by_Name的处理0040D54A??|?|83C0?02??????????????????add?eax,2?????????????????????????????;?开始看到这里还以为是搞什么名堂,等循环了一遍才知道,eax+2是跳过IMAGE_IMPORT_BY_NAME结构的成员Hint,定位到Name成员,以解密出函数名。而这个eax来自[ecx]?,ecx来自[esi+8],因此,[esi+8]就是OriginalFirstThunk了!0040D54D??|?|0385?64254000????????????add?eax,dword?ptr?ss:[ebp+402564]?????;?RVA+ImageBaseAddress定位待解密函数名称字符串的地址0040D553??|?|50???????????????????????push?eax??????????????????????????????;?保存函数名地址0040D554??|?|E8?8BFFFFFF??????????????call?Yoda''s_C.0040D4E4????????????????;?就是前面用过的那个字符串解密函数,在这里是解密函数名??{??0040D4E4?????56???????????????????????push?esi??0040D4E5?????57???????????????????????push?edi??0040D4E6?????8BF0?????????????????????mov?esi,eax??0040D4E8?????8BF8?????????????????????mov?edi,eax??0040D4EA????/AC???????????????????????lods?byte?ptr?ds:[esi]??0040D4EB????|C0C8?04??????????????????ror?al,4??????????????????????;?简单地将每字节循环右移4位??0040D4EE????|AA???????????????????????stos?byte?ptr?es:[edi]????????;?这里将解密后的字符回写

0040D4EF????|803F?00??????????????????cmp?byte?ptr?ds:[edi],0??0040D4F2???^\75?F6????????????????????jnz?short?Yoda''s_C.0040D4EA???;?没到字符串末尾就继续解密??0040D4F4?????5F???????????????????????pop?edi??0040D4F5?????5E???????????????????????pop?esi??0040D4F6?????C3???????????????????????retn??}0040D559??|?|58???????????????????????pop?eax???????????????????????????????;?此时弹出的是解密后的函数名0040D55A??|?|8BF8?????????????????????mov?edi,eax???????????????????????????;?地址保存0040D55C??|?|52???????????????????????push?edx??????????????????????????????;?IAT待填充的地址0040D55D??|?|51???????????????????????push?ecx??????????????????????????????;?FirstThunk0040D55E??|?|50???????????????????????push?eax??????????????????????????????;?参数2:lpProcName?0040D55F??|?|53???????????????????????push?ebx??????????????????????????????;?参数1:hModule0040D560??|?|FF95?F4264000????????????call?dword?ptr?ss:[ebp+4026F4]????????;?kernel32.GetProcAddress0040D566??|?|0BC0?????????????????????or?eax,eax?0040D568??|?|75?07????????????????????jnz?short?Yoda''s_C.0040D571???????????;?成功则跳,否则game?over0040D56A??|?|59???????????????????????pop?ecx0040D56B??|?|5A???????????????????????pop?edx0040D56C??|?|E9?AB000000??????????????jmp?Yoda''s_C.0040D61C0040D571??|?|59???????????????????????pop?ecx???????????????????????????????;?FirstThunk0040D572??|?|5A???????????????????????pop?edx???????????????????????????????;?IAT待填充的地址0040D573??|?|60???????????????????????pushad0040D574??|?|F785?6C254000?04000000???test?dword?ptr?ss:[ebp+40256C],4??????;?3C0040D57E??|?|74?0E????????????????????je?short?Yoda''s_C.0040D58E0040D580??|?|8D85?1B234000????????????lea?eax,dword?ptr?ss:[ebp+40231B]?????;?取下面调用子函数后返回地址:0040D58E0040D586??|?|50???????????????????????push?eax??????????????????????????????;?用push+jmp的形式调用子函数,这里压入子程序的返回地址0040D587??|?|8BC7?????????????????????mov?eax,edi???????????????????????????;?edi=函数名地址0040D589??|?|E9?DB010000??????????????jmp?Yoda''s_C.0040D769?????????????????;?跳入子函数。功能是将eax处的字符串(这里是函数名)擦除,与上面擦除dll名字是同一函数??{??0040D769????/EB?04????????????????????jmp?short?Yoda''s_C.0040D76F??0040D76B????|C600?00??????????????????mov?byte?ptr?ds:[eax],0??0040D76E????|40???????????????????????inc?eax??0040D76F????\8038?00??????????????????cmp?byte?ptr?ds:[eax],0???????;?把刚刚解密出来的函数名称擦除了,即把IMAGE_IMPORT_BY_NAME的Name成员清0,只保留了Hint成员??0040D772???^?75?F7????????????????????jnz?short?Yoda''s_C.0040D76B??0040D774?????C3???????????????????????retn??}0040D58E??|?|61???????????????????????popad?????????????????????????????????;?调用子函数后返回到这里0040D58F??|?|8902?????????????????????mov?dword?ptr?ds:[edx],eax????????????;?填充IAT(by_Name的处理)0040D591??|?|EB?19????????????????????jmp?short?Yoda''s_C.0040D5AC???????????;?跳0040D593??|?|52???????????????????????push?edx??????????????????????????????;?by_Index的处理(本例中未执行到)0040D594??|?|51???????????????????????push?ecx0040D595??|?|8B01?????????????????????mov?eax,dword?ptr?ds:[ecx]

0040D597??|?|2D?00000080??????????????sub?eax,800000000040D59C??|?|50???????????????????????push?eax0040D59D??|?|53???????????????????????push?ebx0040D59E??|?|FF95?F4264000????????????call?dword?ptr?ss:[ebp+4026F4]????????;?kernel32.GetProcAddress0040D5A4??|?|85C0?????????????????????test?eax,eax0040D5A6??|?|74?74????????????????????je?short?Yoda''s_C.0040D61C0040D5A8??|?|59???????????????????????pop?ecx0040D5A9??|?|5A???????????????????????pop?edx0040D5AA??|?|8902?????????????????????mov?dword?ptr?ds:[edx],eax????????????;?填充IAT跳到了这里:0040D5AC??|?|F785?6C254000?20000000???test?dword?ptr?ss:[ebp+40256C],20?????;?3C两种方式分别填充IAT后都转到这里0040D5B6??|?|74?45????????????????????je?short?Yoda''s_C.0040D5FD????????????;?=20则跳到下一个0040D5B8??|?|83BD?78254000?00?????????cmp?dword?ptr?ss:[ebp+402578],0???????;?10040D5BF??|?|74?14????????????????????je?short?Yoda''s_C.0040D5D50040D5C1??|?|81FB?00000070????????????cmp?ebx,70000000??????????????????????;?dll句柄(ebx=7D590000?(shell32.7D590000))0040D5C7??|?|72?08????????????????????jb?short?Yoda''s_C.0040D5D10040D5C9??|?|81FB?FFFFFF77????????????cmp?ebx,77FFFFFF??????????????????????;?user32.wsprintfA的句柄=77D100000040D5CF?/|?|76?0E????????????????????jbe?short?Yoda''s_C.0040D5DF???????????;?user32.dll的函数在此跳0040D5D1?||/|EB?2A????????????????????jmp?short?Yoda''s_C.0040D5FD???????????;?跳0040D5D3?||||EB?0A????????????????????jmp?short?Yoda''s_C.0040D5DF0040D5D5?||||81FB?00000080????????????cmp?ebx,800000000040D5DB?||||73?02????????????????????jnb?short?Yoda''s_C.0040D5DF0040D5DD?||||EB?1E????????????????????jmp?short?Yoda''s_C.0040D5FD0040D5DF?\|||57???????????????????????push?edi??????????????????????????????;?如果我们在处理完第1个dll后在0040D619处F4自动处理完剩余dll的函数,则看不到这里的关键处理,所以要有耐心,把隐藏在中间的步骤看清楚。

0040D5E0??|||56???????????????????????push?esi0040D5E1??|||8DBD?D2274000????????????lea?edi,dword?ptr?ss:[ebp+4027D2]?????;?地址=0040DA45,buffer,此时保存的是堆地址0040D5E7??|||8B77?04??????????????????mov?esi,dword?ptr?ds:[edi+4]??????????;?buffer+4处是前面保存的第2份堆地址001431E00040D5EA??|||8932?????????????????????mov?dword?ptr?ds:[edx],esi????????????;?将刚刚填充的函数地址又改为申请的堆地址0040D5EC??|||2BC6?????????????????????sub?eax,esi???????????????????????????;?从下面几行得知此2句sub是计算跳转的相对距离0040D5EE??|||83E8?05??????????????????sub?eax,5?????????????????????????????;?-5是因为jmp指令E9XXXXXXXX本身占5字节0040D5F1??|||C606?E9??????????????????mov?byte?ptr?ds:[esi],0E9?????????????;?前面申请的堆在这里派上用场。0E9是jmp指令0040D5F4??|||8946?01??????????????????mov?dword?ptr?ds:[esi+1],eax??????????;?填上jmp的目标地址(相对距离)。对IAT做手脚,这样,调用函数就成了对堆中某地址的调用,而堆中的该地址是5个字节的jmp指令到正确的函数地址。0040D5F7??|||8347?04?05???????????????add?dword?ptr?ds:[edi+4],5????????????;?buffer+4处的内容改为指向堆地址第6字节处,即堆中已填充jmp指令的后面,准备下一轮填充下一个函数的jmp指令,这样循环后移填充直到所有函数处理完毕。这里就明白了前面为什么申请的堆空间大小=API个数5字节。实际上没用完,因为已经有部分函数地址被正确填充到了IAT,这里填充的只是函数地址位于70000000和77FFFFFF之间的函数。0040D5FB??|||5E???????????????????????pop?esi0040D5FC??|||5F???????????????????????pop?edi0040D5FD??|\|83C1?04??????????????????add?ecx,4?????????????????????????????;?现在可以知道是取下一个函数指针0040D600??|?|83C2?04??????????????????add?edx,4?????????????????????????????;?IAT下移一项0040D603??|?\8339?00??????????????????cmp?dword?ptr?ds:[ecx],0??????????????;?函数指针是否为空0040D606??|^?0F85?34FFFFFF????????????jnz?Yoda''s_C.0040D540?????????????????;?不为空就继续循环处理0040D60C??|??83C6?0C??????????????????add?esi,0C????????????????????????????;?否则取下一个IID0040D60F??|??837E?04?00???????????????cmp?dword?ptr?ds:[esi+4],0????????????;?输入表是否已到末尾0040D613??\^?0F85?B4FEFFFF????????????jnz?Yoda''s_C.0040D4CD?????????????????;?否,则返回去继续处理下一个dll的函数0040D619?????33C0?????????????????????xor?eax,eax0040D61B?????40???????????????????????inc?eax0040D61C?????83F8?01??????????????????cmp?eax,1?????????????????????????????;?正常填充完毕eax才等于10040D61F?????74?02????????????????????je?short?Yoda''s_C.0040D623????????????;?正常填充完毕则跳0040D621?????61???????????????????????popad0040D622?????C3???????????????????????retn??????????????????????????????????;?否则game?over以上代码完成了IAT填充,开始进行下一步工作跳到了这里:0040D623?????F785?6C254000?02000000???test?dword?ptr?ss:[ebp+40256C],2??????;?3C0040D62D????/74?18????????????????????je?short?Yoda''s_C.0040D647????????????;?跳0040D62F????|8BBD?64254000????????????mov?edi,dword?ptr?ss:[ebp+402564]0040D635????|037F?3C??????????????????add?edi,dword?ptr?ds:[edi+3C]0040D638????|8B4F?54??????????????????mov?ecx,dword?ptr?ds:[edi+54]0040D63B????|8BB5?64254000????????????mov?esi,dword?ptr?ss:[ebp+402564]0040D641????|C606?00??????????????????mov?byte?ptr?ds:[esi],00040D644????|46???????????????????????inc?esi0040D645???^|E2?FA????????????????????loopd?short?Yoda''s_C.0040D6410040D647????\8D85?ED1D4000????????????lea?eax,dword?ptr?ss:[ebp+401DED]?????;?地址=0040D060?(offset?Yoda''s_C.)0040D64D?????B9?2A060000??????????????mov?ecx,62A0040D652?????EB?01????????????????????jmp?short?Yoda''s_C.0040D655???????????;?跳0040D654???-?E9?E8B6FCFF??????????????jmp?003D8D41??????????????????????????;?这次没用C2而是用E9花了

献花(0)
+1
(本文系红人会首藏)