首页
社区
课程
招聘
[翻译]haggar教程:PESpin 1.304 public - repairing IAT
发表于: 2019-2-16 21:56 7840

[翻译]haggar教程:PESpin 1.304 public - repairing IAT

2019-2-16 21:56
7840
======================================
 PESpin 1.304 public - 修复 IAT
======================================

原文地址:http://www.reversing.be/article.php?story=20060224214713516

这个版本的PESpin和以前的1.3完全无关。在这个公开版本中,对脱壳来说没有什么新的东西(除了新的重定向JMP-CMP),因为这个版本只是为了解决可兼容性问题。但是在前面的教程中,没有解释如何正确修复IAT,只是一些在用户机器上运行转储的技巧,所以这部分将在本教程中得到更好的介绍。



1. 工具和材料

工具是常见的:

- OllyDbg 1.10
- ImpREC
- LordPE
- Windows XP
- 目标在这: [http://www.reversing.be/binaries/articles/20060224214414479.rar]


本教程将是简短的,因此,您将检查前面的更详细的那些不会是坏事。



2. OEP and stolen code

如果您记得过去的教程,PESpin在跳转到OEP之前将使用的最后一个API是GetTickCount。 它可能会使用它来获取一些随机值,以破坏它不再需要的代码/数据。 因此,我们可以在该API的末尾放置断点(PESpin检查CC字节的第一个字节)并返回保护代码。 所以我们现在非常接近OEP跳转。 PESpin将使用远跳转到原始代码部分。 所以我们可以到这个PESpin部分的开始并搜索对应于远跳的字节E9 ?????? FF。 然后我们找到所有那些可能的跳转,并且在401000部分跳转的第一个是好的。 我发现了这个跳转:
00417BC4  -E9 0F9AFEFF      JMP KeygenMe.004015D8
但是如前所述,PESpin也可以从OEP中窃取一些字节。 被窃取的代码被混淆了,但它始终以POPAD操作码开头,就是16进制的61。 因此向上滚动并搜索此字节。 你会发现它在调用操作码中被混淆:
00417AD8   E8 61F7D239      CALL 3A14723E
Patch第一个字节:
00417AD8   90               NOP
00417AD9   61               POPAD
现在将bp放在POPAD上,运行,你将在那里中断。 在POPAD之后就开始执行被盗代码。 但是被盗的字节被垃圾代码混淆了。 如果我们知道我们的目标是Visual C ++程序,那么找到它并不是什么大问题。 代码混淆并不难,我可以找到确切的字节:
00417B36   55               PUSH EBP
00417B3A   8BEC             MOV EBP,ESP
00417B3F   6A FF            PUSH -1

00417B44   68 3482111F      PUSH 1F118234 <------------------ 这4个操作码只是两个PUSH的混淆。
00417B49   812C24 6421D11E  SUB DWORD PTR SS:[ESP],1ED12164
00417B50   68 48F020F7      PUSH F720F048
00417B55   810424 B03D1F09  ADD DWORD PTR SS:[ESP],91F3DB0

00417B5C   64:A1 00000000   MOV EAX,DWORD PTR FS:[0]
00417B65   50               PUSH EAX
00417B69   64:8925 00000000 MOV DWORD PTR FS:[0],ESP
00417B73   83EC 58          SUB ESP,58
00417B79   53               PUSH EBX
00417B7D   56               PUSH ESI
00417B81   57               PUSH EDI
00417B85   8965 E8          MOV DWORD PTR SS:[EBP-18],ESP
00417B8B   FF15 CDA44100    CALL DWORD PTR DS:[41A4CD] <---- 混淆的API调用!
00417B94   33D2             XOR EDX,EDX
00417B99   8AD4             MOV DL,AH
00417B9E   8915 5C764000    MOV DWORD PTR DS:[40765C],EDX
00417BA7   8BC8             MOV ECX,EAX
00417BAC   81E1 FF000000    AND ECX,0FF
00417BB5   890D 58764000    MOV DWORD PTR DS:[407658],ECX
00417BBE   C1E1 08          SHL ECX,8
00417BC4  -E9 0F9AFEFF      JMP KeygenMe.004015D8 <------ 没有被盗,它会跳到假的OEP.
我们可以稍后恢复这些字节。 但这4个:
PUSH 1F118234
SUB DWORD PTR SS:[ESP],1ED12164
PUSH F720F048
ADD DWORD PTR SS:[ESP],91F3DB0
有:
PUSH 4060D0
PUSH 402DF8
但所有这一切都没有必要。 我们可以在这一行上转储:
00417B36   55               PUSH EBP
并且转储会很好。 只是OEP将在PESpin部分,而不是在第一部分。

3. Redirected code(三种重定向到PE头)

如果我们执行OEP跳转:
00417BC4  -E9 0F9AFEFF      JMP KeygenMe.004015D8
我们将在代码部分中看到第一种重定向的代码(CALL-JMP):特征码#E8??????FF#
004015EB   . E8 E8EBFFFF    CALL KeygenMe.004001D8
众所周知,从以前的版本中,CALL导致
004001D8  -E9 E6160000      JMP KeygenMe.004018C3
并且JMP只是返回某个位置。 所以CALL到PE头是原始文件CALL到某个地址。 

第二种重定向如下所示(JMP-PUSH):特征码#E9??????FF#
0040169E   .-E9 95EBFFFF    JMP KeygenMe.00400238
跳转到
00400238   68 FF000000      PUSH 0FF <--------------- 这是重定向的操作码。
0040023D  -E9 61140000      JMP KeygenMe.004016A3 <-- 回来了。

Jumps 替代了 pushes.

第三种我在1.3版本的PEspin中没有看到的新的重定向(JMP-CMP):特征码#E9??????FF9090#
00401687   $-E9 94EBFFFF    JMP KeygenMe.00400220
0040168C     90             NOP
0040168D     90             NOP
跳转到
00400220   833D 38764000 01   CMP DWORD PTR DS:[407638],1 <------ 重定向的操作码。
00400227  -E9 62140000        JMP KeygenMe.0040168E <------------ 回来了。
现在我可以编写可以修复该代码的OllyScript插件的小脚本。 在附件中看到它。 该脚本适用于所有1.x版本的PEPsin(应该)。

在运行时解密的代码块,所谓的“清除和加密标记”将不在本教程中讨论。 检查最后一个。

这就是全部。 只是IAT需要修复 :)

4. Problem with IAT

这不是一个难题,但在之前的教程中我没有足够的知识来了解ImpREC,PE结构等。首先我们需要看看我们的导入发生了什么,然后我们会考虑如何修复它们。 我在LoadLibraryA和GetProcAddress上放置断点以捕获正在处理导入的位置,但我什么也没找到。 这意味着PESpin不会使用这些api来加载库并找到api,而是可能有自定义编码函数来完成这项工作。 然后我检查已经加载的模块,当olly打开目标并播种(已经被Windows加载器加载)所有需要的dll:
Executable modules
Base       Size       Entry      Name       File version      Path
00400000   0001C000   004160D4   KeygenMe                     D:\PESpin\PESpin v1.304\KeygenMe.exe
77340000   0008B000   773419ED   COMCTL32   5.82 (xpsp1.0208  C:\WINDOWS\system32\COMCTL32.DLL
77D40000   0008C000   77D53A05   USER32     5.1.2600.1561 (x  C:\WINDOWS\system32\USER32.DLL
77DD0000   0008D000   77DD1D3D   ADVAPI32   5.1.2600.1106 (x  C:\WINDOWS\system32\ADVAPI32.dll
77E60000   000E6000   77E7ADB3   kernel32   5.1.2600.1560 (x  C:\WINDOWS\system32\kernel32.dll
77F50000   000A7000              ntdll      5.1.2600.1106 (x  C:\WINDOWS\System32\ntdll.dll
78000000   00087000   78001E0D   RPCRT4     5.1.2600.1361 (x  C:\WINDOWS\system32\RPCRT4.dll
7F000000   00041000              GDI32      5.1.2600.1561 (x  C:\WINDOWS\system32\GDI32.dll
如果我只是在olly中运行目标,则不会加载新模块。 这给了我们第一个可能的答案,为什么不使用LoadLibraryA。 实际上它使用了几次,但不是用于API重定向目的。 GetProcAddress也使用了几次,但不适用于我们的api。 所以我采用另一种方法来节省跟踪代码的时间。

让我们找到OEP,看看第一次导入跳转的位置。 这是第一次导入跳转,即。 call:
00401605   . FF15 C8A44100  CALL DWORD PTR DS:[41A4C8]
我们看到它指向PESpin壳段而不是406000的IAT(应该)段。 检查该地址的转储:
0041A4C8  4B 02 3B 00 00 6A 02 3B 00 00 8E 02 3B 00 00 A9  K.;..j.;....;..?
0041A4D8  02 3B 00 00 BD 02 3B 00 00 DD 02 3B 00 00 F9 02  .;....;....;....
0041A4E8  3B 00 00 11 03 3B 00 00 30 03 3B 00 00 48 03 3B  ;....;..0.;..H.;
...
我们看到PESpin创建了一个指向003B0000部分的表。 指针dwords用0字节分隔。 这可能会扰乱ImpREC获取表,因为指针分隔应该用零终止dword(就是什么也没有)。 指针导致混淆的api跳转,或整个模拟api(如果它非常小,只有一行):
003B024B   EB 01            JMP SHORT 003B024E;跳到混淆的地方去了
003B024D   D9A1 1476ED77    FLDENV (28-BYTE) PTR DS:[ECX+77ED7614]
003B0253   C3               RETN
为Olly编写可以重建新表的小脚本很容易,但我们可以从导入跳转中删除混淆。 作为easies选项,我决定将内存断点放在003B0000部分,这样我就可以找到PESpin在那里写入混淆代码的地方。 好的,在VirtualAlloc上bp,等待直到它分配该部分。 然后内存bp就可以了。 我在这里停了下来:
00416BCE   66:C706 EB01     MOV WORD PTR DS:[ESI],1EB
00416BD3   C646 02 D9       MOV BYTE PTR DS:[ESI+2],0D9
00416BD7   83C6 03          ADD ESI,3
00416BDA   2BD2             SUB EDX,EDX
00416BDC   EB 01            JMP SHORT KeygenMe.00416BDF
00416BDE   EA EB04EAEB 0400 JMP FAR 0004:EBEA04EB
...
...
PESpin在这里写了某些东西。 我们处于混淆正在进行中的代码的一部分。 如果我们从上一个教程中记得,这个过程(IAT重定向)从PUSHAD开始,以POPAD结束。 向上滚动以查找PUSHAD:
00416BAF   60               PUSHAD <----------------------- 呀,在这里。
00416BB0   EB 01            JMP SHORT KeygenMe.00416BB3
00416BB2  ^71 EB            JNO SHORT KeygenMe.00416B9F
00416BB4   04 D5            ADD AL,0D5
00416BB6   EB 04            JMP SHORT KeygenMe.00416BBC
00416BB8   6BEB FB          IMUL EBP,EBX,-5
...
...
我们非常接近任务的结束,将硬件执行bp放在PUSHAD上并重新启动目标。 在Olly中运行它你应该会在那里中断。 再次,在之前的教程中,我们宣称这个步骤可以这样:从PUSHAD到POPAD NOP-ed,我们将杀死混淆:
00416BAF   60               PUSHAD
00416BB0   90               NOP
00416BB1   90               NOP
00416BB2   90               NOP
...
...
...
00416C95   90               NOP
00416C96   90               NOP
00416C97   90               NOP
00416C98   61               POPAD
00416C99   C9               LEAVE
00416C9A   C2 0800          RETN 8
此代码也不会通过完整性检查进行检查,因此我们可以保留它。 现在我们找到了本教程第一部分所描述的被盗代码(注意,已经使用了GetTickCount,因此您需要在此步骤之前找到代码地址),然后我们在正确的OEP上恢复它:
00401591  /. 55             PUSH EBP
00401592  |. 8BEC           MOV EBP,ESP
00401594  |. 6A FF          PUSH -1
00401596  |. 68 D0604000    PUSH KeygenMe.004060D0
0040159B  |. 68 F82D4000    PUSH KeygenMe.00402DF8                   ;  SE handler installation
004015A0  |. 64:A1 00000000 MOV EAX,DWORD PTR FS:[0]
004015A6  |. 50             PUSH EAX
004015A7  |. 64:8925 000000>MOV DWORD PTR FS:[0],ESP
004015AE  |. 83EC 58        SUB ESP,58
004015B1  |. 53             PUSH EBX
004015B2  |. 56             PUSH ESI
004015B3  |. 57             PUSH EDI                                 ;  KeygenMe.004188EA
004015B4  |. 8965 E8        MOV DWORD PTR SS:[EBP-18],ESP
004015B7  |. FF15 CDA44100  CALL DWORD PTR DS:[41A4CD]               ;  kernel32.GetVersion
004015BD  |. 33D2           XOR EDX,EDX
004015BF  |. 8AD4           MOV DL,AH
004015C1  |. 8915 5C764000  MOV DWORD PTR DS:[40765C],EDX
004015C7  |. 8BC8           MOV ECX,EAX
004015C9  |. 81E1 FF000000  AND ECX,0FF
004015CF  |. 890D 58764000  MOV DWORD PTR DS:[407658],ECX
004015D5  |. C1E1 08        SHL ECX,8
然后我们使用脚本来修复重定向的代码。

5. Fixing IAT

现在我们可以修复IAT了。 我为这个VC ++应用程序编写了一个小脚本,它将更改指向新选项卡的所有指针。 例如,这个call:
004015B7  |. FF15 CDA44100  CALL DWORD PTR DS:[41A4CD]               ;  kernel32.GetVersion
现在将指向新的地方:
004015B7  |. FF15 90604100  CALL DWORD PTR DS:[416090]               ;  kernel32.GetVersion
在那里我创建了新标签:
00416000  00 00 00 00 00 00 00 00 E0 56 D6 77 00 00 00 00  .........V.w....
00416010  1F 97 D4 77 00 00 00 00 1D 5F D4 77 00 00 00 00  ...w....._.w....
00416020  52 65 D6 77 00 00 00 00 52 65 D6 77 00 00 00 00  Re.w....Re.w....
00416030  52 65 D6 77 00 00 00 00 E4 D9 D4 77 00 00 00 00  Re.w.......w....
00416040  FE 65 D6 77 00 00 00 00 FE 65 D6 77 00 00 00 00  .e.w.....e.w....
00416050 >FE 65 D6 77 00 00 00 00 0F 6E D5 77 00 00 00 00  .e.w.....n.w....
00416060 >0F 6E D5 77 00 00 00 00 0F 6E D5 77 00 00 00 00  .n.w.....n.w....
00416070  93 5A E7 77 00 00 00 00 0C 16 E6 77 00 00 00 00  .Z.w.......w....
00416080  53 95 E7 77 00 00 00 00 A1 16 F5 77 00 00 00 00  S..w.......w....
00416090  95 D0 E7 77 00 00 00 00 AB E2 E7 77 00 00 00 00  ...w.......w....
004160A0  7E 17 E6 77 00 00 00 00 D9 AC E7 77 00 00 00 00  ~..w.......w....
004160B0  63 98 E7 77 00 00 00 00 25 E2 E7 77 00 00 00 00  c..w....%..w....
004160C0  7C 88 E7 77 00 00 00 00 A1 16 F5 77 00 00 00 00  |..w.......w....
004160D0  6B 15 F5 77 00 00 00 00 5F 8C F5 77 00 00 00 00  k..w...._..w....
004160E0  A1 16 F5 77 00 00 00 00 C5 AB E7 77 00 00 00 00  ...w.......w....
004160F0  6B 15 F5 77 00 00 00 00 C5 AB E7 77 00 00 00 00  k..w.......w....
00416100  0C E6 E7 77 00 00 00 00 B8 16 E6 77 00 00 00 00  ...w.......w....
00416110  63 98 E7 77 00 00 00 00 95 9B E9 77 00 00 00 00  c..w.......w....
00416120  FC AC E7 77 00 00 00 00 3B 95 E6 77 00 00 00 00  ...w....;..w....
00416130  E8 E4 E7 77 00 00 00 00 3B 95 E6 77 00 00 00 00  ...w....;..w....
00416140  2F E0 E9 77 00 00 00 00 7E 17 E6 77 00 00 00 00  /..w....~..w....
00416150  4E E3 E7 77 00 00 00 00 E7 E3 E7 77 00 00 00 00  N..w.......w....
00416160  4E E3 E7 77 00 00 00 00 A4 E2 E7 77 00 00 00 00  N..w.......w....
00416170  FC AC E7 77 00 00 00 00 E7 E3 E7 77 00 00 00 00  ...w.......w....
00416180  8D F0 E7 77 00 00 00 00 53 95 E7 77 00 00 00 00  ...w....S..w....
00416190  1B E0 E7 77 00 00 00 00 7F C9 E6 77 00 00 00 00  ...w.......w....
004161A0  7F C9 E6 77 00 00 00 00 4F A7 E7 77 00 00 00 00  ...w....O..w....
004161B0  4F A7 E7 77 00 00 00 00 1B E0 E7 77 00 00 00 00  O..w.......w....
004161C0  B1 E2 E7 77 00 00 00 00 B1 E2 E7 77 00 00 00 00  ...w.......w....
004161D0  6B 15 F5 77 00 00 00 00 A1 16 F5 77 00 00 00 00  k..w.......w....
004161E0  B4 D8 E7 77 00 00 00 00 D1 DD E7 77 00 00 00 00  ...w.......w....
004161F0  84 9F E7 77 00 00 00 00 84 9F E7 77 00 00 00 00  ...w.......w....
00416200  4F A7 E7 77 00 00 00 00 4F A7 E7 77 00 00 00 00  O..w....O..w....
00416210  D1 DD E7 77 00 00 00 00 D1 DD E7 77 00 00 00 00  ...w.......w....
00416220  D1 DD E7 77 00 00 00 00 9C A8 E7 77 00 00 00 00  ...w.......w....
00416230  E8 D8 E7 77 00 00 00 00 23 5D E7 77 00 00 00 00  ...w....#].w....
00416240  23 5D E7 77 00 00 00 00 B1 E2 E7 77 00 00 00 00  #].w.......w....
00416250  4F A7 E7 77 00 00 00 00 4F A7 E7 77 00 00 00 00  O..w....O..w....
00416260  E8 D8 E7 77 00 00 00 00 B4 90 E6 77 00 00 00 00  ...w.......w....
00416270  A1 16 F5 77 00 00 00 00 5F 8C F5 77 00 00 00 00  ...w...._..w....
00416280  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00416290  C2 25 E7 77 00 00 00 00 DE AF E7 77 00 00 00 00  .%.w.......w....
004162A0  44 0C F6 77 00 00 00 00 00 00 00 00 00 00 00 00  D..w............
004162B0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00     ...............
现在我们有了thunk,每个导入值用4个零终止字节分隔,ImpREC可以很容易地读取它。 现在我们只运行ImpREC并修复转储文件。 保存文件,运行,...,呀,它工作起来了 :)

这不是完美的工作,因为属于同一个dll的thunk应该粘在一起,这会减少文件的大小,我们也可以删除PESpin部分,但是,嘿,现在dump工作在每台机器上 :)

再见!

haggar

快捷脱壳:
1、找回代码+OEP:忽略所有异常OD载入目标,ESP定律+F7单步+去除花指令找到被偷代码及伪OEP=004015D8
2、API 处理:HE 00416BAF重启OD并F9运行断下来,NOP掉00416BB0-00416C97(从PUSHAD到POPAD)
             删掉硬件断点,M镜像401000处F2下断,F9运行到伪OEP=004015D8
3、修复代码:伪OEP=004015D8处上翻,空代码处二进制粘贴 
55  8B EC  6A FF  68 D0 60 40 00 68 F8 2D 40 00 64 A1 00 00 00 00  50  64 89 25
   00 00 00 00  83 EC 58 53  56  57  89 65 E8  FF 15 CD A4 41 00  33 D2 8A D4  89
   15 5C 76 40 00  8B C8  81 E1 FF 00 00 00  89 0D 58 76 40 00  C1 E1 08
4、重定向处理+IAT修复:运行脚本PESpin 1.x - Code Fixer.txt及PESpin 1.304 - VC imports.txt
5、Dump修复:用LordPE来Dump,OEP=1591,ImportREC高级方式获取API,剪掉多余项,转存即可运行了。

PEspin各版本历史:
History历史

v1.33 (c101)
★双进程
Added support for vs2010 files--------添加了对vs2010文件的支持
Minor bugs fixed--------小错误已修复

v1.32
★双进程
Added DLLs support--------添加了DLL支持

v1.304
★可以双进程
Fixed compatible with VMWare--------修复了与VMWare的兼容
Updated aPlib--------更新了aPlib
★在这个公开版本中,对脱壳来说没有什么新的东西(除了新的重定向JMP-CMP),因为这个版本只是为了解决可兼容性问题。
它具有三种重定向到PE头:
第一种重定向(CALL-JMP):特征码#E8??????FF#
第二种重定向(JMP-PUSH):特征码#E9??????FF#
第三种重定向(JMP- CMP):特征码#E9??????FF9090#

v1.3
Added Debug blocker option--------添加了阻止调试选项★双进程
★1.3版本具有高级代码重定向选项,公共版本中没有该选项。
它具有两种重定向到PE头:
第一种重定向(call-jmp):特征码#E8??????FF#
第二种重定向(JMP-PUSH):特征码#E9??????FF#

v1.2
Private version not available to public--------私人版本不向公众开放

v1.1
Added CRYPT_START & CRYPT_END markers--------添加了CRYPT_START和CRYPT_END标记
Added CLEAR_START & CLEAR_END markers--------添加了CLEAR_START和CLEAR_END标记
它具有两种重定向到PE头:
第一种重定向(call-jmp):特征码#E8??????FF#
第二种重定向(JMP-PUSH):特征码#E9??????FF#

v1.0
Added Code redirection option--------添加了代码重定向选项
Added optimize MS-DOS header size option--------添加了优化MS-DOS标头大小选项
Cleaned up GUI a bit--------稍微清理了GUI
★在这个版本中,PESpin有两个新技巧:API bp检查和代码重定向。
它具有两种重定向到PE头:
第一种重定向(call-jmp):特征码#E8??????FF#
第二种重定向(JMP-PUSH):特征码#E9??????FF#

 v0.7
Added auto configuration saving--------添加了自动配置保存
Generally improve file protection--------常规改善文件保护
 
v0.41
Added Compress resources option--------添加了压缩资源选项
Win2003 bug fixed--------已修复Win2003错误

v0.3
Added compression--------添加压缩
Added Strip Overlays option--------添加了“剥离附加数据”选项
★PESpin v0.3 有一些很好的功能; 良好的IAT重定向与一些仿真API操作码和被盗的OEP是它的最佳武器。 它也有一些基于异常的反调试技巧,但是Olly是免疫的,它检查SoftICE和NTICE,它有几个CRC校验,它有密码锁定和时间限制,但这不是问题。 在使用不同编译器编译的打包文件之间也存在一些小的差异 (VC++,Borland C++, Delphi, VB, ASM...).

v0.2
Generally improve a little bit whole loader code--------整个加载器代码的一点点常规改进

v0.1
Added password protection option--------添加了密码保护选项
Added remove the OEP option--------添加抽离OEP选项

v0.b
First official version--------第一个正式版


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 1
支持
分享
最新回复 (1)
雪    币: 403
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
2019-2-18 10:59
0
游客
登录 | 注册 方可回帖
返回
//