【文章标题】: yoda's Protector 1.03.3主程序简单分析
【文章作者】: frozenrain
【作者邮箱】: frozenrain86@163.com
【软件名称】: yoda's Protector 1.03.3
【下载地址】: 自己搜索下载
【保护方式】: yoda's Protector 1.03.3
【编写语言】: VC
【使用工具】: OD,LORDPE IMPORTREC
【操作平台】: WIN XP
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
最近看坛子里有人问这个壳,所以拿来看看,当作一次学习过程吧,高手飘过。
OD载入,F7单步跟踪
0043E795 33C0 xor eax, eax
0043E797 64:FF30 push dword ptr fs:[eax]
0043E79A 64:8920 mov dword ptr fs:[eax], esp
0043E79D 4B dec ebx
0043E79E CC int3
第一次异常看堆栈 在SE句柄上下断就过去了
0043E783 33C0 xor eax, eax
0043E785 64:FF30 push dword ptr fs:[eax]
0043E788 64:8920 mov dword ptr fs:[eax], esp
0043E78B CC int3
同样的方法,跳过了几个int3后,F7走到这里
0043E74B 60 pushad
0043E74C E8 00000000 call 0043E751
0043E751 5D pop ebp
0043E752 81ED 07E24000 sub ebp, 0040E207 ; 入口地址
0043E758 8BD5 mov edx, ebp
花指令太多了,可能有贴出来的有点乱
下面是解码部分。
0043E808 /EB 01 jmp short 0043E80B
0043E80A |C2 EB01 retn 1EB
0043E80D E8 C0C8822A call 2AC6B0D2
0043E812 C1EB 01 shr ebx, 1
0043E815 E8 EB01C2C0 call C105EA05
0043E81A C8 973467 enter 3497, 67
0043E81E EB 01 jmp short 0043E821
0043E820 E8 F8F802C1 call C146E11D
0043E825 34 0C xor al, 0C
0043E827 F9 stc
0043E828 EB 01 jmp short 0043E82B
0043E82A C2 EB01 retn 1EB
0043E82D - E9 EB01C22C jmp 2D05EA1D
0043E832 D1EB shr ebx, 1
0043E834 01E9 add ecx, ebp
0043E836 02C1 add al, cl
0043E838 C0C0 41 rol al, 41
0043E83B EB 01 jmp short 0043E83E
0043E83D E8 04552AC1 call C16E3D46
0043E842 2C 53 sub al, 53
0043E844 F8 clc
0043E845 D9D0 fnop
0043E847 90 nop
0043E848 AA stos byte ptr es:[edi]
0043E849 ^ E2 9C loopd short 0043E7E7
见到CALL,除去系统API外,一般F7跟进,否则可能跑飞。
到了这里
0043F3BB CC int3
0043F3BC 8BEF mov ebp, edi
0043F3BE 33DB xor ebx, ebx
还是SHE ,SE句柄上下断
到这里,这就是SHE处理程序
00440CAC 55 push ebp
00440CAD 8BEC mov ebp, esp
00440CAF 57 push edi
00440CB0 36:8B45 10 mov eax, dword ptr [ebp+10]
00440CB4 3E:8BB8 9C00000>mov edi, dword ptr [eax+9C]
00440CBB 8BD7 mov edx, edi
00440CBD 81C2 4C0B4100 add edx, 00410B4C
00440CC3 3E:FF32 push dword ptr [edx]
00440CC6 3E:8F80 B800000>pop dword ptr [eax+B8] 修改EIP
00440CCD 3E:89B8 B400000>mov dword ptr [eax+B4], edi
00440CD4 3E:C780 B000000>mov dword ptr [eax+B0], 4
00440CDF B8 00000000 mov eax, 0
00440CE4 5F pop edi
00440CE5 C9 leave
上面EAX指向线程上下文,B0,B4,B8是偏移。具体多少查资料
PE头变形了,引入表只有两个函数,下面是程序解出了大部分API用于后面的解码
0043F477 8B85 E0074100 mov eax, dword ptr [ebp+4107E0]
0043F47D 0340 3C add eax, dword ptr [eax+3C]
0043F480 05 80000000 add eax, 80 ; 引入表
0043F485 8B08 mov ecx, dword ptr [eax]
0043F487 038D E0074100 add ecx, dword ptr [ebp+4107E0]
0043F48D 83C1 10 add ecx, 10
0043F490 8B01 mov eax, dword ptr [ecx]
0043F492 0385 E0074100 add eax, dword ptr [ebp+4107E0]
这里是读取开机到现在的时间,后面用的着。
0043E937 E8 03FDFFFF call 0043E63F ; jmp 到 kernel32.GetTickCount
0043E93C 8985 68084100 mov dword ptr [ebp+410868], eax 保存地址可记下来
0043E942 E8 03000000 call 0043E94A
0043E947 EB 01 jmp short 0043E94A
获取操作系统版本,用XP实践的其他版本没尝试。
0043F412 E8 2EF2FFFF call 0043E645 ; jmp 到 kernel32.GetVersion
0043F417 A9 00000080 test eax, 80000000
0043F41C 74 20 je short 0043F43E
0043F41E 3C 04 cmp al, 4
0043F420 75 0C jnz short 0043F42E
0043F422 C785 F4074100 0>mov dword ptr [ebp+4107F4], 2
0043F42C EB 40 jmp short 0043F46E
0043F42E 3C 03 cmp al, 3
继续往下走
0043E990 E8 68FCFFFF call 0043E5FD ; jmp 到 kernel32.GetPriorityClass
0043E995 8985 0C084100 mov dword ptr [ebp+41080C], eax
0043E99B 58 pop eax
0043E99C 68 80000000 push 80
0043E9A1 50 push eax
0043E9A2 E8 50FCFFFF call 0043E5F7 ; jmp 到 kernel32.SetPriorityClass
0043E9A7 F785 F4074100 0>test dword ptr [ebp+4107F4], 8
0043E9B1 75 07 jnz short 0043E9BA
0043E9B3 6A 01 push 1
0043E9B5 E8 BBFCFFFF call 0043E675 ; jmp 到 User32.BlockInput
BlockInput这个函数用于阻止键盘输入,可NOP掉,用CTRL+ALT+DEL比较方便
再往下走就有很多反调试的东西了,基本上涵盖了看雪那基本书上介绍的那几种方法。IsDebugPresent函数,CreateFile检测SOFTICE,ToolHelp32快照函数检测父进程,还有BlockInput.用海风大侠插件就不用怕了。
下面有个anti-dump的代码
0043ED82 64:FF35 3000000>push dword ptr fs:[30]
0043ED89 58 pop eax PEB
0043ED8A 85C0 test eax, eax
0043ED8C 78 0F js short 0043ED9D
0043ED8E 8B40 0C mov eax, dword ptr [eax+C] LDR
0043ED91 8B40 0C mov eax, dword ptr [eax+C] InLoadOderModule-
0043ED94 C740 20 0020000>mov dword ptr [eax+20], 2000
SizeOfImage改为2000,如果后面DUMP失败,则可以将这里NOP掉。
继续往下走,校验的地方,参考其他文章。
0043EF3E 02C1 add al, cl
0043EF40 EB 01 jmp short 0043EF43
0043EF42 - E9 2AC1EB01 jmp 022FB071
0043EF47 C2 D9D0 retn 0D0D9
0043EF4A C0C0 8B rol al, 8B
0043EF4D F9 stc
0043EF4E 02C1 add al, cl
0043EF50 C0C8 58 ror al, 58
0043EF53 AA stos byte ptr es:[edi]
0043EF54 ^ E2 CC loopd short 0043EF22
0043EF56 C3 retn
上面是解码部分,有花,估计贴出来的有些部分代码改变了
继续下面是区块表的处理。
0043F199 8BF7 mov esi, edi
0043F19B 81C6 F8000000 add esi, 0F8
0043F1A1 8D9D 600B4100 lea ebx, dword ptr [ebp+410B60]
0043F1A7 33D2 xor edx, edx
0043F1A9 52 push edx
0043F1AA 51 push ecx
0043F1AB 50 push eax
0043F1AC 56 push esi
0043F1AD 57 push edi
0043F1AE 8BFE mov edi, esi
0043F1B0 8BF3 mov esi, ebx
0043F1B2 B9 08000000 mov ecx, 8
0043F1B7 AC lods byte ptr [esi]
0043F1B8 AA stos byte ptr es:[edi]
0043F1B9 ^ E2 FC loopd short 0043F1B7
0043F1BB 5F pop edi
0043F1BC 5E pop esi
0043F1BD 58 pop eax
0043F1BE 59 pop ecx
0043F1BF 5A pop edx
0043F1C0 83C3 08 add ebx, 8
0043F1C3 83C6 28 add esi, 28
0043F1C6 42 inc edx
0043F1C7 66:3E:3B57 06 cmp dx, word ptr [edi+6]
0043F1CC ^ 75 DB jnz short 0043F1A9
0043F1CE C3 retn
继续往下走,到了IAT处理部分。外壳保存引入表格式的信息为 Name,FirstThunk,OrignalFirstThunK,ESI指向Name,后面偏移分别为4,8.
ESI指向->Name
0044046C 3E:837E 04 00 cmp dword ptr [esi+4], 0 FirstThunk
00440471 0F84 19030000 je 00440790
00440477 3E:8B1E mov ebx, dword ptr [esi] Name
0044047A 039D E0074100 add ebx, dword ptr [ebp+4107E0]
00440480 8BC3 mov eax, ebx
00440482 E8 08000000 call 0044048F 解码出DLL名字
00440487 8D85 14014100 lea eax, dword ptr [ebp+410114]
0044048D 50 push eax
0044048E C3 retn
0044065E 53 push ebx
0044065F BA 21DF4000 mov edx, 0040DF21 ; ASCII CC,"烫烫"
00440664 FF5415 00 call dword ptr [ebp+edx] ; kernel32.LoadLibraryA
00440668 85C0 test eax, eax
0044066A 0F84 23010000 je 00440793
00440670 52 push edx
00440671 50 push eax
00440672 F785 500B4100 0>test dword ptr [ebp+410B50], 4
0044067C 74 0E je short 0044068C
0044067E 8D85 42014100 lea eax, dword ptr [ebp+410142]
00440684 50 push eax
00440685 8BC3 mov eax, ebx
00440687 E9 12060000 jmp 00440C9E
下面是将字符串清空
00440CA0 3E:C600 00 mov byte ptr [eax], 0 这里要NOP掉
00440CA4 40 inc eax
00440CA5 3E:8038 00 cmp byte ptr [eax], 0
00440CA9 ^ 75 F5 jnz short 00440CA0
00440CAB C3 retn
0044068C 5B pop ebx
0044068D 5A pop edx
0044068E 3E:8B4E 08 mov ecx, dword ptr [esi+8] OringnalFirstThunk
00440692 0BC9 or ecx, ecx
00440694 75 04 jnz short 0044069A
004406D0 52 push edx
004406D1 51 push ecx
004406D2 50 push eax
004406D3 53 push ebx
004406D4 BA 25DF4000 mov edx, 0040DF25 ; ASCII CC,"烫烫烫"
004406D9 FF5415 00 call dword ptr [ebp+edx] ; kernel32.GetProcAddress
004406DD 0BC0 or eax, eax
004406DF 75 07 jnz short 004406E8
00440706 61 popad
00440707 5A pop edx
00440708 8902 mov dword ptr [edx], eax ; 写入内存
0044070A EB 1C jmp short 00440728
下面是对不同的DLL库做不同的处理,他里面的OPENGL32.DLL,GLU32.DLL不处理。
00440728 51 push ecx ; yP.00432984
00440729 F785 500B4100 2>test dword ptr [ebp+410B50], 20
00440733 74 47 je short 0044077C
00440735 83BD 580B4100 0>cmp dword ptr [ebp+410B58], 0
0044073C 74 14 je short 00440752
0044073E 81FB 00000070 cmp ebx, 70000000
00440744 72 08 jb short 0044074E
00440746 81FB FFFFFF77 cmp ebx, 77FFFFFF
0044074C 76 0E jbe short 0044075C
0044074E EB 2C jmp short 0044077C 不处理
00440750 EB 0A jmp short 0044075C
00440752 81FB 00000080 cmp ebx, 80000000
00440758 73 02 jnb short 0044075C
0044075A EB 20 jmp short 0044077C
0044075C 57 push edi
0044075D 56 push esi
0044075E 8DBD 7B0C4100 lea edi, dword ptr [ebp+410C7B]
00440764 3E:8B77 04 mov esi, dword ptr [edi+4]
00440768 8932 mov dword ptr [edx], esi 这里要NOP掉
0044076A 2BC6 sub eax, esi
0044076C 83E8 05 sub eax, 5
0044076F C606 E9 mov byte ptr [esi], 0E9 构造跳转表
00440772 8946 01 mov dword ptr [esi+1], eax
00440775 3E:8347 04 05 add dword ptr [edi+4], 5
0044077A 5E pop esi
0044077B 5F pop edi
0044077C 59 pop ecx
0044077D 83C1 04 add ecx, 4
00440780 83C2 04 add edx, 4
00440783 ^ E9 22FFFFFF jmp 004406AA
00440788 83C6 0C add esi, 0C
0044078B ^ E9 DCFCFFFF jmp 0044046C
上面程序在动态申请的空间构造了以个跳转表,然后将檫掉程序里的IAT。所以NOP掉那两句就可以用IMPORTREC得到完整的IAT,保存后面使用。
IAT完了后,继续往下走
00440890 E8 AADDFFFF call 0043E63F ; jmp 到 kernel32.GetTickCount
00440895 8B8D 68084100 mov ecx, dword ptr [ebp+410868]
0044089B 2BC1 sub eax, ecx
0044089D 3D E02E0000 cmp eax, 2EE0
004408A2 78 08 js short 004408AC 这里要跳,不跳就挂
004408A4 EB 01 jmp short 004408A7
004408A6 2C 61 sub al, 61
004408A8 ^ EB E5 jmp short 0044088F
GetTickCount来和上次获取的时间进行比较,改标志位跳过。
下面又到了继续解码的地方,F4跳过去
004408FE AA stos byte ptr es:[edi]
004408FF ^ E2 CC loopd short 004408CD
00440901 8D85 C3034100 lea eax, dword ptr [ebp+4103C3]
00440907 50 push eax
00440908 C3 retn
下面有个异常,看堆栈跳过去
00440C8D 50 push eax
00440C8E 33C0 xor eax, eax
00440C90 64:FF30 push dword ptr fs:[eax]
00440C93 64:8920 mov dword ptr fs:[eax], esp
00440C96 EB 01 jmp short 00440C99
00440C98 C3 retn
00440C99 0000 add byte ptr [eax], al
到了异常处理处
00440A2C 55 push ebp
00440A2D 8BEC mov ebp, esp
00440A2F 57 push edi
00440A30 36:8B45 10 mov eax, dword ptr [ebp+10]
00440A34 3E:8BB8 C400000>mov edi, dword ptr [eax+C4]
00440A3B 3E:FF37 push dword ptr [edi]
00440A3E 33FF xor edi, edi
00440A40 64:8F07 pop dword ptr fs:[edi]
00440A43 3E:8380 C400000>add dword ptr [eax+C4], 8
00440A4B 3E:8BB8 A400000>mov edi, dword ptr [eax+A4]
00440A52 C1C7 07 rol edi, 7
00440A55 3E:89B8 B800000>mov dword ptr [eax+B8], edi 这里改了EIP
00440A5C B8 00000000 mov eax, 0
00440A61 5F pop edi
00440A62 C9 leave
00440A63 C3 retn
在EDI地址上下段后F9过去就是OEP了
0041B295 . 6A 60 push 60
0041B297 . 68 D05B4000 push 00405BD0
0041B29C . E8 670D0000 call 0041C008
0041B2A1 . BF 94000000 mov edi, 94
0041B2A6 . 8BC7 mov eax, edi
0041B2A8 . E8 C3FCFFFF call 0041AF70
0041B2AD . 8965 E8 mov dword ptr [ebp-18], esp
0041B2B0 . 8BF4 mov esi, esp
0041B2B2 . 893E mov dword ptr [esi], edi
0041B2B4 . 56 push esi ; /pVersionInformation
0041B2B5 . FF15 48114000 call dword ptr [401148] ; \GetVersionExA
dump后,修复下IAT可以运行。
参考资料:fly大侠的yoda's Protector V1.03.2.02脱壳——yP.exe全过程分析
http://bbs.pediy.com/showthread.php?t=13927
--------------------------------------------------------------------------------
【经验总结】
学脱壳得单步走,多用F7,少用F8。
壳比较老,没什么价值,而且前辈也写有文章。算是新手的一次练习。
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
2009年04月23日 22:54:58
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!