首页
社区
课程
招聘
[旧帖] [原创]手工脱Themida.V1.9.2.0壳 0.00雪花
发表于: 2008-4-16 10:59 7553

[旧帖] [原创]手工脱Themida.V1.9.2.0壳 0.00雪花

2008-4-16 10:59
7553
壳:Themida.V1.9.2.0猛壳。
使用软件:OllyDBG1.1 ,ImportREC ,PEid
操作系统:XP SP2

附件:用Themida.V1.9.2.0加壳过的记事本
http://www.live-share.com/files/318431/unpackme.rar.html
--------------------------------------------------------------------------------
开始:
此壳会Anit-Debug,所以先设置好OD的PhantOm插件,将"hide from PEB",
"change Olly caption -[Drivers]-","load driver","hide OllyDbg windows"打上勾。
在调试选项中勿略所有异常。

然后F3加载,unpackme.exe
提示代码可能被压缩过,取消分析。
入口点为01014014。

01014014 >  B8 >mov     eax, 0       //入口点
01014019    60  pushad
0101401A    0BC>or      eax, eax
0101401C    74 >je      short 01014086
0101401E    E8 >call    01014023
01014023    58  pop     eax
01014024    05 >add     eax, 53
01014029    803>cmp     byte ptr [eax], 0E9
0101402C    75 >jnz     short 01014041

打开[Memory map],在unpackme代码段设置内存写入断点,F9走
异常后,Shift+F7,Alt+F9,又异常,Shift+F7,Alt+F9走到0083DF33,
往上看,原来这里调用了个异常(0083DF2D处)!

0083DF22    57  push    edi
0083DF23    8D7>lea     edi, dword ptr [ebp-3C]
0083DF26    F3:>rep     movs dword ptr es:[edi], dword>
0083DF28    5F  pop     edi
0083DF29    8D4>lea     eax, dword ptr [ebp-50]
0083DF2C    50  push    eax
0083DF2D    FF1>call    dword ptr [<&ntdll.RtlRaiseExc>; ntdll.RtlRaiseException
0083DF33    5E  pop     esi                            ; unpackme.010D4A42

     0083DF33 的ESI发现 "Themida Professional  (c)2007 Oreans Technologies"字符串
     Themida专业版!走吧,F9

内存写入中断出在01119D6B

01119D6B    F3:>rep     movs byte ptr es:[edi], byte ptr [esi] //往[edi]处写入代码,写ecx=6000h个字节
01119D6D    C68>mov     byte ptr [ebp+9742145], 56
01119D74    68 >push    D41F6D39
01119D79    FFB>push    dword ptr [ebp+97425DD]
01119D7F    8D8>lea     eax, dword ptr [ebp+977C6A1]

按F7,F8走过写部份,F9继续上路。
中断在011287F5处,

011287F5    891>mov     dword ptr [ebx], edx
011287F7    5B  pop     ebx
011287F8    5A  pop     edx
011287F9    F9  stc
011287FA    AD  lods    dword ptr [esi]

   011287F5处的edx=comdlg32.PageSetupDlgW,ebx=unpackme.010012C4,
   看来是写入PageSetupDlgW的调用地址。

删除代码内存写入断点,F8走
走到01128A90处

01128A90    803>cmp     byte ptr [edi], 90
01128A93    0F8>je      01128AC4
01128A99    F5  cmc
01128A9A    50  push    eax
01128A9B    B8 >mov     eax, 5
01128AA0    01C>add     edi, eax
01128AA2    8B0>mov     eax, dword ptr [esp]
01128AA5    83C>add     esp, 4
01128AA8    FC  cld
01128AA9    E9 >jmp     01128C93

01128A90处进行比较,[edi]处是否90,然后去[edi]处往上看,发现很多压栈
后的代码就90,即调用函数是空的。现在这里是如果发现是空的就重写。
接着走,F8

走到01128B77处,准备写入comdlg32.PageSetupDlgW的调用地址
这里写一个字节,al=E8  (即call的机器码)

01128B77    AA  stos    byte ptr es:[edi]
01128B78    60  pushad
01128B79    BE >mov     esi, 769CD237
01128B7E    0F8>jno     01128B86
01128B84    8BF>mov     esi, ecx

F8走到01128CD8D处,写调用(call comdlg32.PageSetupDlgW)地址。
01128C8D    AB  stos    dword ptr es:[edi]
01128C8E    60  pushad
01128C8F    0FB>movzx   eax, ax
01128C92    61  popad
01128C93    AD  lods    dword ptr [esi]

F8走,又倒回到01128A90处,(这里edi=01006576)

01128A90    803>cmp     byte ptr [edi], 90
01128A93    0F8>je      01128AC4
01128A99    F5  cmc
01128A9A    50  push    eax
01128A9B    B8 >mov     eax, 5

F8走,走到01128B77向[edi]写入E8, 即Call的机器码,F8走到01128C8D写
调用(call comdlg32.PageSetupDlgW)地址。
F8走过漫长的一断,到01125CDC,F7进入这个Call

01125CDC    E8 >call    01125CF0
01125CE1    43  inc     ebx
01125CE2    D22>shl     byte ptr [edx], cl
01125CE4    3F  aas
01125CE5    0C >or      al, 0B7
01125CE7    C8 >enter   0A4DE, 89

然后F8继续走,同样经过漫长的一断走到 0112648F这个Call,F7走入
0112648F    E8 >call    011264A5
01126494    CE  into
01126495    AF  scas    dword ptr es:[edi]
01126496    CF  iretd
01126497    2B5>sub     ebx, dword ptr [ebx-66]

经过一段,走到011265F1,这里F7单步走过
011265F1    E8 >call    01126605
011265F6    4A  dec     edx
011265F7    D8E>fsub    st, st(1)
011265F9    49  dec     ecx
011265FA    BD >mov     ebp, C2FFB29A

F8继续走,走到 0112664E

0112664E    83B>cmp     dword ptr [ebp+9741E31], 1
01126655    0F8>je      0112670E   //跳到IAT加密码部份
0112665B    F8  clc
0112665C    3B8>cmp     ecx, dword ptr [ebp+97401F9]
01126662    0F8>je      0112670E   //跳到IAT加密码部份
01126668    60  pushad
01126669    0FB>movzx   eax, cx
0112666C    8AE>mov     ah, dh
0112666E    61  popad
0112666F    E9 >jmp     0112667C

je 0112670E是跳到IAT表加密码的地方,所以这里用NOP修改je 0112670E。并把程序里
所有je 0112670E都改成NOP指令,使其取消加密IAT表。
用Ctrl+F找"je 0112670E",找到以下四个地址,这四个地址的汇编指令改成NOP

01126655
01126662
01126682
011266A3

由于改动过代码,壳的自检验未能通过,所以要修改01125EC7处的代码,
原代码为 je 01125F3D,我们修改为jmp 01125F3D

然的在ntdll.dll 的ZwFreeVirtualMemory下断点,然后F9继续走吧,
中断在7C92DA48处,取消7C92DA48处的中断,直接在7C92DA54下F2断点。
7C92DA48 >  B8 >mov     eax, 53
7C92DA4D    BA >mov     edx, 7FFE0300
7C92DA52    FF1>call    dword ptr [edx]
7C92DA54    C2 >retn    10   //在这里下F2下断点

这里我们需要在7C92DA54处下断点和代码段下写入断点,按F9走,
中断在00828F5F,用F8走到 程序领空

00828F5F    8BF8            mov     edi, eax
00828F61    85FF            test    edi, edi
00828F63    0F8C B39C0100   jl      00842C1C
00828F69    33C0            xor     eax, eax
00828F6B    40              inc     eax
00828F6C    5F              pop     edi
00828F6D    5E              pop     esi
00828F6E    5D              pop     ebp
00828F6F    C2 1000         retn    10

F8继续走,走到0112BA2F程序领空,
0112BA2F    F5              cmc
0112BA30    60              pushad
0112BA31    B9 5E2D4312     mov     ecx, 12432D5E
0112BA36    60              pushad
0112BA37    0F80 00000000   jo      0112BA3D
0112BA3D    8BF0            mov     esi, eax

然后在unpackme代码段下F2断点。
接着F9走,中断后用F8走到程序领空,然后查看代码段中断是否还有,没有的话用F2加入中断!
重复以上动作,几次循还后会停在 01007568

01007568    68 BA75>push    010075BA
0100756D    64:A1 0>mov     eax, dword ptr fs:[0]
01007573    50      push    eax
01007574    8B4424 >mov     eax, dword ptr [esp+10]
01007578    896C24 >mov     dword ptr [esp+10], ebp
0100757C    8D6C24 >lea     ebp, dword ptr [esp+10]

然后F8单步走,然后将光标向下移到最近一个retn 指令,在retn处一次F4,然后F8

01119ED7    68 E07A>push    97C7AE0
01119EDC  ^ E9 CC43>jmp     0109E2AD
01119EE1    68 BF7B>push    97C7BBF
01119EE6  ^ E9 C243>jmp     0109E2AD
01119EEB    CC      int3
01119EEC    41      inc     ecx

然在代码段用F2下中断,F9走。
中断在 010ADB90处,

010ADB90    FF32    push    dword ptr [edx]              ; kernel32.GetModuleHandleA
010ADB92  ^ E9 5D07>jmp     0109E2F4
010ADB97    B8 FFFF>mov     eax, -1
010ADB9C    01C1    add     ecx, eax
010ADB9E    8B0424  mov     eax, dword ptr [esp]
010ADBA1  ^ E9 7039>jmp     010A1516

这时记下[edx]的值,010010CC ,这里的010010CC是假的OEP地址。
然后按2次F8走过,然后下代码段F2中断。F9走到010073CC,

010073CC    3D 0B01>cmp     eax, 10B
010073D1    74 1F   je      short 010073F2
010073D3    3D 0B02>cmp     eax, 20B
010073D8    74 05   je      short 010073DF
010073DA    895D E4 mov     dword ptr [ebp-1C], ebx
010073DD    EB 27   jmp     short 01007406
010073DF    83B9 84>cmp     dword ptr [ecx+84], 0E

从010073CC向上查找CC汇编代码,从找到的CC的后一个地址即为OEP地址。

01007399    CC      int3
0100739A    CC      int3
0100739B    CC      int3
0100739C    CC      int3
0100739D    F2:     prefix repne:           //真正的入口地址,从010010CC到这里的代码被偷了
0100739E    6BC5 57 imul    eax, ebp, 57
010073A1    EE      out     dx, al
010073A2  ^ E3 90   jecxz   short 01007334
010073A4    54      push    esp
010073A5    4A      dec     edx
010073A6    A2 D6CA>mov     byte ptr [E3AACAD6], al
010073AB    6C      ins     byte ptr es:[edi], dx
010073AC    36:2144>and     dword ptr ss:[edi+ebp*4-1B],>
010073B1    BF A70B>mov     edi, 18C70BA7
010073B6    EA 801F>jmp     far B24B:ADD61F80
010073BD    46      inc     esi
010073BE    91      xchg    eax, ecx
010073BF    A8 FC   test    al, 0FC
010073C1    0D 4B52>or      eax, 176C524B
010073C6    A7      cmps    dword ptr [esi], dword ptr e>
010073C7    13EA    adc     ebp, edx
010073C9    8929    mov     dword ptr [ecx], ebp
010073CB    E1 3D   loopde  short 0100740A
010073CD    0B01    or      eax, dword ptr [ecx]
010073CF    0000    add     byte ptr [eax], al
010073D1    74 1F   je      short 010073F2
010073D3    3D 0B02>cmp     eax, 20B
010073D8    74 05   je      short 010073DF
010073DA    895D E4 mov     dword ptr [ebp-1C], ebx
010073DD    EB 27   jmp     short 01007406

这里找到的是0100739D。
由于从0100739D到010010CC处的代码被偷,所以我们从其它VC7程序的开头处复制一份到
0100739D处进行修补。修复如下:
VC7 开头的二进制代码(复制到0100739D到010073CC)

6A 70 68 98 18 00 01 E8 BF 01 00 00 33 DB 53 8B 3D CC 10 00 01 FF D7 66 81 38 4D 5A 75 1F 8B 48
3C 03 C8 81 39 50 45 00 00 75 12 0F B7 41 18 3D 0B 01 00 00

0100739D    6A 70           push    70
0100739F    68 98180001     push    01001898
010073A4    E8 BF010000     call    01007568
010073A9    33DB            xor     ebx, ebx
010073AB    53              push    ebx
010073AC    8B3D CC100001   mov     edi, dword ptr [10010CC]     ; kernel32.GetModuleHandleA
010073B2    FFD7            call    edi
010073B4    66:8138 4D5A    cmp     word ptr [eax], 5A4D
010073B9    75 1F           jnz     short 010073DA
010073BB    8B48 3C         mov     ecx, dword ptr [eax+3C]
010073BE    03C8            add     ecx, eax
010073C0    8139 50450000   cmp     dword ptr [ecx], 4550
010073C6    75 12           jnz     short 010073DA
010073C8    0FB741 18       movzx   eax, word ptr [ecx+18]
010073CC    3D 0B010000     cmp     eax, 10B
010073D1    74 1F           je      short 010073F2
010073D3    3D 0B020000     cmp     eax, 20B
010073D8    74 05           je      short 010073DF
010073DA    895D E4         mov     dword ptr [ebp-1C], ebx

然后用OD的OllyDump插件,入口地址重写成739D,然后 Dump 下来。

接下来是修复IAT表,可手工查找API函数地址。
在OD的数据窗口中定位到0100739D,然后查看方式为“长型”->“地址”,往上一直找。
发现API函数地址从01001000到01001344结束。

01001000  77DA6FC8  ADVAPI32.RegQueryValueExW
01001004  77DA6BF0  ADVAPI32.RegCloseKey
01001008  77DC8F7D  ADVAPI32.RegCreateKeyW
0100100C  77DCD5FD  ADVAPI32.IsTextUnicode
01001010  77DA7883  ADVAPI32.RegQueryValueExA
01001014  77DA761B  ADVAPI32.RegOpenKeyExA
.................................................

0100132C  77C323D8  offset msvcrt._adjust_fdiv
01001330  77BEF1A4  msvcrt.__p__commode
01001334  77BEF1DB  msvcrt.__p__fmode
01001338  77C0537C  msvcrt.__set_app_type
0100133C  77C1EE2F  msvcrt._controlfp
01001340  77C1806B  msvcrt.wcsncpy
01001344  00000000  //这里结束
01001348  00000000

打开Import REC软件,选择我们脱壳的进程,

OEP为739D
RVA为1000
Size为344

然后,Get Imports,最后Fix Dump刚才从OD 中Dump出来的PE文件。

脱壳完成!
最后可删除.Themida块区,然后修复IAT表,以实现减肥。
减肥后只有88K大小。

说明,脱壳后一般不能跨平台,只以在脱壳的那台机用。因为Themida用在本机调用
LoadLibraryA和GetProcAddress得到本机API的调用地址,然后进行还原API函数的调用
地址。所以,当两台机的DLL调用地址不同时,就不能跨平台了。
这个可手工或利用工具进行修复,论坛上有相关文章。

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 0
支持
分享
最新回复 (14)
雪    币: 474
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
我跟你走了几步
就不对路了
2008-4-16 11:04
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
这么复杂啊,顶
2008-4-16 11:05
0
雪    币: 226
活跃值: (10)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
4
开头很象,第二步就不对路了。
2008-4-18 11:43
0
雪    币: 86
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
是啊。我也是这样!一直跟不到.CODE下断我按下SHIFT+F9就不一样了.1
2008-4-18 12:11
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
不知所云,高,高,高啊~~~
2008-4-24 20:58
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
我是新手啊。这个壳这么复杂啊,看着很难。
2008-4-25 09:16
0
雪    币: 38
活跃值: (546)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
8
不错,学习了!顶
2008-4-25 12:18
0
雪    币: 201
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
xyu
9
都看糊涂了“所以先设置好OD的PhantOm插件,将"hide from PEB",
"change Olly caption -[Drivers]-","load driver","hide OllyDbg windows"打上勾。
”把od看来几遍就是找不到哦
2008-5-24 20:12
0
雪    币: 142
活跃值: (22)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
10
F8继续走,走到0112BA2F程序领空,
0112BA2F    F5              cmc
0112BA30    60              pushad
0112BA31    B9 5E2D4312     mov     ecx, 12432D5E
0112BA36    60              pushad
0112BA37    0F80 00000000   jo      0112BA3D
0112BA3D    8BF0            mov     esi, eax
这里不知道你是怎么过来的?????
2008-7-6 21:22
0
雪    币: 317
活跃值: (93)
能力值: ( LV9,RANK:140 )
在线值:
发帖
回帖
粉丝
11
太深奥啦学习下手脱,我还不懂呢,碰上都是脚本!
2008-7-6 22:12
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
不同的OD,结果不一样啊
2008-7-7 12:14
0
雪    币: 427
活跃值: (65)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
13
不是OD的缘故,而是不同的系统的缘故!
具体数值会有所不同但方法一样的
2008-7-7 15:22
0
雪    币: 205
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
打开[Memory map],在unpackme代码段设置内存写入断点,F9走
异常后,Shift+F7,Alt+F9,又异常,Shift+F7,Alt+F9走到0083DF33,
往上看,原来这里调用了个异常(0083DF2D处)!
就看不懂了 打开[Memory map], 怎么弄啊?
2008-7-8 04:42
0
雪    币: 201
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
不知所云。。。。。。。。。。。。。。。
2008-7-8 10:35
0
游客
登录 | 注册 方可回帖
返回
//