Obsidium1.2x脱壳实例
这次脱的是XX外挂,感觉应该是Obsidium1.2x版加的。
Obsidium1.2x的anti有个节点,代码是:
CALL DWORD PTR SS:[EBP-4] <--anti代码入口
TEST DWORD PTR DS:[EDI+C],4
......
OD的异常中不选择[内存访问异常]和[整数除零异常]
然后使用下面的Script到节点:
===================================
/////////////////////
//jjzc-ob1.2x Script
//by fxyang
//2005.5.31
/////////////////
var addrs
var memad
dbh
esto
EOE exp0
exp0:
mov addrs,6
bprm 0040FC10,1
eob exp1
esto
exp1:
dec addrs
cmp addrs,0
je exp2
esto
exp2:
bpmc
bp 0040FC10
pause
=========================================
脚本完成后来到:
0040FC10 CALL DWORD PTR SS:[EBP-4] <--anti入口节点
0040FC13 TEST DWORD PTR DS:[EDI+C],4
0040FC1A JE SHORT jjzc.0040FC25
0040FC1C TEST EAX,EAX
0040FC1E JE SHORT jjzc.0040FC25
0040FC20 PUSH EAX
0040FC21 PUSH EBP
0040FC22 JMP DWORD PTR DS:[EBX+4C]
0040FC25 TEST DWORD PTR DS:[EDI+C],40 <--这里是出口
0040FC2C JE SHORT jjzc.0040FC34
0040FC2E MOV EDX,DWORD PTR SS:[EBP-8]
0040FC31 MOV DWORD PTR DS:[EBX+4],EDX
0040FC34 MOV EAX,DWORD PTR DS:[EDI]
0040FC36 LEA EDI,DWORD PTR DS:[EDI+EAX+14]
0040FC3A JMP jjzc.0040FA72
0040FC3F LEA EAX,DWORD PTR DS:[EDI+14]
0040FC42 POP DWORD PTR FS:[0]
0040FC48 ADD ESP,4
0040FC4B POP EDI
0040FC4C POP EBX
0040FC4D POP ESI
0040FC4E MOV ESP,EBP
0040FC50 POP EBP
0040FC51 RETN 0C
下面的操作就能躲过anti
Stack SS:[0012FF88]=003A026C 第1次
EIP -->
0040FC25 F747 0C 4000000>TEST DWORD PTR DS:[EDI+C],40
Stack SS:[0012FF88]=003A0468 第3次
EIP -->
0040FC25 F747 0C 4000000>TEST DWORD PTR DS:[EDI+C],40
Stack SS:[0012FF88]=003AA368 第1,2次
EIP -->
0040FC25 F747 0C 4000000>TEST DWORD PTR DS:[EDI+C],40
不要问为什么?跟踪看看就知道了:-)
到这里要解码代码了:
bp kernel32.VirtualAllocEx
Shift+F9,停在:
77E5ABD6 E8 9CFFFFFF CALL kernel32.VirtualAllocEx
Alt+F9,返回到:
0040FE1C FF93 80000000 CALL DWORD PTR DS:[EBX+80] ; call kernel32.VirtualAlloc
0040FE22 85C0 TEST EAX,EAX ; EAX=00950000
0040FE24 0F84 3A010000 JE jjzc.0040FF64
返回值EAX=00950000就是被壳重定位的原程序段。向下找到:
(非常多的教程让你了解了为什么)
0040FF1E F747 10 0100000>TEST DWORD PTR DS:[EDI+10],1 ; DS:[00907D08]=00000005
0040FF25 74 16 JE SHORT jjzc.0040FF3D
0040FF27 8B43 10 MOV EAX,DWORD PTR DS:[EBX+10] ; new imagebase
0040FF2A 2B43 3C SUB EAX,DWORD PTR DS:[EBX+3C] ; 内存中是基地址00400000
//完成这句代码后修改EAX的值=0
//这样代码段中需要重定位的地址又恢复了
0040FF2D FF77 08 PUSH DWORD PTR DS:[EDI+8] ; DS:[00907D00]=00081000 codesize ,00002000 datasize
0040FF30 FF77 04 PUSH DWORD PTR DS:[EDI+4] ; RVA=1000 ,00082000
//这2个参数就知道了段的RVA和SIZE,记录下来。
0040FF33 FF73 78 PUSH DWORD PTR DS:[EBX+78]
0040FF36 50 PUSH EAX
0040FF37 FF73 10 PUSH DWORD PTR DS:[EBX+10]
0040FF3A FF53 70 CALL DWORD PTR DS:[EBX+70]
0040FF3D 83C7 14 ADD EDI,14
0040FF40 FF4D FC DEC DWORD PTR SS:[EBP-4]
0040FF43 ^ 0F85 F4FEFFFF JNZ jjzc.0040FE3D
0040FF49 8B47 F8 MOV EAX,DWORD PTR DS:[EDI-8]
0040FF4C 0347 EC ADD EAX,DWORD PTR DS:[EDI-14]
0040FF4F 0345 08 ADD EAX,DWORD PTR SS:[EBP+8]
0040FF52 64:67:8F06 0000 POP DWORD PTR FS:[0]
0040FF58 83C4 04 ADD ESP,4
0040FF5B 5F POP EDI
0040FF5C 5E POP ESI
0040FF5D 5B POP EBX
0040FF5E 8BE5 MOV ESP,EBP
0040FF60 5D POP EBP
0040FF61 C2 0C00 RETN 0C
上面看得出来重定位了2个段,因为这个程序看得出来是delphi编译的所以:
第一个段的rva:00001000;size:00081000 <--CODE
第二个段的rva:00082000;size:00002000 <--DATA
完成代码代码后Shift+F9,继续来到节点,下面该是处理IAT了:
0040FC10 CALL DWORD PTR SS:[EBP-4] <--anti入口节点
0040FC13 TEST DWORD PTR DS:[EDI+C],4
0040FC1A JE SHORT jjzc.0040FC25
0040FC1C TEST EAX,EAX
0040FC1E JE SHORT jjzc.0040FC25
0040FC20 PUSH EAX
0040FC21 PUSH EBP
0040FC22 JMP DWORD PTR DS:[EBX+4C]
0040FC25 TEST DWORD PTR DS:[EDI+C],40 <--这里是出口
0040FC2C JE SHORT jjzc.0040FC34
Stack SS:[0012FF80]=003AB520 第1次
EIP -->
0040FC25 F747 0C 4000000>TEST DWORD PTR DS:[EDI+C],40
当出现这个异常时:
003AC29F CD 68 INT 68
003AC2A1 66:3D 86F3 CMP AX,0F386
003AC2A5 74 0A JE SHORT 003AC2B1
003AC2A7 33C0 XOR EAX,EAX
003AC2A9 64:8F00 POP DWORD PTR FS:[EAX]
003AC2AC 83C4 04 ADD ESP,4
003AC2AF 5B POP EBX
003AC2B0 C3 RETN
在 上面call kernel32.VirtualAlloc申请的段00950000下内存访问中断来到:
003ACA1D 893E MOV DWORD PTR DS:[ESI],EDI
寄存器的值:
EDI=00AE0000
DS:[009D517C]=00000000 计算一下iat表的rva
=009D517C-00950000=0008517C
根据页对齐,所以import段的rva:00085000 <--.idata
从delphi的iat表结构也可以知道
计算一下,从DATA段到.idata之间还有 00001000 大小的段
rva:000084000;size:00001000 <--BSS
接下来应该是.tls段和.rdata段,大小各为00001000 (4096.)
现在就能知道.idata 的大小了
size:=0008A000-00002000-00085000=00003000
重排段应该是-基地址:00950000
PE header -- rva:00000000;size:00001000
CODE -- rva:00001000;size:00081000
DATA -- rva:00082000;size:00002000
BSS -- rva:00084000;size:00001000
.idata -- rva:00085000;size:00003000
.tls -- rva:00088000;size:00001000
.rdata -- rva:00089000;size:00001000
这就是被重定位在临时空间中的各个段的排列和大小
.rsrc 段被重定位在基地址00400000:rva:00002000;size:0000B000
知道了这些参数用LordPE dump下内存中的数据,以便重新生成原来的程序。
这是处理IAT表时的主要流程:
003AC773 0145 EC ADD DWORD PTR SS:[EBP-14],EAX
003AC776 8B46 10 MOV EAX,DWORD PTR DS:[ESI+10]
003AC779 8B56 14 MOV EDX,DWORD PTR DS:[ESI+14]
003AC77C 0343 10 ADD EAX,DWORD PTR DS:[EBX+10]
003AC77F 0353 44 ADD EDX,DWORD PTR DS:[EBX+44]
003AC782 FF36 PUSH DWORD PTR DS:[ESI]
003AC784 53 PUSH EBX
003AC785 52 PUSH EDX
003AC786 50 PUSH EAX
003AC787 FF76 0C PUSH DWORD PTR DS:[ESI+C]
003AC78A E8 F4000000 CALL 003AC883 ; <--解码普通函数
003AC78F 85C0 TEST EAX,EAX
003AC791 0F84 80000000 JE 003AC817
003AC797 837D F0 00 CMP DWORD PTR SS:[EBP-10],0
003AC79B 74 1D JE SHORT 003AC7BA
003AC79D 8B46 10 MOV EAX,DWORD PTR DS:[ESI+10]
003AC7A0 8B56 14 MOV EDX,DWORD PTR DS:[ESI+14]
003AC7A3 0343 10 ADD EAX,DWORD PTR DS:[EBX+10]
003AC7A6 0353 44 ADD EDX,DWORD PTR DS:[EBX+44]
003AC7A9 FF75 EC PUSH DWORD PTR SS:[EBP-14]
003AC7AC 53 PUSH EBX
003AC7AD 52 PUSH EDX
003AC7AE 50 PUSH EAX
003AC7AF FF76 0C PUSH DWORD PTR DS:[ESI+C]
003AC7B2 E8 40010000 CALL 003AC8F7 ; <--解码特殊函数
003AC7B7 0145 EC ADD DWORD PTR SS:[EBP-14],EAX
003AC7BA 33C0 XOR EAX,EAX
003AC7BC 8946 0C MOV DWORD PTR DS:[ESI+C],EAX
003AC7BF 8946 10 MOV DWORD PTR DS:[ESI+10],EAX
003AC7C2 83C6 18 ADD ESI,18
003AC7C5 FF45 F8 INC DWORD PTR SS:[EBP-8]
003AC7C8 FF4D FC DEC DWORD PTR SS:[EBP-4]
003AC7CB ^ 0F85 CEFEFFFF JNZ 003AC69F
003AC7D1 33C0 XOR EAX,EAX
003AC7D3 5F POP EDI
003AC7D4 5E POP ESI
003AC7D5 5B POP EBX
003AC7D6 8BE5 MOV ESP,EBP
003AC7D8 5D POP EBP
003AC7D9 C3 RETN
==============================================
解码普通函数:
003AC886 56 PUSH ESI
003AC887 57 PUSH EDI
003AC888 8B75 10 MOV ESI,DWORD PTR SS:[EBP+10]
003AC88B 8B7D 0C MOV EDI,DWORD PTR SS:[EBP+C] //修改,前人的经验:
003AC88E 66:F706 2000 TEST WORD PTR DS:[ESI],20 ;TEST WORD PTR DS:[ESI],8
003AC893 74 46 JE SHORT 003AC8DB ;JNZ SHORT 003AC8DB
003AC895 66:F706 0200 TEST WORD PTR DS:[ESI],2
003AC89A 75 1F JNZ SHORT 003AC8BB
003AC89C 66:C706 0400 MOV WORD PTR DS:[ESI],4
003AC8A1 8B45 14 MOV EAX,DWORD PTR SS:[EBP+14]
003AC8A4 6A 01 PUSH 1
003AC8A6 6A 00 PUSH 0
003AC8A8 FF76 04 PUSH DWORD PTR DS:[ESI+4]
003AC8AB 6A 00 PUSH 0
003AC8AD FF75 18 PUSH DWORD PTR SS:[EBP+18]
003AC8B0 FF50 50 CALL DWORD PTR DS:[EAX+50]
003AC8B3 85C0 TEST EAX,EAX
003AC8B5 74 38 JE SHORT 003AC8EF ;JE SHORT 003AC8DB
003AC8B7 8907 MOV DWORD PTR DS:[EDI],EAX
003AC8B9 EB 20 JMP SHORT 003AC8DB
003AC8BB 66:C706 0400 MOV WORD PTR DS:[ESI],4
003AC8C0 8B45 14 MOV EAX,DWORD PTR SS:[EBP+14]
003AC8C3 0FB756 02 MOVZX EDX,WORD PTR DS:[ESI+2]
003AC8C7 6A 01 PUSH 1
003AC8C9 52 PUSH EDX
003AC8CA 6A 00 PUSH 0
003AC8CC FF76 04 PUSH DWORD PTR DS:[ESI+4]
003AC8CF FF75 18 PUSH DWORD PTR SS:[EBP+18]
003AC8D2 FF50 50 CALL DWORD PTR DS:[EAX+50]
003AC8D5 85C0 TEST EAX,EAX
003AC8D7 74 16 JE SHORT 003AC8EF ;JE SHORT 003AC8DB
003AC8D9 8907 MOV DWORD PTR DS:[EDI],EAX
003AC8DB 83C6 08 ADD ESI,8
003AC8DE 83C7 04 ADD EDI,4
003AC8E1 FF4D 08 DEC DWORD PTR SS:[EBP+8]
003AC8E4 ^ 75 A8 JNZ SHORT 003AC88E
003AC8E6 33C0 XOR EAX,EAX
003AC8E8 40 INC EAX
003AC8E9 5F POP EDI
003AC8EA 5E POP ESI
003AC8EB 5D POP EBP
003AC8EC C2 1400 RETN 14
===================================================
解码特殊函数:
003AC8F7 55 PUSH EBP
003AC8F8 8BEC MOV EBP,ESP
003AC8FA 53 PUSH EBX
003AC8FB 56 PUSH ESI
003AC8FC 57 PUSH EDI
003AC8FD 8B75 10 MOV ESI,DWORD PTR SS:[EBP+10]
003AC900 8B7D 0C MOV EDI,DWORD PTR SS:[EBP+C]
003AC903 8B5D 18 MOV EBX,DWORD PTR SS:[EBP+18]
003AC906 66:833E 08 CMP WORD PTR DS:[ESI],8
//特殊函数标志
003A900C 08 00 00 00 00 00 00 00 .......
003A9014 04 00 47 00 63 7E F8 8D .G.c~?
003A901C 04 00 49 00 0F 28 8C 73 .I.(?
003A9024 04 00 49 00 0E D3 A9 DF .I.萤
003AC90A 74 1A JE SHORT 003AC926
003AC90C 83C6 08 ADD ESI,8
003AC90F 83C7 04 ADD EDI,4
003AC912 8B45 14 MOV EAX,DWORD PTR SS:[EBP+14]
003AC915 FF4D 08 DEC DWORD PTR SS:[EBP+8]
003AC918 ^ 75 EC JNZ SHORT 003AC906
003AC91A 8BC3 MOV EAX,EBX
003AC91C 2B45 18 SUB EAX,DWORD PTR SS:[EBP+18]
003AC91F 5F POP EDI
003AC920 5E POP ESI
003AC921 5B POP EBX
003AC922 5D POP EBP
003AC923 C2 1400 RETN 14
003AC926 8B46 04 MOV EAX,DWORD PTR DS:[ESI+4]
//根据EAX值选择不同的CALL解码特殊函数
003AC929 83F8 00 CMP EAX,0
003AC92C 74 45 JE SHORT 003AC973
003AC92E 83F8 01 CMP EAX,1
003AC931 74 4F JE SHORT 003AC982
003AC933 83F8 02 CMP EAX,2
003AC936 74 59 JE SHORT 003AC991
003AC938 83F8 03 CMP EAX,3
003AC93B 74 12 JE SHORT 003AC94F
003AC93D 83F8 04 CMP EAX,4
003AC940 ^ 75 CA JNZ SHORT 003AC90C
003AC942 8B45 14 MOV EAX,DWORD PTR SS:[EBP+14]
003AC945 8B90 DC000000 MOV EDX,DWORD PTR DS:[EAX+DC]
003AC94B 8917 MOV DWORD PTR DS:[EDI],EDX
003AC94D ^ EB BD JMP SHORT 003AC90C
003AC94F 8B45 14 MOV EAX,DWORD PTR SS:[EBP+14]
003AC952 68 C5B1662D PUSH 2D66B1C5
003AC957 6A 00 PUSH 0
003AC959 FF50 18 CALL DWORD PTR DS:[EAX+18]
003AC95C 50 PUSH EAX
003AC95D 53 PUSH EBX
003AC95E E8 87010000 CALL 003ACAEA
003AC963 53 PUSH EBX
003AC964 E8 08010000 CALL 003ACA71
003AC969 8BCB MOV ECX,EBX
003AC96B 8D5C03 01 LEA EBX,DWORD PTR DS:[EBX+EAX+1]
003AC96F 8BC1 MOV EAX,ECX
003AC971 EB 2B JMP SHORT 003AC99E
003AC973 8B45 14 MOV EAX,DWORD PTR SS:[EBP+14]
003AC976 68 0F1ACF4C PUSH 4CCF1A0F
003AC97B 6A 00 PUSH 0
003AC97D FF50 18 CALL DWORD PTR DS:[EAX+18]
003AC980 EB 1C JMP SHORT 003AC99E
003AC982 8B45 14 MOV EAX,DWORD PTR SS:[EBP+14]
003AC985 68 A41A86D0 PUSH D0861AA4
003AC98A 6A 00 PUSH 0
003AC98C FF50 18 CALL DWORD PTR DS:[EAX+18]
003AC98F EB 0D JMP SHORT 003AC99E
003AC991 8B45 14 MOV EAX,DWORD PTR SS:[EBP+14]
003AC994 68 E313B41D PUSH 1DB413E3
003AC999 6A 00 PUSH 0
003AC99B FF50 18 CALL DWORD PTR DS:[EAX+18]
003AC99E C603 B8 MOV BYTE PTR DS:[EBX],0B8
003AC9A1 8943 01 MOV DWORD PTR DS:[EBX+1],EAX
003AC9A4 8B45 14 MOV EAX,DWORD PTR SS:[EBP+14]
003AC9A7 8B90 90010000 MOV EDX,DWORD PTR DS:[EAX+190]
003AC9AD 8D43 0A LEA EAX,DWORD PTR DS:[EBX+A]
003AC9B0 2BD0 SUB EDX,EAX
003AC9B2 C643 05 E9 MOV BYTE PTR DS:[EBX+5],0E9
003AC9B6 8953 06 MOV DWORD PTR DS:[EBX+6],EDX
003AC9B9 891F MOV DWORD PTR DS:[EDI],EBX
003AC9BB 83C3 0A ADD EBX,0A
003AC9BE ^ E9 49FFFFFF JMP 003AC90C 到这里能跟踪出正确的函数:
00417921 CALL DWORD PTR DS:[EBX+50] ; 查找正确函数
00417924 TEST EAX,EAX ; EAX=kernel32.GetVersion
00417926 JE jjzc.004179E2 // 返回正确的函数值
0041792C MOV ESI,EAX
=====================================================
经过上面的修改和跟踪基本上搞定大部分函数,剩下的就手动跟踪了,没有什么要说的。 IAT处理完成后,继续在上面call kernel32.VirtualAlloc申请的段00950000下内存访问中断来到:
伪OEP-->
009D1ED4 CALL 00956590
009D1ED9 PUSH 9D1F8C ; ASCII "lszcOneCopy"
009D1EDE PUSH 0
009D1EE0 PUSH 0
009D1EE2 CALL 009567B8
009D1EE7 MOV EBX,EAX
009D1EE9 PUSH 0
009D1EEB PUSH EBX
009D1EEC CALL 009569E8
009D1EF1 CMP EAX,102
009D1EF6 JE 009D1F85
检查寄存器的值和堆栈的值:
EAX 009D1C30
ECX 0012FFB0
EDX 7FFE0304
EBX 7FFDF000
ESP 0012FFAC
EBP 0012FFC0
ESI 004AA38C
EDI 0012CEA8
EIP 009D1ED4 0012FFAC 7FFDF000
0012FFB0 7FFDF000
0012FFB4 7FFE0304
0012FFB8 0012FFB0
0012FFBC 00000000
0012FFC0 0012FFF0
0012FFC4 77E6141A 返回到 kernel32.77E6141A
0012FFC8 0012CEA8
0012FFCC 004AA38C
0012FFD0 7FFDF000
0012FFD4 EEC46CF0
0012FFD8 0012FFC8
0012FFDC 805416D6
打开一个正常的delphi程序发现OEP应该是这样的:
0045AB00 >PUSH EBP
0045AB01 MOV EBP,ESP
0045AB03 ADD ESP,-10
0045AB06 PUSH EBX
0045AB07 MOV EAX,Project1.0045A908
0045AB0C CALL Project1.00405C34
现在来补回代码:
PUSH EBP
MOV EBP,ESP
ADD ESP,-10
PUSH EBX
下面的EAX值正确的应该是什么呢,计算一下:
EAX 009D1C30 是基于地址00950000的,原来的应该是:
EAX=009D1C30-00950000+00400000=00481C30
再补上这句:
MOV EAX,00481C30
完整的代码是:
009D1EC8 PUSH EBP
009D1EC9 MOV EBP,ESP
009D1ECB ADD ESP,-10
009D1ECE PUSH EBX
009D1ECF MOV EAX,481C30
009D1ED4 CALL 00956590
009D1ED9 PUSH 9D1F8C ; ASCII "lszcOneCopy"
现在是用LordPE dump下内存数据的时候了,按照上面的分段dump:
PE header 用壳的PE header文件-
Region00400000-00401000-1.dmp
Region00951000-009D2000-2.dmp
Region009D2000-009D4000-3.dmp
Region009D4000-009D5000-4.dmp
Region009D5000-009D8000-5.dmp
Region009D8000-009D9000-6.dmp
Region009D9000-009DA000-7.dmp
Region00402000-0040D000-9.dmp
为了完美在别的delphi程序中dump个.reloc段
Region00463000-0046A000-8.dmp
用工具依次连接成新的程序。用LordPE修正各个参数。需要修正的参数有:
1.资源表-RVA:00091000;size:0000B000
2.Tls表 -RVA: 00089000; size: 00000018
打开Tls信息窗口--
数据块起始VA:00488000
数据块结束VA:00488010
索引变量VA: 004820C4
返回表VA: 00489020
用Import.Reconstructor 得到正确的IAT表,修复时勾掉增加新的区段,
为了完美,在RVA中填入:0008517C 这样让IAT表还原到原来的位置。
运行程序看看发现程序没有图标,即资源段错误,原来壳把资源段重定位到00402000处
现在修正到00910000处,索引的RVA值是错误的,需要重新定位,我是手工修复的,太
麻烦。有工具可以修复的就不介绍了。
到这里就算是比较完美的脱出来了这个Obsidium1.2x版壳,头大了好些,写得更乱。 by fxyang
2005.6.3
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)