好友
阅读权限40
听众
最后登录1970-1-1
|
【文章作者】: [UnPacKcN]XuZhenG
【作者邮箱】: xuzheng1111@126.com
【作者主页】: http://hi.baidu.com/xuzheng1111
http://xz.bee.pl
【软件名称】: RLPacK Full Protection 1.21
【下载地址】: 自己去华军下载
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
如有人将此用入商业用途,给作者造成损失本人概不负责。
--------------------------------------------------------------------------------
【详细过程】
上次在壳狂下载了性价比很高的壳哈...
RLPacK全保护,既然ASPr TMD 和穿山甲 被壳狂的高手 玩得乱转...
我们菜鸟捡个漏...
捏个软柿子...
OD载入
F9第一次运行,状态栏提示Terminated 试了N个调试器隐藏插件和N个OD都不行...
那怎么办呢?那只能Step往下走了...
大胆得往前走啊,往前走,莫回头~~~~~~~~~~
不好意思,献丑了,言归正传...
入口如下:01001000 > $ /EB 06 jmp short 复件_cal.0100100801001002 . |68 2EA80000 push 0A82E01001007 . |C3retn01001008 > \9Cpushfd01001009 .60pushad0100100A .E8 02000000 call 复件_cal.010010110100100F .33C0xor eax,eax01001011 $8BC4mov eax,esp01001013 .83C0 04 add eax,401001016 .93xchg eax,ebx01001017 .8BE3mov esp,ebx01001019 .8B5B FC mov ebx,dword ptr ds:[ebx-4]0100101C .81EB 3F904000 sub ebx,40903F01001022 .61popad01001023 .9Dpopfd01001024 .- E9 D3B50200 jmp 复件_cal.0102C5FC
------------------------------------------------过五关斩六将之 Anti(真的挺邪恶的)被斩----------------------------------------------------
一路狂F7,过JMP后到了这里0102C5FC60pushad0102C5FDE8 00000000 call 复件_cal.0102C6020102C60283C4 04 add esp,40102C6058B6C24 FC mov ebp,dword ptr ss:[esp-4]0102C609E8 8B020000 call 复件_cal.0102C8990102C60EE8 74240000 call 复件_cal.0102EA870102C613E8 88430000 call 复件_cal.010309A00102C618837C24 28 01cmp dword ptr ss:[esp+28],10102C61D75 0C jnz short 复件_cal.0102C62B0102C61F8B4424 24 mov eax,dword ptr ss:[esp+24]0102C6238985 7E470000 mov dword ptr ss:[ebp+477E],eax0102C629EB 0C jmp short 复件_cal.0102C6370102C62B8B85 7A470000 mov eax,dword ptr ss:[ebp+477A]0102C6318985 7E470000 mov dword ptr ss:[ebp+477E],eax0102C637E8 100D0000 call 复件_cal.0102D34C0102C63CE8 6F240000 call 复件_cal.0102EAB00102C641E8 1F230000 call 复件_cal.0102E965;Anti10102C6468DB5 AD530000 lea esi,dword ptr ss:[ebp+53AD]0102C64C8D9D 17030000 lea ebx,dword ptr ss:[ebp+317]0102C65233FFxor edi,edi0102C654E8 3B3D0000 call 复件_cal.01030394;检测调试器Call
关于RLPacK的Anti
Anti1: 这个Anti很容易过哈,很简单,把下面有注释的那一行Nop掉就可以...0102E96560pushad0102E96681BD C2470000 0>cmp dword ptr ss:[ebp+47C2],ABBC680>0102E97075 11 jnz short 复件_cal.0102E983省略一部分代码0102E9CA64:8925 0000000>mov dword ptr fs:[0],esp0102E9D133C0xor eax,eax0102E9D38700xchg dword ptr ds:[eax],eax ; Anti-Exchange 0 and ???????? Please Nop it And Step Over it Easily.0102E9D564:8F05 0000000>pop dword ptr fs:[0]0102E9DC83C4 04 add esp,40102E9DF61popad0102E9E0C3retn
检测调试器Call: 用了很多复杂的API函数哈,我慢慢解释,开头还有两个小插曲,既然也在Anti里面,我也简单说下...0103039460pushad01030395E8 4D030000 call 复件_cal.010306E7 ; 镜像大小+3000 使加载出错... NOP掉 这就是为什么天草大哥要教育我们要修正镜像大小0103039AE8 FB020000 call 复件_cal.0103069A ; 抹除PE头 NOp掉0103039FE8 AC030000 call 复件_cal.01030750 ; 这个Call用Kernel32.DLL基址回写堆栈中的程序基址010303A48985 A2470000 mov dword ptr ss:[ebp+47A2],eax010303AA6A 40 push 40010303AC68 00100000 push 1000010303B168 00100000 push 1000010303B66A 00 push 0010303B8FF95 FD030000 call dword ptr ss:[ebp+3FD]; VirtualAlloc申请空间010303BE8985 3B4A0000 mov dword ptr ss:[ebp+4A3B],eax010303C48D9D 114A0000 lea ebx,dword ptr ss:[ebp+4A11]010303CABE 05000000 mov esi,5010303CFEB 29 jmp short 复件_cal.010303FA010303D1FF33push dword ptr ds:[ebx]; /这个循环的作用是读取一部分壳的输入表其中有几个Anti函数 包括CreateFileA IsDebuggerPresent 和CheckRemoteDebuggerPresent010303D3FFB5 A2470000 push dword ptr ss:[ebp+47A2]010303D9E8 28050000 call 复件_cal.01030906010303DE0BC0or eax,eax ; 此处Eax存放函数指针010303E074 14 je short 复件_cal.010303F6010303E2FF30push dword ptr ds:[eax]010303E459pop ecx010303E580F9 CC cmp cl,0CC010303E875 0A jnz short 复件_cal.010303F4010303EAC785 434A0000 0>mov dword ptr ss:[ebp+4A43],1010303F48903mov dword ptr ds:[ebx],eax010303F683C3 04 add ebx,4010303F94Edec esi010303FA83FE 00 cmp esi,0010303FD^ 77 D2 ja short 复件_cal.010303D1 ; \循环结束010303FF83BD 434A0000 0>cmp dword ptr ss:[ebp+4A43],1; 判断是否已经检测出调试器010304060F84 57010000 je 复件_cal.010305630103040CC785 4F4A0000 9>mov dword ptr ss:[ebp+4A4F],94010304168D85 4F4A0000 lea eax,dword ptr ss:[ebp+4A4F]0103041C50push eax0103041DFF95 194A0000 call dword ptr ss:[ebp+4A19] ; 获得系统版本 并写入ebp+4A190103042383BD 5F4A0000 0>cmp dword ptr ss:[ebp+4A5F],10103042A74 19 je short 复件_cal.010304450103042C83BD 114A0000 0>cmp dword ptr ss:[ebp+4A11],00103043374 10 je short 复件_cal.01030445 ; 检测是否已经成功读取IsDebuggerPresent01030435FF95 114A0000 call dword ptr ss:[ebp+4A11] ; 调用IsDebuggerPresent判断是否有除Ring0之外调试器0103043B0BC0or eax,eax ; 有则返回1 无则返回0(eax)0103043D74 06 je short 复件_cal.010304450103043F8985 434A0000 mov dword ptr ss:[ebp+4A43],eax0103044583BD 5F4A0000 0>cmp dword ptr ss:[ebp+4A5F],2; 判断系统版本是否为NT/2K0103044C75 38 jnz short 复件_cal.010304860103044E81BD 154A0000 7>cmp dword ptr ss:[ebp+4A15],6D3A82720103045874 27 je short 复件_cal.010304810103045A8D85 474A0000 lea eax,dword ptr ss:[ebp+4A47]0103046050push eax010304616A FF push -101030463FF95 154A0000 call dword ptr ss:[ebp+4A15] ; 调用CheckRemoteDebuggerPresent判断是否有调试器010304698B85 154A0000 mov eax,dword ptr ss:[ebp+4A15]0103046F8138 8B442408 cmp dword ptr ds:[eax],824448B0103047575 0A jnz short 复件_cal.01030481; 如果有调试器,则不跳转 赋值ebp+4A47为1代表已有调试器,以后会有判断并Anti01030477C785 474A0000 0>mov dword ptr ss:[ebp+4A47],101030481E8 62FDFFFF call 复件_cal.010301E801030486FFB5 254A0000 push dword ptr ss:[ebp+4A25]0103048CFFB5 A6470000 push dword ptr ss:[ebp+47A6]01030492E8 6F040000 call 复件_cal.0103090601030497EB 03 jmp short 复件_cal.0103049C01030499FE???; 未知命令0103049AFFFF???; 未知命令0103049C8D9D 294A0000 lea ebx,dword ptr ss:[ebp+4A29]; 取"OllyDbg"字符串010304A26A 00 push 0010304A453push ebx010304A5FFD0call eax ; 调用FindWindowA找OLLYDBG窗口(本人用修改版OD哈哈)010304A70BC0or eax,eax ; 有则返回句柄,无则返回0(eax)010304A974 0A je short 复件_cal.010304B5010304ABC785 434A0000 0>mov dword ptr ss:[ebp+4A43],1; 如果有,则赋值ebp+4A43为1 以后有Anti判断,虽然用了修改版OD,但是还是被发现了,不知为何010304B533DBxor ebx,ebx010304B768 50D4AC0C push 0CACD450010304BCFFB5 A6470000 push dword ptr ss:[ebp+47A6]010304C2E8 3F040000 call 复件_cal.01030906010304C7FFD0call eax ; 调用GetForeGroundWindow获取当前工作窗口的句柄010304C98BF0mov esi,eax010304CB68 0A10299C push 9C29100A010304D0FFB5 A6470000 push dword ptr ss:[ebp+47A6]010304D6E8 2B040000 call 复件_cal.01030906010304DB68 00100000 push 1000010304E0FFB5 3B4A0000 push dword ptr ss:[ebp+4A3B]010304E656push esi010304E7FFD0call eax ; 获取窗口类名 GetWindowTextA:中间略去一部分...:010305316A 00 push 00103053368 80000000 push 80010305386A 03 push 30103053A6A 00 push 00103053C6A 01 push 10103053E68 00000080 push 800000000103054357push edi01030544FF95 1D4A0000 call dword ptr ss:[ebp+4A1D] ; 此处调用CreateFileA找寻Services 判断是否有调试器服务0103054A83F8 FF cmp eax,-10103054D74 0A je short 复件_cal.010305590103054FC785 434A0000 0>mov dword ptr ss:[ebp+4A43],10103055947inc edi0103055A803F 00 cmp byte ptr ds:[edi],00103055D^ 75 FA jnz short 复件_cal.010305590103055F47inc edi010305604Edec esi01030561^ 75 CE jnz short 复件_cal.01030531; 循环判断是否有调试器服务01030563FF85 3F4A0000 inc dword ptr ss:[ebp+4A3F]0103056968 00400000 push 40000103056E68 00100000 push 100001030573FFB5 3B4A0000 push dword ptr ss:[ebp+4A3B]01030579FF95 05040000 call dword ptr ss:[ebp+405]0103057F61popad01030580C3retn
既然在Anti里面,那就简单说下吧...
咱们看那个邪恶的修改镜像大小的Call... 简单找一下吧...010306E760pushad010306E864:A1 30000000mov eax,dword ptr fs:[30]010306EE85C0test eax,eax010306F078 0F js short 复件_cal.01030701010306F28B40 0C mov eax,dword ptr ds:[eax+C]010306F58B40 0C mov eax,dword ptr ds:[eax+C]010306F88140 20 0030000>add dword ptr ds:[eax+20],3000 ; 这句话修改了镜像大小 本来为31C8C + 3000 = 34C8C 用LoadPE修复可得原来的31C8C…………………………0103071D61popad0103071EC3retn
更邪恶的抹除PE头的Call010306DBC60401 00 mov byte ptr ds:[ecx+eax],0; 这句话是用0填充原来的PE头 故NOP掉010306DF49dec ecx010306E083F9 00 cmp ecx,0010306E3^ 77 F6 ja short 复件_cal.010306DB ; 这个循环抹除了PE头,是LoadPE不能正确地识别程序 ImportREC不能正确附加在这个程序上010306E561popad010306E6C3retn
上面的类名和调试器服务在内存中可以找到...010310DB46 69 6C 65 4D 6FFileMo010310EB6E 43 6C 61 73 73 00 31 38 34 36 37 2D 34 31 00nClass.18467-41.010310FB5C 5C 2E 5C 53 49 43 45 00 5C 5C 2E 5C 53 49 57\\.\SICE.\\.\SIW0103110B56 49 44 00 5C 5C 2E 5C 4E 54 49 43 45 00 5C 5CVID.\\.\NTICE.\\0103111B2E 5C 52 45 47 53 59 53 00 5C 5C 2E 5C 52 45 47.\REGSYS.\\.\REG0103112B56 58 47 00 5C 5C 2E 5C 46 49 4C 45 56 58 47 00VXG.\\.\FILEVXG.0103113B5C 5C 2E 5C 46 49 4C 45 4D 00 5C 5C 2E 5C 54 52\\.\FILEM.\\.\TR0103114B57 00 5C 5C 2E 5C 49 43 45 45 58 54W.\\.\ICEEXT
下面还有Anti的提示内容哈...0103114B B7 A2 CF 发0103115BD6 B5 F7 CA D4 C6 F7 20 2D 20 C7 EB B9 D8 B1 D5值魇云?- 请关闭0103116BB5 F7 CA D4 C6 F7 B2 A2 D6 D8 D0 C2 C6 F4 B6 AF调试器并重新启动0103117BD3 A6 D3 C3 B3 CC D0 F2 A3 A1 0D 0A 57 69 6E 64应用程序!..Wind0103118B6F 77 73 20 4E 54 20 D3 C3 BB A7 C7 EB D7 A2 D2ows NT 用户请注0103119BE2 A3 BA C8 E7 B9 FB B0 B2 D7 B0 C1 CB 20 57 69猓喝绻沧傲?Wi010311AB6E 49 63 65 2F 53 6F 66 74 49 63 65 20 B7 FE CEnIce/SoftIce 服010311BBF1 A3 AC 0D 0A BC B4 D2 E2 CE B6 D7 C5 C4 FA D4瘢?.即意味着您010311CBCB D0 D0 C1 CB B5 F7 CA D4 C6 F7 A3 A1 00 B7 A2诵辛说魇云鳎?发010311DBCF D6 BC E0 CA D3 C6 F7 20 2D 20 C7 EB B9 D8 B1现监视器 - 请关010311EBD5 BC E0 CA D3 C6 F7 B2 A2 D6 D8 D0 C2 C6 F4 B6占嗍悠鞑⒅匦缕舳010311FBAF D3 A6 D3 C3 B3 CC D0 F2 A3 A1 0D 0A 57 69 6Eτ贸绦颍?.Win0103120B64 6F 77 73 20 4E 54 20 D3 C3 BB A7 C7 EB D7 A2dows NT 用户请注0103121BD2 E2 A3 BA C8 E7 B9 FB B0 B2 D7 B0 C1 CB 20 46意:如果安装了 F0103122B69 6C 65 4D 6F 6E 2F 52 65 67 4D 6F 6E 20 B7 FEileMon/RegMon 服0103123BCE F1 A3 AC 0D 0A BC B4 D2 E2 CE B6 D7 C5 C4 FA务,..即意味着您0103124BD4 CB D0 D0 C1 CB BC E0 CA D3 C6 F7 A3 运行了监视器!..
有点乱码哈,没关系...
F8往下走啊 大胆的走啊,莫回头啊~~~0102C70BFFD3call ebx0102C70D83C4 08 add esp,80102C710E8 D53E0000 call 复件_cal.010305EA ; Anti2 (Main)0102C715E8 91340000 call 复件_cal.0102FBAB
找到Anti2了,那咱们F7进入哈...
Anti2了,用到了很多刚才咱们检测调试器Call 里面的内容哈... 当然修改的内容也可以通过修改ZFlag实现010305EA60pushad010305EB83BD 434A0000 0>cmp dword ptr ss:[ebp+4A43],1 ; 检测FindWindowAnti010305F274 09 je short 复件_cal.010305FD; 不能跳,跳了就完了,可以Nop掉010305F483BD 474A0000 0>cmp dword ptr ss:[ebp+4A47],1 ; 检测是否存在RemoteDebugger010305FB75 4A jnz short 复件_cal.01030647 ; 这里一定要跳,不跳就完了,可以改成jMP010305FD83BD E04C0000 0>cmp dword ptr ss:[ebp+4CE0],00103060475 3B jnz short 复件_cal.010306410103060681BD C2470000 0>cmp dword ptr ss:[ebp+47C2],ABBC680D; 检测操作系统是否为Nt/2K0103061075 17 jnz short 复件_cal.0103062901030612FFB5 C2470000 push dword ptr ss:[ebp+47C2]01030618FFB5 A6470000 push dword ptr ss:[ebp+47A6]0103061EE8 E3020000 call 复件_cal.01030906010306238985 C2470000 mov dword ptr ss:[ebp+47C2],eax010306296A 30 push 300103062B8D85 DD470000 lea eax,dword ptr ss:[ebp+47DD]0103063150push eax010306328D85 564B0000 lea eax,dword ptr ss:[ebp+4B56]0103063850push eax010306396A 00 push 00103063BFF95 C2470000 call dword ptr ss:[ebp+47C2]; 这里MessageBoxA提示检测到调试器,请关闭调试服务(还挺友好的~~)0103064161popad0103064258pop eax ; 这个Anti的精华在这里...破坏返回地址(使该子程序不能正常地返回主程序而出现异常退出),即下面的两行 如果上面的第一个Je跳了 则可以NOP掉下面两句,运行效果与直接跳开ANti的效果基本相同,不过会多MessageBox提示^_^0103064361popad01030644C3retn01030645EB 51 jmp short 复件_cal.010306980103064783BD 4B4A0000 0>cmp dword ptr ss:[ebp+4A4B],1 ; 上面的那个必须要跳得跳就跳到这里0103064E75 48 jnz short 复件_cal.01030698 ; 这里他跳了,咱们让他跳,因为跳了就可以绕过Anti0103065083BD E04C0000 0>cmp dword ptr ss:[ebp+4CE0],0 ; 如果3个Jnz都不跳又会被Anti 看下面的pop eax 和popad0103065775 3B jnz short 复件_cal.01030694 ; 下面这部分与上面惊人类似,本人就不详述了...0103065981BD C2470000 0>cmp dword ptr ss:[ebp+47C2],ABBC680D0103066375 17 jnz short 复件_cal.0103067C01030665FFB5 C2470000 push dword ptr ss:[ebp+47C2]0103066BFFB5 A6470000 push dword ptr ss:[ebp+47A6]01030671E8 90020000 call 复件_cal.01030906010306768985 C2470000 mov dword ptr ss:[ebp+47C2],eax0103067C6A 30 push 300103067E8D85 DD470000 lea eax,dword ptr ss:[ebp+47DD]0103068450push eax010306858D85 D74B0000 lea eax,dword ptr ss:[ebp+4BD7]0103068B50push eax0103068C6A 00 push 00103068EFF95 C2470000 call dword ptr ss:[ebp+47C2]0103069461popad0103069558pop eax ; 又是精华Anti0103069661popad01030697C3retn0103069861popad ; 让他跳到这里,看见没有,这里有popad没有pop eax和popad了,返回就正常了...01030699C3retn
很郁闷哈,其实这个壳不仅有AntiDebug AntiLoad 还有AntiDUMP啊上面剥离PE头,修改镜像大小都是,最可怕的是下面这个AntiDump
如果这个Call过了,用LoadPE完整脱壳会出现,Can't Paste Original PE Header的提示... 这个Call呢,咱们要NOP掉,
问题是这个Call隐藏得很深哈... 在输入表加密之后0102C8448985 A5530000 mov dword ptr ss:[ebp+53A5],eax0102C84A803E 01 cmp byte ptr ds:[esi],10102C84D^ 0F85 46FFFFFF jnz 复件_cal.0102C7990102C853E8 B0350000 call 复件_cal.0102FE080102C85868 00400000 push 40000102C85D68 87020000 push 2870102C862FFB5 A9530000 push dword ptr ss:[ebp+53A9]0102C868FF95 05040000 call dword ptr ss:[ebp+405]0102C86EE8 D0220000 call 复件_cal.0102EB43 ; 这个Call抹除了Original PE Header (AntiDUMP)NOp掉0102C873E8 CC340000 call 复件_cal.0102FD440102C878E8 DF0B0000 call 复件_cal.0102D45C0102C87DE8 850A0000 call 复件_cal.0102D307
---------------------------------------------到了这里呢,Anti基本上是过了,下面该干什么呢?该寻找输入表了--------------------------------
----------------------------------------------------------的卢飞跃之跳过IAT加密----------------------------------------------------------
这里呢,就是传说中的IAT填写循环了,这里为了节省篇幅,我少Copy一点...0102C7B78B85 A5530000 mov eax,dword ptr ss:[ebp+53A5]; /解出函数表循环0102C7BD8B00mov eax,dword ptr ds:[eax]0102C7BFE8 16360000 call 复件_cal.0102FDDA ; 直接返回,不知何用0102C7C450push eax0102C7C5FFB5 A1530000 push dword ptr ss:[ebp+53A1] 0102C7CBE8 E9400000 call 复件_cal.010308B9 ; 此Call过后EAX已经被解出函数指针0102C7D085C0test eax,eax0102C7D20F84 5B200000 je 复件_cal.0102E8330102C7D8E8 FF360000 call 复件_cal.0102FEDC ; 这个就是传说中的加密Call (高智商!可惜被NOP掉了)0102C7DDE8 85350000 call 复件_cal.0102FD67 ; 这个Call负责填写IAT(干苦力的...)0102C7E283C7 04 add edi,4; edi += 4 可见要写入的函数RVA在edi中0102C7E58B85 A5530000 mov eax,dword ptr ss:[ebp+53A5]0102C7EB8938mov dword ptr ds:[eax],edi0102C7ED8385 A5530000 0>add dword ptr ss:[ebp+53A5],40102C7F48B85 A5530000 mov eax,dword ptr ss:[ebp+53A5]0102C7FA8338 00 cmp dword ptr ds:[eax],00102C7FD^ 75 B8 jnz short 复件_cal.0102C7B7; \循环结束 注释:这里不仅写IAT而且
咱们看那个高智商的Call,很复杂哈,我这里找下Magic Jump,不全部复制了...0102FEDC60pushad0102FEDD83BD 7C4C0000 0>cmp dword ptr ss:[ebp+4C7C],0 ; 这里判断原加密表中函数地址是否为空0102FEE40F85 FA000000 jnz 复件_cal.0102FFE4
跳完后单步到这里...0102FFEA83BD 804C0000 0>cmp dword ptr ss:[ebp+4C80],0 ; 这个大概是RLPacK设置中是否对所有函数加密,为1就不加密,为0就加密0102FFF174 14 je short 复件_cal.01030007; 这个不能跳0102FFF33BBD A2470000 cmp edi,dword ptr ss:[ebp+47A2] ; 这个cmp控制对Kernel32.dll中的函数一定要加密0102FFF974 0C je short 复件_cal.01030007; 这个也不能跳0102FFFB3BBD A6470000 cmp edi,dword ptr ss:[ebp+47A6] ; 这个cmp控制对USER32.dll中的函数一定要加密010300010F85 67010000 jnz 复件_cal.0103016E ; 但是这个一定要跳,所以为了保险 前面两个NOP掉,这个改成JmP
那怎么处理呢... 要么把整个CallNOP掉,如果怕影响程序正常工作 可以将上面这3个跳中前两个跳 NOP掉 最后一个jnz改成JMP
这个IAT加密的处理就算是完成了!
哦,差点忘了那个做苦力的了...0102FD6760pushad0102FD6883BD 804C0000 0>cmp dword ptr ss:[ebp+4C80],10102FD6F74 09 je short 复件_cal.0102FD7A0102FD7183BD 684C0000 0>cmp dword ptr ss:[ebp+4C68],00102FD7875 07 jnz short 复件_cal.0102FD810102FD7AE8 58000000 call 复件_cal.0102FDD7; 这个Call过后呢 IAT就被填写了 F7 Step InTo0102FD7FEB 3B jmp short 复件_cal.0102FDBC
0102FDD78907mov dword ptr ds:[edi],eax ; 果然不出所料(看上面的绿字),看这里~~看这里~~~看这里~~~~0102FDD9C3retn
-------------------------------飞跃了!不知道的卢比不比得上木婉清的黑玫瑰..(本人最近武侠看得有点多)--------------------------------------
-------------------------------------------------------慧眼什么不能洞穿?VM! ------------------------------------------------------------
这样呢,要找OEP了,因为OEP里面有VM,单指在F8上一点,就到了这里...
StolenCode + VM 确实很头大...
(其实虚拟机(Virtual Machine)从一定角度讲也可以讲是StolenCode,但是我个人认为对于这个壳前面的5行可以说是StolenCode后面其他的代码说VM更加恰当)0102D8A461popad ; 恢复初始 寄存器状态,打起精神,要到OEP了0102D8A58980 A44C0000 mov dword ptr ds:[eax+4CA4],eax ; 保存寄存器内容!0102D8AB8998 A84C0000 mov dword ptr ds:[eax+4CA8],ebx0102D8B18988 AC4C0000 mov dword ptr ds:[eax+4CAC],ecx0102D8B78990 B04C0000 mov dword ptr ds:[eax+4CB0],edx0102D8BD89B0 B44C0000 mov dword ptr ds:[eax+4CB4],esi0102D8C389B8 B84C0000 mov dword ptr ds:[eax+4CB8],edi0102D8C989A0 C04C0000 mov dword ptr ds:[eax+4CC0],esp0102D8CF89A0 C44C0000 mov dword ptr ds:[eax+4CC4],esp0102D8D589A8 BC4C0000 mov dword ptr ds:[eax+4CBC],ebp
F8 ~~~~~~~ ->0102DA5889AB 87000000 mov dword ptr ds:[ebx+87],ebp ;打起精神要到了...0102DA5E89AB 0B010000 mov dword ptr ds:[ebx+10B],ebp0102DA6489A3 C7000000 mov dword ptr ds:[ebx+C7],esp0102DA6A89BB D8000000 mov dword ptr ds:[ebx+D8],edi0102DA7089B3 02010000 mov dword ptr ds:[ebx+102],esi0102DA768D8B 81000000 lea ecx,dword ptr ds:[ebx+81]0102DA7C8B46 04 mov eax,dword ptr ds:[esi+4]
哈哈,到了这里...0102DA98FF36push dword ptr ds:[esi] ; 这个循环即是StolenCode的开始 = 两个语句,很明显哈,这里被代码变形得很厉害啊...0102DA9A83C6 04 add esi,4 ; push 70 传说中的Microsoft Visual C++ 7.0 Method2 [Debug]头0102DA9D3BF7cmp esi,edi ; push 010015E00102DA9F^ 72 F7 jb short 复件_cal.0102DA980102DAA18B85 A44C0000 mov eax,dword ptr ss:[ebp+4CA4] ; 此处恢复寄存器起始状态0102DAA78B9D A84C0000 mov ebx,dword ptr ss:[ebp+4CA8]0102DAAD8B8D AC4C0000 mov ecx,dword ptr ss:[ebp+4CAC]0102DAB38B95 B04C0000 mov edx,dword ptr ss:[ebp+4CB0]0102DAB98BB5 B44C0000 mov esi,dword ptr ss:[ebp+4CB4]0102DABF8BBD B84C0000 mov edi,dword ptr ss:[ebp+4CB8]0102DAC58BA5 C04C0000 mov esp,dword ptr ss:[ebp+4CC0]0102DACB89A5 C84C0000 mov dword ptr ss:[ebp+4CC8],esp ; 这个壳太会折腾了... 受不了了...0102DAD18BAD BC4C0000 mov ebp,dword ptr ss:[ebp+4CBC]
我上面还原了一些代码,是不是类似某些语言的OEP?但是因为太多CodeReplace,咱们要做一些记录...
不想复制的太多,因为有一句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地址就可以了00DA260383EC 04 sub esp,400DA2606C70424 04120001 mov dword ptr ss:[esp],1001204 ;这一部分解析出函数IAT00DA260D50push eax00DA260E8B4424 04 mov eax,dword ptr ss:[esp+4]00DA26128B00mov eax,dword ptr ds:[eax]00DA2614894424 04 mov dword ptr ss:[esp+4],eax00DA261858pop eax00DA261983C4 04 add esp,4; 下面负责Call 修改方法 比如函数地址是1001204就写 FF 15 04 12 00 01 00DA261CFF5424 FC call dword ptr ss:[esp-4]; msvcrt.__p__commode00DA2620- E9 E7FE2600 jmp 复件_cal.0101250C
这里负责push值00DA26259Cpushfd00DA2626FF35 08500101 push dword ptr ds:[1015008];就是这里了...00DA262C813424 00000000 xor dword ptr ss:[esp],000DA2633E8 C8D9FEFF call 00D9000000DA263859pop ecx00DA26399Dpopfd00DA263A- E9 D3FE2600 jmp 复件_cal.01012512
变态push 方式00DA273B9Cpushfd00DA273C83EC 04 sub esp,400DA273FC70424 34120001 mov dword ptr ss:[esp],1001234 ; 这里其实就是等于push 1001234,所以是变态push00DA2746E8 B5D8FEFF call 00D9000000DA274B50push eax00DA274CFF7424 08 push dword ptr ss:[esp+8]00DA27508B4424 08 mov eax,dword ptr ss:[esp+8]00DA2754894424 0C mov dword ptr ss:[esp+C],eax00DA27588B0424mov eax,dword ptr ss:[esp]00DA275B894424 08 mov dword ptr ss:[esp+8],eax00DA275F83C4 04 add esp,400DA276258pop eax00DA27639Dpopfd00DA2764- E9 DAFD2600 jmp 复件_cal.01012543
在本地调用的时候(非API)他是这样做的00DA2673E8 00000000 call 00DA267800DA2678830424 0F add dword ptr ss:[esp],0F00DA267C68 C2270101 push 10127C2 ;这一句压入子程序地址00DA2681E8 7AD9FEFF call 00D90000;这个子过程需要详细解释...00DA2686C3retn ;由这一句返回到子程序
这是cmp的处理00DA268C83EC 04 sub esp,4; esp -400DA268F50push eax00DA2690A1 D0490101 mov eax,dword ptr ds:[10149D0] ; 这里是比较的第一个数00DA2695894424 04 mov dword ptr ss:[esp+4],eax ; 赋给esp+400DA269958pop eax00DA269A60pushad00DA269BB8 0000D900 mov eax,0D9000000DA26A0B9 13000000 mov ecx,1300DA26A599cdq00DA26A6021408add dl,byte ptr ds:[eax+ecx]00DA26A9C1C2 07 rol edx,700DA26AC^ E2 F8 loopd short 00DA26A600DA26AE015424 20 add dword ptr ss:[esp+20],edx00DA26B261popad; 这里esp还原00DA26B3812C24 DBE99119 sub dword ptr ss:[esp],1991E9DB00DA26BA813424 00000000 xor dword ptr ss:[esp],000DA26C1E8 3AD9FEFF call 00D9000000DA26C683C4 04 add esp,4; esp + 400DA26C9395C24 FC cmp dword ptr ss:[esp-4],ebx ; 所以要比较的数就跑到esp-4去了,这里和ebx比较00DA26CD- E9 59FE2600 jmp 复件_cal.0101252B; 然后呢?
cmp后的跳转0101252B /75 0C jnz short 复件_cal.01012539; 哈哈我就不讲了... 就这一句...0101252D-|E9 A001D9FF jmp 00DA26D201012532-|E9 C901D9FF jmp 00DA270001012537 |0059 E9 add byte ptr ds:[ecx-17],bl
其实还有很多哈 变形Call 等等 不加详述了...
补的累死了
代码我就不贴上了,正在找简便方法...
--------------------------------------------------慧眼什么不能洞穿?-VM! -谁说的!!-----------------------------------------------------
--------------------------------------------------化境: VM代码生成的分析------------------------------------------------------
分析出来之后简单方法就找到啦!0102C6608B85 7E470000 mov eax,dword ptr ss:[ebp+477E]; /这个循环解压出很多代码0102C666FF7437 04 push dword ptr ds:[edi+esi+4]0102C66A010424add dword ptr ss:[esp],eax0102C66DFF3437push dword ptr ds:[edi+esi]0102C670010424add dword ptr ss:[esp],eax0102C673FFD3call ebx0102C67583C4 08 add esp,80102C67883C7 08 add edi,80102C67B833C37 00 cmp dword ptr ds:[edi+esi],00102C67F^ 75 DF jnz short 复件_cal.0102C660; \这个循环解压代码,只解压不需变形的代码0102C68183BD 8D530000 00cmp dword ptr ss:[ebp+538D],00102C68874 0E je short 复件_cal.0102C6980102C68A83BD 91530000 00cmp dword ptr ss:[ebp+5391],00102C69174 05 je short 复件_cal.0102C6980102C693E8 F30B0000 call 复件_cal.0102D28B0102C6988D7437 04 lea esi,dword ptr ds:[edi+esi+4]0102C69CE8 660B0000 call 复件_cal.0102D2070102C6A18B85 5C4C0000 mov eax,dword ptr ss:[ebp+4C5C]0102C6A70BC0or eax,eax0102C6A974 0B je short 复件_cal.0102C6B60102C6AB0385 7E470000 add eax,dword ptr ss:[ebp+477E]0102C6B1E8 C2030000 call 复件_cal.0102CA78 ; 这里为关键的代码变形Call
原来壳狂的faint88已经给出了避开代码变形的过程了...咱们先看那个关键Call0102CAA1FF95 FD030000 call dword ptr ss:[ebp+3FD]; VirtualAlloc申请空间0102CAA78BF8mov edi,eax0102CAA950push eax0102CAAA56push esi0102CAABFFD3call ebx0102CAAD83C4 08 add esp,80102CAB08B85 604C0000 mov eax,dword ptr ss:[ebp+4C60]0102CAB66BC0 32 imul eax,eax,320102CAB96A 40 push 400102CABB68 00100000 push 10000102CAC050push eax0102CAC16A 00 push 00102CAC3FF95 FD030000 call dword ptr ss:[ebp+3FD]; VirtualAlloc再次申请空间0102CAC98BF0mov esi,eax0102CACBE8 A83C0000 call 复件_cal.010307780102CAD0E8 823D0000 call 复件_cal.010308570102CAD58B8D 604C0000 mov ecx,dword ptr ss:[ebp+4C60]0102CADBE9 BB060000 jmp 复件_cal.0102D19B; while循环的标志
记住特点 两个VirtualAlloc后面一个jmp 后面粘上faint88写的代码就可以避开代码变形了。只需要找前面5句StolenCode就可以了...
本来我也写了个,不过写到一半发现中间有一些不能用,又太多,发现现成的了,就懒了...(我也很邪恶...)
大家可以看faint88的文章哈...
Fiant88脱文
-------------------------------------------------- 冰封VM :CodeReplace的哭泣 ------------------------------------------------------
-----------------------------------------------------飞翔的梦:飞向光明之巅-----------------------------------------------------------
看上面找SC的地方,继续单步走,F8不放... 到这里0102DDF868 00400000 push 40000102DDFD68 00000200 push 200000102DE02FFB5 A04C0000 push dword ptr ss:[ebp+4CA0]0102DE08FF95 05040000 call dword ptr ss:[ebp+405]0102DE0E68 00400000 push 40000102DE13FFB5 984C0000 push dword ptr ss:[ebp+4C98]0102DE19FFB5 9C4C0000 push dword ptr ss:[ebp+4C9C]0102DE1FFF95 05040000 call dword ptr ss:[ebp+405]0102DE258B85 A44C0000 mov eax,dword ptr ss:[ebp+4CA4]0102DE2B8B9D A84C0000 mov ebx,dword ptr ss:[ebp+4CA8]0102DE318B8D AC4C0000 mov ecx,dword ptr ss:[ebp+4CAC]0102DE378B95 B04C0000 mov edx,dword ptr ss:[ebp+4CB0]0102DE3D8BB5 B44C0000 mov esi,dword ptr ss:[ebp+4CB4]0102DE438BBD B84C0000 mov edi,dword ptr ss:[ebp+4CB8]0102DE498BA5 C04C0000 mov esp,dword ptr ss:[ebp+4CC0]0102DE4F8BAD BC4C0000 mov ebp,dword ptr ss:[ebp+4CBC]0102DE55^ E9 39EAFFFF jmp 复件_cal.0102C893;飞向那什么地方哈... ~~~
跳到这里0102C893- E9 DD5BFEFF jmp 复件_cal.01012475;这个... 哈哈哈 走出去之后...
0101247590nop0101247690nop0101247790nop0101247890nop0101247990nop0101247A90nop0101247B90nop0101247C90nop0101247D90nop0101247E90nop0101247F90nop0101248090nop0101248190nop0101248290nop0101248390nop010124848B3D 20100001 mov edi,dword ptr ds:[1001020] ; kernel32.GetModuleHandleA0101248AFFD7call edi0101248C66:8138 4D5Acmp word ptr ds:[eax],5A4D0101249175 1F jnz short 复件_cal.010124B2
为什么一大堆NOP呢?哈哈把前面的5句SC粘上去吧...
粘上去后...哈哈 LoadPE了... 加上ImportREC ... 不用多说了吧...
-----------------------------------------------------一飞冲天:告别RLPacK-----------------------------------------------------------
------------------------------------------------------凌波微步:总结快脱方法----------------------------------------------------------
OD载入-> F7单步走 -> 到这里0102C5FC60pushad0102C5FDE8 00000000 call 复件_cal.0102C6020102C60283C4 04 add esp,40102C6058B6C24 FC mov ebp,dword ptr ss:[esp-4]0102C609E8 8B020000 call 复件_cal.0102C899 ; 解Anti1和检测调试器Call代码
F7进入第二个Call,找到段尾,0102C8DD5Fpop edi0102C8DE68 00400000 push 40000102C8E368 00000800 push 800000102C8E857push edi0102C8E9FF95 05040000 call dword ptr ss:[ebp+405]0102C8EF61popad0102C8F0C3retn
再找一片零区域,简单记录下,我这里找的是0102D3AB将段尾的代码改成如下0102C8E9FF95 05040000 call dword ptr ss:[ebp+405]0102C8EFE9 B70A0000 jmp 复件_cal.0102D3AB0102C8F461popad; popad0102C8F5C3retn
记下 102C8F4的地址,在跟踪JmP到0102D3AB 粘贴我下面这一段代码(作用是处理掉所有Anti和IAT加密)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 059D 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 9090 90 90 C6 05 DC C7 02 01 90 C6 05 72 C8 02 01 90
粘完之后不要忘记补上,jmp 0102C8F4的语句跳回 ,否则大麻烦...
执行回到主程序之后,就看到了这里0102C609E8 8B020000 call 复件_cal.0102C899 ; 解Anti1和检测调试器Call代码0102C60EE8 74240000 call 复件_cal.0102EA870102C613E8 88430000 call 复件_cal.010309A00102C618837C24 28 01cmp dword ptr ss:[esp+28],10102C61D75 0C jnz short 复件_cal.0102C62B0102C61F8B4424 24 mov eax,dword ptr ss:[esp+24]0102C6238985 7E470000 mov dword ptr ss:[ebp+477E],eax0102C629EB 0C jmp short 复件_cal.0102C6370102C62B8B85 7A470000 mov eax,dword ptr ss:[ebp+477A]0102C6318985 7E470000 mov dword ptr ss:[ebp+477E],eax0102C637E8 100D0000 call 复件_cal.0102D34C0102C63CE8 6F240000 call 复件_cal.0102EAB00102C641E8 1F230000 call 复件_cal.0102E965 ; Anti10102C6468DB5 AD530000 lea esi,dword ptr ss:[ebp+53AD]0102C64C8D9D 17030000 lea ebx,dword ptr ss:[ebp+317]0102C65233FFxor edi,edi0102C654E8 3B3D0000 call 复件_cal.01030394 ; 检测调试器Call,PE头也在这里被处理,怎么处理呢?咱们F7进去就可以看了0102C659EB 03 jmp short 复件_cal.0102C65E
找到一个call一个jmp的地方 在jmp处F4
然后下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 90 90 |
|