【文章作者】: [UnPacKcN]XuZhenG
【作者邮箱】: xuzheng1111@126.com
【作者主页】: http://hi.baidu.com/xuzheng1111
http://xz.osa.pl
http://xz.bee.pl
【软件名称】: RLPacK Full Protection 1.21
【下载地址】: 自己去UnPacKcN下载
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
如有人将此用入商业用途,给作者造成损失本人概不负责。
--------------------------------------------------------------------------------
【详细过程】
上次在壳狂下载了性价比很高的壳哈...
RLPacK全保护,既然ASPr TMD 和穿山甲 被壳狂的高手 玩得乱转...
我们菜鸟捡个漏...
捏个软柿子...
OD载入
F9第一次运行,状态栏提示Terminated 试了N个调试器隐藏插件和N个OD都不行...
那怎么办呢?那只能Step往下走了...
大胆得往前走啊,往前走,莫回头~~~~~~~~~~
不好意思,献丑了,言归正传...
入口如下:
代码:
01001000 > $ /EB 06 jmp short 复件_cal.01001008 01001002 . |68 2EA80000 push 0A82E 01001007 . |C3 retn 01001008 > \9C pushfd 01001009 . 60 pushad 0100100A . E8 02000000 call 复件_cal.01001011 0100100F . 33C0 xor eax,eax 01001011 $ 8BC4 mov eax,esp 01001013 . 83C0 04 add eax,4 01001016 . 93 xchg eax,ebx 01001017 . 8BE3 mov esp,ebx 01001019 . 8B5B FC mov ebx,dword ptr ds:[ebx-4] 0100101C . 81EB 3F904000 sub ebx,40903F 01001022 . 61 popad 01001023 . 9D popfd 01001024 .- E9 D3B50200 jmp 复件_cal.0102C5FC
一路狂F7,过JMP后到了这里
代码:
0102C5FC 60 pushad 0102C5FD E8 00000000 call 复件_cal.0102C602 0102C602 83C4 04 add esp,4 0102C605 8B6C24 FC mov ebp,dword ptr ss:[esp-4] 0102C609 E8 8B020000 call 复件_cal.0102C899 0102C60E E8 74240000 call 复件_cal.0102EA87 0102C613 E8 88430000 call 复件_cal.010309A0 0102C618 837C24 28 01 cmp dword ptr ss:[esp+28],1 0102C61D 75 0C jnz short 复件_cal.0102C62B 0102C61F 8B4424 24 mov eax,dword ptr ss:[esp+24] 0102C623 8985 7E470000 mov dword ptr ss:[ebp+477E],eax 0102C629 EB 0C jmp short 复件_cal.0102C637 0102C62B 8B85 7A470000 mov eax,dword ptr ss:[ebp+477A] 0102C631 8985 7E470000 mov dword ptr ss:[ebp+477E],eax 0102C637 E8 100D0000 call 复件_cal.0102D34C 0102C63C E8 6F240000 call 复件_cal.0102EAB0 0102C641 E8 1F230000 call 复件_cal.0102E965 ;Anti1 0102C646 8DB5 AD530000 lea esi,dword ptr ss:[ebp+53AD] 0102C64C 8D9D 17030000 lea ebx,dword ptr ss:[ebp+317] 0102C652 33FF xor edi,edi 0102C654 E8 3B3D0000 call 复件_cal.01030394 ;检测调试器Call
Anti1: 这个Anti很容易过哈,很简单,把下面有注释的那一行Nop掉就可以...
代码:
0102E965 60 pushad 0102E966 81BD C2470000 0>cmp dword ptr ss:[ebp+47C2],ABBC680> 0102E970 75 11 jnz short 复件_cal.0102E983 省略一部分代码 0102E9CA 64:8925 0000000>mov dword ptr fs:[0],esp 0102E9D1 33C0 xor eax,eax 0102E9D3 8700 xchg dword ptr ds:[eax],eax ; Anti-Exchange 0 and ???????? Please Nop it And Step Over it Easily. 0102E9D5 64:8F05 0000000>pop dword ptr fs:[0] 0102E9DC 83C4 04 add esp,4 0102E9DF 61 popad 0102E9E0 C3 retn
代码:
01030394 60 pushad 01030395 E8 4D030000 call 复件_cal.010306E7 ; 镜像大小+3000 使加载出错... NOP掉 这就是为什么天草大哥要教育我们要修正镜 像大小 0103039A E8 FB020000 call 复件_cal.0103069A ; 抹除PE头 NOp掉 0103039F E8 AC030000 call 复件_cal.01030750 ; 这个Call用Kernel32.DLL基址回写堆栈中的程序基址 010303A4 8985 A2470000 mov dword ptr ss:[ebp+47A2],eax 010303AA 6A 40 push 40 010303AC 68 00100000 push 1000 010303B1 68 00100000 push 1000 010303B6 6A 00 push 0 010303B8 FF95 FD030000 call dword ptr ss:[ebp+3FD] ; VirtualAlloc申请空间 010303BE 8985 3B4A0000 mov dword ptr ss:[ebp+4A3B],eax 010303C4 8D9D 114A0000 lea ebx,dword ptr ss:[ebp+4A11] 010303CA BE 05000000 mov esi,5 010303CF EB 29 jmp short 复件_cal.010303FA 010303D1 FF33 push dword ptr ds:[ebx] ; /这个循环的作用是读取一部分壳的输入表其中有几个Anti函数 包括CreateFileA IsDebuggerPresent 和CheckRemoteDebuggerPresent 010303D3 FFB5 A2470000 push dword ptr ss:[ebp+47A2] 010303D9 E8 28050000 call 复件_cal.01030906 010303DE 0BC0 or eax,eax ; 此处Eax存放函数指针 010303E0 74 14 je short 复件_cal.010303F6 010303E2 FF30 push dword ptr ds:[eax] 010303E4 59 pop ecx 010303E5 80F9 CC cmp cl,0CC 010303E8 75 0A jnz short 复件_cal.010303F4 010303EA C785 434A0000 0>mov dword ptr ss:[ebp+4A43],1 010303F4 8903 mov dword ptr ds:[ebx],eax 010303F6 83C3 04 add ebx,4 010303F9 4E dec esi 010303FA 83FE 00 cmp esi,0 010303FD ^ 77 D2 ja short 复件_cal.010303D1 ; \循环结束 010303FF 83BD 434A0000 0>cmp dword ptr ss:[ebp+4A43],1 ; 判断是否已经检测出调试器 01030406 0F84 57010000 je 复件_cal.01030563 0103040C C785 4F4A0000 9>mov dword ptr ss:[ebp+4A4F],94 01030416 8D85 4F4A0000 lea eax,dword ptr ss:[ebp+4A4F] 0103041C 50 push eax 0103041D FF95 194A0000 call dword ptr ss:[ebp+4A19] ; 获得系统版本 并写入ebp+4A19 01030423 83BD 5F4A0000 0>cmp dword ptr ss:[ebp+4A5F],1 0103042A 74 19 je short 复件_cal.01030445 0103042C 83BD 114A0000 0>cmp dword ptr ss:[ebp+4A11],0 01030433 74 10 je short 复件_cal.01030445 ; 检测是否已经成功读取IsDebuggerPresent 01030435 FF95 114A0000 call dword ptr ss:[ebp+4A11] ; 调用IsDebuggerPresent判断是否有除Ring0之外调试器 0103043B 0BC0 or eax,eax ; 有则返回1 无则返回0(eax) 0103043D 74 06 je short 复件_cal.01030445 0103043F 8985 434A0000 mov dword ptr ss:[ebp+4A43],eax 01030445 83BD 5F4A0000 0>cmp dword ptr ss:[ebp+4A5F],2 ; 判断系统版本是否为NT/2K 0103044C 75 38 jnz short 复件_cal.01030486 0103044E 81BD 154A0000 7>cmp dword ptr ss:[ebp+4A15],6D3A8272 01030458 74 27 je short 复件_cal.01030481 0103045A 8D85 474A0000 lea eax,dword ptr ss:[ebp+4A47] 01030460 50 push eax 01030461 6A FF push -1 01030463 FF95 154A0000 call dword ptr ss:[ebp+4A15] ; 调用CheckRemoteDebuggerPresent判断是否有调试器 01030469 8B85 154A0000 mov eax,dword ptr ss:[ebp+4A15] 0103046F 8138 8B442408 cmp dword ptr ds:[eax],824448B 01030475 75 0A jnz short 复件_cal.01030481 ; 如果有调试器,则不跳转 赋值ebp+4A47为1代表已有调试器,以后会有判断并Anti 01030477 C785 474A0000 0>mov dword ptr ss:[ebp+4A47],1 01030481 E8 62FDFFFF call 复件_cal.010301E8 01030486 FFB5 254A0000 push dword ptr ss:[ebp+4A25] 0103048C FFB5 A6470000 push dword ptr ss:[ebp+47A6] 01030492 E8 6F040000 call 复件_cal.01030906 01030497 EB 03 jmp short 复件_cal.0103049C 01030499 FE ??? ; 未知命令 0103049A FFFF ??? ; 未知命令 0103049C 8D9D 294A0000 lea ebx,dword ptr ss:[ebp+4A29] ; 取"OLLYDBG"字符串 010304A2 6A 00 push 0 010304A4 53 push ebx 010304A5 FFD0 call eax ; 调用FindWindowA找OLLYDBG窗口(本人用修改版OD哈哈) 010304A7 0BC0 or eax,eax ; 有则返回句柄,无则返回0(eax) 010304A9 74 0A je short 复件_cal.010304B5 010304AB C785 434A0000 0>mov dword ptr ss:[ebp+4A43],1 ; 如果有,则赋值ebp+4A43为1 以后有Anti判断,虽然用了修改版OD,但是还是被发现了,不知为何 010304B5 33DB xor ebx,ebx 010304B7 68 50D4AC0C push 0CACD450 010304BC FFB5 A6470000 push dword ptr ss:[ebp+47A6] 010304C2 E8 3F040000 call 复件_cal.01030906 010304C7 FFD0 call eax ; 调用GetForeGroundWindow获取当前工作窗口的句柄 010304C9 8BF0 mov esi,eax 010304CB 68 0A10299C push 9C29100A 010304D0 FFB5 A6470000 push dword ptr ss:[ebp+47A6] 010304D6 E8 2B040000 call 复件_cal.01030906 010304DB 68 00100000 push 1000 010304E0 FFB5 3B4A0000 push dword ptr ss:[ebp+4A3B] 010304E6 56 push esi 010304E7 FFD0 call eax ; 获取窗口类名 GetWindowTextA :中间略去一部分...: 01030531 6A 00 push 0 01030533 68 80000000 push 80 01030538 6A 03 push 3 0103053A 6A 00 push 0 0103053C 6A 01 push 1 0103053E 68 00000080 push 80000000 01030543 57 push edi 01030544 FF95 1D4A0000 call dword ptr ss:[ebp+4A1D] ; 此处调用CreateFileA找寻Services 判断是否有调试器服务 0103054A 83F8 FF cmp eax,-1 0103054D 74 0A je short 复件_cal.01030559 0103054F C785 434A0000 0>mov dword ptr ss:[ebp+4A43],1 01030559 47 inc edi 0103055A 803F 00 cmp byte ptr ds:[edi],0 0103055D ^ 75 FA jnz short 复件_cal.01030559 0103055F 47 inc edi 01030560 4E dec esi 01030561 ^ 75 CE jnz short 复件_cal.01030531 ; 循环判断是否有调试器服务 01030563 FF85 3F4A0000 inc dword ptr ss:[ebp+4A3F] 01030569 68 00400000 push 4000 0103056E 68 00100000 push 1000 01030573 FFB5 3B4A0000 push dword ptr ss:[ebp+4A3B] 01030579 FF95 05040000 call dword ptr ss:[ebp+405] 0103057F 61 popad 01030580 C3 retn
咱们看那个邪恶的修改镜像大小的Call... 简单找一下吧...
代码:
010306E7 60 pushad 010306E8 64:A1 30000000 mov eax,dword ptr fs:[30] 010306EE 85C0 test eax,eax 010306F0 78 0F js short 复件_cal.01030701 010306F2 8B40 0C mov eax,dword ptr ds:[eax+C] 010306F5 8B40 0C mov eax,dword ptr ds:[eax+C] 010306F8 8140 20 0030000>add dword ptr ds:[eax+20],3000 ; 这句话修改了镜像大小 本来为31C8C + 3000 = 34C8C 用LoadPE修复可得原来的31C8C ………………………… 0103071D 61 popad 0103071E C3 retn
代码:
010306DB C60401 00 mov byte ptr ds:[ecx+eax],0 ; 这句话是用0填充原来的PE头 故NOP掉 010306DF 49 dec ecx 010306E0 83F9 00 cmp ecx,0 010306E3 ^ 77 F6 ja short 复件_cal.010306DB ; 这个循环抹除了PE头,是LoadPE不能正确地识别程序 ImportREC不能正确附加在这个程序上 010306E5 61 popad 010306E6 C3 retn
代码:
010310DB 46 69 6C 65 4D 6F FileMo 010310EB 6E 43 6C 61 73 73 00 31 38 34 36 37 2D 34 31 00 nClass.18467-41. 010310FB 5C 5C 2E 5C 53 49 43 45 00 5C 5C 2E 5C 53 49 57 \\.\SICE.\\.\SIW 0103110B 56 49 44 00 5C 5C 2E 5C 4E 54 49 43 45 00 5C 5C VID.\\.\NTICE.\\ 0103111B 2E 5C 52 45 47 53 59 53 00 5C 5C 2E 5C 52 45 47 .\REGSYS.\\.\REG 0103112B 56 58 47 00 5C 5C 2E 5C 46 49 4C 45 56 58 47 00 VXG.\\.\FILEVXG. 0103113B 5C 5C 2E 5C 46 49 4C 45 4D 00 5C 5C 2E 5C 54 52 \\.\FILEM.\\.\TR 0103114B 57 00 5C 5C 2E 5C 49 43 45 45 58 54 W.\\.\ICEEXT
代码:
0103114B B7 A2 CF 发 0103115B D6 B5 F7 CA D4 C6 F7 20 2D 20 C7 EB B9 D8 B1 D5 值魇云?- 请关闭 0103116B B5 F7 CA D4 C6 F7 B2 A2 D6 D8 D0 C2 C6 F4 B6 AF 调试器并重新启动 0103117B D3 A6 D3 C3 B3 CC D0 F2 A3 A1 0D 0A 57 69 6E 64 应用程序!..Wind 0103118B 6F 77 73 20 4E 54 20 D3 C3 BB A7 C7 EB D7 A2 D2 ows NT 用户请注 0103119B E2 A3 BA C8 E7 B9 FB B0 B2 D7 B0 C1 CB 20 57 69 猓喝绻沧傲?Wi 010311AB 6E 49 63 65 2F 53 6F 66 74 49 63 65 20 B7 FE CE nIce/SoftIce 服 010311BB F1 A3 AC 0D 0A BC B4 D2 E2 CE B6 D7 C5 C4 FA D4 瘢?.即意味着您 010311CB CB D0 D0 C1 CB B5 F7 CA D4 C6 F7 A3 A1 00 B7 A2 诵辛说魇云鳎?发 010311DB CF D6 BC E0 CA D3 C6 F7 20 2D 20 C7 EB B9 D8 B1 现监视器 - 请关 010311EB D5 BC E0 CA D3 C6 F7 B2 A2 D6 D8 D0 C2 C6 F4 B6 占嗍悠鞑⒅匦缕舳 010311FB AF D3 A6 D3 C3 B3 CC D0 F2 A3 A1 0D 0A 57 69 6E τ贸绦颍?.Win 0103120B 64 6F 77 73 20 4E 54 20 D3 C3 BB A7 C7 EB D7 A2 dows NT 用户请注 0103121B D2 E2 A3 BA C8 E7 B9 FB B0 B2 D7 B0 C1 CB 20 46 意:如果安装了 F 0103122B 69 6C 65 4D 6F 6E 2F 52 65 67 4D 6F 6E 20 B7 FE ileMon/RegMon 服 0103123B CE F1 A3 AC 0D 0A BC B4 D2 E2 CE B6 D7 C5 C4 FA 务,..即意味着您 0103124B D4 CB D0 D0 C1 CB BC E0 CA D3 C6 F7 A3 运行了监视器!..
F8往下走啊 大胆的走啊,莫回头啊~~~
代码:
0102C70B FFD3 call ebx 0102C70D 83C4 08 add esp,8 0102C710 E8 D53E0000 call 复件_cal.010305EA ; Anti2 (Main) 0102C715 E8 91340000 call 复件_cal.0102FBAB
Anti2了,用到了很多刚才咱们检测调试器Call 里面的内容哈... 当然修改的内容也可以通过修改ZFlag实现
代码:
010305EA 60 pushad 010305EB 83BD 434A0000 0>cmp dword ptr ss:[ebp+4A43],1 ; 检测FindWindowAnti 010305F2 74 09 je short 复件_cal.010305FD ; 不能跳,跳了就完了,可以Nop掉 010305F4 83BD 474A0000 0>cmp dword ptr ss:[ebp+4A47],1 ; 检测是否存在RemoteDebugger 010305FB 75 4A jnz short 复件_cal.01030647 ; 这里一定要跳,不跳就完了,可以改成jMP 010305FD 83BD E04C0000 0>cmp dword ptr ss:[ebp+4CE0],0 01030604 75 3B jnz short 复件_cal.01030641 01030606 81BD C2470000 0>cmp dword ptr ss:[ebp+47C2],ABBC680D ; 检测操作系统是否为Nt/2K 01030610 75 17 jnz short 复件_cal.01030629 01030612 FFB5 C2470000 push dword ptr ss:[ebp+47C2] 01030618 FFB5 A6470000 push dword ptr ss:[ebp+47A6] 0103061E E8 E3020000 call 复件_cal.01030906 01030623 8985 C2470000 mov dword ptr ss:[ebp+47C2],eax 01030629 6A 30 push 30 0103062B 8D85 DD470000 lea eax,dword ptr ss:[ebp+47DD] 01030631 50 push eax 01030632 8D85 564B0000 lea eax,dword ptr ss:[ebp+4B56] 01030638 50 push eax 01030639 6A 00 push 0 0103063B FF95 C2470000 call dword ptr ss:[ebp+47C2] ; 这里MessageBoxA提示检测到调试器,请关闭调试服务(还挺友好的~~) 01030641 61 popad 01030642 58 pop eax ; 这个Anti的精华在这里...破坏返回地址(使该子程序不能正常地返回主程序而出现异 常退出),即下面的两行 如果上面的第一个Je跳了 则可以NOP掉下面两句,运行效果与直接跳开ANti的效果基本相同,不过会多MessageBox提示^_^ 01030643 61 popad 01030644 C3 retn 01030645 EB 51 jmp short 复件_cal.01030698 01030647 83BD 4B4A0000 0>cmp dword ptr ss:[ebp+4A4B],1 ; 上面的那个必须要跳得跳就跳到这里 0103064E 75 48 jnz short 复件_cal.01030698 ; 这里他跳了,咱们让他跳,因为跳了就可以绕过Anti 01030650 83BD E04C0000 0>cmp dword ptr ss:[ebp+4CE0],0 ; 如果3个Jnz都不跳又会被Anti 看下面的pop eax 和popad 01030657 75 3B jnz short 复件_cal.01030694 ; 下面这部分与上面惊人类似,本人就不详述了... 01030659 81BD C2470000 0>cmp dword ptr ss:[ebp+47C2],ABBC680D 01030663 75 17 jnz short 复件_cal.0103067C 01030665 FFB5 C2470000 push dword ptr ss:[ebp+47C2] 0103066B FFB5 A6470000 push dword ptr ss:[ebp+47A6] 01030671 E8 90020000 call 复件_cal.01030906 01030676 8985 C2470000 mov dword ptr ss:[ebp+47C2],eax 0103067C 6A 30 push 30 0103067E 8D85 DD470000 lea eax,dword ptr ss:[ebp+47DD] 01030684 50 push eax 01030685 8D85 D74B0000 lea eax,dword ptr ss:[ebp+4BD7] 0103068B 50 push eax 0103068C 6A 00 push 0 0103068E FF95 C2470000 call dword ptr ss:[ebp+47C2] 01030694 61 popad 01030695 58 pop eax ; 又是精华Anti 01030696 61 popad 01030697 C3 retn 01030698 61 popad ; 让他跳到这里,看见没有,这里有popad没有pop eax和popad了,返回就正常了... 01030699 C3 retn
如果这个Call过了,用LoadPE完整脱壳会出现,Can't Paste Original PE Header的提示... 这个Call呢,咱们要NOP掉,
问题是这个Call隐藏得很深哈... 在输入表加密之后
代码:
0102C844 8985 A5530000 mov dword ptr ss:[ebp+53A5],eax 0102C84A 803E 01 cmp byte ptr ds:[esi],1 0102C84D ^ 0F85 46FFFFFF jnz 复件_cal.0102C799 0102C853 E8 B0350000 call 复件_cal.0102FE08 0102C858 68 00400000 push 4000 0102C85D 68 87020000 push 287 0102C862 FFB5 A9530000 push dword ptr ss:[ebp+53A9] 0102C868 FF95 05040000 call dword ptr ss:[ebp+405] 0102C86E E8 D0220000 call 复件_cal.0102EB43 ; 这个Call抹除了Original PE Header (AntiDUMP) NOp掉 0102C873 E8 CC340000 call 复件_cal.0102FD44 0102C878 E8 DF0B0000 call 复件_cal.0102D45C 0102C87D E8 850A0000 call 复件_cal.0102D307
----------------------------------------------------------的卢飞跃之跳过IAT加密----------------------------------------------------------
这里呢,就是传说中的IAT填写循环了,这里为了节省篇幅,我少Copy一点...
代码:
0102C7B7 8B85 A5530000 mov eax,dword ptr ss:[ebp+53A5] ; /解出函数表循环 0102C7BD 8B00 mov eax,dword ptr ds:[eax] 0102C7BF E8 16360000 call 复件_cal.0102FDDA ; 直接返回,不知何用 0102C7C4 50 push eax 0102C7C5 FFB5 A1530000 push dword ptr ss:[ebp+53A1] 0102C7CB E8 E9400000 call 复件_cal.010308B9 ; 此Call过后EAX已经被解出函数指针 0102C7D0 85C0 test eax,eax 0102C7D2 0F84 5B200000 je 复件_cal.0102E833 0102C7D8 E8 FF360000 call 复件_cal.0102FEDC ; 这个就是传说中的加密Call (高智商!可惜被NOP掉了) 0102C7DD E8 85350000 call 复件_cal.0102FD67 ; 这个Call负责填写IAT(干苦力的...) 0102C7E2 83C7 04 add edi,4 ; edi += 4 可见要写入的函数RVA在edi中 0102C7E5 8B85 A5530000 mov eax,dword ptr ss:[ebp+53A5] 0102C7EB 8938 mov dword ptr ds:[eax],edi 0102C7ED 8385 A5530000 0>add dword ptr ss:[ebp+53A5],4 0102C7F4 8B85 A5530000 mov eax,dword ptr ss:[ebp+53A5] 0102C7FA 8338 00 cmp dword ptr ds:[eax],0 0102C7FD ^ 75 B8 jnz short 复件_cal.0102C7B7 ; \循环结束 注释:这里不仅写IAT而且
代码:
0102FEDC 60 pushad 0102FEDD 83BD 7C4C0000 0>cmp dword ptr ss:[ebp+4C7C],0 ; 这里判断原加密表中函数地址是否为空 0102FEE4 0F85 FA000000 jnz 复件_cal.0102FFE4
代码:
0102FFEA 83BD 804C0000 0>cmp dword ptr ss:[ebp+4C80],0 ; 这个大概是RLPacK设置中是否对所有函数加密,为1就不加密,为0就加密 0102FFF1 74 14 je short 复件_cal.01030007 ; 这个不能跳 0102FFF3 3BBD A2470000 cmp edi,dword ptr ss:[ebp+47A2] ; 这个cmp控制对Kernel32.dll中的函数一定要加密 0102FFF9 74 0C je short 复件_cal.01030007 ; 这个也不能跳 0102FFFB 3BBD A6470000 cmp edi,dword ptr ss:[ebp+47A6] ; 这个cmp控制对USER32.dll中的函数一定要加密 01030001 0F85 67010000 jnz 复件_cal.0103016E ; 但是这个一定要跳,所以为了保险 前面两个NOP掉,这个改成JmP
这个IAT加密的处理就算是完成了!
哦,差点忘了那个做苦力的了...
代码:
0102FD67 60 pushad 0102FD68 83BD 804C0000 0>cmp dword ptr ss:[ebp+4C80],1 0102FD6F 74 09 je short 复件_cal.0102FD7A 0102FD71 83BD 684C0000 0>cmp dword ptr ss:[ebp+4C68],0 0102FD78 75 07 jnz short 复件_cal.0102FD81 0102FD7A E8 58000000 call 复件_cal.0102FDD7 ; 这个Call过后呢 IAT就被填写了 F7 Step InTo 0102FD7F EB 3B jmp short 复件_cal.0102FDBC
代码:
0102FDD7 8907 mov dword ptr ds:[edi],eax ; 果然不出所料(看上面的绿字),看这里~~看这里~~~看这里~~~~ 0102FDD9 C3 retn
-------------------------------------------------------慧眼什么不能洞穿?VM! ------------------------------------------------------------
这样呢,要找OEP了,因为OEP里面有VM,单指在F8上一点,就到了这里...
StolenCode + VM 确实很头大...
(其实虚拟机(Virtual Machine)从一定角度讲也可以讲是StolenCode,但是我个人认为对于这个壳前面的5行可以说是StolenCode后面其他的代码说VM更加恰当)
代码:
0102D8A4 61 popad ; 恢复初始 寄存器状态,打起精神,要到OEP了 0102D8A5 8980 A44C0000 mov dword ptr ds:[eax+4CA4],eax ; 保存寄存器内容! 0102D8AB 8998 A84C0000 mov dword ptr ds:[eax+4CA8],ebx 0102D8B1 8988 AC4C0000 mov dword ptr ds:[eax+4CAC],ecx 0102D8B7 8990 B04C0000 mov dword ptr ds:[eax+4CB0],edx 0102D8BD 89B0 B44C0000 mov dword ptr ds:[eax+4CB4],esi 0102D8C3 89B8 B84C0000 mov dword ptr ds:[eax+4CB8],edi 0102D8C9 89A0 C04C0000 mov dword ptr ds:[eax+4CC0],esp 0102D8CF 89A0 C44C0000 mov dword ptr ds:[eax+4CC4],esp 0102D8D5 89A8 BC4C0000 mov dword ptr ds:[eax+4CBC],ebp
代码:
0102DA58 89AB 87000000 mov dword ptr ds:[ebx+87],ebp ;打起精神要到了... 0102DA5E 89AB 0B010000 mov dword ptr ds:[ebx+10B],ebp 0102DA64 89A3 C7000000 mov dword ptr ds:[ebx+C7],esp 0102DA6A 89BB D8000000 mov dword ptr ds:[ebx+D8],edi 0102DA70 89B3 02010000 mov dword ptr ds:[ebx+102],esi 0102DA76 8D8B 81000000 lea ecx,dword ptr ds:[ebx+81] 0102DA7C 8B46 04 mov eax,dword ptr ds:[esi+4]
代码:
0102DA98 FF36 push dword ptr ds:[esi] ; 这个循环即是StolenCode的开始 = 两个语句,很明显哈,这里被代码变形得很厉害啊... 0102DA9A 83C6 04 add esi,4 ; push 70 传说中的Microsoft Visual C++ 7.0 Method2 [Debug]头 0102DA9D 3BF7 cmp esi,edi ; push 010015E0 0102DA9F ^ 72 F7 jb short 复件_cal.0102DA98 0102DAA1 8B85 A44C0000 mov eax,dword ptr ss:[ebp+4CA4] ; 此处恢复寄存器起始状态 0102DAA7 8B9D A84C0000 mov ebx,dword ptr ss:[ebp+4CA8] 0102DAAD 8B8D AC4C0000 mov ecx,dword ptr ss:[ebp+4CAC] 0102DAB3 8B95 B04C0000 mov edx,dword ptr ss:[ebp+4CB0] 0102DAB9 8BB5 B44C0000 mov esi,dword ptr ss:[ebp+4CB4] 0102DABF 8BBD B84C0000 mov edi,dword ptr ss:[ebp+4CB8] 0102DAC5 8BA5 C04C0000 mov esp,dword ptr ss:[ebp+4CC0] 0102DACB 89A5 C84C0000 mov dword ptr ss:[ebp+4CC8],esp ; 这个壳太会折腾了... 受不了了... 0102DAD1 8BAD BC4C0000 mov ebp,dword ptr ss:[ebp+4CBC]
不想复制的太多,因为有一句xor ebx,ebx是隐藏得很深,用了很变态的方式代替,所以这个StolenCode我贴在下面
push 70
push 010015E0
call 010127C8
xor ebx,ebx
push ebx
最后打老怪了 Virtual Machine~
修补之 笔记...
因为VM代码太多,手动修复肯定几乎是不可能的了,那咱们研究如何自动修复
因为 VM中的代码存储在一张表中
每条代码由12个字节组成,
前4个字节写在原程序中应该写代码的位置,中间四个写操作标志,最后四个写操作标志的参数...
下面是VM处理一些代码时的做法...
这个是调用系统API时VM的做法...
碰到有些时候 用ESP解析出函数地址,咱们简单还原一下就行了 因为esp中存储的是函数IAT地址 所以改成FF15 函数IAT的DWORD地址就可以了
代码:
00DA2603 83EC 04 sub esp,4 00DA2606 C70424 04120001 mov dword ptr ss:[esp],1001204 ;这一部分解析出函数IAT 00DA260D 50 push eax 00DA260E 8B4424 04 mov eax,dword ptr ss:[esp+4] 00DA2612 8B00 mov eax,dword ptr ds:[eax] 00DA2614 894424 04 mov dword ptr ss:[esp+4],eax 00DA2618 58 pop eax 00DA2619 83C4 04 add esp,4 ; 下面负责Call 修改方法 比如函数地址是1001204就写 FF 15 04 12 00 01 00DA261C FF5424 FC call dword ptr ss:[esp-4] ; msvcrt.__p__commode 00DA2620 - E9 E7FE2600 jmp 复件_cal.0101250C
代码:
00DA2625 9C pushfd 00DA2626 FF35 08500101 push dword ptr ds:[1015008] ;就是这里了... 00DA262C 813424 00000000 xor dword ptr ss:[esp],0 00DA2633 E8 C8D9FEFF call 00D90000 00DA2638 59 pop ecx 00DA2639 9D popfd 00DA263A - E9 D3FE2600 jmp 复件_cal.01012512
代码:
00DA273B 9C pushfd 00DA273C 83EC 04 sub esp,4 00DA273F C70424 34120001 mov dword ptr ss:[esp],1001234 ; 这里其实就是等于push 1001234,所以是变态push 00DA2746 E8 B5D8FEFF call 00D90000 00DA274B 50 push eax 00DA274C FF7424 08 push dword ptr ss:[esp+8] 00DA2750 8B4424 08 mov eax,dword ptr ss:[esp+8] 00DA2754 894424 0C mov dword ptr ss:[esp+C],eax 00DA2758 8B0424 mov eax,dword ptr ss:[esp] 00DA275B 894424 08 mov dword ptr ss:[esp+8],eax 00DA275F 83C4 04 add esp,4 00DA2762 58 pop eax 00DA2763 9D popfd 00DA2764 - E9 DAFD2600 jmp 复件_cal.01012543
代码:
00DA2673 E8 00000000 call 00DA2678 00DA2678 830424 0F add dword ptr ss:[esp],0F 00DA267C 68 C2270101 push 10127C2 ;这一句压入子程序地址 00DA2681 E8 7AD9FEFF call 00D90000 ;这个子过程需要详细解释... 00DA2686 C3 retn ;由这一句返回到子程序
代码:
00DA268C 83EC 04 sub esp,4 ; esp -4 00DA268F 50 push eax 00DA2690 A1 D0490101 mov eax,dword ptr ds:[10149D0] ; 这里是比较的第一个数 00DA2695 894424 04 mov dword ptr ss:[esp+4],eax ; 赋给esp+4 00DA2699 58 pop eax 00DA269A 60 pushad 00DA269B B8 0000D900 mov eax,0D90000 00DA26A0 B9 13000000 mov ecx,13 00DA26A5 99 cdq 00DA26A6 021408 add dl,byte ptr ds:[eax+ecx] 00DA26A9 C1C2 07 rol edx,7 00DA26AC ^ E2 F8 loopd short 00DA26A6 00DA26AE 015424 20 add dword ptr ss:[esp+20],edx 00DA26B2 61 popad ; 这里esp还原 00DA26B3 812C24 DBE99119 sub dword ptr ss:[esp],1991E9DB 00DA26BA 813424 00000000 xor dword ptr ss:[esp],0 00DA26C1 E8 3AD9FEFF call 00D90000 00DA26C6 83C4 04 add esp,4 ; esp + 4 00DA26C9 395C24 FC cmp dword ptr ss:[esp-4],ebx ; 所以要比较的数就跑到esp-4去了,这里和ebx比较 00DA26CD - E9 59FE2600 jmp 复件_cal.0101252B ; 然后呢?
代码:
0101252B /75 0C jnz short 复件_cal.01012539 ; 哈哈我就不讲了... 就这一句... 0101252D -|E9 A001D9FF jmp 00DA26D2 01012532 -|E9 C901D9FF jmp 00DA2700 01012537 |0059 E9 add byte ptr ds:[ecx-17],bl
补的累死了
代码我就不贴上了,正在找简便方法...
--------------------------------------------------慧眼什么不能洞穿?-VM! -谁说的!!-----------------------------------------------------
--------------------------------------------------化境: VM代码生成的分析------------------------------------------------------
分析出来之后简单方法就找到啦!
代码:
0102C660 8B85 7E470000 mov eax,dword ptr ss:[ebp+477E] ; /这个循环解压出很多代码 0102C666 FF7437 04 push dword ptr ds:[edi+esi+4] 0102C66A 010424 add dword ptr ss:[esp],eax 0102C66D FF3437 push dword ptr ds:[edi+esi] 0102C670 010424 add dword ptr ss:[esp],eax 0102C673 FFD3 call ebx 0102C675 83C4 08 add esp,8 0102C678 83C7 08 add edi,8 0102C67B 833C37 00 cmp dword ptr ds:[edi+esi],0 0102C67F ^ 75 DF jnz short 复件_cal.0102C660 ; \这个循环解压代码,只解压不需变形的代码 0102C681 83BD 8D530000 00 cmp dword ptr ss:[ebp+538D],0 0102C688 74 0E je short 复件_cal.0102C698 0102C68A 83BD 91530000 00 cmp dword ptr ss:[ebp+5391],0 0102C691 74 05 je short 复件_cal.0102C698 0102C693 E8 F30B0000 call 复件_cal.0102D28B 0102C698 8D7437 04 lea esi,dword ptr ds:[edi+esi+4] 0102C69C E8 660B0000 call 复件_cal.0102D207 0102C6A1 8B85 5C4C0000 mov eax,dword ptr ss:[ebp+4C5C] 0102C6A7 0BC0 or eax,eax 0102C6A9 74 0B je short 复件_cal.0102C6B6 0102C6AB 0385 7E470000 add eax,dword ptr ss:[ebp+477E] 0102C6B1 E8 C2030000 call 复件_cal.0102CA78 ; 这里为关键的代码变形Call
代码:
0102CAA1 FF95 FD030000 call dword ptr ss:[ebp+3FD] ; VirtualAlloc申请空间 0102CAA7 8BF8 mov edi,eax 0102CAA9 50 push eax 0102CAAA 56 push esi 0102CAAB FFD3 call ebx 0102CAAD 83C4 08 add esp,8 0102CAB0 8B85 604C0000 mov eax,dword ptr ss:[ebp+4C60] 0102CAB6 6BC0 32 imul eax,eax,32 0102CAB9 6A 40 push 40 0102CABB 68 00100000 push 1000 0102CAC0 50 push eax 0102CAC1 6A 00 push 0 0102CAC3 FF95 FD030000 call dword ptr ss:[ebp+3FD] ; VirtualAlloc再次申请空间 0102CAC9 8BF0 mov esi,eax 0102CACB E8 A83C0000 call 复件_cal.01030778 0102CAD0 E8 823D0000 call 复件_cal.01030857 0102CAD5 8B8D 604C0000 mov ecx,dword ptr ss:[ebp+4C60] 0102CADB E9 BB060000 jmp 复件_cal.0102D19B ; while循环的标志
本来我也写了个,不过写到一半发现中间有一些不能用,又太多,发现现成的了,就懒了...(我也很邪恶...)
大家可以看faint88的文章哈...
Fiant88脱文
-------------------------------------------------- 冰封VM :CodeReplace的哭泣 ------------------------------------------------------
-----------------------------------------------------飞翔的梦:飞向光明之巅-----------------------------------------------------------
看上面找SC的地方,继续单步走,F8不放... 到这里
代码:
0102DDF8 68 00400000 push 4000 0102DDFD 68 00000200 push 20000 0102DE02 FFB5 A04C0000 push dword ptr ss:[ebp+4CA0] 0102DE08 FF95 05040000 call dword ptr ss:[ebp+405] 0102DE0E 68 00400000 push 4000 0102DE13 FFB5 984C0000 push dword ptr ss:[ebp+4C98] 0102DE19 FFB5 9C4C0000 push dword ptr ss:[ebp+4C9C] 0102DE1F FF95 05040000 call dword ptr ss:[ebp+405] 0102DE25 8B85 A44C0000 mov eax,dword ptr ss:[ebp+4CA4] 0102DE2B 8B9D A84C0000 mov ebx,dword ptr ss:[ebp+4CA8] 0102DE31 8B8D AC4C0000 mov ecx,dword ptr ss:[ebp+4CAC] 0102DE37 8B95 B04C0000 mov edx,dword ptr ss:[ebp+4CB0] 0102DE3D 8BB5 B44C0000 mov esi,dword ptr ss:[ebp+4CB4] 0102DE43 8BBD B84C0000 mov edi,dword ptr ss:[ebp+4CB8] 0102DE49 8BA5 C04C0000 mov esp,dword ptr ss:[ebp+4CC0] 0102DE4F 8BAD BC4C0000 mov ebp,dword ptr ss:[ebp+4CBC] 0102DE55 ^ E9 39EAFFFF jmp 复件_cal.0102C893 ;飞向那什么地方哈... ~~~
代码:
0102C893 - E9 DD5BFEFF jmp 复件_cal.01012475 ;这个... 哈哈哈 走出去之后...
代码:
01012475 90 nop 01012476 90 nop 01012477 90 nop 01012478 90 nop 01012479 90 nop 0101247A 90 nop 0101247B 90 nop 0101247C 90 nop 0101247D 90 nop 0101247E 90 nop 0101247F 90 nop 01012480 90 nop 01012481 90 nop 01012482 90 nop 01012483 90 nop 01012484 8B3D 20100001 mov edi,dword ptr ds:[1001020] ; kernel32.GetModuleHandleA 0101248A FFD7 call edi 0101248C 66:8138 4D5A cmp word ptr ds:[eax],5A4D 01012491 75 1F jnz short 复件_cal.010124B2
粘上去后...哈哈 LoadPE了... 加上ImportREC ... 不用多说了吧...
-----------------------------------------------------一飞冲天:告别 RLPacK-----------------------------------------------------------
------------------------------------------------------凌波微步:总结快脱方法----------------------------------------------------------
OD载入-> F7单步走 -> 到这里
代码:
0102C5FC 60 pushad 0102C5FD E8 00000000 call 复件_cal.0102C602 0102C602 83C4 04 add esp,4 0102C605 8B6C24 FC mov ebp,dword ptr ss:[esp-4] 0102C609 E8 8B020000 call 复件_cal.0102C899 ; 解Anti1和检测调试器Call代码
代码:
0102C8DD 5F pop edi 0102C8DE 68 00400000 push 4000 0102C8E3 68 00000800 push 80000 0102C8E8 57 push edi 0102C8E9 FF95 05040000 call dword ptr ss:[ebp+405] 0102C8EF 61 popad 0102C8F0 C3 retn
代码:
0102C8E9 FF95 05040000 call dword ptr ss:[ebp+405] 0102C8EF E9 B70A0000 jmp 复件_cal.0102D3AB 0102C8F4 61 popad ; popad 0102C8F5 C3 retn
代码:
66 C7 05 D3 E9 02 01 90 90 C7 05 95 03 03 01 90 90 90 90 C7 05 99 03 03 01 90 90 90 90 66 C7 05 9D 03 03 01 90 90 66 C7 05 F2 05 03 01 90 90 C7 05 D8 C7 02 01 90 90 90 90 C7 05 6E C8 02 01 90 90 90 90 C6 05 DC C7 02 01 90 C6 05 72 C8 02 01 90
执行回到主程序之后,就看到了这里
代码:
0102C609 E8 8B020000 call 复件_cal.0102C899 ; 解Anti1和检测调试器Call代码 0102C60E E8 74240000 call 复件_cal.0102EA87 0102C613 E8 88430000 call 复件_cal.010309A0 0102C618 837C24 28 01 cmp dword ptr ss:[esp+28],1 0102C61D 75 0C jnz short 复件_cal.0102C62B 0102C61F 8B4424 24 mov eax,dword ptr ss:[esp+24] 0102C623 8985 7E470000 mov dword ptr ss:[ebp+477E],eax 0102C629 EB 0C jmp short 复件_cal.0102C637 0102C62B 8B85 7A470000 mov eax,dword ptr ss:[ebp+477A] 0102C631 8985 7E470000 mov dword ptr ss:[ebp+477E],eax 0102C637 E8 100D0000 call 复件_cal.0102D34C 0102C63C E8 6F240000 call 复件_cal.0102EAB0 0102C641 E8 1F230000 call 复件_cal.0102E965 ; Anti1 0102C646 8DB5 AD530000 lea esi,dword ptr ss:[ebp+53AD] 0102C64C 8D9D 17030000 lea ebx,dword ptr ss:[ebp+317] 0102C652 33FF xor edi,edi 0102C654 E8 3B3D0000 call 复件_cal.01030394 ; 检测调试器Call,PE头也在这里被处理,怎么处理呢?咱们F7进去就可以看了 0102C659 EB 03 jmp short 复件_cal.0102C65E
然后下BP VirtualAlloc F9两次后,执行到返回,就能看到代码变形的处理了...咱们按上面的方法粘贴代码替换调换代码避开代码变形
最后单步跟踪,分析出StolenCode粘入OEP即可Dump
----------------------------------------------------飞升了,亲爱的RLPacK---------------------------------------------------------------
到此,咱们就告一段落了...
脱壳完成,我这里再包上源程序,和脱壳后的程序...
完善后的代码
66 C7 05 D3 E9 02 01 90 90 C7 05 95 03 03 01 90 90 90 90 C7 05 99 03 03 01 90 90 90 90 66 C7 05
9D 03 03 01 90 90 66 C7 05 F2 05 03 01 90 90 C7 05 D8 C7 02 01 90 90 90 90 C7 05 6E C8 02 01 90
90 90 90 C6 05 DC C7 02 01 90 C6 05 72 C8 02 01 90 66 C7 05 F7 EA 02 01