Alex-protect外壳完全分析【目 标】:Alex-Protect v1.0 beta2
【工 具】:
【任 务】:
【操作平台】:
【作 者】: LOVEBOOM[DFCG][FCG][US]
【相关链接】: 看雪里,自己找找
【简要说明】: 快到圣诞节了,献上文章一篇.这个壳不算强,不过花指令到不少。【详细过程】:OD设置:打开全部异常。我先自己写了一个去花指令脚本,方便我分析。因为壳后面分检查代码,所以实际跟时可以不去掉垃圾代码的。载入程序开始我们的旅程:00438000 > 60 PUSHAD ; 保护现场00438001 E8 00000000 CALL 0043800600438006 5D POP EBP00438007 81ED 06104000 SUB EBP,00401006 ; 取BASE=37000…… ;这里有一堆垃圾,我清除了先。00438103 /E9 B3000000 JMP 004381BB ; 清完垃圾就直接到这里了……004381BB 8B85 C4244000 MOV EAX,DWORD PTR SS:[EBP+4024C4] ; 把GetProcAddress的地址放到EAX中,用于后面的比较有没有下CC断……00438266 E8 46FFFFFF CALL 004381B1 ; 这里进去就是比较有没有在相关的api上下断,第一次我们时去看看进入后:004381B1 8038 CC CMP BYTE PTR DS:[EAX],0CC ; 看到了吧,这里比较相关API的第一位是否为CC,也就是判断有没有下断004381B4 74 01 JE SHORT 004381B7 ; 如果下断了,就跳,也就over了004381B6 C3 RETN004381B7 F0:0FC7C8 LOCK CMPXCHG8B EAX 好了,知道情况后,后面的CALL 4381B1就不用再跟进去.00438310 8B85 C8244000 MOV EAX,DWORD PTR SS:[EBP+4024C8] ; 比较GetModuleHandleA有没有下断00438367 E8 45FEFFFF CALL 004381B1……00438411 8B85 CC244000 MOV EAX,DWORD PTR SS:[EBP+4024CC] ; 判断LoadLibraryA有没有下断00438417 E8 95FDFFFF CALL 004381B1 ; 同上,进去检测00438512 8B85 BC244000 MOV EAX,DWORD PTR SS:[EBP+4024BC] ; 判断MessageBoxA00438518 E8 94FCFFFF CALL 004381B1 ; 同上……004385C2 E8 35060000 CALL 00438BFC ; 这里跟进……00438CA1 8D85 25244000 LEA EAX,DWORD PTR SS:[EBP+402425]00438CA7 50 PUSH EAX00438CA8 FF95 C8244000 CALL DWORD PTR SS:[EBP+4024C8] ; 获取Kernel32的handle00438CAE 8BF8 MOV EDI,EAX ; 获取到的handle入edi00438CB0 8D9D 3D244000 LEA EBX,DWORD PTR SS:[EBP+40243D] ; 把VirtualAlloc所在的地址传递到ebx中00438CB6 53 PUSH EBX00438CB7 50 PUSH EAX ; push handle00438CB8 E8 B4030000 CALL 00439071再跟进:00439071 60 PUSHAD00439072 8B5C24 24 MOV EBX,DWORD PTR SS:[ESP+24] ; handle 入ebx0043911B 8B43 3C MOV EAX,DWORD PTR DS:[EBX+3C] ; 定位pe头004391C3 03C3 ADD EAX,EBX004391C5 8B48 7C MOV ECX,DWORD PTR DS:[EAX+7C] ; Size Export Table入ecx(6c7b)004391C8 E3 2F JECXZ SHORT 004391F9004391CA 8B68 78 MOV EBP,DWORD PTR DS:[EAX+78] ; RVA Export table导出表相对虚拟地址(262C)004391CD 03EB ADD EBP,EBX004391CF 8B4424 28 MOV EAX,DWORD PTR SS:[ESP+28]004391D3 8B00 MOV EAX,DWORD PTR DS:[EAX]004391D5 A9 0000FFFF TEST EAX,FFFF0000004391DA 51 PUSH ECX004391DB 74 21 JE SHORT 004391FE004391DD 8B55 20 MOV EDX,DWORD PTR SS:[EBP+20]004391E0 FC CLD004391E1 03D3 ADD EDX,EBX004391E3 33C0 XOR EAX,EAX004391E5 8B4D 18 MOV ECX,DWORD PTR SS:[EBP+18]004391E8 8BF3 MOV ESI,EBX004391EA 8B7C24 2C MOV EDI,DWORD PTR SS:[ESP+2C]004391EE 033482 ADD ESI,DWORD PTR DS:[EDX+EAX*4]004391F1 A6 CMPS BYTE PTR DS:[ESI],BYTE PTR ES:[EDI]004391F2 74 12 JE SHORT 00439206004391F4 40 INC EAX004391F5 49 DEC ECX004391F6 ^ 75 F0 JNZ SHORT 004391E8 ; 通过遍历的方法找到VirtualAlloc的地址004391F8 59 POP ECX004391F9 E9 7F010000 JMP 0043937D004391FE 2B45 10 SUB EAX,DWORD PTR SS:[EBP+10]00439201 E9 B5000000 JMP 004392BB……004392B2 8B55 24 MOV EDX,DWORD PTR SS:[EBP+24]004392B5 03D3 ADD EDX,EBX004392B7 0FB70442 MOVZX EAX,WORD PTR DS:[EDX+EAX*2]004392BB 3B45 14 CMP EAX,DWORD PTR SS:[EBP+14]004392BE ^ 0F83 35FFFFFF JNB 004391F9004392C4 8B55 1C MOV EDX,DWORD PTR SS:[EBP+1C]004392C7 03D3 ADD EDX,EBX004392C9 031C82 ADD EBX,DWORD PTR DS:[EDX+EAX*4]004392CC 8BC3 MOV EAX,EBX ; 获取到的地址入eax004392CE 90 NOP00439373 2BDD SUB EBX,EBP00439375 3BD9 CMP EBX,ECX00439377 ^ 0F82 7CFEFFFF JB 004391F90043937D 894424 1C MOV DWORD PTR SS:[ESP+1C],EAX ; 取出的值入[esp+c](7c809a81)00439381 61 POPAD00439382 C2 0800 RETN 8出来后我们就可以知道:CALL 00439071实际上就是 call GetProcAddress.……00438D62 E8 4AF4FFFF CALL 004381B1 ; 无聊,又进去检查有没有下断00438D67 8985 11244000 MOV DWORD PTR SS:[EBP+402411],EAX ; 取出VirtualAlloc的实际地址放到变量[EBP+402411]中00438D6D 8D9D 4A244000 LEA EBX,DWORD PTR SS:[EBP+40244A]00438D73 53 PUSH EBX ; /ProcNameOrOrdinal = "VirtualFree"00438D74 57 PUSH EDI ; |hModule = 7C800000 (kernel32)00438D75 E8 F7020000 CALL 00439071 ; \GetProcAddress……00438E1F E8 8DF3FFFF CALL 004381B1 ; 又是无聊的判断00438E24 8985 15244000 MOV DWORD PTR SS:[EBP+402415],EAX ; 取出VirtualFree地址放到变量[EBP+402415]处00438E2A 8D9D 56244000 LEA EBX,DWORD PTR SS:[EBP+402456]00438E30 53 PUSH EBX ; /ProcNameOrOrdinal = "GetstdHandle"00438E31 57 PUSH EDI ; |hModule = 7C800000 (kernel32)00438E32 E8 3A020000 CALL 00439071 ; \GetProcAddress……00438EDC E8 D0F2FFFF CALL 004381B1 ; 无聊判断00438EE1 8985 19244000 MOV DWORD PTR SS:[EBP+402419],EAX ; 取出GetStdHandle的地址放入变量[EBP+402419]处00438EE7 8D9D 63244000 LEA EBX,DWORD PTR SS:[EBP+402463]00438EED 53 PUSH EBX ; /ProcNameOrOrdinal = "CreateThread"00438EEE 57 PUSH EDI ; |hModule = 7C800000 (kernel32)00438EEF E8 7D010000 CALL 00439071 ; \GetProcAddress……00438F99 E8 13F2FFFF CALL 004381B1 ; 无聊的判断00438F9E 8985 21244000 MOV DWORD PTR SS:[EBP+402421],EAX ; 取出CreateThread的地址入变量[EBP+402421]处00438FA4 8D85 32244000 LEA EAX,DWORD PTR SS:[EBP+402432] ; 准备获取USER32.DLL中要用的API00438FAA 50 PUSH EAX ; /FileName = "user32.dll"00438FAB FF95 CC244000 CALL DWORD PTR SS:[EBP+4024CC] ; \LoadLibraryA00438FB1 8BF8 MOV EDI,EAX ; 这个作者为了"节省"代码,不用GetModuleHandleA来判断有没有加载00438FB3 8D9D 70244000 LEA EBX,DWORD PTR SS:[EBP+402470]00438FB9 53 PUSH EBX ; /ProcNameOrOrdinal = "FindWindowA"00438FBA 57 PUSH EDI ; |hModule = 77D10000 (USER32)00438FBB E8 B1000000 CALL 00439071 ; \GetProcAddress……00439065 E8 47F1FFFF CALL 004381B1 ; 又一个无聊的判断0043906A 8985 1D244000 MOV DWORD PTR SS:[EBP+40241D],EAX ; 取出FindWindowA的地址入变量[EBP+40241D]处00439070 C3 RETN ; 取完这么几个API后返回……004386BD 8D85 00104000 LEA EAX,DWORD PTR SS:[EBP+401000] ; EP(438000)入EAX004386C3 B9 85130000 MOV ECX,1385 ; 这里开始CRC前面的代码了检查范围是438000-439385(438000+1385)004386C8 E8 E7040000 CALL 00438BB4 ; 这里进去就是CRC(35FAFA4B,每次的值不同)004386CD 8DBD 31254000 LEA EDI,DWORD PTR SS:[EBP+402531] ; [EBP+402531]=439531004386D3 EB 01 JMP SHORT 004386D6……004386F7 8BC3 MOV EAX,EBX004386F9 8B8D B5234000 MOV ECX,DWORD PTR SS:[EBP+4023B5] ; 准备解压的大小(4B7)004386FF 3007 XOR BYTE PTR DS:[EDI],AL ; 从439531处开始解压下一段代码00438701 47 INC EDI00438702 49 DEC ECX00438703 ^ 75 FA JNZ SHORT 004386FF ; 没解压完继续……00438756 6A 04 PUSH 4 ; 解压完准备分配空间004388AE FF95 11244000 CALL DWORD PTR SS:[EBP+402411] ; VirtualAlloc004388B4 8985 BD234000 MOV DWORD PTR SS:[EBP+4023BD],EAX ; 申请到的空间入[EBP+4023BD](3d0000)……0012FF84 004388B4 /CALL to VirtualAlloc from alexprot.004388AE0012FF88 00000000 |Address = NULL0012FF8C 0000EF74 |Size = EF74 (61300.)0012FF90 00001000 |AllocationType = MEM_COMMIT……0043895F 8BF8 MOV EDI,EAX ; 申请到的地址放入EDI中EDI=3D000000438961 57 PUSH EDI ; 地址入栈……00438A07 8D85 31254000 LEA EAX,DWORD PTR SS:[EBP+402531] ; EAX=43953100438A0D 50 PUSH EAX ; PUSH 439531……00438AB4 E8 4FF6FFFF CALL 00438108 ; apLib解压代码00438AB9 83C4 08 ADD ESP,8……00438BB2 - FFE7 JMP EDI ; 解压完毕跳去已经解压的代码处……003D0015 E8 88130000 CALL 003D13A2 ; 这里进去看看进来首先看到的就是清除断点:003D138B 8948 04 MOV DWORD PTR DS:[EAX+4],ECX ; 开始清除断点003D138E 8948 08 MOV DWORD PTR DS:[EAX+8],ECX003D1391 8948 0C MOV DWORD PTR DS:[EAX+C],ECX003D1394 8948 10 MOV DWORD PTR DS:[EAX+10],ECX003D1397 C740 18 55010000 MOV DWORD PTR DS:[EAX+18],155003D139E 59 POP ECX003D139F 33C0 XOR EAX,EAX003D13A1 C3 RETN……返回后,分析一下就会发现CALL 003D13A2就是清除断点CALL.003D001A 6A 04 PUSH 4003D00C1 68 00100000 PUSH 1000003D00C6 8B85 A1234000 MOV EAX,DWORD PTR SS:[EBP+4023A1] ; EAX=F0003D0171 BB 4A000000 MOV EBX,4A003D0176 F7E3 MUL EBX003D0178 50 PUSH EAX ‘计算要申请空间的size003D021E 6A 00 PUSH 0003D0220 FF95 11244000 CALL DWORD PTR SS:[EBP+402411] ; VirtualAlloc003D0226 8985 A5234000 MOV DWORD PTR SS:[EBP+4023A5],EAX ; 第二次申请的空间地址3E0000入[EBP+4023A5]……0012FF78 003D0226 /CALL to VirtualAlloc from 003D02200012FF7C 00000000 |Address = NULL0012FF80 00004560 |Size = 4560 (17760.)0012FF84 00001000 |AllocationType = MEM_COMMIT ……003D02D1 8DB5 C1234000 LEA ESI,DWORD PTR SS:[EBP+4023C1] ; ESI=4393C1003D02D7 8B46 04 MOV EAX,DWORD PTR DS:[ESI+4] ; EAX=9BE8(text段的大小)003D02DA 6A 04 PUSH 4003D02DC 68 00100000 PUSH 1000003D02E1 50 PUSH EAX003D0387 6A 00 PUSH 0003D0389 FF95 11244000 CALL DWORD PTR SS:[EBP+402411] ; VirtualAlloc003D038F 8985 9D234000 MOV DWORD PTR SS:[EBP+40239D],EAX ; 第三次申请到的空间地址3F0000存放在[EBP+40239D]处……0012FF78 003D038F /CALL to VirtualAlloc from 003D03890012FF7C 00000000 |Address = NULL0012FF80 00009BE8 |Size = 9BE8 (39912.)0012FF84 00001000 |AllocationType = MEM_COMMIT……003D0395 56 PUSH ESI003D0396 8B1E MOV EBX,DWORD PTR DS:[ESI] ; Voffset 1000003D0398 039D 99234000 ADD EBX,DWORD PTR SS:[EBP+402399] ; 转为VA(401000)003D039E 50 PUSH EAX ; 刚才申请的空间入栈003D0444 53 PUSH EBX ; push Text section地址003D0445 8D8D 08114000 LEA ECX,DWORD PTR SS:[EBP+401108] ; ECX=438108003D044B FFD1 CALL ECX ; 这里进去就是ApLib解压text段003D044D 83C4 08 ADD ESP,8003D0450 8BC8 MOV ECX,EAX ; text段的大小9BE8入ECX003D0452 8B3E MOV EDI,DWORD PTR DS:[ESI] ; text段的RVA入edi……003D04F9 03BD 99234000 ADD EDI,DWORD PTR SS:[EBP+402399] ; 转换成VA(401000)003D04FF 8BB5 9D234000 MOV ESI,DWORD PTR SS:[EBP+40239D] ; 这里实际就是先申请一个空间把Text段解压数据临时到到申请空间里,完毕后,写回实际地址003D0505 F3:A4 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[>003D0507 5E POP ESI003D0508 8B85 9D234000 MOV EAX,DWORD PTR SS:[EBP+40239D]003D050E 68 00800000 PUSH 8000003D0513 6A 00 PUSH 0003D0515 50 PUSH EAX003D0516 FF95 15244000 CALL DWORD PTR SS:[EBP+402415] ; 还原出text段的数据后,释放临时空间(3F0000)……003D05C1 83C6 08 ADD ESI,8003D05C4 833E 00 CMP DWORD PTR DS:[ESI],0003D05C7 ^ 0F85 0AFDFFFF JNZ 003D02D7 ; 判断有没有解压完全部段,没有则回去继续解压003D05CD E8 D00D0000 CALL 003D13A2 ; 这里前面说是是清除断点的,所以不用跟进去003D05D2 6A 04 PUSH 4003D05D4 68 00100000 PUSH 1000003D05D9 8B85 91234000 MOV EAX,DWORD PTR SS:[EBP+402391] ; EAX=C5E003D05DF 6BC0 02 IMUL EAX,EAX,2003D0687 50 PUSH EAX ;push申请空间大小003D0688 6A 00 PUSH 0003D068A FF95 11244000 CALL DWORD PTR SS:[EBP+402411] ; VirtualAlloc……0012FF74 003D0690 /CALL to VirtualAlloc from 003D068A0012FF78 00000000 |Address = NULL0012FF7C 000018BC |Size = 18BC (6332.)0012FF80 00001000 |AllocationType = MEM_COMMIT……003D0690 8985 AD234000 MOV DWORD PTR SS:[EBP+4023AD],EAX ; 申请的空间3F0000入[EBP+4023AD]处003D0696 6A 04 PUSH 4003D0698 68 00100000 PUSH 1000003D069D 8B85 8D234000 MOV EAX,DWORD PTR SS:[EBP+40238D] ; EAX=830(申请空间大小)……003D0748 50 PUSH EAX003D0749 6A 00 PUSH 0003D074B FF95 11244000 CALL DWORD PTR SS:[EBP+402411] ; VirtualAlloc……0012FF74 003D0751 /CALL to VirtualAlloc from 003D074B0012FF78 00000000 |Address = NULL0012FF7C 00000830 |Size = 830 (2096.)0012FF80 00001000 |AllocationType = MEM_COMMIT……003D0757 8D85 00104000 LEA EAX,DWORD PTR SS:[EBP+401000] ; EP入EAX003D075D B9 85130000 MOV ECX,1385 ;要解压的大小003D0762 8D95 B41B4000 LEA EDX,DWORD PTR SS:[EBP+401BB4] ; 下一段要解压的起始地址438bb4003D0768 FFD2 CALL EDX ; 这个CALL就是计算CRC的值……003D080F 8DBD 31254000 LEA EDI,DWORD PTR SS:[EBP+402531] ; 这里又开始解压下一面的代码003D0815 03BD B5234000 ADD EDI,DWORD PTR SS:[EBP+4023B5]003D081B 33D2 XOR EDX,EDX003D081D B9 00010000 MOV ECX,100003D0822 F7F1 DIV ECX003D0824 8BDA MOV EBX,EDX003D0826 F7F1 DIV ECX003D0828 03DA ADD EBX,EDX003D082A F7F1 DIV ECX003D082C 03DA ADD EBX,EDX003D082E F7F1 DIV ECX003D0830 03DA ADD EBX,EDX003D0832 59 POP ECX003D0833 8BC3 MOV EAX,EBX003D0835 8B8D B9234000 MOV ECX,DWORD PTR SS:[EBP+4023B9]003D083B 3007 XOR BYTE PTR DS:[EDI],AL ; 这次从4399e8处开始解码003D083D 47 INC EDI003D083E 49 DEC ECX003D083F ^ 75 FA JNZ SHORT 003D083B ; 没解压完跳回去继续……003D08E6 E8 B70A0000 CALL 003D13A2 ; 又清除断点003D08EB 8B85 A9234000 MOV EAX,DWORD PTR SS:[EBP+4023A9] ; 把上面申请的地址空间920000入EAX003D08F1 8BF0 MOV ESI,EAX003D08F3 50 PUSH EAX003D08F4 8D9D 31254000 LEA EBX,DWORD PTR SS:[EBP+402531]003D08FA 039D B5234000 ADD EBX,DWORD PTR SS:[EBP+4023B5] ; 004399E8……003D09A5 53 PUSH EBX003D09A6 8D95 08114000 LEA EDX,DWORD PTR SS:[EBP+401108]003D09AC FFD2 CALL EDX ; ApLib解码003D09AE 83C4 08 ADD ESP,8003D09B1 8BBD A9234000 MOV EDI,DWORD PTR SS:[EBP+4023A9] ; 申请的空间920000入EDI003D09B7 803F C3 CMP BYTE PTR DS:[EDI],0C3 ; 判断是否开始处理相关的DLL(也就是就是否第一次处理相应的DLL中的API)003D09BA 0F85 CC000000 JNZ 003D0A8C ; 如果不是则跳003D09C0 83C7 02 ADD EDI,2003D09C3 57 PUSH EDI ; /Push "User32.dll"003D09C4 FF95 C8244000 CALL DWORD PTR SS:[EBP+4024C8] ; \GetModuleHandleA判断DLL有没有载入003D09CA 85C0 TEST EAX,EAX003D09CC 0F85 AC000000 JNZ 003D0A7E ; 如果已经加载则跳……003D0A77 57 PUSH EDI ; 如果没有载入则加载user32.dll003D0A78 FF95 CC244000 CALL DWORD PTR SS:[EBP+4024CC] ; LoadLibraryA003D0A7E 8985 7C244000 MOV DWORD PTR SS:[EBP+40247C],EAX ; hModule(77D1000.USER32.DLL)入[EBP+40247C]处003D0A84 33DB XOR EBX,EBX003D0A86 8A5F FF MOV BL,BYTE PTR DS:[EDI-1]003D0A89 03FB ADD EDI,EBX003D0A8B 47 INC EDI003D0A8C 803F C4 CMP BYTE PTR DS:[EDI],0C4 ; 对输入表的几种不同情况进行处理??003D0A8F 0F84 98010000 JE 003D0C2D ; 第一次这里没有跳,主程序没有跳。003D0A95 47 INC EDI003D0A96 57 PUSH EDI ; /PUSH "TranslateMessage"003D0A97 FFB5 7C244000 PUSH DWORD PTR SS:[EBP+40247C] ; |hModule = 77D10000 (USER32)003D0A9D FF95 C4244000 CALL DWORD PTR SS:[EBP+4024C4] ; \GetProcAddress…… 003D0B4A 8A5F FF MOV BL,BYTE PTR DS:[EDI-1] ; 加地址003D0B4D 03FB ADD EDI,EBX003D0B4F 47 INC EDI003D0B50 8A1F MOV BL,BYTE PTR DS:[EDI]003D0B52 47 INC EDI003D0B53 E9 B5000000 JMP 003D0C0D……003D0C0D 80FB 00 CMP BL,0 ; 如果BL大于0就跳003D0C10 ^ 0F87 42FFFFFF JA 003D0B58……003D0B58 50 PUSH EAX ; PUSH API(77D18bce)003D0B59 8B0F MOV ECX,DWORD PTR DS:[EDI] ; 把要写入iat的地址入ECX003D0B5B E8 62090000 CALL 003D14C2 ; 这看到这里我就猜它里面应该填充API,进去看看003D14C2 60 PUSHAD ; 进入后到这里003D14C3 8BF0 MOV ESI,EAX ; API地址入esi003D14C5 8B85 A5234000 MOV EAX,DWORD PTR SS:[EBP+4023A5] ; EAX=003E0000……003D1570 0385 B1234000 ADD EAX,DWORD PTR SS:[EBP+4023B1] ; [EBP+4023B1](4393b1)处保存放后的值,比如第一没写就是0,第二的话就是4了003D1576 894424 1C MOV DWORD PTR SS:[ESP+1C],EAX ; 这里的用意就是把API的部分放到申请的空间里,真正的IAT调用申请的地址003D157A E8 00000000 CALL 003D157F003D157F 5B POP EBX003D1580 81C3 61020000 ADD EBX,261 ; 3d157F+261=3D17E0 处临时保存API的地址003D1586 8933 MOV DWORD PTR DS:[EBX],ESI ; API临时保存到3D17E0处003D1588 8BF8 MOV EDI,EAX ; EDI=3E0000……003D162F 8BF3 MOV ESI,EBX ; 再把API存放的地址放到ESI中003D1631 81EE 38000000 SUB ESI,38003D1637 B9 4A000000 MOV ECX,4A003D163C FC CLD003D163D F3:A4 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI] ; 这里把作者自己搞的花指令先填在我们去API的代码前003D163F 8B85 A5234000 MOV EAX,DWORD PTR SS:[EBP+4023A5]003D1645 0385 B1234000 ADD EAX,DWORD PTR SS:[EBP+4023B1] ; EAX=3E0000……003D16F0 8BD8 MOV EBX,EAX ; 再把003E0000的地址放到ebx上去003D16F2 83C3 04 ADD EBX,4003D179A 8918 MOV DWORD PTR DS:[EAX],EBX003D179C 8185 B1234000 4A00>ADD DWORD PTR SS:[EBP+4023B1],4A ; 这也就是说代码指定大小为4A003D17A6 61 POPAD003D17A7 C3 RETN ;返回上去……003D0C05 8901 MOV DWORD PTR DS:[ECX],EAX ; 把加密后的地址放到IAT中,这个值是壳计算生成的.003D0C07 83C7 04 ADD EDI,4 ; 继续指向下一个要处理的API003D0C0A FECB DEC BL003D0C0C 58 POP EAX003D0C0D 80FB 00 CMP BL,0 ; 如果BL大于0就跳003D0C10 ^ 0F87 42FFFFFF JA 003D0B58003D0C16 803F C3 CMP BYTE PTR DS:[EDI],0C3 ; 到这里跟过就会发现壳是通过两个C3来判断有没有处理完当前的DLL003D0C19 ^ 0F84 A1FDFFFF JE 003D09C0 ; 判断当前DLL是否已经处理完,处理则跳去下一个DLL的api处理003D0C1F 833F 00 CMP DWORD PTR DS:[EDI],0003D0C22 0F84 DE000000 JE 003D0D06 ; 判断有没有处理完全部的API,如果处理完就跳003D0C28 ^ E9 8AFDFFFF JMP 003D09B7 ; 没处理完则回去继续好了,处理完输入表,到这里:003D0D06 E8 97060000 CALL 003D13A2 ; 处理完IAT就到这里,清除断点,不用跟进003D0D0B 8D9D 31254000 LEA EBX,DWORD PTR SS:[EBP+402531] ; EBX=439531……003D0DB6 039D B5234000 ADD EBX,DWORD PTR SS:[EBP+4023B5]003D0DBC 039D B9234000 ADD EBX,DWORD PTR SS:[EBP+4023B9] ; 00439C6D……003D0E67 8B8D 95234000 MOV ECX,DWORD PTR SS:[EBP+402395] ; ECX=A1E……003D0F12 8B85 AD234000 MOV EAX,DWORD PTR SS:[EBP+4023AD] ; EAX=3F0000003D0F18 50 PUSH EAX003D0F19 53 PUSH EBX ; 解开439c6d开始,大小为A1E的代码段003D0F1A 8D95 08114000 LEA EDX,DWORD PTR SS:[EBP+401108]003D0F20 FFD2 CALL EDX ; ApLib解压003D0F22 90 NOP……003D0FC7 83C4 08 ADD ESP,8003D0FCA 8B85 AD234000 MOV EAX,DWORD PTR SS:[EBP+4023AD] ; EAX=3F0000003D0FD0 8B9D 91234000 MOV EBX,DWORD PTR SS:[EBP+402391] ; EBX=C5E……003D107B 8BB5 85234000 MOV ESI,DWORD PTR SS:[EBP+402385] ; ESI=406B07(这个就是OEP后的第二条指令来的,第一行代码被壳抽掉了)003D1081 03C3 ADD EAX,EBX ; EAX=eax+ebx=3F0000+C5E003D1083 C600 E9 MOV BYTE PTR DS:[EAX],0E9 ; 003F0C5E处写入E9远程跳003D1086 40 INC EAX003D1087 8BCE MOV ECX,ESI ; alexprot.00406B07……003D112E 2BC8 SUB ECX,EAX ; 计算跳去OEP后第二条指令的代码的值003D1130 83E9 04 SUB ECX,4003D1133 8908 MOV DWORD PTR DS:[EAX],ECX ; 计算出来值当然要填到上面的地址了……003D11DA 8B85 AD234000 MOV EAX,DWORD PTR SS:[EBP+4023AD] ; 好了快到站了003D11E0 894424 1C MOV DWORD PTR SS:[ESP+1C],EAX ; 这里还要再玩一下,先跳去申请的3F0000的那里再跳去OEP后的第二条指令003D11E4 61 POPAD003D11E5 - FFE0 JMP EAX ; 跳去壳里,然后壳再跳去OEP后的第二条指令进入壳抽代码处一下就可以找到第一行代码。好了,分析到此结束。
输入表的处理: 我取的以下两个地址411000 开始写入数据地址410FD0 记录地址 003D0A61 /EB 11 JMP SHORT 003D0A74003D0A63 |90 NOP003D0A64 |8305 D00F4100 04 ADD DWORD PTR DS:[410FD0],4 ; 当处理不同DLL时加8(第一次自己写个地址)003D0A6B |8985 7C244000 MOV DWORD PTR SS:[EBP+40247C],EAX ; 执行原壳的代码003D0A71 |C3 RETN003D0A72 |90 NOP003D0A73 |90 NOP003D0A74 \90 NOP003D0A75 90 NOP003D0A76 90 NOP ; ---------------------------003D0A77 57 PUSH EDI ; 原壳代码003D0A78 FF95 CC244000 CALL DWORD PTR SS:[EBP+4024CC] ; ---------------------------003D0A7E E8 E1FFFFFF CALL 003D0A64 ; 这里修改Call上面的代码003D0A83 90 NOP…… 第二处就是写入输入表:003D0BEC 58 POP EAX ; 出栈003D0BED 53 PUSH EBX003D0BEE 8B1D D00F4100 MOV EBX,DWORD PTR DS:[410FD0] ; 把要写入IAT的地址放到EBX中003D0BF4 8903 MOV DWORD PTR DS:[EBX],EAX ; API写到IAT中003D0BF6 8919 MOV DWORD PTR DS:[ECX],EBX ; IAT地址写到程序调用中003D0BF8 8305 D00F4100 04 ADD DWORD PTR DS:[410FD0],4 ; 调用完毕递增003D0BFF 5B POP EBX ; EBX出栈003D0C00 90 NOP003D0C01 90 NOP003D0C02 90 NOP003D0C03 90 NOP003D0C04 90 NOP003D0C05 90 NOP ; 去除原来的代码003D0C06 90 NOP003D0C07 83C7 04 ADD EDI,4003D0C0A FECB DEC BL003D0C0C 90 NOP ; 前面已经出栈了,所以不用再出栈 附两个去花指令脚本:PatList_Alex=_alex_push01,_alex_call01 [CODE_alex_push01]S =60EB03EB03??EBFBE801000000??83C4040F318BD8EB03EB03??EBFBE801000000??83C4048BCAEB03EB03??EBFBE801000000??83C4040F312BC3EB03EB03??EBFBE801000000??83C4041BD10F3103C3EB03EB03??EBFBE801000000??83C40413D10F312BC3EB03EB03??EBFBE801000000??83C404EB05??????????EB03EB03??EBFBE801000000??83C4041BD1EB03EB03??EBFBE801000000??83C40485D275D661R =909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090 [CODE_alex_call01]S =E824000000EB01E98B44240CEB03EB03C7EBFBE801000000A883C4048380B80000000233C0EB01E9C35883C404EB03EB03C7EBFBE801000000A883C4045064FF350000000064892500000000EB01??FFFFR =909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090909090 全文完,跟完后才发现这个壳原来……:-) 圣诞节快到了,先祝大家圣诞节愉快!身体健康!
Greetz: Fly.Jingulong,yock,tDasm.David.hexer,hmimys,ahao.UFO(brother).alan(sister).all of my friends and you! By loveboom[DFCG][FCG][US]Email:bmd2chen#tom.com
本文地址:http://com.8s8s.com/it/it22386.htm