【文章标题】: 新手补给之脱壳+破解 —— HwndSpy v1.9(Armadillo) 【文章作者】: rocktx 【软件名称】: HwndSpy 【软件大小】: 920KB 【下载地址】: http://www.highplains.net/public/HPSHwndSpy.exe 【加壳方式】: Armadillo 【保护方式】: Armadillo 【编写语言】: VC6 【操作平台】: WinXP SP3 【软件介绍】: 简直就是 SpyXX 加强版 【作者声明】: 拙作一篇,献给像我一样的精品菜鸟,好好学习,天天向上! -------------------------------------------------------------------------------- 【详细过程】 本来去年就打算写个完全手脱 Armadillo 全保护的文章,作为新手补给系列中的一篇,但是不幸碰上网络管制,进度中断10月之久; 现在好了,终于可以上msdn、csdn、pediy了,这个程序是我在浏览 codeproject 时看到的,SpyXX 的加强版,如果有使用 过的朋友,可以嗤我以鼻一下; 原以为是免费的,结果安装完后发现主程序身披 Armadillo,遂脱之,由于破解部分实在比较典型,故炮制脱文一篇,以飨初学脱壳的朋友; 本文大纲: 1、脱壳 —— 非完全手脱,仅展示现在绝大多数 Armadillo 双进程壳程序的处理流程,没有涉及Code Splicing和nano; 2、破解 —— 重在思路,不仅仅是 Armadillo 3、优化 —— 要想掌握PE文件格式,请优化您的程序,Armadillo本来就是个增肥壳 一、脱壳 保护方式: !- Protected Armadillo Protection system (Professional) !- Debug-Blocker CopyMem-II Enable Import Table Elimination Enable Memory-Patching Protections !- Variable Backup Keys !- Better/Slower Compression !- !- 版本号: 4.10 08Apr2005 !- Elapsed Time 00h 00m 12s 734ms 重点是前三项保护方式: Debug-Blocker CopyMem-II Enable Import Table Elimination 准备工具: OD (with HideOD 插件) ——— 插件用于 AntiAntiDebug ArmaDetach 1.3 —————— 主要功臣,大大加快脱壳进度,有时候在处理 Debug-Blocker 时,1.1 版会比较稳定 LordPE —————————— 处理 PE 模块 ImportRec 1.6 or 1.7 —— 处理IAT ArmInline 0.96 —————— 处理 IAT 乱序 FixRes —————————— 处理资源 ODbgScript plugin v1.47 —— OD脚本插件,一般使用 1.47 或以上的版本 CFF Explorer —————— 又一款 PE 编辑器,可以不用,纯粹个人喜好 准备脚本(将下面的文本保存为 .osc 或者 .txt 文件): //////////////////////////////////////////////////////////////////////////////////////////////////// //转单进程脚本 msg "请忽略所有异常,并添加忽略C000001E异常,然后运行本脚本!" gpa "OpenMutexA","kernel32.dll" bp $RESULT esto exec pushad pushfd push edx xor eax,eax push eax push eax call kernel32.CreateMutexA popfd popad jmp kernel32.OpenMutexA ende bc eip msg "现已转换成单进程!" ret //////////////////////////////////////////////////////////////////////////////////////////////////// 首先用 HideOD 隐藏好OD,然后忽略所有异常,如果实在搞不定,可以用看雪的 OllyICE; 下面开始流水作业(考虑到篇幅和精力,本人未启用完全手脱功能); 1、寻找OEP 打开 ArmaDetach v1.3,选择 CopyMem-II 模式,拖入 HwndSpy.exe 文件,显示信息 ------------------------------------- Filename: HwndSpy.exe Parent process iD: [000004BC] Processing... [PROTECTiON SYSTEM] Professional Edition [PROTECTiON OPTiONS] Debug-Blocker protection detected CopyMem-II protection detected Memory-Patching Protections enabled Import Table Elimination enabled [CHiLD iNFO] Crypto call found: [0049BA76] Child process iD: [00000D9C] // 进程ID Entry point: [0042A2C6] // OEP Original bytes: [558BEC6A] // OEP 处4个字节值 Detached successfully :) ------------------------------------- 打开OD,附加进程 00000D9C 后 Alt+F9,会停在 OEP,还原上面的4个字节值后: 0042A2C6 55 push ebp 0042A2C7 8BEC mov ebp,esp 0042A2C9 6A FF push -1 0042A2CB 68 F8424500 push HwndSpy.004542F8 0042A2D0 68 B8914200 push HwndSpy.004291B8 0042A2D5 64:A1 00000000 mov eax,dword ptr fs:[0] 0042A2DB 50 push eax 2、处理IAT 为避免功亏一篑,这里推荐使用 ArmaDetach v1.1,拖入 HwndSpy.exe 文件后显示信息 ------------------------------------- DONE! Child process ID: 0000092C // 进程ID Entry point: 004BD000 // 壳的入口 Original bytes: 60E8 // 壳的入口处头2个字节值 ------------------------------------- 再打开一个OD,附加进程 00000B54,Alt+F9返回并还原上面的2个字节到入口: 004BD000 > 60 pushad 004BD001 E8 00000000 call HwndSpy.004BD006 004BD006 5D pop ebp 004BD007 50 push eax 004BD008 51 push ecx 004BD009 0FCA bswap edx 004BD00B F7D2 not edx 004BD00D 9C pushfd 用 ODbgScript v1.47 载入上面保存的脚本文件,程序会自动执行,将进程由双变单; 然后 he GetModuleHandleA,Shift + F9一直运行,注意观察堆栈窗口,直到依次出现: 00127A6C 00D752BA /CALL 到 GetModuleHandleA 来自 00D752B4 00127A70 00D88BAC \pModule = "kernel32.dll" 00127A74 00D89CC4 ASCII "VirtualAlloc" ... 00127A6C 00D752D7 /CALL 到 GetModuleHandleA 来自 00D752D1 00127A70 00D88BAC \pModule = "kernel32.dll" 00127A74 00D89CB8 ASCII "VirtualFree" ... 001277D0 00D64F0D /CALL 到 GetModuleHandleA 来自 00D64F07 001277D4 00127920 \pModule = "kernel32.dll" 001277D8 00000000 取消断点,Alt+F9返回到 00D64F0D 8B0D AC0DD900 mov ecx,dword ptr ds:[D90DAC] 00D64F13 89040E mov dword ptr ds:[esi+ecx],eax 00D64F16 A1 AC0DD900 mov eax,dword ptr ds:[D90DAC] 00D64F1B 391C06 cmp dword ptr ds:[esi+eax],ebx 00D64F1E 75 16 jnz short 00D64F36 00D64F20 8D85 B4FEFFFF lea eax,dword ptr ss:[ebp-14C] 00D64F26 50 push eax 00D64F27 FF15 B432D800 call dword ptr ds:[D832B4] ; kernel32.LoadLibraryA 00D64F2D 8B0D AC0DD900 mov ecx,dword ptr ds:[D90DAC] 00D64F33 89040E mov dword ptr ds:[esi+ecx],eax 00D64F36 A1 AC0DD900 mov eax,dword ptr ds:[D90DAC] 00D64F3B 391C06 cmp dword ptr ds:[esi+eax],ebx 00D64F3E 0F84 2F010000 je 00D65073 ; Magic jump, 改成 jmp 后,Enter 跟随 来到 00D65073 83C7 0C add edi,0C 00D65076 89BD 78FDFFFF mov dword ptr ss:[ebp-288],edi 00D6507C 83C6 04 add esi,4 00D6507F 395F FC cmp dword ptr ds:[edi-4],ebx 00D65082 ^ 0F85 49FEFFFF jnz 00D64ED1 00D65088 EB 03 jmp short 00D6508D ; 这里F4 00D6508A D6 salc 00D6508B D6 salc 00D6508C 8F ??? ; 未知命令 恢复上面的修改,在内存镜像的 .text 段F2下断,Shift+F9运行后断下,IAT解码完毕; 现在回到前一个OD,右键查找模块调用(Search for all intermodular calls),在结果中随便点一个已解码函数调 用,回车后跟随IAT地址,比如到 00F21748 7C80E87C kernel32.FileTimeToSystemTime 00F2174C 7C80E8F6 kernel32.FileTimeToLocalFileTime 00F21750 773D7E70 COMCTL32.CreatePropertySheetPageA 随便复制几个字节的二进制码,到后一个 OD 的内存镜像中查找该值,会找到 00F312CC 020C0119 00F312D0 77F18BEE GDI32.SaveDC 00F312D4 7E41945D USER32.GetWindowLongA 00F312D8 00D6623E 00F312DC 7E42D312 USER32.DestroyIcon 00F312E0 7E42D312 USER32.DestroyIcon ... 00F31BF0 77F1E9BE GDI32.Rectangle 00F31BF4 7E4186C7 USER32.GetDC 00F31BF8 77F1DCFF GDI32.GetTextExtentPointA 00F31BFC 00000000 将这些已完全解码的 IAT 指针值,用二进制方式复制并粘贴到前一个OD的IAT中,注意不要错位; 然后打开 ArmInline,载入前一个OD,在输入表乱序选项卡中填写: New base va of IAT = 0046D000 Length of existing IAT = 1000 (AmrInline 提供的值通常会偏小) 最后点 Rebase IAT,输入表就移动到 0046D000 处了; 当然,如果不想用 ArmInline,可以试试 ImportRec的重建IAT功能; 3、dump 内存镜像,用 ImportRec 恢复一下 IAT,脱壳完毕; 二、破解: Armadillo 壳的破解起来比较简单,主要用到两个函数:LoadLibrary、GetEnvironmentVariable,对于某些版 本可以 直接修改验证段的返回值,但是如果程序在多处有检测,逐一修改不仅麻烦,还有可能会错过暗桩的处理; 1、bp LoadLibraryA Armadillo 在验证时,一般会先 LoadLibrary("Armaccess.dll"),凭该函数断点,很容易找到关键代码: 004145A6 8D85 30FFFFFF lea eax,dword ptr ss:[ebp-D0] 004145AC 50 push eax 004145AD FF15 14D24600 call dword ptr ds:[<&kernel32.LoadLibraryA>] ; kernel32.LoadLibraryA 004145B3 8BF8 mov edi,eax 004145B5 3BFB cmp edi,ebx 004145B7 897D F8 mov dword ptr ss:[ebp-8],edi 004145BA 75 09 jnz short 004145C5 ; 成 功载入就会跳走 004145BC 5F pop edi 004145BD 5E pop esi 004145BE 33C0 xor eax,eax ; 否 则返回0,所以要让它返回1 004145C0 5B pop ebx 004145C1 8BE5 mov esp,ebp 004145C3 5D pop ebp 004145C4 C3 retn 往上到段首 00414550 55 push ebp 00414551 8BEC mov ebp,esp 00414553 81EC 98010000 sub esp,198 00414559 53 push ebx 0041455A 56 push esi 0041455B 57 push edi 改为 00414550 33C0 xor eax,eax 00414552 40 inc eax 00414553 C3 retn 2、bp GetEnvironmentVariableA Armadillo 会使用该函数获取一些环境变量,也就是注册信息,对于本程序,要检测的变量为: HPSKEYTYPE、USESLEFT、HPSMAXDAYS、DAYSINSTALLED、USERKEY、USERNAME、 HPSVERSION、HPSPRODUCTID 当然前面还有个 FIRSTRUN,这些变量名是用 GetEnvironmentVariableA 断点跟踪获得的,本程序的调用方式如下: ----------------------------------------------------------- typedef DWORD (WINAPI * PGENV)(LPCTSTR, LPTSTR, DWORD); HMODULE hDLL = LoadLibrary("kernel32.dll"); // hDLL = GetModuleHandle("kernel32.dll"); if (hDLL) { PGENV getenv = (PGENV)GetProcAddress(hDLL, "GetEnvironmentVariableA"); if (getenv) { getenv("USERKEY", szKey, sizeof(szKey) / sizeof(TCHAR)); // 检查 szKey 值 } } ----------------------------------------------------------- 下面是找到的验证过程函数之一: 00401A50 64:A1 00000000 mov eax,dword ptr fs:[0] 00401A56 6A FF push -1 00401A58 68 2DA04400 push 0044A02D 00401A5D 50 push eax 00401A5E 64:8925 00000000 mov dword ptr fs:[0],esp 00401A65 81EC E0030000 sub esp,3E0 00401A6B 8D4424 18 lea eax,dword ptr ss:[esp+18] 00401A6F 50 push eax 00401A70 E8 4BEB0000 call 004105C0 ; 这 里开始Patch,改成 jmp 0044D150 00401A75 83C4 04 add esp,4 00401A78 85C0 test eax,eax 00401A7A 0F84 47090000 je 004023C7 Patch代码: 0044D150 60 pushad 0044D151 E8 00000000 call 0044D156 0044D156 5F pop edi 0044D157 83EF 06 sub edi,6 0044D15A 83C7 50 add edi,50 0044D15D 33C0 xor eax,eax 0044D15F 66:8B07 mov ax,word ptr ds:[edi] 0044D162 66:85C0 test ax,ax 0044D165 74 13 je short 0044D17A 0044D167 03C7 add eax,edi 0044D169 50 push eax 0044D16A 66:0347 02 add ax,word ptr ds:[edi+2] 0044D16E 50 push eax 0044D16F FF15 C8D34600 call dword ptr ds:[46D3C8] ; kernel32.SetEnvironmentVariableA 0044D175 83C7 04 add edi,4 0044D178 ^ EB E3 jmp short 0044D15D 0044D17A 61 popad 0044D17B E8 4034FCFF call 004105C0 0044D180 ^ E9 F048FBFF jmp 00401A75 二进制: 60 E8 00 00 00 00 5F 83 EF 06 83 C7 50 33 C0 66 8B 07 66 85 C0 74 13 03 C7 50 66 03 47 02 50 FF 15 C8 D3 46 00 83 C7 04 EB E3 61 E8 40 34 FC FF E9 F0 48 FB FF 数据部分: 0044D1A0 00040060 0044D1A4 0004006C 0044D1A8 00040078 0044D1AC 00040084 0044D1B0 00380094 0044D1B4 000800D4 0044D1B8 000400E8 0044D1BC 000800F4 二进制: 60 00 04 00 6C 00 04 00 78 00 04 00 84 00 04 00 94 00 38 00 D4 00 08 00 E8 00 04 00 F4 00 08 00 ... 0044D200 00000034 4... 0044D204 4B535048 HPSK 0044D208 59545945 EYTY 0044D20C 00004550 PE.. 0044D210 00000031 1... 0044D214 53455355 USES 0044D218 5446454C LEFT 0044D21C 00000000 .... 0044D220 00000032 2... 0044D224 4D535048 HPSM 0044D228 41445841 AXDA 0044D22C 00005359 YS.. 0044D230 00000030 0... 0044D234 53594144 DAYS 0044D238 54534E49 INST 0044D23C 454C4C41 ALLE 0044D240 00000044 D... 0044D244 31313131 1111 0044D248 31313131 1111 0044D24C 3232322D -222 0044D250 32323232 2222 0044D254 33332D32 2-33 0044D258 33333333 3333 0044D25C 342D3333 33-4 0044D260 34343434 4444 0044D264 2D343434 444- 0044D268 35353535 5555 0044D26C 35353535 5555 0044D270 3636362D -666 0044D274 36363636 6666 0044D278 00000036 6... 0044D27C 52455355 USER 0044D280 0059454B KEY. 0044D284 00000000 .... 0044D288 6B636F72 rock 0044D28C 00007874 tx.. 0044D290 52455355 USER 0044D294 454D414E NAME 0044D298 00000000 .... 0044D29C 00000000 .... 0044D2A0 00000031 1... 0044D2A4 56535048 HPSV 0044D2A8 49535245 ERSI 0044D2AC 00004E4F ON.. 0044D2B0 31303546 F501 0044D2B4 00000000 .... 0044D2B8 50535048 HPSP 0044D2BC 55444F52 RODU 0044D2C0 44495443 CTID 二进制: 34 00 00 00 48 50 53 4B 45 59 54 59 50 45 00 00 31 00 00 00 55 53 45 53 4C 45 46 54 00 00 00 00 32 00 00 00 48 50 53 4D 41 58 44 41 59 53 00 00 30 00 00 00 44 41 59 53 49 4E 53 54 41 4C 4C 45 44 00 00 00 31 31 31 31 31 31 31 31 2D 32 32 32 32 32 32 32 32 2D 33 33 33 33 33 33 33 33 2D 34 34 34 34 34 34 34 34 2D 35 35 35 35 35 35 35 35 2D 36 36 36 36 36 36 36 36 00 00 00 55 53 45 52 4B 45 59 00 00 00 00 00 72 6F 63 6B 74 78 00 00 55 53 45 52 4E 41 4D 45 00 00 00 00 00 00 00 00 31 00 00 00 48 50 53 56 45 52 53 49 4F 4E 00 00 46 35 30 31 00 00 00 00 48 50 53 50 52 4F 44 55 43 54 49 44 原理是调用 SetEnvironmentVariableA 设置环境变量: -------------------------------------------------------- HPSKEYTYPE = "4" (注册码类型,必须为4) USESLEFT = "1" HPSMAXDAYS = "2" (日期限制) DAYSINSTALLED = "0" USERKEY = "11111111-22222222-33333333-44444444-55555555-66666666" (注 册码任意,长度区间[41, 100]) USERNAME = "rocktx" (用户名任意,但不能是"DEFAULT",长度不大于100) HPSVERSION = "1" (版本ID,即:1.9版,是程序之前用 GetFileVersion 获得的) HPSPRODUCTID = "F501" -------------------------------------------------------- 最后要导入注册表(要和环境变量相匹配): -------------------------------------------------------- Windows Registry Editor Version 5.00 [HKEY_CURRENT_USER\Software\High Plains Software\HPS HwndSpy\User] "UserName"="rocktx" "User"="rocktx" "RegistrationKey"="11111111-22222222-33333333-44444444-55555555-66666666" -------------------------------------------------------- 三、优化 1、挪动IAT (这一步可以合并到脱壳阶段) 对于一般的 VC 程序,IAT是在 .rdata 区段,以 Notepad98.exe 为例,用 LordPE 查看输入表 在 00406000 处,在OD中: 00406000 000061B4 00406004 FFFFFFFF 00406008 FFFFFFFF 0040600C 00006592 // 这里就是第一个模块 shell32.dll 的偏移,查看 00406592 就会看到 00406010 000063F8 现在回到 HwndSpy 的.rdata段,右键查找字符串:kernel32.dll,找到 0045D1BE 4E52454B KERN 0045D1C2 32334C45 EL32 0045D1C6 6C6C642E .dll 显然,该模块的偏移值为 0005D1BE,继续查找这个常量,来到 0045BFA8 00000000 // 这里就是IAT的原始位置,RVA = 0005BFA8 0045BFAC 00000000 0045BFB0 00000000 0045BFB4 0005D1BE // 这里指向 kernel32.dll 0045BFB8 00000000 当然,kernel32.dll 不一定是第一个模块,数据窗口中上下翻翻,自己确定一下。 从 0045BFA8 到 .rdata 段尾用 00 清空(如果程序有导出表,注意不要一并清空了),将程序保存为一个副本 0001.exe, 以后的操作 都针对这个副本进行,打开 ImportRec,选项中只勾选 Create New IAT (重建IAT) ,获取 IAT 后还原 到 RVA 0005BFA8 处即可; 2、挪动资源 LordPE 查看 .text1 区段的偏移为 0006D000,下面的步骤就是将资源放到这里: a、用 FixRes 打开0001.exe,NewRVA = 0006D000,FileAlignment = 1000,选择导出路径后, 点 Dump Resource; b、用 CFF Explorer 打开0001.exe,除了前三个区段,将后面的垃圾区段全部删除 (Delete Section (Header and Data))后保存; c、用 LordPE 打开0001.exe,查看区段表,右键 Load section from disk...(从磁盘中载入区段),载入刚 才 Dump 的资源文件; 如果想要完美,可以将区段名改为 .rsrc,区段属性改为 40000040; d、修正资源的 RVA 为 0006D000,重建一下PE; e、最后修正可选头中的编译器链接版本为 0600,以免 Peid 认不出来,将 Base of Code 改成 00001000,以 免 OD 分析不了代码结构; 3、去掉多余的菜单项( 这些菜单项的功能纯粹是增加右键菜单长度 ): 00405CB4 8B55 04 mov edx,dword ptr ss: [ebp+4] ; 改成 jmp 00405D05 00405CB7 6A 00 push 0 00405CB9 6A 00 push 0 00405CBB 68 00080000 push 800 00405CC0 52 push edx 00405CC1 FFD7 call edi 00405CC3 8B45 04 mov eax,dword ptr ss:[ebp+4] 00405CC6 68 B8FF4500 push 0045FFB8 ; ASCII "Re&gister..." 至此,程序处理完毕,大小 568 kb,可以用UPX压缩; -------------------------------------------------------------------------------- 【经验总结】 全在上面了,好累,以后注意劳逸结合,Armageddon处理一下就可以了。 -------------------------------------------------------------------------------- 【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢! 2010年06月03 日 22:05:12 |
2010年6月4日星期五
轉帖:Armadillo脫殼
訂閱:
發佈留言 (Atom)
沒有留言:
發佈留言