-
-
[翻译]haggar教程:PESpin v1.0 , 1.1 & 1.3 - manually unpacking
-
发表于: 2019-2-16 17:20 7693
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
PESpin v1.x - 手动脱壳
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
原文地址:http://www.reversing.be/article.php?story=20050811173217736
嗨,欢迎来到我的新脱壳教程。
本教程是关于手动脱壳PESpin 1.x版本,更准确地说是1.0、1.1和1.3版本。但是,本教程有一些限制:
- 不会叙述PESpin v0.7,因为不需要这样做。如果您知道如何脱壳版本1.3,那么您就知道如何脱壳所有以前的版本。
- 版本1.2是私有版本,不能公开,所以我无法对这个版本进行检测。
- PESpin v1.3有高级代码重定向选项,这在公共版本中不可用,因此本教程将不涵盖这种保护(如果您发现目标包含该选项,请在论坛上给我发送一个PM)。
- 本教程中所有已脱壳的目标只在解包所在的计算机上运行。关于这一点,请阅读第一个教程。
教程面向高级初学者。您必须具备有关PE文件结构和如何使用脱壳工具的基本知识。
内容:
1. 工具和使用材料
2. 教程 1 - PESpin v1.0
3. 教程 2 - PESpin v1.1
4. 教程 3 - PESpin v1.3
5. 最后的话和致谢
1. 工具和使用材料
- OllyDbg 1.10
- LordPE
- Hex Editor
- 目标和材料: http://www.reversing.be/binaries/articles/20050811172936661.rar(图片不清晰请点此下载原作者Word文档)
在这个档案中,你会发现两个文件夹:“PESpin脚本”和“PESpin签名”。第一个文件夹包含一些用于解包PESpin的有用脚本。这些脚本离完美还很远,但它们能帮你一点忙。稍后再了解更多信息,或者只需在记事本中打开它们并阅读信息即可。在第二个文件夹中,您将找到PEID的签名。如果用peid扫描一些加了壳PESpin 1.x版本的文件,它将无法正确识别。只需将这些签名复制粘贴到peid文件夹中的userdb.txt,对压缩文件使用外部扫描,peid就可以识别真正的PESpin版本。如果你注意到一些错误,请发邮件或者PM给我。
如果您想更好地理解本教程,您应该阅读一些优秀的论文:
- Descryption of PE format(解密 PE 格式) by Michael J.O'Leary ; 我认为这是可以在BIW旧网站发现的。
- PORTABLE EXECUTABLE FILE FORMAT(可移植可执行文件格式) by Goppit ; 在这里找到它 http://cracking.accessroot.com/ , 它是6兆大的文件,值得下载。
- 阅读我以前的教程,了解如何解包PESpin 0.3,因为新版本在以前的版本中得到了改进。
2. 教程 1 - PESpin v1.0
在这个版本中,PESpin有两个新技巧:API bp检查和代码重定向。抓取第一个目标packed1.0.exe并在olly中打开它(设置为忽略所有异常)。查找oep和阻止输入表重定向与我们在0.3版本中所做的类似。
保护壳会检查API断点,打开“可执行模块”窗口,选择kernel32.dll并单击“查看名称”。找到GetTickCount并双击它。您现在应该在Kernel32:
77E7A1EE > BA 0000FE7F MOV EDX,7FFE0000 77E7A1F3 8B02 MOV EAX,DWORD PTR DS:[EDX] 77E7A1F5 F762 04 MUL DWORD PTR DS:[EDX+4] 77E7A1F8 0FACD0 18 SHRD EAX,EDX,18 77E7A1FC C3 RETN
77E7A1EE > BA 0000FE7F MOV EDX,7FFE0000 77E7A1F3 8B02 MOV EAX,DWORD PTR DS:[EDX] 77E7A1F5 F762 04 MUL DWORD PTR DS:[EDX+4] 77E7A1F8 0FACD0 18 SHRD EAX,EDX,18 77E7A1FC C3 RETN
把bp放在retn操作码(因为有API bp检查,不能放头部)上并运行目标程序。您将中断在kernel中的断点bp。删除BP并返回目标代码:
00409D17 8BD8 MOV EBX,EAX 00409D19 F7D3 NOT EBX 00409D1B 33D8 XOR EBX,EAX 00409D1D 43 INC EBX ... ...
00409D17 8BD8 MOV EBX,EAX 00409D19 F7D3 NOT EBX 00409D1B 33D8 XOR EBX,EAX 00409D1D 43 INC EBX ... ...
现在向上滚动,找到这个地方:
00409109 F9 STC ;也可能是 CLC (F8hex).(二进制查找:F9 72为无保护;F8 72为有保护,要NOP掉两J之间字节) 0040910A 72 0D JB SHORT packed1_.00409119 ;这里下断!!! 0040910C 8D85 0660271E LEA EAX,DWORD PTR SS:[EBP+1E276006] 00409112 2D 8417E71D SUB EAX,1DE71784 00409117 FFD0 CALL EAX ;调用计时器函数。 00409119 EB 01 JMP SHORT packed1_.0040911C
这是跳到OEP之前的最后一个地方,就像0.3版一样,除了这里有点不同:如果目标用定时器选项打包,那么将有clc=F8hex而不是第一个stc操作码。在这种情况下,将不执行JB,程序流将继续在创建计时器线程的地方校准EAX。这个地方对于所有下一个PESpin版本都是一样的。你只要把bp放在jb操作码上(不要运行目标)。再次向上滚动并查看这部分代码:
00409109 F9 STC ;也可能是 CLC (F8hex).(二进制查找:F9 72为无保护;F8 72为有保护,要NOP掉两J之间字节) 0040910A 72 0D JB SHORT packed1_.00409119 ;这里下断!!! 0040910C 8D85 0660271E LEA EAX,DWORD PTR SS:[EBP+1E276006] 00409112 2D 8417E71D SUB EAX,1DE71784 00409117 FFD0 CALL EAX ;调用计时器函数。 00409119 EB 01 JMP SHORT packed1_.0040911C
这是跳到OEP之前的最后一个地方,就像0.3版一样,除了这里有点不同:如果目标用定时器选项打包,那么将有clc=F8hex而不是第一个stc操作码。在这种情况下,将不执行JB,程序流将继续在创建计时器线程的地方校准EAX。这个地方对于所有下一个PESpin版本都是一样的。你只要把bp放在jb操作码上(不要运行目标)。再次向上滚动并查看这部分代码:
0040905F JMP DWORD PTR SS:[ESP-4] ;重要跳转,这里下断。 00409063 CALL FAR EB00:000003E8 ... ... ... ... 0040909B ??? 0040909C CALL packed1_.004089F2 004090A1 CALL packed1_.004090A9
0040905F JMP DWORD PTR SS:[ESP-4] ;重要跳转,这里下断。 00409063 CALL FAR EB00:000003E8 ... ... ... ... 0040909B ??? 0040909C CALL packed1_.004089F2 004090A1 CALL packed1_.004090A9
在那个跳转下断并运行目标。当你中断它,你会看到跳转到409022地址。该跳转对IAT重定向负责。如果没有IAT重定向,该跳转将跳转到它调用的40909C地址,并跳过所有重定向过程。为了避免IAT重定向,您只需在该跳转和40909C的call之间patch掉所有字节(您也可以对它本身进行patch):
0040905F NOP 00409060 NOP ... ... ... 0040909A NOP 0040909B NOP 0040909C CALL packed1_.004089F2 004090A1 CALL packed1_.004090A9 004090A6 JMP SHORT packed1_.004090AC 现在按下F9,中断在前面设置的断点: 00409109 STC ;F9(Hex) 0040910A JB SHORT packed1_.00409119 ;你在这里!!! 0040910C LEA EAX,DWORD PTR SS:[EBP+1E276006] 00409112 SUB EAX,1DE71784 00409117 CALL EAX 00409119 JMP SHORT packed1_.0040911C
现在,如果第一个操作码是clc(替代STC),请在0040910c、00409112和00409117处(两J之间)修补所有指令,以防止调用计时器函数。其实,你总是可以修补那个指令,在这种情况下它不会改变任何东西。然后向下滚动搜索popad操作码。您将看不到它,所以在一些指令中搜索61hex字节。我应该在这里:
0040905F NOP 00409060 NOP ... ... ... 0040909A NOP 0040909B NOP 0040909C CALL packed1_.004089F2 004090A1 CALL packed1_.004090A9 004090A6 JMP SHORT packed1_.004090AC 现在按下F9,中断在前面设置的断点: 00409109 STC ;F9(Hex) 0040910A JB SHORT packed1_.00409119 ;你在这里!!! 0040910C LEA EAX,DWORD PTR SS:[EBP+1E276006] 00409112 SUB EAX,1DE71784 00409117 CALL EAX 00409119 JMP SHORT packed1_.0040911C
现在,如果第一个操作码是clc(替代STC),请在0040910c、00409112和00409117处(两J之间)修补所有指令,以防止调用计时器函数。其实,你总是可以修补那个指令,在这种情况下它不会改变任何东西。然后向下滚动搜索popad操作码。您将看不到它,所以在一些指令中搜索61hex字节。我应该在这里:
00409278 E8 616A00EB CALL EB40FCDE 修补第一个字节,将bp放在popad上并运行: 00409278 90 NOP ;Patch这个字节. 00409279 61 POPAD ;这里下断 0040927A C1E2 F3 SHL EDX,0F3 0040927D 23D0 AND EDX,EAX 0040927F 0FC1D1 XADD ECX,EDX 00409282 BA 69533D94 MOV EDX,943D5369 00409287 69C8 262C4AF2 IMUL ECX,EAX,F24A2C26 0040928D 11C2 ADC EDX,EAX 0040928F 0FBDD0 BSR EDX,EAX 00409292 C7C2 BDCC6DB9 MOV EDX,B96DCCBD 00409298 42 INC EDX 00409299 FFC2 INC EDX 0040929B C1D2 83 RCL EDX,83 0040929E 0FBCC8 BSF ECX,EAX 004092A1 23D0 AND EDX,EAX 004092A3 39C2 CMP EDX,EAX 004092A5 81E9 B576A23F SUB ECX,3FA276B5 004092AB EB 01 JMP SHORT packed1_.004092AE 004092AD E7 0F OUT 0F,EAX 004092AF AF SCAS DWORD PTR ES:[EDI] 004092B0 C8 0FB7D0 ENTER 0B70F,0D0 004092B4 C7C1 0EE985D6 MOV ECX,D685E90E 004092BA F3: PREFIX REP: 004092BB F7C1 1E8ABDAB TEST ECX,ABBD8A1E 004092C1 -E9 3A7DFFFF JMP packed1_.00401000
00409278 E8 616A00EB CALL EB40FCDE 修补第一个字节,将bp放在popad上并运行: 00409278 90 NOP ;Patch这个字节. 00409279 61 POPAD ;这里下断 0040927A C1E2 F3 SHL EDX,0F3 0040927D 23D0 AND EDX,EAX 0040927F 0FC1D1 XADD ECX,EDX 00409282 BA 69533D94 MOV EDX,943D5369 00409287 69C8 262C4AF2 IMUL ECX,EAX,F24A2C26 0040928D 11C2 ADC EDX,EAX 0040928F 0FBDD0 BSR EDX,EAX 00409292 C7C2 BDCC6DB9 MOV EDX,B96DCCBD 00409298 42 INC EDX 00409299 FFC2 INC EDX 0040929B C1D2 83 RCL EDX,83 0040929E 0FBCC8 BSF ECX,EAX 004092A1 23D0 AND EDX,EAX 004092A3 39C2 CMP EDX,EAX 004092A5 81E9 B576A23F SUB ECX,3FA276B5 004092AB EB 01 JMP SHORT packed1_.004092AE 004092AD E7 0F OUT 0F,EAX 004092AF AF SCAS DWORD PTR ES:[EDI] 004092B0 C8 0FB7D0 ENTER 0B70F,0D0 004092B4 C7C1 0EE985D6 MOV ECX,D685E90E 004092BA F3: PREFIX REP: 004092BB F7C1 1E8ABDAB TEST ECX,ABBD8A1E 004092C1 -E9 3A7DFFFF JMP packed1_.00401000
你现在是在壳保护代码的最后一部分。在这里,您可以找到与垃圾代码混合的被盗OEP字节。我打包文件时并没有选择删除OEP,所以这里只有一些垃圾可以让你迷惑。无论你有没有偷过oep,当你到达popad之后的第一个操作码时,你总是可以转储文件,它将正常工作。无所谓oep在壳代码中、目标执行从壳开始。但是如果你想要的话,你可以找到被盗的字节,把它恢复到原来的位置,然后从那里转储。现在,只需跟踪,直到到达某个跳转,该跳转指向代码部分:
004092C1 -E9 3A7DFFFF JMP packed1_.00401000 在这种情况下,跳转直接进入OEP: 00401000 . 6A 00 PUSH 0 00401002 . E8 F1F1FFFF CALL packed1_.004001F8 00401007 . A3 CA204000 MOV DWORD PTR DS:[4020CA],EAX 0040100C . 6A 00 PUSH 0 0040100E .-E9 EBF1FFFF JMP packed1_.004001FE 00401013 . E8 F1F1FFFF CALL packed1_.00400209 00401018 . 0BC0 OR EAX,EAX 0040101A . 74 01 JE SHORT packed1_.0040101D 0040101C . C3 RETN 0040101D > C705 64204000 >MOV DWORD PTR DS:[402064],4003 00401027 . C705 68204000 >MOV DWORD PTR DS:[402068],packed1_.00401>
如果您转储文件,它将无法正常工作。 原因是代码重定向。 注意一些CALL和JMP引导的地方:
004092C1 -E9 3A7DFFFF JMP packed1_.00401000 在这种情况下,跳转直接进入OEP: 00401000 . 6A 00 PUSH 0 00401002 . E8 F1F1FFFF CALL packed1_.004001F8 00401007 . A3 CA204000 MOV DWORD PTR DS:[4020CA],EAX 0040100C . 6A 00 PUSH 0 0040100E .-E9 EBF1FFFF JMP packed1_.004001FE 00401013 . E8 F1F1FFFF CALL packed1_.00400209 00401018 . 0BC0 OR EAX,EAX 0040101A . 74 01 JE SHORT packed1_.0040101D 0040101C . C3 RETN 0040101D > C705 64204000 >MOV DWORD PTR DS:[402064],4003 00401027 . C705 68204000 >MOV DWORD PTR DS:[402068],packed1_.00401>
如果您转储文件,它将无法正常工作。 原因是代码重定向。 注意一些CALL和JMP引导的地方:
00401002 CALL packed1_.004001F8 ... 0040100E JMP packed1_.004001FE
它们指向的地址低于401000,这意味着PE头。 这不正常。 我会快速解释一下:
00401002 CALL packed1_.004001F8 ... 0040100E JMP packed1_.004001FE
它们指向的地址低于401000,这意味着PE头。 这不正常。 我会快速解释一下:
PESpin将加载所有段到内存中,解密并完成解包所需的所有操作。之后,PE头对任何事情都不再重要,所以它可以随心所欲地改变 - 它不会影响程序在内存中。 PESpin将采用这个事实的优点,它将用FFFFF填充PE头的一部分...(顺便说一句,它会破坏掉保存有段信息的PE头的一部分)。 然后它将在代码段搜索PUSH xxxxxxxx或CALL xxxxxxxx(也许是JMP)指令,因为它们长5个字节。 然后它将该操作码替换为一些JMP或CALL到PE头,它将放置原始指令并返回代码段(如果需要)。 指令必须长5个字节的原因是因为它们很容易用JMP操作码替换(它的长度为5个字节)。 我们来看两个例子:
a) CALL example(call-jmp):特征码#E8??????FF#---->处理:直接用后者替换前者
00401002 . E8 F1F1FFFF CALL packed1_.004001F8
此CALL指向PE头。 右键单击它并跟随它。 在那里你会发现原始的“被盗代码”:
00401002 . E8 F1F1FFFF CALL packed1_.004001F8
此CALL指向PE头。 右键单击它并跟随它。 在那里你会发现原始的“被盗代码”:
004001F8 -E9 09130000 JMP packed1_.00401506
所以你只需要用JMP 401506替换CALL 4001F8。如你所见,它非常简单。
004001F8 -E9 09130000 JMP packed1_.00401506
所以你只需要用JMP 401506替换CALL 4001F8。如你所见,它非常简单。
b) JMP example(JMP-PUSH):特征码#E9??????FF#---->处理:直接用后者替换前者
0040100E .-E9 EBF1FFFF JMP packed1_.004001FE
再次,跟随此跳转到PE头,您将看到被盗的原始代码:
0040100E .-E9 EBF1FFFF JMP packed1_.004001FE
再次,跟随此跳转到PE头,您将看到被盗的原始代码:
004001FE 68 F4204000 PUSH packed1_.004020F4
您将在像第一个示例中一样修复此问题,您放置PUSH 4020F4指令替换那个跳转。
004001FE 68 F4204000 PUSH packed1_.004020F4
您将在像第一个示例中一样修复此问题,您放置PUSH 4020F4指令替换那个跳转。
好的,你处理它并不难。 首个想法是“为什么要恢复那些代码,为什么不把它留在那里而一起dump它?”。 原因是PE头被破坏(部分信息被删除),我们不再拥有有效的PE文件。 如果我们从磁盘粘贴原始头,程序将跳转到它,它将找不到重定向的代码,因此结果是崩溃。 第二个想法是“但是有很多重定向的代码,如何解决所有这些问题?手动?我不会疯狂地在电脑前浪费一整夜!”。 其实,由于PE头的大小决定了重定向的代码数量可能有限,但这个数字也很大。 因此,要修复大量代码,我们将使用/编写Olly Script来自动执行作业。 这根本不难。 它应该是这样的:
- 首先,我们需要找到这样的JMP/CALL操作码。 我们的srcipt必须搜索以F结尾的JMP/CALL,因为这意味着它会跳转到后面。 因此搜索带有E9???????F或E8???????F字节的指令。
- 然后我们必须检查它是否跳转到PE头。 以我们的a) CALL example为例。 取CALL的地址=401002并取CALL值(E8后的四个字节,按相反顺序)FFFFF1F1。 现在相加这两个值401002 + FFFFF1F1 = 4001F3,如果结果在400000 <= RESULT <401000之间,那么你知道你在正确的位置。
- 然后,使用基本数学,您必须恢复原始操作码。 它不能被复制粘贴,必须进行计算。 这里需要基本的十六进制数学,很少的计算和一些时间。 之后,您将拥有完美的脚本。 如果你不(或不知道如何)自己做,你可以使用我的“PESpin - Code Fixer.txt”(包含在档案中)。
现在,如果你已完成所有操作,就像我写的那样,然后使用脚本来修复重定向代码,转储文件。 如果你运行它,你可能会得到错误消息,告诉你这个应用程序是如何无效的Win32应用程序。 别担心。 打开LordPE,转到选项并在重建PE下仅选中“验证PE”选项。 关闭选项,打开重建PE并打开我们的转储文件。 验证转储后,运行它,它将工作得很完美;)干得好! 你刚刚解压缩了PEspin v1.0。
这种方法适用于ASM和BC ++程序,但不适用于Delphi和MSVC ++。 原因是不同的IAT重定向,OllyDump插件无法处理。 这可以通过构建新的导入段来解决。 我们将在下一个教程中看到。
但是有一个原因就是为什么转储文件可能只能在解压缩文件的机器上运行。 如果你看看入口跳转,你会发现大多数跳转都是绝对跳转,跳转到内存中的指定位置。 因此,在另一台具有不同版本dll的计算机上,转储文件可能会崩溃。 这可以修复,但对于更大的文件,手动操作是不可能的。 这是所有PESpin版本的问题。
3. 教程 2 - PESpin v1.1
在这个版本中,一切都与1.0相同,除了这个带来了新选项 - CRYPT和CLEAR 守护。 那是什么? 简单,阅读PESpin的帮助文件:
CRYPT守护:
加密标记CRYPT_START和CRYPT_END之间的代码在文件保护过程中被加密,并且当执行受保护文件时,代码在使用之前被严密地解密,并在使用后立即再次加密(运行时防止转储)。
CLEAR守护:
CLEAR_START和CLEAR_END标记提供了在执行后删除代码块的功能。这些宏应该只放在应用程序中执行一次的代码区域。在受保护的应用程序中,任何尝试在这些宏中重新执行代码块都会导致异常。
这对我们来说不是什么大问题。 对于我们的第二个目标,我们将选择keygen.exe,它包含所有CLEAR和CRYPT选项(感谢detten;)。 查找OEP的过程与1.0版本中的完全相同,因此没有必要再将其全部写出。 简而言之; 不忽略所有异常,将bp放在GetTickCount API的末尾并运行目标,删除bp并返回目标代码。 但是......我们将遇到一个问题,我们将在所有PESpin 1.x版本中使用Delphi和MSVC ++目标。 问题是OllyDump无法重建IAT。 我们必须手动完成所有操作。 由于这个问题,我们必须知道我们的打包目标正在使用哪个dll。 让我们开始吧!
首先,我们将找到keygen.exe需要什么dll。 命令行中将bp放在LoadLibraryA(API中的最后一个RETN)上并运行目标。 你会在奇怪的地方中断(也许你的值不同):
77ED6FC4 >-E9 1860FB42 JMP BAE8CFE1 77ED6FC9 90 NOP 77ED6FCA 90 NOP 77ED6FCB 90 NOP 77ED6FCC 90 NOP 77ED6FCD 90 NOP 77ED6FCE 90 NOP 77ED6FCF 90 NOP 77ED6FD0 90 NOP 77ED6FD1 90 NOP 77ED6FD2 90 NOP 77ED6FD3 >-E9 7D61FB42 JMP BAE8D155 77ED6FD8 90 NOP 77ED6FD9 90 NOP 77ED6FDA 90 NOP 77ED6FDB 90 NOP 77ED6FDC 90 NOP 77ED6FDD 90 NOP 77ED6FDE 90 NOP 77ED6FDF 90 NOP
删除bp,打开内存窗口并在最后一节放置“访问内存bp”。 这是一个SFX。 现在按Shift + F9,你将返回到壳代码(然后删除mem bp):
77ED6FC4 >-E9 1860FB42 JMP BAE8CFE1 77ED6FC9 90 NOP 77ED6FCA 90 NOP 77ED6FCB 90 NOP 77ED6FCC 90 NOP 77ED6FCD 90 NOP 77ED6FCE 90 NOP 77ED6FCF 90 NOP 77ED6FD0 90 NOP 77ED6FD1 90 NOP 77ED6FD2 90 NOP 77ED6FD3 >-E9 7D61FB42 JMP BAE8D155 77ED6FD8 90 NOP 77ED6FD9 90 NOP 77ED6FDA 90 NOP 77ED6FDB 90 NOP 77ED6FDC 90 NOP 77ED6FDD 90 NOP 77ED6FDE 90 NOP 77ED6FDF 90 NOP
删除bp,打开内存窗口并在最后一节放置“访问内存bp”。 这是一个SFX。 现在按Shift + F9,你将返回到壳代码(然后删除mem bp):
0040D491 85C0 TEST EAX,EAX 0040D493 0F84 3F090000 JE keygen.0040DDD8 0040D499 E8 01000000 CALL keygen.0040D49F 0040D49E FF59 50 CALL FAR FWORD PTR DS:[ECX+50] 0040D4A1 51 PUSH ECX 0040D4A2 55 PUSH EBP 0040D4A3 810424 12374000 ADD DWORD PTR SS:[ESP],keygen.00403712 0040D4AA 814424 04 220000>ADD DWORD PTR SS:[ESP+4],22
我们在这里搜索什么? 如果您记得上一章,PESpin解密DLL名称,将其加载到内存中,然后删除它的名称。 我们现在在壳加载DLL的地方,我们将找到他删除DLL名称的地方。 我们将修补该擦除过程,以便稍后我们可以看到使用了什么DLL。 使用F7追踪,直到你到达(这是很多追踪):
0040D491 85C0 TEST EAX,EAX 0040D493 0F84 3F090000 JE keygen.0040DDD8 0040D499 E8 01000000 CALL keygen.0040D49F 0040D49E FF59 50 CALL FAR FWORD PTR DS:[ECX+50] 0040D4A1 51 PUSH ECX 0040D4A2 55 PUSH EBP 0040D4A3 810424 12374000 ADD DWORD PTR SS:[ESP],keygen.00403712 0040D4AA 814424 04 220000>ADD DWORD PTR SS:[ESP+4],22
我们在这里搜索什么? 如果您记得上一章,PESpin解密DLL名称,将其加载到内存中,然后删除它的名称。 我们现在在壳加载DLL的地方,我们将找到他删除DLL名称的地方。 我们将修补该擦除过程,以便稍后我们可以看到使用了什么DLL。 使用F7追踪,直到你到达(这是很多追踪):
0040D4F0 800B 00 OR BYTE PTR DS:[EBX],0 0040D4F3 74 0D JE SHORT keygen.0040D502 0040D4F5 8813 MOV BYTE PTR DS:[EBX],DL 0040D4F7 C1C2 04 ROL EDX,4 0040D4FA 75 01 JNZ SHORT keygen.0040D4FD 0040D4FC E8 43FF6424 CALL 24A5D444 0040D501 FC CLD 0040D502 93 XCHG EAX,EBX 0040D503 8B56 10 MOV EDX,DWORD PTR DS:[ESI+10]
0040D4F0 800B 00 OR BYTE PTR DS:[EBX],0 0040D4F3 74 0D JE SHORT keygen.0040D502 0040D4F5 8813 MOV BYTE PTR DS:[EBX],DL 0040D4F7 C1C2 04 ROL EDX,4 0040D4FA 75 01 JNZ SHORT keygen.0040D4FD 0040D4FC E8 43FF6424 CALL 24A5D444 0040D501 FC CLD 0040D502 93 XCHG EAX,EBX 0040D503 8B56 10 MOV EDX,DWORD PTR DS:[ESI+10]
这是删除DLL名称的地方。 走到这一行
0040D4F5 8813 MOV BYTE PTR DS:[EBX],DL
并在转储窗口中跟随它。 在那里你会看到KERNEL32.DLL的名字。 修补此操作码MOV BYTE PTR DS:[EBX],DL然后就运行目标。 我们的目标将开始,但这就是我们想要的。 进入转储窗口,在那里你会发现目标使用的所有dll:
0040D4F5 8813 MOV BYTE PTR DS:[EBX],DL
并在转储窗口中跟随它。 在那里你会看到KERNEL32.DLL的名字。 修补此操作码MOV BYTE PTR DS:[EBX],DL然后就运行目标。 我们的目标将开始,但这就是我们想要的。 进入转储窗口,在那里你会发现目标使用的所有dll:
00402102 4B 45 52 4E 45 4C 33 32 2E 44 4C 4C 00 00 F7 00 KERNEL32.DLL..÷. 00402112 00 00 00 00 00 00 00 00 00 00 C4 00 00 00 00 00 ..........?..... 00402122 00 00 00 00 00 00 00 00 00 00 00 00 C5 00 00 00 ............?... 00402132 00 00 00 00 00 00 00 00 CC 00 00 00 00 00 00 00 ........?....... 00402142 00 00 00 00 00 00 CC 00 00 00 00 00 00 00 00 00 ......?......... 00402152 00 00 D2 00 00 00 00 00 00 00 00 00 00 00 00 00 ..?............. 00402162 00 00 00 00 D3 00 00 00 00 00 00 00 00 00 00 00 ....?........... 00402172 00 00 00 00 00 00 00 00 00 00 D3 00 00 00 00 00 ..........?..... 00402182 00 00 00 00 00 00 00 00 00 00 D3 00 00 00 00 00 ..........?..... 00402192 00 00 00 00 00 00 00 00 00 00 00 00 55 53 45 52 ............USER 004021A2 33 32 2E 44 4C 4C 00 00 C3 00 00 00 00 00 00 00 32.DLL..?....... 004021B2 00 00 00 00 00 00 00 00 00 00 00 00 D3 00 00 00 ............?... 004021C2 00 00 00 00 00 00 00 00 00 00 D3 00 00 00 00 00 ..........?..... 004021D2 00 00 00 00 00 00 D3 00 00 00 00 00 00 00 00 00 ......?......... 004021E2 00 00 00 00 00 00 47 44 49 33 32 2E 44 4C 4C 00 ......GDI32.DLL. 004021F2 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
我们的目标很小,它只使用kernel32.dll,user32.dll和gdi32.dll。 好! 现在我们将在Olly中重新启动目标并找到OEP。 将bp放在GetTickCount API中的最后一个RETN上,运行目标,删除bp并返回代码:
00402102 4B 45 52 4E 45 4C 33 32 2E 44 4C 4C 00 00 F7 00 KERNEL32.DLL..÷. 00402112 00 00 00 00 00 00 00 00 00 00 C4 00 00 00 00 00 ..........?..... 00402122 00 00 00 00 00 00 00 00 00 00 00 00 C5 00 00 00 ............?... 00402132 00 00 00 00 00 00 00 00 CC 00 00 00 00 00 00 00 ........?....... 00402142 00 00 00 00 00 00 CC 00 00 00 00 00 00 00 00 00 ......?......... 00402152 00 00 D2 00 00 00 00 00 00 00 00 00 00 00 00 00 ..?............. 00402162 00 00 00 00 D3 00 00 00 00 00 00 00 00 00 00 00 ....?........... 00402172 00 00 00 00 00 00 00 00 00 00 D3 00 00 00 00 00 ..........?..... 00402182 00 00 00 00 00 00 00 00 00 00 D3 00 00 00 00 00 ..........?..... 00402192 00 00 00 00 00 00 00 00 00 00 00 00 55 53 45 52 ............USER 004021A2 33 32 2E 44 4C 4C 00 00 C3 00 00 00 00 00 00 00 32.DLL..?....... 004021B2 00 00 00 00 00 00 00 00 00 00 00 00 D3 00 00 00 ............?... 004021C2 00 00 00 00 00 00 00 00 00 00 D3 00 00 00 00 00 ..........?..... 004021D2 00 00 00 00 00 00 D3 00 00 00 00 00 00 00 00 00 ......?......... 004021E2 00 00 00 00 00 00 47 44 49 33 32 2E 44 4C 4C 00 ......GDI32.DLL. 004021F2 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
我们的目标很小,它只使用kernel32.dll,user32.dll和gdi32.dll。 好! 现在我们将在Olly中重新启动目标并找到OEP。 将bp放在GetTickCount API中的最后一个RETN上,运行目标,删除bp并返回代码:
0040E4D8 8BD8 MOV EBX,EAX 0040E4DA F7D3 NOT EBX 0040E4DC 33D8 XOR EBX,EAX 0040E4DE 43 INC EBX 0040E4DF 68 87000000 PUSH 87 0040E4E4 59 POP ECX 0040E4E5 66:35 4C50 XOR AX,504C 0040E4E9 66:05 8911 ADD AX,1189 0040E4ED AA STOS BYTE PTR ES:[EDI] 0040E4EE EB 01 JMP SHORT keygen.0040E4F1 0040E4F0 68 499CC12C PUSH 2CC19C49 0040E4F5 24 06 AND AL,6
0040E4D8 8BD8 MOV EBX,EAX 0040E4DA F7D3 NOT EBX 0040E4DC 33D8 XOR EBX,EAX 0040E4DE 43 INC EBX 0040E4DF 68 87000000 PUSH 87 0040E4E4 59 POP ECX 0040E4E5 66:35 4C50 XOR AX,504C 0040E4E9 66:05 8911 ADD AX,1189 0040E4ED AA STOS BYTE PTR ES:[EDI] 0040E4EE EB 01 JMP SHORT keygen.0040E4F1 0040E4F0 68 499CC12C PUSH 2CC19C49 0040E4F5 24 06 AND AL,6
查找导致重定向过程的跳转并修补介于它与良好调用之间的所有字节:
0040D5DF FF6424 FC JMP DWORD PTR SS:[ESP-4] <--- Jump!!! ... ... <--- Patch所有这些操作码!!! ... 0040D643 E8 C4F6FFFF CALL keygen.0040CD0C <--- Good call!!! 0040D648 E8 03000000 CALL keygen.0040D650 然后向下滚动到我们众所周知的地方: 0040D6D7 B0 F9 MOV AL,0F9 0040D6D9 72 3F JB SHORT keygen.0040D71A 0040D6DB 8D85 F469271E LEA EAX,DWORD PTR SS:[EBP+1E2769F4] 0040D6E1 2D 8417E71D SUB EAX,1DE71784 0040D6E6 FFD0 CALL EAX 0040D6E8 EB 02 JMP SHORT keygen.0040D6EC
0040D5DF FF6424 FC JMP DWORD PTR SS:[ESP-4] <--- Jump!!! ... ... <--- Patch所有这些操作码!!! ... 0040D643 E8 C4F6FFFF CALL keygen.0040CD0C <--- Good call!!! 0040D648 E8 03000000 CALL keygen.0040D650 然后向下滚动到我们众所周知的地方: 0040D6D7 B0 F9 MOV AL,0F9 0040D6D9 72 3F JB SHORT keygen.0040D71A 0040D6DB 8D85 F469271E LEA EAX,DWORD PTR SS:[EBP+1E2769F4] 0040D6E1 2D 8417E71D SUB EAX,1DE71784 0040D6E6 FFD0 CALL EAX 0040D6E8 EB 02 JMP SHORT keygen.0040D6EC
这是可能调用计时器的地方。 我们的目标在加壳时没有启用该选项,我们不需要修补40D6DB到40D6E6的操作码。 好的,向下滚动并找到POPAD操作码。 你会发现它稍稍被混淆。
0040D8FA E8 610FC90F CALL 1009E860 所以修补第一个字节以获得清晰的画面。 0040D8FA 90 NOP 0040D8FB 61 POPAD POPAD之后,开始窃取OEP代码并混之以垃圾代码。 看起来没有被盗的OEP字节,因为指向代码段的跳转现在跳到段开头401000: 0040D8FC 0FC9 BSWAP ECX 0040D8FE 0FACC2 13 SHRD EDX,EAX,13 ... ... ... 0040D947 -E9 B436FFFF JMP keygen.00401000 <---跳到OEP!!!
0040D8FA E8 610FC90F CALL 1009E860 所以修补第一个字节以获得清晰的画面。 0040D8FA 90 NOP 0040D8FB 61 POPAD POPAD之后,开始窃取OEP代码并混之以垃圾代码。 看起来没有被盗的OEP字节,因为指向代码段的跳转现在跳到段开头401000: 0040D8FC 0FC9 BSWAP ECX 0040D8FE 0FACC2 13 SHRD EDX,EAX,13 ... ... ... 0040D947 -E9 B436FFFF JMP keygen.00401000 <---跳到OEP!!!
执行跳转,你将落在OEP上。 即使按Ctrl + A分析代码,代码仍然看起来很糟糕,所以右键单击它,选择分析并从模块中删除分析。 然后你会有更好的画面:
00401000 9C PUSHFD 00401001 60 PUSHAD 00401002 B9 B5381023 MOV ECX,231038B5 00401007 BF 7896AA00 MOV EDI,0AA9678 0040100C 81E9 91381023 SUB ECX,23103891 00401012 B8 5F1360C2 MOV EAX,C260135F ... ...
首先,我们将检查PE头部分是否有被盗/重定向的代码。 只需运行“PESpin - Code Fixer.txt”脚本即可。 检查日志窗口,您将看到该脚本修复了4A操作码:
00401000 9C PUSHFD 00401001 60 PUSHAD 00401002 B9 B5381023 MOV ECX,231038B5 00401007 BF 7896AA00 MOV EDI,0AA9678 0040100C 81E9 91381023 SUB ECX,23103891 00401012 B8 5F1360C2 MOV EAX,C260135F ... ...
首先,我们将检查PE头部分是否有被盗/重定向的代码。 只需运行“PESpin - Code Fixer.txt”脚本即可。 检查日志窗口,您将看到该脚本修复了4A操作码:
[ Simple Code Fixing - number of stolen opcodes ] stolen = 0000004A
[ Simple Code Fixing - number of stolen opcodes ] stolen = 0000004A
好的,这就是我们从PESpin的早期版本中所知道的,但现在我们将遇到新的技巧 - 代码解密和擦除。 这部分代码一开始就是第一个解密过程的开始:
00401000 9C PUSHFD 00401001 60 PUSHAD 00401002 B9 B5381023 MOV ECX,231038B5 00401007 BF 7896AA00 MOV EDI,0AA9678 0040100C 81E9 91381023 SUB ECX,23103891 00401012 B8 5F1360C2 MOV EAX,C260135F 00401017 05 DCE1E03D ADD EAX,3DE0E1DC 0040101C FF0D 22104000 DEC DWORD PTR DS:[401022] 00401022 0011 ADD BYTE PTR DS:[ECX],DL<--- 跟踪这一行!!! 00401024 61 POPAD 00401025 9D POPFD
使用F8跟踪我在上面显示的行,你会看到它变为:
00401000 9C PUSHFD 00401001 60 PUSHAD 00401002 B9 B5381023 MOV ECX,231038B5 00401007 BF 7896AA00 MOV EDI,0AA9678 0040100C 81E9 91381023 SUB ECX,23103891 00401012 B8 5F1360C2 MOV EAX,C260135F 00401017 05 DCE1E03D ADD EAX,3DE0E1DC 0040101C FF0D 22104000 DEC DWORD PTR DS:[401022] 00401022 0011 ADD BYTE PTR DS:[ECX],DL<--- 跟踪这一行!!! 00401024 61 POPAD 00401025 9D POPFD
使用F8跟踪我在上面显示的行,你会看到它变为:
00401022 FF10 CALL DWORD PTR DS:[EAX]
该调用将引导您进入一个程序,该程序将解密目标中的某些代码并擦除某些内容。 如果你想看看那里发生了什么,你可以去F7。 它只会解密POPFD操作码以下的几个操作码并擦除以上所有操作码。 按F8而不是F7,你会看到变化:
00401022 FF10 CALL DWORD PTR DS:[EAX]
该调用将引导您进入一个程序,该程序将解密目标中的某些代码并擦除某些内容。 如果你想看看那里发生了什么,你可以去F7。 它只会解密POPFD操作码以下的几个操作码并擦除以上所有操作码。 按F8而不是F7,你会看到变化:
00401000 0000 ADD BYTE PTR DS:[EAX],AL 00401002 0000 ADD BYTE PTR DS:[EAX],AL 00401004 0000 ADD BYTE PTR DS:[EAX],AL 00401006 0000 ADD BYTE PTR DS:[EAX],AL 00401008 0000 ADD BYTE PTR DS:[EAX],AL 0040100A 0000 ADD BYTE PTR DS:[EAX],AL 0040100C 0000 ADD BYTE PTR DS:[EAX],AL 0040100E 0000 ADD BYTE PTR DS:[EAX],AL 00401010 0000 ADD BYTE PTR DS:[EAX],AL 00401012 0000 ADD BYTE PTR DS:[EAX],AL 00401014 0000 ADD BYTE PTR DS:[EAX],AL 00401016 0000 ADD BYTE PTR DS:[EAX],AL 00401018 0000 ADD BYTE PTR DS:[EAX],AL 0040101A 0000 ADD BYTE PTR DS:[EAX],AL 0040101C 0000 ADD BYTE PTR DS:[EAX],AL 0040101E 0000 ADD BYTE PTR DS:[EAX],AL 00401020 0000 ADD BYTE PTR DS:[EAX],AL 00401022 0000 ADD BYTE PTR DS:[EAX],AL 00401024 61 POPAD 00401025 9D POPFD 00401026 6A 00 PUSH 0 00401028 E8 83F1FFFF CALL keygen.004001B0 0040102D A3 E4304000 MOV DWORD PTR DS:[4030E4],EAX 00401032 6A 00 PUSH 0 00401034 -E9 7DF1FFFF JMP keygen.004001B6 <--- 到PE头! 00401039 6A 00 PUSH 0 0040103B 6A 01 PUSH 1 0040103D 50 PUSH EAX 0040103E E8 7EF1FFFF CALL keygen.004001C1 <--- 到PE头! 00401043 6A 00 PUSH 0 00401045 E8 7DF1FFFF CALL keygen.004001C7 <--- 到PE头!
请注意,一些新的解密跳转和调用会指向PE头,因此我们必须再次运行脚本来修复重定向,然后使用NOP填充401000到401025的所有代码:
00401000 0000 ADD BYTE PTR DS:[EAX],AL 00401002 0000 ADD BYTE PTR DS:[EAX],AL 00401004 0000 ADD BYTE PTR DS:[EAX],AL 00401006 0000 ADD BYTE PTR DS:[EAX],AL 00401008 0000 ADD BYTE PTR DS:[EAX],AL 0040100A 0000 ADD BYTE PTR DS:[EAX],AL 0040100C 0000 ADD BYTE PTR DS:[EAX],AL 0040100E 0000 ADD BYTE PTR DS:[EAX],AL 00401010 0000 ADD BYTE PTR DS:[EAX],AL 00401012 0000 ADD BYTE PTR DS:[EAX],AL 00401014 0000 ADD BYTE PTR DS:[EAX],AL 00401016 0000 ADD BYTE PTR DS:[EAX],AL 00401018 0000 ADD BYTE PTR DS:[EAX],AL 0040101A 0000 ADD BYTE PTR DS:[EAX],AL 0040101C 0000 ADD BYTE PTR DS:[EAX],AL 0040101E 0000 ADD BYTE PTR DS:[EAX],AL 00401020 0000 ADD BYTE PTR DS:[EAX],AL 00401022 0000 ADD BYTE PTR DS:[EAX],AL 00401024 61 POPAD 00401025 9D POPFD 00401026 6A 00 PUSH 0 00401028 E8 83F1FFFF CALL keygen.004001B0 0040102D A3 E4304000 MOV DWORD PTR DS:[4030E4],EAX 00401032 6A 00 PUSH 0 00401034 -E9 7DF1FFFF JMP keygen.004001B6 <--- 到PE头! 00401039 6A 00 PUSH 0 0040103B 6A 01 PUSH 1 0040103D 50 PUSH EAX 0040103E E8 7EF1FFFF CALL keygen.004001C1 <--- 到PE头! 00401043 6A 00 PUSH 0 00401045 E8 7DF1FFFF CALL keygen.004001C7 <--- 到PE头!
请注意,一些新的解密跳转和调用会指向PE头,因此我们必须再次运行脚本来修复重定向,然后使用NOP填充401000到401025的所有代码:
00401000 . 90 NOP ... ... ... 00401024 . 90 NOP 00401025 . 90 NOP 00401026 . 6A 00 PUSH 0 00401028 . E8 1B040000 CALL keygen.00401448 0040102D . A3 E4304000 MOV DWORD PTR DS:[4030E4],EAX 00401032 . 6A 00 PUSH 0 00401034 . 68 7F104000 PUSH keygen.0040107F 00401039 . 6A 00 PUSH 0 0040103B . 6A 01 PUSH 1 0040103D . 50 PUSH EAX 0040103E . E8 11040000 CALL keygen.00401454 00401043 . 6A 00 PUSH 0 00401045 . E8 F8030000 CALL keygen.00401442 0040104A . EB 0B JMP SHORT keygen.00401057 0040104C EB DB EB
我们已经修复了第一种解密类型CLEAR。 现在我们要找到并修复CRYPT。 由于目标很小,你可以向下滚动,找到两个有趣的call:
00401000 . 90 NOP ... ... ... 00401024 . 90 NOP 00401025 . 90 NOP 00401026 . 6A 00 PUSH 0 00401028 . E8 1B040000 CALL keygen.00401448 0040102D . A3 E4304000 MOV DWORD PTR DS:[4030E4],EAX 00401032 . 6A 00 PUSH 0 00401034 . 68 7F104000 PUSH keygen.0040107F 00401039 . 6A 00 PUSH 0 0040103B . 6A 01 PUSH 1 0040103D . 50 PUSH EAX 0040103E . E8 11040000 CALL keygen.00401454 00401043 . 6A 00 PUSH 0 00401045 . E8 F8030000 CALL keygen.00401442 0040104A . EB 0B JMP SHORT keygen.00401057 0040104C EB DB EB
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2020-1-28 22:33
被kanxue编辑
,原因:
赞赏
他的文章
看原图
赞赏
雪币:
留言: