• 标 题:【原创】UltraProtect脱壳
  • 作 者:peansen
  • 时 间:2004-12-01,16:18
  • 链 接:http://bbs.pediy.com

UltraProtect脱壳

作者:peansen

这里以notepad为例子,我这里主要是讲输入表的恢复
用pied得知是UltraProtect 1.x -> RISCO Software Inc.的壳
*要注意它会检测很多调试器和lorder,把不必要的调试器和lorder关掉
用flyodbg载入
0040D000 >  60               pushad;停在这里
0040D001    FC               cld
0040D002    87FE             xchg esi,edi
0040D004    66:C1CE A5       ror si,0A5
0040D008    66:13F0          adc si,ax
0040D00B    7E 03            jle short NOTEPAD.0040D010
0040D00D    7F 01            jg short NOTEPAD.0040D010
0040D00F  - EB BF            jmp short NOTEPAD.0040CFD0
0040D011    C7               ???                                     ; 未知命令
0040D012    F2:              prefix repne:
忽略所有异常隐藏od,直接F9运行,发现连od都退出了。说明程序还是知道自己被调试了,记得下次用bp Process32First+2设断ALT+F9来到
00412100    FF95 01454000    call near dword ptr ss:[ebp+404501]
00412106    0BC0             or eax,eax----------here
00412108    0F84 1D010000    je NOTEPAD.0041222B
0041210E    8DB5 61424000    lea esi,dword ptr ss:[ebp+404261]
00412114    8BFE             mov edi,esi
00412116    8A07             mov al,byte ptr ds:[edi]
00412118    0AC0             or al,al
0041211A    74 12            je short NOTEPAD.0041212E
由于我们用的是fly所以这里的检测没有关系,再按F9被刚才的断点(bp Process32First+2)断下,取消该断点,用ALT+F9来到
004117B9    FF95 01454000    call near dword ptr ss:[ebp+404501]
004117BF    E9 AD000000      jmp NOTEPAD.00411871------here
004117C4    60               pushad
004117C5    8DBD E1444000    lea edi,dword ptr ss:[ebp+4044E1]
004117CB    B9 26000000      mov ecx,26
004117D0    E8 29F1FFFF      call NOTEPAD.004108FE
004117D5    AB               stos dword ptr es:[edi]----------------------程序里很多都是这个东西让我们死的
004117D6  ^ E2 F8            loopd short NOTEPAD.004117D0
004117D8    61               popad
004117D9    60               pushad
004117DA    E8 72F3FFFF      call NOTEPAD.00410B51
004117DF    B8 05000000      mov eax,5
004117E4    E8 01F1FFFF      call NOTEPAD.004108EA
004117E9    83F8 00          cmp eax,0
004117EC    74 28            je short NOTEPAD.00411816
跳到这边
00411871    0BC0             or eax,eax
00411873    0F84 A7050000    je NOTEPAD.00411E20
00411879    8B95 45424000    mov edx,dword ptr ss:[ebp+404245]
0041187F    3B95 31424000    cmp edx,dword ptr ss:[ebp+404231]-----和自己的ProcessId相比,再此下断点并设条件为edx==790(这时候我的ProcessId=790)
00411885    0F84 DC000000    je NOTEPAD.00411967,找到了就跳,没有就继续找
0041188B    B8 3D424000      mov eax,NOTEPAD.0040423D
00411890    03C5             add eax,ebp
00411892    50               push eax
00411893    FFB5 39424000    push dword ptr ss:[ebp+404239]
00411899    50               push eax
0041189A    8B85 05454000    mov eax,dword ptr ss:[ebp+404505]
004118A0    8038 CC          cmp byte ptr ds:[eax],0CC
004118A3    74 10            je short NOTEPAD.004118B5
004118A5    90               nop
找到以后跳到这边
00411967    8B85 55424000    mov eax,dword ptr ss:[ebp+404255]----父进程的id到eax,
0041196D    8985 35424000    mov dword ptr ss:[ebp+404235],eax----我们在这里动一下手脚,把eax改为5a4(此时我的)explorer的进程id,这样以后他就不会检测出被调试了
00411973    FFB5 39424000    push dword ptr ss:[ebp+404239]
00411979    50               push eax
0041197A    8B85 09454000    mov eax,dword ptr ss:[ebp+404509]
00411980    8038 CC          cmp byte ptr ds:[eax],0CC
00411983    74 10            je short NOTEPAD.00411995
00411985    90               nop
00411986    90               nop
00411987    90               nop
用ALT+M在
内存镜像,项目 20
 地址=00401000
 大小=00004000 (16384.)
 Owner=NOTEPAD  00400000
 区段=.text
 包含=code
 类型=Imag 01001002
 访问=R
 初始访问=RWE
 
下内存访问断点,直接到OEP,但是被切掉一截,还需要修复(这是我的痛处我不太会,这点就不说了)
004010D2    56               push esi---here
004010D3    FF15 E4634000    call near dword ptr ds:[4063E4]         ; NOTEPAD.0040D1BA
004010D9    8BF0             mov esi,eax
004010DB    8A00             mov al,byte ptr ds:[eax]
004010DD    3C 22            cmp al,22
004010DF    75 1B            jnz short NOTEPAD.004010FC
004010E1    56               push esi
004010E2    FF15 F4644000    call near dword ptr ds:[4064F4]         ; NOTEPAD.0040D4C6
004010E8    8BF0             mov esi,eax
004010EA    8A00             mov al,byte ptr ds:[eax]
004010EC    84C0             test al,al


打开ImportRec准备修复IAT,在OEP处填10d2(他的附近都行)这样我们可以获得一个输入表,但是里面很多无效的函数
目标: G:\Practice\NOTEPAD.EXE
OEP: 000010D1  IATRVA: 000062E0  IATSize: 00000248

FThunk: 000062E4  NbFunc: 00000005
1  000062E4  advapi32.dll  01EE  RegQueryValueExA
1  000062E8  advapi32.dll  01CB  RegCloseKey
1  000062EC  advapi32.dll  01FB  RegSetValueExA
1  000062F0  advapi32.dll  01E3  RegOpenKeyA
1  000062F4  advapi32.dll  01CE  RegCreateKeyA

FThunk: 000062FC  NbFunc: 00000017
1  000062FC  gdi32.dll  0196  GetObjectA
1  00006300  gdi32.dll  016C  GetDeviceCaps
1  00006304  gdi32.dll  003B  CreateFontIndirectA
1  00006308  gdi32.dll  020F  SelectObject
1  0000630C  gdi32.dll  0001  AbortDoc
1  00006310  gdi32.dll  0097  EndDoc
1  00006314  gdi32.dll  008D  DeleteDC
1  00006318  gdi32.dll  0249  StartPage
1  0000631C  gdi32.dll  0246  StartDocA
1  00006320  gdi32.dll  0099  EndPage
1  00006324  gdi32.dll  01B7  GetTextExtentPointA
1  00006328  gdi32.dll  003A  CreateFontA
1  0000632C  gdi32.dll  0211  SetAbortProc
1  00006330  gdi32.dll  0217  SetBkMode
1  00006334  gdi32.dll  022C  SetMapMode
1  00006338  gdi32.dll  01BD  GetTextMetricsA
1  0000633C  gdi32.dll  0243  SetWindowExtEx
1  00006340  gdi32.dll  023F  SetViewportExtEx
1  00006344  gdi32.dll  01CC  LPtoDP
1  00006348  gdi32.dll  002F  CreateDCA
1  0000634C  gdi32.dll  01AE  GetTextCharset
1  00006350  gdi32.dll  0090  DeleteObject
1  00006354  gdi32.dll  01A6  GetStockObject

FThunk: 0000635C  NbFunc: 00000026
0  0000635C  ?  0000  0040D000
。。。很多
0  000063F0  ?  0000  0040D1E1

FThunk: 000063F8  NbFunc: 00000006
1  000063F8  shell32.dll  008B  DragFinish
1  000063FC  shell32.dll  0162  ShellAboutA
1  00006400  shell32.dll  0167  ShellExecuteA
1  00006404  shell32.dll  008A  DragAcceptFiles
1  00006408  shell32.dll  013D  SHGetSpecialFolderPathA
1  0000640C  shell32.dll  008C  DragQueryFile

FThunk: 00006414  NbFunc: 0000003C
0  00006414  ?  0000  0040D1EE
。。。。。很多
0  00006500  ?  0000  0040D4ED

FThunk: 00006508  NbFunc: 00000007
1  00006508  comdlg32.dll  006E  GetOpenFileNameA
1  0000650C  comdlg32.dll  0067  ChooseFontA
1  00006510  comdlg32.dll  006A  FindTextA
1  00006514  comdlg32.dll  0073  PageSetupDlgA
1  00006518  comdlg32.dll  0070  GetSaveFileNameA
1  0000651C  comdlg32.dll  0069  CommDlgExtendedError
1  00006520  comdlg32.dll  006C  GetFileTitleA
可以看出主要有两段是无效的,用d 40635c察看内存
0040635C  00 D0 40 00 0D D0 40 00 1A D0 40 00 27 D0 40 00  .蠤..蠤.蠤.'蠤.
0040636C  34 D0 40 00 41 D0 40 00 4E D0 40 00 5B D0 40 00  4蠤.A蠤.N蠤.[蠤.
0040637C  68 D0 40 00 75 D0 40 00 82 D0 40 00 8F D0 40 00  h蠤.u蠤.傂@.徯@.
0040638C  9C D0 40 00 A9 D0 40 00 B6 D0 40 00 C3 D0 40 00  溞@.┬@.缎@.眯@.
0040639C  D0 D0 40 00 DD D0 40 00 EA D0 40 00 F7 D0 40 00  行@.菪@.晷@.餍@.
004063AC  04 D1 40 00 11 D1 40 00 1E D1 40 00 2B D1 40 00  袬.袬.袬.+袬.
004063BC  38 D1 40 00 45 D1 40 00 52 D1 40 00 5F D1 40 00  8袬.E袬.R袬._袬.
004063CC  6C D1 40 00 79 D1 40 00 86 D1 40 00 93 D1 40 00  l袬.y袬.喲@.撗@.
004063DC  A0 D1 40 00 AD D1 40 00 BA D1 40 00 C7 D1 40 00  _袬.@.貉@.茄@.
004063EC  D4 D1 40 00 E1 D1 40 00 00 00 00 00              匝@.嵫@.....?E
可以看到第一个是指向40d000,到那边看看
0040D000 >  68 9F7DEC7E      push 7EEC7D9F
0040D005    813424 0CF06F02  xor dword ptr ss:[esp],26FF00C
0040D00C    C3               retn-------和上面组成一个jmp 7EEC7D9F xor 26FF00C
0040D00D    68 0814EE7E      push 7EEE1408
0040D012    813424 54FC6F02  xor dword ptr ss:[esp],26FFC54
0040D019    C3               retn
0040D01A    68 FC90F37E      push 7EF390FC
0040D01F    813424 F4037002  xor dword ptr ss:[esp],27003F4
0040D026    C3               retn
0040D027    68 F0ECF57E      push 7EF5ECF0
0040D02C    813424 E00A7002  xor dword ptr ss:[esp],2700AE0
0040D033    C3               retn
0040D034    68 E53AF27E      push 7EF23AE5
0040D039    813424 C4147002  xor dword ptr ss:[esp],27014C4
0040D040    C3               retn
随便算出一个来看看,确认一下。好了,现在是写一些东西来修复它。
有3种选择:1.在空白处写一段程序修复;2.脚本修复;3.用Luo写的ollydbg machine来修复
我用了第三种,新东西嘛,总是要多尝试一下,程序如下:
mov reg01,0x40635c
lp:
invoke ReadMemLong,reg01,4---先取出要跳转的指针
;invoke PrintNum,reg00,16----这些是我最初拿来验证数据是否正确的
mov reg02,reg00--------------存一下,下面还要用,寄存器多就是好
inc reg00--------------------上面的代码中可以看出来,xor的前一个数在被指向地址+1处
invoke ReadMemLong,reg00,4---读取
;invoke PrintNum,reg00,16
mov reg10,reg00
add reg02,8------------------xor后一个数在+8处
invoke ReadMemLong,reg02,4---读取
xor reg00,reg10--------------xor,我们要的api地址
;invoke PrintNum,reg00,16
invoke WriteMemLong,reg01,reg00,4---写入到IAT中
add reg01,4
cmp reg01,0x4063f4-----------懒得算到底有多长,直接用地址一比较算了
jb lp
还有第二部分的无效函数和这个一样
mov reg01,0x406414
lp:
invoke ReadMemLong,reg01,4
;invoke PrintNum,reg00,16
mov reg02,reg00
inc reg00
invoke ReadMemLong,reg00,4
;invoke PrintNum,reg00,16
mov reg10,reg00
add reg02,8
invoke ReadMemLong,reg02,4
xor reg00,reg10
;invoke PrintNum,reg00,16
invoke WriteMemLong,reg01,reg00,4
add reg01,4
cmp reg01,0x406504
jb lp
经过这样以后,只有一个没有被修复(其实不能说没有被修复,只是他修复以后还是指在自己的程序中,跟踪一下就好了,是MessageBoxA)
这样就全部完了

谢谢看完