[转贴]
PELock 1.0x 脱壳之全科医生
【破解作者】 龙[D.4s]
【作者主页】
http://www.chinadforce.com
【使用工具】 OD,ImportREC,API_addr_Expert
【破解平台】 WinXP
【软件名称】 全科医生中西医结合诊疗咨询系统2004
【下载地址】
http://xwy48.3322.net/qkruanjian/qkzhuye.html
【软件简介】 该系统包括西医、中医和综合三大部分。
【软件大小】 11.3M
【加壳方式】 PELock 1.0x + 简单SDK
【破解声明】 只是抛砖引玉,还望各位指正。
--------------------------------------------------------------------------------
【破解内容】
一、到达OEP,Dump
OD载入,隐藏OD,忽略除内存访问外的所有异常
005A905C > C1C0 05 ROL EAX,5
005A905F F8 CLC
005A9060 73 01 JNB SHORT Doctor.005A9063
005A9062 78 0F JS SHORT Doctor.005A9073
005A9064 AF SCAS DWORD PTR ES:[EDI]
005A9065 C8 F20FB6 ENTER 0FF2,0B6
005A9069 C0E8 01 SHR AL,1
005A906C 0000 ADD BYTE PTR DS:[EAX],AL
005A906E 00EE ADD DH,CH
005A9070 58 POP EAX
005A9071 F8 CLC
Shift+F9,10次,查看堆栈
0012FFA4 /0012FFB8 指针到下一个 SEH 记录
0012FFA8 |0037382B SE 句柄
0012FFAC |005B0000 ASCII "WTNE / MADE BY E COMPILER - WUTAO "
0012FFB0 |00183000
0012FFB4 |00004000
0012FFB8 \0012FFE0 指针到下一个 SEH 记录
CPU窗口,Ctrl+G,来到37382B,F2设断,Shift+F9
0037382B /EB 02 JMP SHORT 0037382F
0037382D ^|70 E5 JO SHORT 00373814
0037382F \57 PUSH EDI
00373830 8B7C24 10 MOV EDI,DWORD PTR SS:[ESP+10]
00373834 EB 02 JMP SHORT 00373838
F8来到
00373841 018F B8000000 ADD DWORD PTR DS:[EDI+B8],ECX ; 特征,修改ConText结构,DS:[12FD90]=00373876,ECX=3
所以Ctrl+G来到37387+3=373879处,F2设断,F9运行
00373879 2BC9 SUB ECX,ECX
0037387B 64:8F01 POP DWORD PTR FS:[ECX]
0037387E 59 POP ECX
0037387F EB 01 JMP SHORT 00373882
00373881 65:EB 02 JMP SHORT 00373886 ; 多余的前缀
00373884 65:9C PUSHFD ; 多余的前缀
00373886 EB 01 JMP SHORT 00373889
Alt+M打开内存
内存镜像,项目 20
地址=00401000 //F2设断,F9运行
大小=00001000 (4096.)
Owner=Doctor 00400000
区段=XPROT
含=code
类型=Imag 01001002
访问=R
初始访问=RWE
来到
003773FD C602 E9 MOV BYTE PTR DS:[EDX],0E9
00377400 8BC7 MOV EAX,EDI
00377402 2BC2 SUB EAX,EDX
00377404 83E8 05 SUB EAX,5
00377407 8942 01 MOV DWORD PTR DS:[EDX+1],EAX
0037740A 8A06 MOV AL,BYTE PTR DS:[ESI]
0037740C 46 INC ESI
0037740D 0FB6C8 MOVZX ECX,AL
00377410 83E0 03 AND EAX,3
00377413 C1E9 02 SHR ECX,2
00377416 F3:A5 REP MOVS DWORD PTR ES:[EDI],DWO>
00377418 8BC8 MOV ECX,EAX
0037741A F3:A4 REP MOVS BYTE PTR ES:[EDI],BYTE>
0037741C 8A06 MOV AL,BYTE PTR DS:[ESI]
0037741E 46 INC ESI
0037741F 03D0 ADD EDX,EAX
00377421 C607 E9 MOV BYTE PTR DS:[EDI],0E9
00377424 2BD7 SUB EDX,EDI
00377426 83EA 05 SUB EDX,5
00377429 8957 01 MOV DWORD PTR DS:[EDI+1],EDX
0037742C 83C7 05 ADD EDI,5
0037742F 4B DEC EBX
00377430 ^ 75 C3 JNZ SHORT 003773F5
00377432 5F POP EDI
00377433 8D4D 66 LEA ECX,DWORD PTR SS:[EBP+66]
00377436 2BCF SUB ECX,EDI
00377438 F3:AA REP STOS BYTE PTR ES:[EDI]
0037743A 61 POPAD ; F4下来
0037743B C3 RETN
返回到
00376391 /EB 03 JMP SHORT 00376396
00376393 ^|71 9C JNO SHORT 00376331
00376395 |36:EB 02 JMP SHORT 0037639A ; 多余的前缀
00376398 0FF8EB PSUBB MM5,MM3
0037639B 0291 66EB02CD ADD DL,BYTE PTR DS:[ECX+CD02EB6>
003763A1 207403 75 AND BYTE PTR DS:[EBX+EAX+75],DH
003763A5 0148 78 ADD DWORD PTR DS:[EAX+78],ECX
003763A8 0379 01 ADD EDI,DWORD PTR DS:[ECX+1]
003763AB 8AE8 MOV CH,AL
003763AD 0100 ADD DWORD PTR DS:[EAX],EAX
003763AF 0000 ADD BYTE PTR DS:[EAX],AL
003763B1 ^ E0 8F LOOPDNE SHORT 00376342
再次Alt+M打开内存
内存镜像,项目 20
地址=00401000 //F2设断,F9运行
大小=00001000 (4096.)
Owner=Doctor 00400000
区段=XPROT
含=code
类型=Imag 01001002
访问=R
初始访问=RWE
在401000处中断,取消分析后,代码如下
00401000 E8 06000000 CALL Doctor.0040100B ; OEP
00401005 50 PUSH EAX
00401006 E8 A1010000 CALL Doctor.004011AC
0040100B 55 PUSH EBP
0040100C 8BEC MOV EBP,ESP
0040100E 81C4 F0FEFFFF ADD ESP,-110
00401014 EB 6D JMP SHORT Doctor.00401083
00401016 6B72 6E 6C IMUL ESI,DWORD PTR DS:[EDX+6E],>
0040101A 6E OUTS DX,BYTE PTR ES:[EDI] ; I/O 命令
0040101B 2E:66:6E OUTS DX,BYTE PTR ES:[EDI] ; I/O 命令
0040101E 72 00 JB SHORT Doctor.00401020
00401020 6B72 6E 6C IMUL ESI,DWORD PTR DS:[EDX+6E],>
00401024 6E OUTS DX,BYTE PTR ES:[EDI] ; I/O 命令
00401025 2E:66:6E OUTS DX,BYTE PTR ES:[EDI] ; I/O 命令
00401028 65:0047 65 ADD BYTE PTR GS:[EDI+65],AL
0040102C 74 4E JE SHORT Doctor.0040107C
0040102E 65:77 53 JA SHORT Doctor.00401084 ; 多余的前缀
二、函数修复
用ImprotREC只能修复一个无效指针,需要跟踪原程序,重新载入,10次Shift+F9后,直接在373879下断,Shift+F9到达后,在Dump区,Ctrl+G到402000,选中从402000到402030处下内存访问断点,F9,寄存器窗口依次可见每个待处理的函数,顺序是从402030开始的。根据寄存器窗口看到的函数名称,依次修复函数如下:
FThunk: 00002000 NbFunc: 00000003
1 00002000 advapi32.dll 01EC RegQueryValueExA
1 00002004 advapi32.dll 01C9 RegCloseKey
1 00002008 advapi32.dll 01E2 RegOpenKeyExA
FThunk: 00002010 NbFunc: 00000007
1 00002010 kernel32.dll 00E6 FreeLibrary
1 00002014 kernel32.dll 038F lstrcat
1 00002018 kernel32.dll 0166 GetModuleFileNameA
1 0000201C kernel32.dll 00AC ExitProcess
1 00002020 kernel32.dll 022F LoadLibraryA
1 00002024 kernel32.dll 018A GetProcAddress
1 00002028 kernel32.dll 039E lstrlen
FThunk: 00002030 NbFunc: 00000001
1 00002030 user32.dll 01DD MessageBoxA
三、SDK修复
函数修复完之后,还无法运行,有SDK,我们来逐一修复。运行脱壳文件,提示“3C00AD处不易读取”,OK,搜索常数“3C00AD”,找到如下地址
004011D3 - E9 D5EEFBFF JMP 003C00AD ; SDK
跟踪原程序,发现壳中只是简单的JMP 4011D8而已,所以这里NOP即可,保存修改,重新运行,提示“3C0095处不易读取”,找到如下地址。
004011C4 - E9 CCEEFBFF JMP 003C0095
跟踪原程序,发现最终进入函数
77E54155 > 6A 08 PUSH 8
77E54157 68 4019E677 PUSH kernel32.77E61940
77E5415C E8 80330000 CALL kernel32.77E574E1 ; 返回到这里
拿出API地址专家(感谢kongfoo为我们提供这么好的工具),输入77E54155,找API名,结果
77E54155 lstrcat 所在库:kernel32.dll
根据我们修复的IAT,lstrcat对应的是00002014,所以我们把 JMP 003C0095 修改成 JMP DWORD PTR DS:[402014]即可,保存修改,重新运行,提示“3C0089处不易读取”,OK,搜索常数“3C0089”,找到如下地址
004011BE $- E9 C6EEFBFF JMP 003C0089
F8一下,看到
003C0089 - FF25 20204000 JMP DWORD PTR DS:[402020] ; 哈哈,这不就是
LoadLibraryA吗,OK,不用跟了,直接修改,把 JMP 003C0089 修改成 JMP DWORD PTR DS:[402020]即可,保存修改,重新运行,到这里出错
00401152 - E9 D6EEFBFF JMP 003C002D
跟踪原程序,壳中代码是
003C002D 68 2A104000 PUSH 40102A ; Stolen Code,补上
003C0032 - E9 20110400 JMP Doctor.00401157
把 JMP 003C002D 修改为 PUSH 40102A,即可,保存修改,重新运行,这里出错
00401158 . E8 5B000000 CALL 1_.004011B8
F7进入后,发现SDK
004011B8 $- E9 C0EEFBFF JMP 003C007D
跟踪原程序,代码如下
003C007D - FF25 24204000 JMP DWORD PTR DS:[402024]
同上,把 JMP 003C007D 改成 JMP DWORD PTR DS:[402024]即可,保存修改,重新运行,这里出错
00401161 - E9 D2EEFBFF JMP 003C0038
跟踪原程序,代码如下
003C0038 68 E8030000 PUSH 3E8 ; Stolen Code,补上
003C003D - E9 24110400 JMP Doctor.00401166
把 JMP 003C0038 修改为 PUSH 3E8,即可,保存修改,重新运行,OK,修复完毕。
当然,现在程序中还有一下地方有类似 JMP 003CXXXX 的代码,不过不影响程序的运行和功能,就懒得去修复了:)
四、破解
破解就比较简单了,修改以下两处即可:
00573009 /0F85 0A000000 JNZ 1_.00573019 ; 改为JMP
005712EF /0F84 77000000 JE fix.0057136C ; NOP
===============================================================
|| 我在学习中,遇到很多疑问也,希望大哥们指教: :) ||||
===============================================================
一、到达OEP,Dump
F8来到
00373841 018F B8000000 ADD DWORD PTR DS:[EDI+B8],ECX ; 特征,修改ConText结构,DS:[12FD90]=00373876,ECX=3 <--------
<1>为什么要将00373873 改为 00373876 呢???
所以Ctrl+G来到373876+3=373879处,F2设断,F9运行 <--------
<2>37387 漏了个6 :)
00373879 2BC9 SUB ECX,ECX
二、函数修复
用ImprotREC只能修复一个无效指针,需要跟踪原程序,重新载入,10次Shift+F9后,直接在373879下断,Shift+F9到达后,在Dump区,Ctrl+G到402000,选中从402000到402030处下内存访问断点,F9,寄存器窗口依次可见每个待处理的函数,顺序是从402030开始的。根据寄存器窗口看到的函数名称,依次修复函数如下: <-----
<3>402000 这个值是如何确定的呢?
FThunk: 00002000 NbFunc: 00000003
1 00002000 advapi32.dll 01EC RegQueryValueExA
1 00002004 advapi32.dll 01C9 RegCloseKey
1 00002008 advapi32.dll 01E2 RegOpenKeyExA ----<&2>----
FThunk: 00002010 NbFunc: 00000007
1 00002010 kernel32.dll 00E6 FreeLibrary
1 00002014 kernel32.dll 0390 lstrcatA <------
<4> 我查到的不是lstrcat ?
1 00002018 kernel32.dll 0166 GetModuleFileNameA
1 0000201C kernel32.dll 00AC ExitProcess
1 00002020 kernel32.dll 022F LoadLibraryA
1 00002024 kernel32.dll 018A GetProcAddress
1 00002028 kernel32.dll 039F lstrlenA <------
<5>和龙哥的不同,会有差异吗?
FThunk: 00002030 NbFunc: 00000001
1 00002030 user32.dll 01DD MessageBoxA ----<&1>----修改了以后为什么ImprotREC的 自动追踪 会认为它无效呢?
===================================================================================
EAX 77DA22EA ADVAPI32.RegOpenKeyExA ----<&2>----
ECX 00402008 <=== 这个:)
EDX 77DA0000 ADVAPI32.77DA0000
EBX 0038028A <=== 这个:) 未定位前,你可以看到它
ESP 0012FFAC
EBP 0037062D
ESI 005B0086
EDI 005B0062 ASCII "ADVAPI32.dll" <=== 这个:)
EIP 00374661
--------------------------------------
EAX 77D3ADD7 USER32.MessageBoxA ----<&1>----
ECX 00402030 Doctor.00402030
EDX 77D10000 USER32.77D10000
EBX 00380000
ESP 0012FFAC
EBP 0037062D
ESI 005B0010
EDI 005B0000 ASCII "USER32.dll"
EIP 00374661
---------------------------------------
ImprotREC
IAT 所需信息
OEP 0000100B
RVA 00002000 大小 00000038
按 获得输入信息 就能看到 FThunk ,按照龙哥写的改就好了:)
三、SDK修复
77E54155 > 6A 08 PUSH 8 <-------
<6>一定要用这个地址查找,是吗??好像是的:)
77E54157 68 4019E677 PUSH kernel32.77E61940
77E5415C E8 80330000 CALL kernel32.77E574E1
拿出API地址专家(感谢kongfoo为我们提供这么好的工具),输入77E54155,找API名,结果
77E54155 lstrcat 所在库:kernel32.dll
根据我们修复的IAT,lstrcat对应的是00002014,所以我们把 JMP 003C0095 修改成 JMP DWORD PTR DS:[402014]即可,保存 <------
<7>我尝试的结果和龙哥的一样,是lstrcat,但在函数修复中我看到的是lstrcatA,有差异吗??会不会有问题?? 还是出了问题...~~:( 跟了一下
我便将其改成了 004011C4 ^\E9 DDFEFFFF jmp Doctor_2.004010A6 不知道可不可以????
估计是不行~!重新来过~~~~~~!ImprotREC的选项全不勾[ 问题就出在这里:) ]
LoadLibraryA吗,OK,不用跟了,直接修改,把 JMP 003C0089 修改成 JMP DWORD PTR DS:[402020]即可,保存修改,重新运行,到这里出错 <------
<8>为什么只能保存这一句,而不能用全部保存(包括一个NOP)?????
00401152 - E9 D6EEFBFF JMP 003C002D
003C002D 68 2A104000 push 40102A ; ASCII "GetNewSock" <---
<9>有含义吗?
四、破解
破解就比较简单了,修改以下两处即可:
00573009 /0F85 0A000000 JNZ 1_.00573019 ; 改为JMP <-------
<10>检测了什么,为什么不跳过去就会自动退出呢?????
005712EF /0F84 77000000 JE fix.0057136C ; NOP
00572FE0 83C4 0C add esp, 0C <========跳出一个大循环
00571107 8B45 E4 mov eax, dword ptr ss:[ebp-1C]
|----1317604842
0057114E 68 89324000 push Doctor_X.00403289 ; ASCII "\Key.dat"
005712D0 837D FC 14 cmp dword ptr ss:[ebp-4], 14
005712D4 0F8F 11000000 jg Doctor_X.005712EB
005712DA 837D FC 00 cmp dword ptr ss:[ebp-4], 0
005712DE 0F8C 07000000 jl Doctor_X.005712EB
005712E4 B8 01000000 mov eax, 1
005712E9 EB 02 jmp short Doctor_X.005712ED
005712EB 33C0 xor eax, eax
005712ED 85C0 test eax, eax
005712EF 0F84 77000000 je Doctor_X.0057136C <------
<11> 修改完后,在移动到按钮处时仍然会很卡,不知道这算不算破解未完成呢?大家是不是都是这样?
脱了壳的程序似乎很杂乱`~~~~~有谁注册成功了吗??
[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法