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)
这样就全部完了
谢谢看完
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)