~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
PESpin v0.3 - 手动脱壳
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
原文地址:http://www.reversing.be/article.php?story=20050726211417143
作者: haggar
OS: Windows XP
水平: 菜鸟-飞鸡
目标和材料: http://www.reversing.be/binaries/articles/200507262109322.rar(亲测可以下载)
欢迎!
这是PESpin的旧版本,但我决定从它开始,稍后尝试新版本会更容易。 教程适用于有脱壳经验的初学者,也必须熟悉工具 (Olly, ImpREc, LordPE).
PESpin v0.3 有一些很好的功能; 良好的IAT重定向与一些仿真API操作码和被盗的OEP是它的最佳武器。 它也有一些基于异常的反调试技巧,但是Olly是免疫的,它检查SoftICE和NTICE,它有几个CRC校验,它有密码锁定和时间限制,但这不是问题。 在使用不同编译器编译的打包文件之间也存在一些小的差异 (VC++,Borland C++, Delphi, VB, ASM...).
1. 分析 PESpin 代码
打开 Olly,不忽略所有异常选项和加载目标,cruehead的CRACKME3.EXE,我用PESpin打包。 向下滚动,您将看到两个解密PESpin代码段的循环:
00407127 XOR BYTE PTR DS:[ECX+EDI],BL
0040712A DEC BL
0040712C LOOPD SHORT CRACKME3.00407127 ;First loop.
0040712E PUSH 13C
00407133 POP ECX
00407134 LEA EDI,DWORD PTR SS:[EBP+4036B6]
0040713A ROR BYTE PTR DS:[ECX+EDI],2
0040713E LOOPD SHORT CRACKME3.0040713A ;Second loop.
00407140 CALL CRACKME3.00407147 ;将bp放在这里以通过它们。
00407127 XOR BYTE PTR DS:[ECX+EDI],BL
0040712A DEC BL
0040712C LOOPD SHORT CRACKME3.00407127 ;First loop.
0040712E PUSH 13C
00407133 POP ECX
00407134 LEA EDI,DWORD PTR SS:[EBP+4036B6]
0040713A ROR BYTE PTR DS:[ECX+EDI],2
0040713E LOOPD SHORT CRACKME3.0040713A ;Second loop.
00407140 CALL CRACKME3.00407147 ;将bp放在这里以通过它们。 经过这些循环并且跟踪到这里:
00408138 MOV EDI,DWORD PTR SS:[ESP+20]
0040813C AND EDI,FFFF0000
00408142 CMP WORD PTR DS:[EDI],5A4D
00408147 JNZ SHORT CRACKME3.0040815A
00408149 MOVZX EDX,WORD PTR DS:[EDI+3C]
0040814D TEST DX,0F800
00408152 JNZ SHORT CRACKME3.0040815A
00408154 CMP EDI,DWORD PTR DS:[EDX+EDI+34]
00408158 JE SHORT CRACKME3.00408162
0040815A SUB EDI,10000
00408160 JMP SHORT CRACKME3.00408142
00408162 XCHG EAX,EDI
00408163 PUSH CRACKME3.00402CFC
00408168 PUSH EAX
00408169 XCHG DWORD PTR SS:[EBP+402CED],EAX
0040816F ADD DWORD PTR SS:[ESP+4],EBP
00408173 LEA EAX,DWORD PTR SS:[EBP+EB8382F8]
00408179 LEA EAX,DWORD PTR DS:[EAX+14BCAABD]
0040817F CALL EAX
这里启动的程序将找到PESpin工作所需的kernel32中的所有API。 首先要确保它在kernel32.dll中。 然后你将进入CALL EAX,那里PESpin以某种奇怪的方式搜索API。 对我们来说重要的是那些API。 跟踪到这里,你会看到这里的API地址存储在某个位置:
00408138 MOV EDI,DWORD PTR SS:[ESP+20]
0040813C AND EDI,FFFF0000
00408142 CMP WORD PTR DS:[EDI],5A4D
00408147 JNZ SHORT CRACKME3.0040815A
00408149 MOVZX EDX,WORD PTR DS:[EDI+3C]
0040814D TEST DX,0F800
00408152 JNZ SHORT CRACKME3.0040815A
00408154 CMP EDI,DWORD PTR DS:[EDX+EDI+34]
00408158 JE SHORT CRACKME3.00408162
0040815A SUB EDI,10000
00408160 JMP SHORT CRACKME3.00408142
00408162 XCHG EAX,EDI
00408163 PUSH CRACKME3.00402CFC
00408168 PUSH EAX
00408169 XCHG DWORD PTR SS:[EBP+402CED],EAX
0040816F ADD DWORD PTR SS:[ESP+4],EBP
00408173 LEA EAX,DWORD PTR SS:[EBP+EB8382F8]
00408179 LEA EAX,DWORD PTR DS:[EAX+14BCAABD]
0040817F CALL EAX
这里启动的程序将找到PESpin工作所需的kernel32中的所有API。 首先要确保它在kernel32.dll中。 然后你将进入CALL EAX,那里PESpin以某种奇怪的方式搜索API。 对我们来说重要的是那些API。 跟踪到这里,你会看到这里的API地址存储在某个位置:
00408307 MOV DWORD PTR DS:[EDI+1],EAX ;这里F2下断,F9多次直到GetModuleFileNameA出现,删除断点
PESpin想要的API是:
00408307 MOV DWORD PTR DS:[EDI+1],EAX ;这里F2下断,F9多次直到GetModuleFileNameA出现,删除断点
PESpin想要的API是:
LoadLibraryA
ExitProcess
GetProcAddress
VirtualProtect
CloseHandle
VirtualAlloc
VirtualFree
CreateFileA
ReadFile
VirtualQuery
GetTickCount
GetModuleHandleA
CreateThread
Sleep
GetCurrentProcessId
OpenProcess
TerminateProcess
GetFileSize
GetModuleFileNameA
然后PESpin会制造一些异常,目的是检测调试器,但是olly不会失足在这上面。所以你这样做:按Shift + F9 四次,然后将内存bp(在该处F2)放在PESpin段(.taz),按Shift + F9直到你中断在mem bp。 我们跳过的代码对于我们的解包没有任何重要意义,只要跳过一些异常暗桩和一个解码循环。 你应该在这:
LoadLibraryA
ExitProcess
GetProcAddress
VirtualProtect
CloseHandle
VirtualAlloc
VirtualFree
CreateFileA
ReadFile
VirtualQuery
GetTickCount
GetModuleHandleA
CreateThread
Sleep
GetCurrentProcessId
OpenProcess
TerminateProcess
GetFileSize
GetModuleFileNameA
然后PESpin会制造一些异常,目的是检测调试器,但是olly不会失足在这上面。所以你这样做:按Shift + F9 四次,然后将内存bp(在该处F2)放在PESpin段(.taz),按Shift + F9直到你中断在mem bp。 我们跳过的代码对于我们的解包没有任何重要意义,只要跳过一些异常暗桩和一个解码循环。 你应该在这:
00407276 MOV ECX,13
0040727B CALL CRACKME3.00407280
...
...
用F7跟踪,你会到达这里:
00407276 MOV ECX,13
0040727B CALL CRACKME3.00407280
...
...
用F7跟踪,你会到达这里:
004072BF JMP DWORD PTR SS:[EBP+402D57]
有一个名为GetModuleFileNameA的API,它搜索我们打包文件的路径,然后CreateFile打开我们的文件,GetFileSize,VirtualAlloc将在内存中保留足够的位置(从我的计算机上的390000开始)加载该文件,ReadFile会将它加载到该分配的位置,CloseHandle等。 然后你将进入计算整个文件CRC的计算程序:
004072BF JMP DWORD PTR SS:[EBP+402D57]
有一个名为GetModuleFileNameA的API,它搜索我们打包文件的路径,然后CreateFile打开我们的文件,GetFileSize,VirtualAlloc将在内存中保留足够的位置(从我的计算机上的390000开始)加载该文件,ReadFile会将它加载到该分配的位置,CloseHandle等。 然后你将进入计算整个文件CRC的计算程序:
00408864 PUSH ECX
00408865 OR DL,4
00408868 INC EDI
00408869 XOR AH,BYTE PTR DS:[EDI]
0040886B SHR EAX,3
0040886E XOR AL,BH
00408870 ADD EAX,7801A018
00408875 XOR EAX,EBX
00408877 MOV CL,BL
00408879 ROR EAX,CL
0040887B XCHG EAX,EBX
0040887C DEC EDX
0040887D JNZ SHORT CRACKME3.0040886E
0040887F POP ECX
00408880 LOOPD SHORT CRACKME3.00408864
00408882 XCHG EAX,EBX
00408883 POP EBX
00408884 POP EDX
00408885 RETN
然后从真实的CRC中减去计算所得CRC(这个真实的CRC写在文件中并存储到它的位置):
00408864 PUSH ECX
00408865 OR DL,4
00408868 INC EDI
00408869 XOR AH,BYTE PTR DS:[EDI]
0040886B SHR EAX,3
0040886E XOR AL,BH
00408870 ADD EAX,7801A018
00408875 XOR EAX,EBX
00408877 MOV CL,BL
00408879 ROR EAX,CL
0040887B XCHG EAX,EBX
0040887C DEC EDX
0040887D JNZ SHORT CRACKME3.0040886E
0040887F POP ECX
00408880 LOOPD SHORT CRACKME3.00408864
00408882 XCHG EAX,EBX
00408883 POP EBX
00408884 POP EDX
00408885 RETN
然后从真实的CRC中减去计算所得CRC(这个真实的CRC写在文件中并存储到它的位置):
00407397 SUB DWORD PTR SS:[EBP+403827],EAX
eax=63A54CF8;ss:[00408CE8]=CE0C6BFF
注:打开M镜像,双击.taz段Hex视图找到real CRC如下
00407397 SUB DWORD PTR SS:[EBP+403827],EAX
eax=63A54CF8;ss:[00408CE8]=CE0C6BFF
注:打开M镜像,双击.taz段Hex视图找到real CRC如下
00408CE0 00 3A 00 00 00 00 00 00 FF 6B 0C CE 00 00 00 00 .:......k.?...
如果你在十六进制编辑器中打开crackme或者看一下olly dump的最后一节,你可以找到real CRC写的地方。 那被称为VirtualFree。 在那之后你会遇到一个异常,把内存访问断点放在.taz部分然后按Shift + F9直到你中断在这里:
00408CE0 00 3A 00 00 00 00 00 00 FF 6B 0C CE 00 00 00 00 .:......k.?...
如果你在十六进制编辑器中打开crackme或者看一下olly dump的最后一节,你可以找到real CRC写的地方。 那被称为VirtualFree。 在那之后你会遇到一个异常,把内存访问断点放在.taz部分然后按Shift + F9直到你中断在这里:
00408240 NOP
00408241 NOP
00408242 XOR EBX,EBX
00408244 POP DWORD PTR FS:[EBX]
00408247 POP EBX
00408248 SUB EBX,16
0040824E JMP SHORT CRACKME3.00408251
....
....
删除内存访问断点并追踪到:
00408240 NOP
00408241 NOP
00408242 XOR EBX,EBX
00408244 POP DWORD PTR FS:[EBX]
00408247 POP EBX
00408248 SUB EBX,16
0040824E JMP SHORT CRACKME3.00408251
....
....
删除内存访问断点并追踪到:
00408251 CMP BYTE PTR DS:[EBX],0CC
00408254 JNZ SHORT CRACKME3.00408261
00408256 AND ESP,0FFFF
0040825C CALL CRACKME3.0040827B
00408261 JMP EBX
这里壳正在检查是否在[ebx] = 4073e0地址上放置了断点。 通过检查,你将到达那个地址,然后跟踪和追踪,直到你到达这里:
00408251 CMP BYTE PTR DS:[EBX],0CC
00408254 JNZ SHORT CRACKME3.00408261
00408256 AND ESP,0FFFF
0040825C CALL CRACKME3.0040827B
00408261 JMP EBX
这里壳正在检查是否在[ebx] = 4073e0地址上放置了断点。 通过检查,你将到达那个地址,然后跟踪和追踪,直到你到达这里:
0040745A MOVZX ECX,WORD PTR SS:[EBP+402CCF]
00407461 MOV EDX,DWORD PTR SS:[EBP+402CD5]
00407467 ADD EDX,0F8
0040746D MOV EBX,DWORD PTR SS:[EBP+403817]
00407473 XOR EAX,EAX
00407475 PUSH ECX
00407476 BT EBX,EAX
00407479 JNB SHORT CRACKME3.0040749F
0040747B PUSH EDX
0040747C MOV EDI,DWORD PTR DS:[EDX+C]
0040747F ADD EDI,DWORD PTR SS:[EBP+402CCB]
00407485 MOV ECX,DWORD PTR DS:[EDX+10]
00407488 MOV EDX,DWORD PTR SS:[EBP+403827] ;采用CRC值=真-算。
0040748E SHR EDX,1
00407490 JB SHORT CRACKME3.00407498
00407492 XOR EDX,ED43AF32
00407498 XOR BYTE PTR DS:[EDI],DL ;解密段。
0040749A INC EDI
0040749B DEC ECX
0040749C LOOPD SHORT CRACKME3.0040748E
0040749E POP EDX
0040749F INC EAX
004074A0 ADD EDX,28
004074A3 POP ECX
004074A4 LOOPD SHORT CRACKME3.00407475
004074A6 OR DWORD PTR SS:[EBP+4036B0],0
004074AD JE SHORT CRACKME3.004074BC
004074AF LEA EAX,DWORD PTR SS:[EBP+403524]
004074B5 SUB EAX,3D1
004074BA CALL EAX
好的,我们看到它采用那个CRC值,然后用它解密.code部分。 嗯,也许这个值根本不是CRC,只是一些解密段的关键值? 也许两者都是? 我认为是一些解密段的关键值。 通过此检查,所有部分都将被解密,但这只是一层。 进一步跟踪,你将进入SOFTICE检查,程序从408620开始,到40867D结束。 它使用CreateFileA搜索SICE和NTICE文件,如果找到它们,程序将终止。 进一步追踪,你会发现另一个解密循环在4074dc,另一个在4088B9,对我们来说没有多大意义。 让我们加速一点,在命令栏放置bp VirtualAlloc下断,然后按Shift + F9直到我们中断它。 删除它并继续跟踪直到你到达这里:
0040745A MOVZX ECX,WORD PTR SS:[EBP+402CCF]
00407461 MOV EDX,DWORD PTR SS:[EBP+402CD5]
00407467 ADD EDX,0F8
0040746D MOV EBX,DWORD PTR SS:[EBP+403817]
00407473 XOR EAX,EAX
00407475 PUSH ECX
00407476 BT EBX,EAX
00407479 JNB SHORT CRACKME3.0040749F
0040747B PUSH EDX
0040747C MOV EDI,DWORD PTR DS:[EDX+C]
0040747F ADD EDI,DWORD PTR SS:[EBP+402CCB]
00407485 MOV ECX,DWORD PTR DS:[EDX+10]
00407488 MOV EDX,DWORD PTR SS:[EBP+403827] ;采用CRC值=真-算。
0040748E SHR EDX,1
00407490 JB SHORT CRACKME3.00407498
00407492 XOR EDX,ED43AF32
00407498 XOR BYTE PTR DS:[EDI],DL ;解密段。
0040749A INC EDI
0040749B DEC ECX
0040749C LOOPD SHORT CRACKME3.0040748E
0040749E POP EDX
0040749F INC EAX
004074A0 ADD EDX,28
004074A3 POP ECX
004074A4 LOOPD SHORT CRACKME3.00407475
004074A6 OR DWORD PTR SS:[EBP+4036B0],0
004074AD JE SHORT CRACKME3.004074BC
004074AF LEA EAX,DWORD PTR SS:[EBP+403524]
004074B5 SUB EAX,3D1
004074BA CALL EAX
好的,我们看到它采用那个CRC值,然后用它解密.code部分。 嗯,也许这个值根本不是CRC,只是一些解密段的关键值? 也许两者都是? 我认为是一些解密段的关键值。 通过此检查,所有部分都将被解密,但这只是一层。 进一步跟踪,你将进入SOFTICE检查,程序从408620开始,到40867D结束。 它使用CreateFileA搜索SICE和NTICE文件,如果找到它们,程序将终止。 进一步追踪,你会发现另一个解密循环在4074dc,另一个在4088B9,对我们来说没有多大意义。 让我们加速一点,在命令栏放置bp VirtualAlloc下断,然后按Shift + F9直到我们中断它。 删除它并继续跟踪直到你到达这里:
004078A4 PUSHAD
004078A5 MOV ESI,DWORD PTR SS:[ESP+24]
004078A9 MOV EDI,DWORD PTR SS:[ESP+28]
004078AD CLD
004078AE MOV DL,80
004078B0 XOR EBX,EBX
004078B2 MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]
004078B3 MOV BL,2
004078B5 CALL CRACKME3.00407927
004078BA JNB SHORT CRACKME3.004078B2
...
...
0040792D INC ESI
0040792E ADC DL,DL
00407930 RETN
00407931 XOR ECX,ECX
00407933 INC ECX
00407934 CALL CRACKME3.00407927
00407939 ADC ECX,ECX
0040793B CALL CRACKME3.00407927
00407940 JB SHORT CRACKME3.00407934
00407942 RETN
00407943 SUB EDI,DWORD PTR SS:[ESP+28]
00407947 MOV DWORD PTR SS:[ESP+1C],EDI
0040794B POPAD
0040794C RETN ;这里下断!!!
这是自脱壳过程,它将自脱壳或解密段。 它是这样的:首先分配了足够的内存,然后在那里解压缩段,然后原始段被擦除并且已解压段从被分配的内存复制到原始段,然后调用VirtuallFree和VirtualProtect。 将bp放在最后一个RETN并运行2次,直到加壳段被解码,删除bp,将bp放在VirtualFree上,Shift+F9直到你中断它,返回用户代码你应该在这里:
004078A4 PUSHAD
004078A5 MOV ESI,DWORD PTR SS:[ESP+24]
004078A9 MOV EDI,DWORD PTR SS:[ESP+28]
004078AD CLD
004078AE MOV DL,80
004078B0 XOR EBX,EBX
004078B2 MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]
004078B3 MOV BL,2
004078B5 CALL CRACKME3.00407927
004078BA JNB SHORT CRACKME3.004078B2
...
...
0040792D INC ESI
0040792E ADC DL,DL
00407930 RETN
00407931 XOR ECX,ECX
00407933 INC ECX
00407934 CALL CRACKME3.00407927
00407939 ADC ECX,ECX
0040793B CALL CRACKME3.00407927
00407940 JB SHORT CRACKME3.00407934
00407942 RETN
00407943 SUB EDI,DWORD PTR SS:[ESP+28]
00407947 MOV DWORD PTR SS:[ESP+1C],EDI
0040794B POPAD
0040794C RETN ;这里下断!!!
这是自脱壳过程,它将自脱壳或解密段。 它是这样的:首先分配了足够的内存,然后在那里解压缩段,然后原始段被擦除并且已解压段从被分配的内存复制到原始段,然后调用VirtuallFree和VirtualProtect。 将bp放在最后一个RETN并运行2次,直到加壳段被解码,删除bp,将bp放在VirtualFree上,Shift+F9直到你中断它,返回用户代码你应该在这里:
00408B60 LEA ESP,DWORD PTR SS:[ESP+4]
00408B64 LEA EAX,DWORD PTR SS:[EBP+12256A5]
00408B6A SUB EAX,0E23546
00408B6F JMP EAX
进入那个EAX,你就会到达最有趣的地方:
00408B60 LEA ESP,DWORD PTR SS:[ESP+4]
00408B64 LEA EAX,DWORD PTR SS:[EBP+12256A5]
00408B6A SUB EAX,0E23546
00408B6F JMP EAX
进入那个EAX,你就会到达最有趣的地方:
00407620 CALL CRACKME3.00407628 ;你在这里!!!!
00407625 JMP SHORT CRACKME3.0040762B
00407627 STC
00407628 JMP SHORT CRACKME3.00407625
0040762A SBB EAX,DWORD PTR DS:[EBX+C30C2404]
00407630 CMP BYTE PTR SS:[EBP+40218485],CL
00407636 ADD BYTE PTR DS:[EAX+9D8D7C00],AL
0040763C MOV FS,WORD PTR DS:[EAX+EAX*2]
0040763F ADD BYTE PTR DS:[EBX],CH
00407641 FADD DWORD PTR DS:[EAX-77]
00407644 SBB BYTE PTR SS:[EBP-5],CH
00407647 AAA
00407648 MOV AL,BYTE PTR DS:[EAX]
0040764A CALL CRACKME3.00407669
0040764F PUSHAD ;这里开始输入表重定向:
....
.... ;很多跳转和东西在这里。
....
....
00407708 POPAD ;这里结束输入表重定向。
00407709 RETN
0040770A ADD DWORD PTR DS:[EDI],ECX
0040770C PUSH EDI
0040770D ADD EDX,ECX
0040770F MOV EDI,ESI
00407711 MOV ESI,EAX
00407713 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[>
00407715 MOV EAX,ESI
00407717 MOV ESI,EDI
00407719 POP EDI
0040771A JMP CRACKME3.00407675
我们现在还不会进入输入表重定向程序,我将在稍后讨论。 所以进一步F7跟踪,你将再次到达VirtualProtect,直到你到达这个看起来像死胡同街的地方:
00407620 CALL CRACKME3.00407628 ;你在这里!!!!
00407625 JMP SHORT CRACKME3.0040762B
00407627 STC
00407628 JMP SHORT CRACKME3.00407625
0040762A SBB EAX,DWORD PTR DS:[EBX+C30C2404]
00407630 CMP BYTE PTR SS:[EBP+40218485],CL
00407636 ADD BYTE PTR DS:[EAX+9D8D7C00],AL
0040763C MOV FS,WORD PTR DS:[EAX+EAX*2]
0040763F ADD BYTE PTR DS:[EBX],CH
00407641 FADD DWORD PTR DS:[EAX-77]
00407644 SBB BYTE PTR SS:[EBP-5],CH
00407647 AAA
00407648 MOV AL,BYTE PTR DS:[EAX]
0040764A CALL CRACKME3.00407669
0040764F PUSHAD ;这里开始输入表重定向:
....
.... ;很多跳转和东西在这里。
....
....
00407708 POPAD ;这里结束输入表重定向。
00407709 RETN
0040770A ADD DWORD PTR DS:[EDI],ECX
0040770C PUSH EDI
0040770D ADD EDX,ECX
0040770F MOV EDI,ESI
00407711 MOV ESI,EAX
00407713 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[>
00407715 MOV EAX,ESI
00407717 MOV ESI,EDI
00407719 POP EDI
0040771A JMP CRACKME3.00407675
我们现在还不会进入输入表重定向程序,我将在稍后讨论。 所以进一步F7跟踪,你将再次到达VirtualProtect,直到你到达这个看起来像死胡同街的地方:
004001F8 MOV ESI,CRACKME3.004001FF
004001FD POP DWORD PTR DS:[ESI]
004001FF ADD BYTE PTR DS:[EAX],AL
00400201 ADC BYTE PTR DS:[EAX],AL
00400203 ADD BYTE PTR DS:[EAX],AL
00400205 ADC BYTE PTR DS:[EAX],AL
00400207 ADD BYTE PTR DS:[EAX],AL
00400209 ADD AL,0
0040020B ADD BYTE PTR DS:[EAX],AL
0040020D PUSH ES
0040020E ADD BYTE PTR DS:[EAX],AL
00400210 ADD BYTE PTR DS:[EAX],AL
将内存访问断点放在.taz部分并Shift + F9运行,直到你中断到:
004001F8 MOV ESI,CRACKME3.004001FF
004001FD POP DWORD PTR DS:[ESI]
004001FF ADD BYTE PTR DS:[EAX],AL
00400201 ADC BYTE PTR DS:[EAX],AL
00400203 ADD BYTE PTR DS:[EAX],AL
00400205 ADC BYTE PTR DS:[EAX],AL
00400207 ADD BYTE PTR DS:[EAX],AL
00400209 ADD AL,0
0040020B ADD BYTE PTR DS:[EAX],AL
0040020D PUSH ES
0040020E ADD BYTE PTR DS:[EAX],AL
00400210 ADD BYTE PTR DS:[EAX],AL
将内存访问断点放在.taz部分并Shift + F9运行,直到你中断到:
00408553 SUB EBX,EBX
00408555 MOV ESP,DWORD PTR SS:[ESP+8]
00408559 POP DWORD PTR FS:[EBX]
0040855C POP ECX
0040855D POP EBP
0040855E MOV EDI,CRACKME3.00400100
清除内存访问断点继续跟踪,直到您抵达第一个GetTickCount API调用:
00408553 SUB EBX,EBX
00408555 MOV ESP,DWORD PTR SS:[ESP+8]
00408559 POP DWORD PTR FS:[EBX]
0040855C POP ECX
0040855D POP EBP
0040855E MOV EDI,CRACKME3.00400100
清除内存访问断点继续跟踪,直到您抵达第一个GetTickCount API调用:
0040857D CALL DWORD PTR SS:[ESP] ; kernel32.GetTickCount
然后直到第二次抵达 (恰好在它下面):
0040857D CALL DWORD PTR SS:[ESP] ; kernel32.GetTickCount
然后直到第二次抵达 (恰好在它下面):
00408591 JMP DWORD PTR SS:[ESP+EBX-4] ; kernel32.GetTickCount
壳使用了两个GetTickCount调用,为什么我不知道,但这对我们来说是有用的信息。 按Shift + F9一次,进入INT3异常(004089B6 2BDB sub ebx,ebx)。 这是另一个调试器检查,将内存访问断点放在.taz部分,Shift + F9运行,你就在这里(如下):
00408591 JMP DWORD PTR SS:[ESP+EBX-4] ; kernel32.GetTickCount
壳使用了两个GetTickCount调用,为什么我不知道,但这对我们来说是有用的信息。 按Shift + F9一次,进入INT3异常(004089B6 2BDB sub ebx,ebx)。 这是另一个调试器检查,将内存访问断点放在.taz部分,Shift + F9运行,你就在这里(如下):
00408A27 JMP SHORT CRACKME3.00408A2A
清除内存访问断点,现在跟踪和跟踪,直到您进入Virtualalloc,退出它,跟踪和跟踪…在这里,壳自己可以解码DLL名称:
00408A27 JMP SHORT CRACKME3.00408A2A
清除内存访问断点,现在跟踪和跟踪,直到您进入Virtualalloc,退出它,跟踪和跟踪…在这里,壳自己可以解码DLL名称:
004086B3 JE SHORT CRACKME3.004086BA
004086B5 NOT BYTE PTR DS:[EDI] ;这个解码。
004086B7 INC EDI
004086B8 JMP SHORT CRACKME3.004086B0
004086BA POP EDI
004086BB RETN
跟踪,你就会被扔进LoadLibraryA。将mem bp放置在.taz段上,然后按Shift F9离开(直接执行到返回也可以):
004086B3 JE SHORT CRACKME3.004086BA
004086B5 NOT BYTE PTR DS:[EDI] ;这个解码。
004086B7 INC EDI
004086B8 JMP SHORT CRACKME3.004086B0
004086BA POP EDI
004086BB RETN
跟踪,你就会被扔进LoadLibraryA。将mem bp放置在.taz段上,然后按Shift F9离开(直接执行到返回也可以):
77ED6FC4 >JMP BAE8CFE1
77ED6FC9 NOP
77ED6FCA NOP
77ED6FCB NOP
77ED6FCC NOP
77ED6FCD NOP
77ED6FCE NOP
77ED6FCF NOP
77ED6FD0 NOP
77ED6FD1 NOP
77ED6FD2 NOP
77ED6FD3 >JMP BAE8D155
77ED6FD8 NOP
77ED6FD9 NOP
77ED6FDA NOP
77ED6FDB NOP
你应该在这里:
77ED6FC4 >JMP BAE8CFE1
77ED6FC9 NOP
77ED6FCA NOP
77ED6FCB NOP
77ED6FCC NOP
77ED6FCD NOP
77ED6FCE NOP
77ED6FCF NOP
77ED6FD0 NOP
77ED6FD1 NOP
77ED6FD2 NOP
77ED6FD3 >JMP BAE8D155
77ED6FD8 NOP
77ED6FD9 NOP
77ED6FDA NOP
77ED6FDB NOP
你应该在这里:
你知道怎么做 :), 再次跟踪,您将抵达DLL名擦除:
你知道怎么做 :), 再次跟踪,您将抵达DLL名擦除:
00407A8A OR BYTE PTR DS:[EBX],0
00407A8D JE SHORT CRACKME3.00407A9C
00407A8F MOV BYTE PTR DS:[EBX],DL
00407A91 ROL EDX,4
当擦除完了就跟到这个有趣的地方:
00407A8A OR BYTE PTR DS:[EBX],0
00407A8D JE SHORT CRACKME3.00407A9C
00407A8F MOV BYTE PTR DS:[EBX],DL
00407A91 ROL EDX,4
当擦除完了就跟到这个有趣的地方:
004077D4 CMP BYTE PTR SS:[EBP+4026E5],0CC;
注:这儿有ss:[00407BA6]=F9
004077DB JNZ SHORT CRACKME3.004077E2
004077DD JE SHORT CRACKME3.004077E0
这里检查BP放在[EBP+xxxxx]地址上的情况,地址是:
004077D4 CMP BYTE PTR SS:[EBP+4026E5],0CC;
注:这儿有ss:[00407BA6]=F9
004077DB JNZ SHORT CRACKME3.004077E2
004077DD JE SHORT CRACKME3.004077E0
这里检查BP放在[EBP+xxxxx]地址上的情况,地址是:
00407BA6 STC
00407BA7 JB SHORT CRACKME3.00407BAE
00407BA9 CALL CRACKME3.0040867E
00407BAE JMP SHORT CRACKME3.00407BB1
那是很重要的地方,因为PESpin正在检查它。这个地方离壳保护代码末端很近。两个跳转之间的调用是可选的;如果您在PESpin选项中选择“在:xxx分钟之后关闭程序”,则调用将被执行,并将在指定的时间之后启动关闭程序的线程。在此之后,壳保护将从IAT重定向开始,就像我前面提到的那样。那么我们必须找到被盗的OEP字节。离这里不远。我们必须找到一个POPAD操作码,这是最后的PESpin代码之前被盗的字节,并跳转到真正的OEP。向下滚动:
00407BA6 STC
00407BA7 JB SHORT CRACKME3.00407BAE
00407BA9 CALL CRACKME3.0040867E
00407BAE JMP SHORT CRACKME3.00407BB1
那是很重要的地方,因为PESpin正在检查它。这个地方离壳保护代码末端很近。两个跳转之间的调用是可选的;如果您在PESpin选项中选择“在:xxx分钟之后关闭程序”,则调用将被执行,并将在指定的时间之后启动关闭程序的线程。在此之后,壳保护将从IAT重定向开始,就像我前面提到的那样。那么我们必须找到被盗的OEP字节。离这里不远。我们必须找到一个POPAD操作码,这是最后的PESpin代码之前被盗的字节,并跳转到真正的OEP。向下滚动:
00407BFA 68 E8030000 PUSH 3E8
00407BFF 00EB ADD BL,CH
00407C01 04 1F ADD AL,1F
00407C03 ^EB FB JMP SHORT CRACKME3.00407C00
00407C05 ^7C 83 JL SHORT CRACKME3.00407B8A
00407C07 04 24 ADD AL,24
00407C09 0C C3 OR AL,0C3
00407C0B E8 616A00EB CALL EB40E671 ;这里是POPAD操作码!!!!!!!
00407C10 01E4 ADD ESP,ESP
00407C12 E8 6D98FFFF CALL CRACKME3.00401484
00407C17 -E9 EB93FFFF JMP CRACKME3.00401007
00407C1C AE SCAS BYTE PTR ES:[EDI]
因为这个地方有混淆的代码,Olly没有正确地显示它,但是在407C0B你会看到一个61字节。61十六进制=POPAD.二进制编辑(NOP一个字节),这一行代码清楚地表明:
00407BFA 68 E8030000 PUSH 3E8
00407BFF 00EB ADD BL,CH
00407C01 04 1F ADD AL,1F
00407C03 ^EB FB JMP SHORT CRACKME3.00407C00
00407C05 ^7C 83 JL SHORT CRACKME3.00407B8A
00407C07 04 24 ADD AL,24
00407C09 0C C3 OR AL,0C3
00407C0B E8 616A00EB CALL EB40E671 ;这里是POPAD操作码!!!!!!!
00407C10 01E4 ADD ESP,ESP
00407C12 E8 6D98FFFF CALL CRACKME3.00401484
00407C17 -E9 EB93FFFF JMP CRACKME3.00401007
00407C1C AE SCAS BYTE PTR ES:[EDI]
因为这个地方有混淆的代码,Olly没有正确地显示它,但是在407C0B你会看到一个61字节。61十六进制=POPAD.二进制编辑(NOP一个字节),这一行代码清楚地表明:
00407C07 04 24 ADD AL,24
00407C09 0C C3 OR AL,0C3
00407C0B 90 NOP
00407C0C 61 POPAD
00407C0D 6A 00 PUSH 0
00407C0F EB 01 JMP SHORT CRACKME3.00407C12
00407C07 04 24 ADD AL,24
00407C09 0C C3 OR AL,0C3
00407C0B 90 NOP
00407C0C 61 POPAD
00407C0D 6A 00 PUSH 0
00407C0F EB 01 JMP SHORT CRACKME3.00407C12 (先处理暗桩:转到00407BDC改为jmp)现在把BP放在POPAD上,然后运行crackme。跟踪,您将在401xxx地址进入代码段,但您可能会对代码的外观感到困惑。接着你进入kernel32,然后返回到壳代码。这是因为PESpin偷了一对初始指令,这个crackme的初始指令是一些API调用,所以这里PESpin仍然干扰crackme。如果您愿意,您可以进一步跟踪并进入IAT重定位。在这里你可以看到PESpin是如何破坏入口的。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2019-2-25 21:30
被ejamse编辑
,原因: 添加附件
上传的附件: