好友
阅读权限40
听众
最后登录1970-1-1
|
小生我怕怕
发表于 2009-1-14 22:20
这一个星期都在弄这个ASPR壳,弄的头晕眼花的。。。
还是上次的目标AllNetic Working Time Tracker - Version 2.2,好像是一个工作时间安排的工具吧?
下载地址是http://www.allnetic.com/
壳的版本:
PEiD扫描:ASProtect 2.1x SKE -> Alexey Solodovnikov
使用verA0.13插件扫描:Version: ASProtect 1.35 build 04.25 Release [Extract]
请关注上一节:ASPR学习笔记(一):修复IAT http://bbs.unpack.cn/viewthread.php?tid=31713
在上一节修复完IAT后可以看出OEP=289BE0,RVA=29CB98,SIZE=9B8
修复IAT还不能算完成,因为ASPR把程序中的跳转表JMP [IAT table]替换成了CALL 01410000这类壳中调用了,还需要把CALL还原成JMP。
先看看壳是怎么把JMP替换成CALL的?
替换CALL XXXXXXXX时同样也会修改程序代码数据,到达OEP在程序开始部分的跳转表中随便找个CALL 01410000,比如:
00401288 call 01410000
在地址部分下硬件断点hw 00401289,重新载入程序后运行,经过几次初始化中断之后就来到了替换CALL的循环。
这一段是生成基本数据并修正所有CALL地址:
01262440 55 push ebp
01262441 8BEC mov ebp, esp
01262443 53 push ebx
01262444 8B5D 08 mov ebx, dword ptr [ebp+8]
01262447 EB 01 jmp short 0126244A
0126244A 85DB test ebx, ebx
0126244C 74 2A je short 01262478
0126244E 8BC3 mov eax, ebx
01262450 E8 4FE5FFFF call 012609A4 ; 生成基本数据
01262455 84C0 test al, al
01262457 75 0A jnz short 01262463 ; 生成出错?
01262459 68 88242601 push 1262488 ; ASCII "107",CR,LF
0126245E E8 812DFFFF call 012551E4 ; 错误提示并退出
01262463 8BC3 mov eax, ebx
01262465 E8 36000000 call 012624A0 ; 修正所有跳转表地址
0126246A 84C0 test al, al
0126246C 75 0A jnz short 01262478 ; 修正出错?
0126246E 68 98242601 push 1262498 ; ASCII "108",CR,LF
01262473 E8 6C2DFFFF call 012551E4 ; 错误提示并退出
01262478 5B pop ebx
01262479 5D pop ebp
0126247A C2 0400 retn 4
其中call 012609A4生成修正跳转表所用的基本数据:
012609A4 53 push ebx
012609A5 56 push esi
012609A6 57 push edi
012609A7 55 push ebp
012609A8 83C4 F8 add esp, -8
012609AB 8BF8 mov edi, eax
012609AD C60424 00 mov byte ptr [esp], 0
012609B1 837F 08 00 cmp dword ptr [edi+8], 0
012609B5 0F84 DF010000 je 01260B9A
012609BB 8D47 5C lea eax, dword ptr [edi+5C]
012609BE BA 0A000000 mov edx, 0A
012609C3 E8 FC27FFFF call 012531C4 ; 初始化随机序列数据
012609C8 8D47 5C lea eax, dword ptr [edi+5C]
012609CB BA 0A000000 mov edx, 0A
012609D0 E8 A327FFFF call 01253178 ; 生成随机序列保存到[edi+5C]
012609D5 33ED xor ebp, ebp
012609D7 8A442F 5C mov al, byte ptr [edi+ebp+5C]
012609DB 8D57 40 lea edx, dword ptr [edi+40]
012609DE 03D5 add edx, ebp
012609E0 8802 mov byte ptr [edx], al
012609E2 45 inc ebp
012609E3 83FD 0A cmp ebp, 0A
012609E6 ^ 75 EF jnz short 012609D7 ; copy随机序列到[edi+40]
012609E8 8B77 08 mov esi, dword ptr [edi+8]
012609EB BD 0A000000 mov ebp, 0A
012609F0 8A1E mov bl, byte ptr [esi] ; 取index
012609F2 46 inc esi
012609F3 80FB 09 cmp bl, 9
012609F6 0F87 9E010000 ja 01260B9A
012609FC 8BD3 mov edx, ebx
012609FE 8BC7 mov eax, edi
01260A00 E8 77FFFFFF call 0126097C ; 取index所在的随机值
01260A05 8BD8 mov ebx, eax
01260A07 80FB FF cmp bl, 0FF ; 随机序列是否正确?
01260A0A 75 0A jnz short 01260A16
01260A0C 68 AC0B2601 push 1260BAC ; ASCII "107",CR,LF
01260A11 E8 CE47FFFF call 012551E4
01260A16 8B06 mov eax, dword ptr [esi]
01260A18 83C6 04 add esi, 4
01260A1B 33D2 xor edx, edx
01260A1D 8AD3 mov dl, bl
01260A1F 8D1452 lea edx, dword ptr [edx+edx*2]
01260A22 894497 6C mov dword ptr [edi+edx*4+6C], eax
01260A26 3D 00200000 cmp eax, 2000
01260A2B 0F87 69010000 ja 01260B9A
01260A31 8B16 mov edx, dword ptr [esi]
01260A33 895424 04 mov dword ptr [esp+4], edx
01260A37 83C6 04 add esi, 4
01260A3A 33D2 xor edx, edx
01260A3C 8AD3 mov dl, bl
01260A3E 8D1452 lea edx, dword ptr [edx+edx*2]
01260A41 8B4C24 04 mov ecx, dword ptr [esp+4]
01260A45 894C97 70 mov dword ptr [edi+edx*4+70], ecx
01260A49 33D2 xor edx, edx
01260A4B 8AD3 mov dl, bl
01260A4D 8D1452 lea edx, dword ptr [edx+edx*2]
01260A50 897497 68 mov dword ptr [edi+edx*4+68], esi
01260A54 03F0 add esi, eax
01260A56 4D dec ebp
01260A57 ^ 75 97 jnz short 012609F0 ; 循环生成函数随机入口
01260A59 8D47 4A lea eax, dword ptr [edi+4A]
01260A5C B9 09000000 mov ecx, 9
01260A61 8BD6 mov edx, esi
01260A63 E8 2C4FFEFF call <CopyStringByByte> ; 复制9字节到[edi+4A]
01260A68 83C6 09 add esi, 9
01260A6B 8A06 mov al, byte ptr [esi]
01260A6D 8847 20 mov byte ptr [edi+20], al ; 标志位
01260A70 46 inc esi
01260A71 8B06 mov eax, dword ptr [esi]
01260A73 8987 E4000000 mov dword ptr [edi+E4], eax ; 数据组的长度
01260A79 83C6 04 add esi, 4
01260A7C 8B06 mov eax, dword ptr [esi]
01260A7E 8987 E0000000 mov dword ptr [edi+E0], eax ; 待修正代码的偏移
01260A84 83C6 04 add esi, 4
01260A87 BA 54652601 mov edx, 1266554
01260A8C 8902 mov dword ptr [edx], eax
01260A8E 8B06 mov eax, dword ptr [esi]
01260A90 8947 18 mov dword ptr [edi+18], eax ; 待修正代码的数据组的数量
01260A93 83C6 04 add esi, 4
01260A96 837F 2C 00 cmp dword ptr [edi+2C], 0 ; 生成4个新段并把入口放入[edi+2C]开始的位置中
01260A9A 74 0D je short 01260AA9 ; 段1是否已经生成?
01260A9C 8D47 2C lea eax, dword ptr [edi+2C]
01260A9F E8 0C99FFFF call 0125A3B0
01260AA4 33C0 xor eax, eax
01260AA6 8947 2C mov dword ptr [edi+2C], eax
01260AA9 8BC7 mov eax, edi
01260AAB E8 74F6FFFF call 01260124 ; 生成段1并生成代码数据
01260AB0 8947 2C mov dword ptr [edi+2C], eax ; 保存段1入口地址
01260AB3 837F 30 00 cmp dword ptr [edi+30], 0
01260AB7 74 0D je short 01260AC6 ; 段2是否已经生成?
01260AB9 8D47 30 lea eax, dword ptr [edi+30]
01260ABC E8 EF98FFFF call 0125A3B0
01260AC1 33C0 xor eax, eax
01260AC3 8947 30 mov dword ptr [edi+30], eax
01260AC6 8BC7 mov eax, edi
01260AC8 E8 87F9FFFF call 01260454 ; 生成段2并生成代码数据
01260ACD 8947 30 mov dword ptr [edi+30], eax ; 保存段2入口地址
01260AD0 837F 34 00 cmp dword ptr [edi+34], 0
01260AD4 74 0D je short 01260AE3 ; 段3是否已经生成?
01260AD6 8D47 34 lea eax, dword ptr [edi+34]
01260AD9 E8 D298FFFF call 0125A3B0
01260ADE 33C0 xor eax, eax
01260AE0 8947 34 mov dword ptr [edi+34], eax
01260AE3 8BC7 mov eax, edi
01260AE5 E8 4AFBFFFF call 01260634 ; 生成段3并生成代码数据
01260AEA 8947 34 mov dword ptr [edi+34], eax ; 保存段3入口地址
01260AED 837F 38 00 cmp dword ptr [edi+38], 0
01260AF1 74 0D je short 01260B00 ; 段4是否已经生成?
01260AF3 8D47 38 lea eax, dword ptr [edi+38]
01260AF6 E8 B598FFFF call 0125A3B0
01260AFB 33C0 xor eax, eax
01260AFD 8947 38 mov dword ptr [edi+38], eax
01260B00 8BC7 mov eax, edi
01260B02 E8 D1FCFFFF call 012607D8 ; 生成段4并生成代码数据
01260B07 8947 38 mov dword ptr [edi+38], eax ; 保存段4入口地址
01260B0A 8977 54 mov dword ptr [edi+54], esi ; 修正跳转表所用的数据组基址
01260B0D 8B47 18 mov eax, dword ptr [edi+18]
01260B10 F7AF E4000000 imul dword ptr [edi+E4] ; 数据组数量*数据组长度
01260B16 03F0 add esi, eax
01260B18 8B06 mov eax, dword ptr [esi]
01260B1A 8947 1C mov dword ptr [edi+1C], eax ; 0
01260B1D 83C6 04 add esi, 4
01260B20 8977 58 mov dword ptr [edi+58], esi ; 数据组的结束地址
01260B23 8B87 E0000000 mov eax, dword ptr [edi+E0]
01260B29 50 push eax
01260B2A 68 00030000 push 300
01260B2F 8B47 2C mov eax, dword ptr [edi+2C]
01260B32 50 push eax
01260B33 57 push edi
01260B34 E8 DF010000 call 01260D18 ; hash(段1,300)
01260B39 8BD8 mov ebx, eax
01260B3B 899F F0000000 mov dword ptr [edi+F0], ebx ; save hash
01260B41 53 push ebx
01260B42 68 00030000 push 300
01260B47 8B47 30 mov eax, dword ptr [edi+30]
01260B4A 50 push eax
01260B4B 57 push edi
01260B4C E8 C7010000 call 01260D18 ; hash(段2,300)
01260B51 8BF0 mov esi, eax
01260B53 89B7 F4000000 mov dword ptr [edi+F4], esi ; save hash
01260B59 56 push esi
01260B5A 68 00030000 push 300
01260B5F 8B47 34 mov eax, dword ptr [edi+34]
01260B62 50 push eax
01260B63 57 push edi
01260B64 E8 AF010000 call 01260D18 ; hash(段3,300)
01260B69 8BD8 mov ebx, eax
01260B6B 899F F8000000 mov dword ptr [edi+F8], ebx ; save hash
01260B71 53 push ebx
01260B72 68 00030000 push 300
01260B77 8B47 38 mov eax, dword ptr [edi+38]
01260B7A 50 push eax
01260B7B 57 push edi
01260B7C E8 97010000 call 01260D18 ; hash(段4,300)
01260B81 8BF0 mov esi, eax
01260B83 89B7 FC000000 mov dword ptr [edi+FC], esi ; save hash
01260B89 56 push esi
01260B8A 57 push edi
01260B8B E8 3C1B0000 call 012626CC ; hash(数据组)
01260B90 8987 04010000 mov dword ptr [edi+104], eax ; save hash
01260B96 C60424 01 mov byte ptr [esp], 1
01260B9A 8A0424 mov al, byte ptr [esp]
01260B9D 59 pop ecx
01260B9E 5A pop edx
01260B9F 5D pop ebp
01260BA0 5F pop edi
01260BA1 5E pop esi
01260BA2 5B pop ebx
01260BA3 C3 retn
call 012624A0修正所有跳转表地址:
012624A0 53 push ebx
012624A1 56 push esi
012624A2 57 push edi
012624A3 55 push ebp
012624A4 83C4 DC add esp, -24
012624A7 8BD8 mov ebx, eax
012624A9 33C0 xor eax, eax
012624AB 8B53 54 mov edx, dword ptr [ebx+54]
012624AE 85D2 test edx, edx
012624B0 0F84 0D020000 je 012626C3
012624B6 83BB E4000000 0>cmp dword ptr [ebx+E4], 0
012624BD 0F84 00020000 je 012626C3
012624C3 837B 18 00 cmp dword ptr [ebx+18], 0
012624C7 0F84 F6010000 je 012626C3
012624CD 837B 24 00 cmp dword ptr [ebx+24], 0
012624D1 0F84 EC010000 je 012626C3
012624D7 837B 2C 00 cmp dword ptr [ebx+2C], 0
012624DB 0F84 E2010000 je 012626C3
012624E1 837B 30 00 cmp dword ptr [ebx+30], 0
012624E5 0F84 D8010000 je 012626C3
012624EB 8BF2 mov esi, edx
012624ED 8B43 18 mov eax, dword ptr [ebx+18]
012624F0 890424 mov dword ptr [esp], eax
012624F3 8B83 E0000000 mov eax, dword ptr [ebx+E0]
012624F9 894424 14 mov dword ptr [esp+14], eax
012624FD 8D7B 40 lea edi, dword ptr [ebx+40]
01262500 833C24 00 cmp dword ptr [esp], 0
01262504 0F86 AB010000 jbe 012626B5
0126250A 33C0 xor eax, eax
0126250C 8A07 mov al, byte ptr [edi] ; 取函数入口index0
0126250E 8D0440 lea eax, dword ptr [eax+eax*2]
01262511 8B6C83 68 mov ebp, dword ptr [ebx+eax*4+68] ; 函数入口:[ebx+index0*3*4+68]
01262515 8BC6 mov eax, esi
01262517 FFD5 call ebp ; 函数功能:mov eax,[eax+4]
01262519 8BE8 mov ebp, eax ; 取出的值为待修正地址的偏移
0126251B 036B 24 add ebp, dword ptr [ebx+24] ; +基址
0126251E 03AB E0000000 add ebp, dword ptr [ebx+E0] ; +段偏移
01262524 EB 01 jmp short 01262527 ; 结果为待修正的地址入口
01262526 90 nop
01262527 33C0 xor eax, eax
01262529 8A47 09 mov al, byte ptr [edi+9] ; 取函数入口index9
0126252C 8D0440 lea eax, dword ptr [eax+eax*2]
0126252F 8B5483 68 mov edx, dword ptr [ebx+eax*4+68] ; 函数入口:[ebx+index9*3*4+68]
01262533 8BC6 mov eax, esi
01262535 FFD2 call edx ; 函数功能:mov eax,byte ptr [eax+1A]
01262537 807B 20 00 cmp byte ptr [ebx+20], 0 ; 取出的值为待修正地址的标志位
0126253B 0F85 3D010000 jnz 0126267E ; 总标志位:是否进行修正?
01262541 3C 01 cmp al, 1
01262543 0F85 35010000 jnz 0126267E ; 数据组标志位:是否进行修正?
0126267E 8B43 2C mov eax, dword ptr [ebx+2C] ; 取call XXXXXXXX的地址值=01410000
01262681 2BC5 sub eax, ebp ; WorkingT.00401268
01262683 83E8 05 sub eax, 5 ; 计算相对偏移
01262686 45 inc ebp
01262687 8945 00 mov dword ptr [ebp], eax ; !!!!!!!!!!!将jmp XXXXXXXX改为call 01410000写到程序中
0126268A 6A 0A push 0A
0126268C E8 1309FFFF call 01252FA4 ; rnd 计算出一个随机值
01262691 8BC8 mov ecx, eax
01262693 038B E4000000 add ecx, dword ptr [ebx+E4] ; 复制的长度:随机多复制几个字节
01262699 8BD6 mov edx, esi
0126269B 8BC3 mov eax, ebx
0126269D E8 BAE6FFFF call 01260D5C ; copy一段代码到一个段中
012626A2 FF0C24 dec dword ptr [esp] ; 循环次数-1
012626A5 03B3 E4000000 add esi, dword ptr [ebx+E4] ; +数据组长度:取下一个数据组
012626AB 833C24 00 cmp dword ptr [esp], 0
012626AF ^ 0F87 55FEFFFF ja 0126250A ; 继续循环
012626B5 53 push ebx
012626B6 E8 5D000000 call 01262718 ; 校验hash:是否修改代码?
012626BB 0183 EC000000 add dword ptr [ebx+EC], eax ; 校验的段:
012626C1 B0 01 mov al, 1 ; 段1
012626C3 83C4 24 add esp, 24 ; 段2
012626C6 5D pop ebp ; 段3
012626C7 5F pop edi ; 段4
012626C8 5E pop esi ; 数据组
012626C9 5B pop ebx ; 2E34-3F10的代码
012626CA C3 retn
对流程进行分析可以知道ASPR壳先生成了一段修正跳转表用到的基本数据,然后根据基本数据分别取数据组中的相关数据进行解密计算,并把计算出的地址替换到跳转表的代码中,让程序在调用跳转表时直接调用CALL 1410000。
对基本数据进行分析:
基本含义:
+0: dword not used
+4: dword not used
+8: dword 基本数据组初始化时所用的随机函数地址所需的数据
+C: dword not used
+10: dword 计算代码段HASH时使用的代码起止位置数据表
+14: dword 程序基址
+18: dword 待修正跳转表地址数量
+1C: dword not used
+20: dword 是否修正跳转表的总标志位
+24: dword 程序代码段起始地址
+28: dword 待修正跳转表地址的范围
+2C: dword 跳转表调用的地址,代码区段1
+30: dword 代码区段2
+34: dword 代码区段3
+38: dword 代码区段4
+3C: dword IAT数据组基址
+40: byte*0A 函数序列的随机地址index,从+5C复制过来
+4A: byte*0A not used--copy from [+8]
+54: dword 修正跳转表所用的数据组的基址
+58: dword 修正跳转表所用的数据组的结束地址
+5C: byte*0A 函数序列的随机地址index
+66: byte*2 not used
+68: dword
{
+0: dword 函数序列index指向的函数地址
+4: dword 标志位? not used, copy from [+8]
+8: dword hash? not used, copy from [+8]
}*8
+E0: dword 对地址加密的offset
+E4: dword 待修正跳转表所用的数据组的每组数据长度
+E8: dword
+EC: dword 修正完毕后的计数
+F0: dword 代码区段1的HASH值
+F4: dword 代码区段2的HASH值
+F8: dword 代码区段3的HASH值
+FC: dword 代码区段4的HASH值
+100:dword not used
+104:dword 修正跳转表所用数据组的HASH值
本程序待修正的数据组有0x79个,每个数据组长度为0x31。
修正跳转表时使用了2个随机函数的index:
index=0时:
0126250A 33C0 xor eax, eax
0126250C 8A07 mov al, byte ptr [edi] ; 取函数入口index0
0126250E 8D0440 lea eax, dword ptr [eax+eax*2]
01262511 8B6C83 68 mov ebp, dword ptr [ebx+eax*4+68] ; 函数入口:[ebx+index0*3*4+68]
01262515 8BC6 mov eax, esi
01262517 FFD5 call ebp ; 函数功能:mov eax,[eax+4]
功能只相当于一句:mov eax,[esi+4]
index=9时:
01262527 33C0 xor eax, eax
01262529 8A47 09 mov al, byte ptr [edi+9] ; 取函数入口index9
0126252C 8D0440 lea eax, dword ptr [eax+eax*2]
0126252F 8B5483 68 mov edx, dword ptr [ebx+eax*4+68] ; 函数入口:[ebx+index9*3*4+68]
01262533 8BC6 mov eax, esi
01262535 FFD2 call edx ; 函数功能:mov eax,byte ptr [eax+1A]
功能只相当于一句:mov eax,byte ptr [esi+1A]
再来看看程序调用修复后的CALL 1410000是怎么变成API地址执行的?
在call 1410000有大量的花指令和无效指令(我所说的无效意思是指令的计算结果完全没有使用),删除掉这些垃圾指令后代码就是这样子:
push edx
pushfd
sub esp, 20
lea edx, dword ptr [esp]
push edi
pop dword ptr [edx+1C]
push eax
pop dword ptr [edx]
or eax, edi
mov dword ptr [edx+14], ebp
push esi
pop dword ptr [edx+18]
mov esi, 42AFF2
push ebx
pop dword ptr [edx+C]
mov ebx, 4716BE
push ecx
pop dword ptr [edx+4]
mov edi, esp
lea edi, dword ptr [edi+2C]
push edi
push edx
push edx
pop edi
add edi, 20
mov edi, dword ptr [edi]
push edi
push edx
pop edi
lea edi, dword ptr [edi+28]
push dword ptr [edi]
pop edi
lea edi, dword ptr [edi-5]
lea edi, dword ptr [edi+EBC]
push edi
push 0
pop edi
push dword ptr fs:[edi]
push 1210620
lea edx, dword ptr [1261F80]
call edx
分析一下这段代码的功能可以知道,其实功能非常简单,只是保存现场后call 1261F80,并把6个参数放入了堆栈:
[-2C]=esp+4 返回地址指针
[-30]=esp-28 返回时的堆栈-28
[-34]=[-8] 返回时的寄存器状态
[-38]=[-0]-5+EBC [-0]-5=CALL XXXXXXXX的后一个字节,EBC=CurrentProcessID
[-3C]=fs:[0] 异常入口
[-40]=1210620 基本数据基址
其中加方括号的是相对于入口的堆栈偏移。
再来看看1261F80处的代码:
01261F80 55 push ebp
01261F81 8BEC mov ebp, esp
01261F83 83C4 D8 add esp, -28
01261F86 53 push ebx
01261F87 56 push esi
01261F88 57 push edi
01261F89 33C0 xor eax, eax
01261F8B 8945 DC mov dword ptr [ebp-24], eax
01261F8E 8945 D8 mov dword ptr [ebp-28], eax
01261F91 8945 E0 mov dword ptr [ebp-20], eax
01261F94 8B5D 08 mov ebx, dword ptr [ebp+8] ; ebx=1210620,基本数据基址
01261F97 33C0 xor eax, eax
01261F99 55 push ebp
01261F9A 68 54222601 push 1262254
01261F9F 64:FF30 push dword ptr fs:[eax]
01261FA2 64:8920 mov dword ptr fs:[eax], esp
01261FA5 EB 01 jmp short 01261FA8
01261FA7 90 nop
01261FA8 A1 54672601 mov eax, dword ptr [1266754]
01261FAD C600 C9 mov byte ptr [eax], 0C9
01261FB0 A1 A8672601 mov eax, dword ptr [12667A8]
01261FB5 C600 72 mov byte ptr [eax], 72
01261FB8 33D2 xor edx, edx
01261FBA 55 push ebp
01261FBB 68 FB212601 push 12621FB
01261FC0 64:FF32 push dword ptr fs:[edx]
01261FC3 64:8922 mov dword ptr fs:[edx], esp
01261FC6 A1 20672601 mov eax, dword ptr [1266720] ; [01266720]=012679D4
01261FCB 8B00 mov eax, dword ptr [eax] ; [012679D4]=01210000
01261FCD FFD0 call eax ; 功能:mov eax,[fs:[18]+34]
01261FCF 8945 F0 mov dword ptr [ebp-10], eax
01261FD2 EB 01 jmp short 01261FD5
01261FD4 90 nop
01261FD5 8B45 1C mov eax, dword ptr [ebp+1C]
01261FD8 83E8 08 sub eax, 8
01261FDB 8B00 mov eax, dword ptr [eax] ; 入口时的EDX值
01261FDD 50 push eax
01261FDE 8A8B 16010000 mov cl, byte ptr [ebx+116]
01261FE4 8B55 18 mov edx, dword ptr [ebp+18]
01261FE7 8BC3 mov eax, ebx
01261FE9 E8 7EFAFFFF call 01261A6C ; 保存EDX值
01261FEE 8B45 1C mov eax, dword ptr [ebp+1C]
01261FF1 50 push eax ; 返回时的地址指针
01261FF2 B1 04 mov cl, 4
01261FF4 8B55 18 mov edx, dword ptr [ebp+18]
01261FF7 8BC3 mov eax, ebx
01261FF9 E8 6EFAFFFF call 01261A6C ; 保存返回时的地址指针
01261FFE A1 DC672601 mov eax, dword ptr [12667DC]
01262003 8B40 34 mov eax, dword ptr [eax+34] ; GetCurrentProcessId
01262006 FFD0 call eax ; 获取线程ID
01262008 2945 10 sub dword ptr [ebp+10], eax ; 计算出调用CALL 1410000时的指令地址codeaddr
0126200B 8B45 10 mov eax, dword ptr [ebp+10]
0126200E 2B43 14 sub eax, dword ptr [ebx+14] ; codeaddr-baseaddr,相对地址
01262011 8B55 10 mov edx, dword ptr [ebp+10]
01262014 2B53 24 sub edx, dword ptr [ebx+24] ; codeaddr-codebase,代码段地址偏移
01262017 2B93 E0000000 sub edx, dword ptr [ebx+E0] ; codeaddr-codebase-offset
0126201D 8955 F8 mov dword ptr [ebp-8], edx
01262020 3B43 28 cmp eax, dword ptr [ebx+28]
01262023 0F83 B2010000 jnb 012621DB ; 代码超出范围?
01262029 8D53 40 lea edx, dword ptr [ebx+40]
0126202C 8955 E8 mov dword ptr [ebp-18], edx
0126202F EB 01 jmp short 01262032
01262031 90 nop
01262032 8B53 18 mov edx, dword ptr [ebx+18] ; 取出待修正跳转表的总数
01262035 8955 F4 mov dword ptr [ebp-C], edx
01262038 8B55 10 mov edx, dword ptr [ebp+10]
0126203B 83C2 05 add edx, 5
0126203E 8A12 mov dl, byte ptr [edx] ; 取出调用的跳转表代码的后一字节数据codeextra
01262040 3293 E0000000 xor dl, byte ptr [ebx+E0] ; codeextra xor offset
01262046 8BFA mov edi, edx
01262048 81E7 FF000000 and edi, 0FF
0126204E 25 FF000000 and eax, 0FF
01262053 33F8 xor edi, eax ; codeextra xor offset xor (codeaddr-baseaddr)
01262055 3B7D F4 cmp edi, dword ptr [ebp-C] ; 异或出的结果为当前API所用数据组的组号
01262058 0F87 9F000000 ja 012620FD
0126205E 8B83 E4000000 mov eax, dword ptr [ebx+E4] ; 取出每组数据的长度
01262064 F7EF imul edi
01262066 0343 54 add eax, dword ptr [ebx+54] ; 获取当前API所用数据组地址
01262069 8945 FC mov dword ptr [ebp-4], eax
0126206C EB 01 jmp short 0126206F
0126206E 90 nop
0126206F 8B45 E8 mov eax, dword ptr [ebp-18]
01262072 0FB600 movzx eax, byte ptr [eax]
01262075 8D0440 lea eax, dword ptr [eax+eax*2]
01262078 8B7483 68 mov esi, dword ptr [ebx+eax*4+68]
0126207C 8B45 FC mov eax, dword ptr [ebp-4]
0126207F FFD6 call esi ; mov eax,[esi+4]
01262081 8BF0 mov esi, eax
01262083 3B75 F8 cmp esi, dword ptr [ebp-8] ; 校验codeaddr-codebase-offset
01262086 75 63 jnz short 012620EB
01262088 807B 20 00 cmp byte ptr [ebx+20], 0 ; 检测总标志位
0126208C 74 3C je short 012620CA
0126208E 8B45 E8 mov eax, dword ptr [ebp-18]
01262091 0FB640 09 movzx eax, byte ptr [eax+9]
01262095 8D0440 lea eax, dword ptr [eax+eax*2]
01262098 8B5483 68 mov edx, dword ptr [ebx+eax*4+68]
0126209C 8B45 FC mov eax, dword ptr [ebp-4]
0126209F FFD2 call edx ; mov eax,byte ptr [esi+1A]
012620A1 3C 01 cmp al, 1 ; 检测数据组标志位
012620A3 75 25 jnz short 012620CA
012620A5 56 push esi ; codeaddr-codebase-offset
012620A6 8D45 FC lea eax, dword ptr [ebp-4]
012620A9 50 push eax ; 数据组地址指针
012620AA 8B45 14 mov eax, dword ptr [ebp+14]
012620AD 50 push eax ; 状态寄存器
012620AE 8B45 18 mov eax, dword ptr [ebp+18]
012620B1 50 push eax ; 返回程序时的堆栈指针
012620B2 8B45 0C mov eax, dword ptr [ebp+C]
012620B5 50 push eax ; fs:[0]
012620B6 8B45 F0 mov eax, dword ptr [ebp-10]
012620B9 50 push eax ; [fs:[18]+34]
012620BA 8B4D 1C mov ecx, dword ptr [ebp+1C] ; 返回程序的地址指针
012620BD 8B55 10 mov edx, dword ptr [ebp+10] ; 调用的跳转表地址指针
012620C0 8BC3 mov eax, ebx ; 修正跳转表所用的基本数据
012620C2 E8 BD010000 call 01262284 ; 计算出API地址并调用
这一段代码的功能是计算出CALL 1410000入口的地址并根据入口地址+5的BYTE数据计算出所用数据组的组号;校验入口地址;校验标志位;把相关参数放入堆栈和寄存器并call 01262284。总的来说这一段代码没有进行太实际的计算。
继续看call 01262284处的代码:
01262284 55 push ebp
01262285 8BEC mov ebp, esp
01262287 83C4 D8 add esp, -28
0126228A 53 push ebx
0126228B 56 push esi
0126228C 57 push edi
0126228D 894D F8 mov dword ptr [ebp-8], ecx
01262290 8955 F0 mov dword ptr [ebp-10], edx
01262293 8945 F4 mov dword ptr [ebp-C], eax
01262296 8B75 18 mov esi, dword ptr [ebp+18] ; 当前API所用的数据组指针
01262299 8B45 F4 mov eax, dword ptr [ebp-C] ; 基本数据
0126229C 8D58 40 lea ebx, dword ptr [eax+40] ; 基本数据+40,随机函数index
0126229F EB 01 jmp short 012622A2
012622A1 90 nop
012622A2 A1 54672601 mov eax, dword ptr [1266754]
012622A7 C600 DD mov byte ptr [eax], 0DD
012622AA 33C0 xor eax, eax
012622AC 8A43 07 mov al, byte ptr [ebx+7] ; index7
012622AF 8D0440 lea eax, dword ptr [eax+eax*2]
012622B2 8B55 F4 mov edx, dword ptr [ebp-C]
012622B5 8B7C82 68 mov edi, dword ptr [edx+eax*4+68]
012622B9 8B06 mov eax, dword ptr [esi]
012622BB FFD7 call edi ; mov eax,[eax+9]
012622BD 8945 EC mov dword ptr [ebp-14], eax ; 保存
012622C0 33C0 xor eax, eax
012622C2 8A43 08 mov al, byte ptr [ebx+8] ; index8
012622C5 8D0440 lea eax, dword ptr [eax+eax*2]
012622C8 8B55 F4 mov edx, dword ptr [ebp-C]
012622CB 8B7C82 68 mov edi, dword ptr [edx+eax*4+68]
012622CF 8B06 mov eax, dword ptr [esi]
012622D1 FFD7 call edi ; mov eax,[eax+11]
012622D3 8945 E8 mov dword ptr [ebp-18], eax ; 保存
012622D6 EB 01 jmp short 012622D9
012622D8 90 nop
012622D9 33C0 xor eax, eax
012622DB 8A43 02 mov al, byte ptr [ebx+2] ; index2
012622DE 8D0440 lea eax, dword ptr [eax+eax*2]
012622E1 8B55 F4 mov edx, dword ptr [ebp-C]
012622E4 8B7C82 68 mov edi, dword ptr [edx+eax*4+68]
012622E8 8B06 mov eax, dword ptr [esi]
012622EA FFD7 call edi ; mov eax,[eax+2C]
012622EC 8BF8 mov edi, eax
012622EE 33C0 xor eax, eax
012622F0 8A43 06 mov al, byte ptr [ebx+6] ; index6
012622F3 8D0440 lea eax, dword ptr [eax+eax*2]
012622F6 8B55 F4 mov edx, dword ptr [ebp-C]
012622F9 8B5482 68 mov edx, dword ptr [edx+eax*4+68]
012622FD 8B06 mov eax, dword ptr [esi]
012622FF FFD2 call edx ; mov eax,byte ptr [eax]
01262301 8845 DF mov byte ptr [ebp-21], al ; 保存
01262304 8B45 F4 mov eax, dword ptr [ebp-C] ; 基本数据
01262307 03B8 E0000000 add edi, dword ptr [eax+E0] ; 计算代码hash的偏移:[+2C]+offset
0126230D EB 01 jmp short 01262310
0126230F 90 nop
01262310 57 push edi
01262311 33C0 xor eax, eax
01262313 8A45 DF mov al, byte ptr [ebp-21] ; [+0]
01262316 05 FF000000 add eax, 0FF ; [+0]+0xFF
0126231B 50 push eax ; 计算代码hash的长度:[+0]+0xFF
0126231C 8B45 F4 mov eax, dword ptr [ebp-C]
0126231F E8 4CFCFFFF call 01261F70 ; 计算代码hash的基址:fixaddr=126099C
01262324 8BC8 mov ecx, eax
01262326 8B45 F4 mov eax, dword ptr [ebp-C]
01262329 8B50 10 mov edx, dword ptr [eax+10] ; 计算代码段HASH时使用的代码起止位置数据表指针
0126232C 8B45 F4 mov eax, dword ptr [ebp-C] ; 基本数据
0126232F E8 70EAFFFF call 01260DA4 ; hash(fixaddr+[+2C]+offset,[+0]+0xFF)
01262334 8945 D8 mov dword ptr [ebp-28], eax ; 保存hash结果
01262337 EB 01 jmp short 0126233A
01262339 90 nop
0126233A 33C0 xor eax, eax
0126233C 8A43 03 mov al, byte ptr [ebx+3] ; index3
0126233F 8D0440 lea eax, dword ptr [eax+eax*2]
01262342 8B55 F4 mov edx, dword ptr [ebp-C]
01262345 8B7C82 68 mov edi, dword ptr [edx+eax*4+68]
01262349 8B06 mov eax, dword ptr [esi]
0126234B FFD7 call edi ; mov eax,[eax+20]
0126234D 8BF8 mov edi, eax
0126234F 8B45 F4 mov eax, dword ptr [ebp-C]
01262352 03B8 E0000000 add edi, dword ptr [eax+E0] ; [+20]+offset
01262358 8B45 EC mov eax, dword ptr [ebp-14] ; [+9]
0126235B 03C7 add eax, edi ; [+20]+offset+[+9]
0126235D 0345 D8 add eax, dword ptr [ebp-28] ; [+20]+offset+[+9]+hash
01262360 8945 EC mov dword ptr [ebp-14], eax ; API所用的DLL名称HASH:[+20]+offset+[+9]+hash
01262363 8B45 E8 mov eax, dword ptr [ebp-18] ; [+11]
01262366 2BC7 sub eax, edi ; [+11]-([+20]+offset)
01262368 2B45 D8 sub eax, dword ptr [ebp-28] ; [+11]-([+20]+offset)-hash
0126236B 8945 E8 mov dword ptr [ebp-18], eax ; API名称字符串HASH:[+11]-([+20]+offset)-hash
0126236E 33C0 xor eax, eax
01262370 8A43 01 mov al, byte ptr [ebx+1] ; index1
01262373 8D0440 lea eax, dword ptr [eax+eax*2]
01262376 8B55 F4 mov edx, dword ptr [ebp-C]
01262379 8B5482 68 mov edx, dword ptr [edx+eax*4+68]
0126237D 8B06 mov eax, dword ptr [esi]
0126237F FFD2 call edx ; mov eax,byte ptr [eax+26]
01262381 8BD8 mov ebx, eax
01262383 EB 01 jmp short 01262386
01262385 90 nop
01262386 8D45 E4 lea eax, dword ptr [ebp-1C]
01262389 50 push eax ; 用于保存计算结果的地址指针
0126238A 66:8B4D EC mov cx, word ptr [ebp-14] ; API所用的DLL名称HASH
0126238E 66:8B55 E8 mov dx, word ptr [ebp-18] ; API名称字符串HASH
01262392 8B45 F4 mov eax, dword ptr [ebp-C] ; 基本数据
01262395 E8 02F7FFFF call 01261A9C ; 查找API相关HASH并获取API地址
0126239A 84C0 test al, al
0126239C 8B45 F4 mov eax, dword ptr [ebp-C]
0126239F 8B80 E0000000 mov eax, dword ptr [eax+E0] ; offset
012623A5 0345 E4 add eax, dword ptr [ebp-1C] ; 计算结果+offset:API实际地址
012623A8 8945 FC mov dword ptr [ebp-4], eax ; !!!!!!!!!!!!!!!API ADDRESS!!
到这里终于出现了所调用API的实际地址,再后面的代码就是把API地址偏移保存到一个表中,更改CALL 1410000为CALL 1460004,避免以后重复获取API地址;恢复堆栈和现场,跳到API入口继续执行。
重点分析一下这一段代码:
1.根据数据组中dword:[+2C]和byte:[+0]处的值计算壳代码的HASH值:hash=hash(fixaddr+[+2C]+offset,[+0]+0xFF)
2.计算出API所用的DLL名称HASH:[+20]+offset+[+9]+hash
3.计算出API名称字符串HASH:[+11]-([+20]+offset)-hash
4.根据DLL名称HASH和API名称HASH查找导入表字符串数据组,并获取API地址
其中加方括号的为使用随机函数的功能,共使用到了6个随机函数index:
7:mov eax,[eax+9]
8:mov eax,[eax+11]
2:mov eax,[eax+2C]
6:mov eax,byte ptr [eax]
3:mov eax,[eax+20]
1:mov eax,byte ptr [eax+26]
分析到这里就可以得到还原跳转表的思路了:对每一个数据组计算出API所用DLL名称的HASH和API名称字符串的HASH,call 01261A9C计算出API实际地址,再将地址与上一节得到的IAT比较得到跳转表地址,最后把跳转表地址写入到数据组指定的代码偏移地址。
还原跳转表需要注意的问题:
1.不能直接在代码上patch,因为获取API相关HASH时会用到fixaddr=126099C开始的代码HASH值,我刚开始在这地方困扰了很长时间,总是获取几个API就出错了,无意间才注意到126099C其实就是正在执行的代码。
2.最好在壳代码执行完毕后进行patch,因为可能会有地方校验。
3.注意调用CALL时有的使用地址,有的使用地址指针,不要弄错。
我的选择是在修复完IAT并到达OEP后,在代码段最后位置00689F00进行patch,patch的代码如下:
00689F00 60 pushad ; 保存现场
00689F01 9C pushfd
00689F02 A1 74662601 mov eax, dword ptr [1266674]
00689F07 8B18 mov ebx, dword ptr [eax] ; 基本数据
00689F09 8BBB E0000000 mov edi, dword ptr [ebx+E0] ; offset
00689F0F 8B6B 18 mov ebp, dword ptr [ebx+18] ; 待修正跳转表地址数量
00689F12 8B73 54 mov esi, dword ptr [ebx+54] ; 修正跳转表所用的数据组的基址
00689F15 83FD 00 cmp ebp, 0
00689F18 74 71 je short 00689F8B ; 循环结束?
00689F1A 8B46 2C mov eax, dword ptr [esi+2C] ; [+2C]
00689F1D 03C7 add eax, edi ; [+2C]+offset
00689F1F 50 push eax
00689F20 33C0 xor eax, eax
00689F22 8A06 mov al, byte ptr [esi] ; [+0]
00689F24 05 FF000000 add eax, 0FF ; [+0]+0xFF
00689F29 50 push eax
00689F2A E8 4180BD00 call 01261F70 ; fixaddr=126099C
00689F2F 8BC8 mov ecx, eax
00689F31 8B53 10 mov edx, dword ptr [ebx+10] ; 计算代码段HASH时使用的代码起止位置数据表
00689F34 8BC3 mov eax, ebx
00689F36 E8 696EBD00 call 01260DA4 ; hash(fixaddr+[+2C]+offset,[+0]+0xFF)
00689F3B 03C7 add eax, edi ; offset+hash
00689F3D 0346 20 add eax, dword ptr [esi+20] ; [+20]+offset+hash
00689F40 8B4E 09 mov ecx, dword ptr [esi+9]
00689F43 03C8 add ecx, eax ; [+9]+[+20]+offset+hash
00689F45 8B56 11 mov edx, dword ptr [esi+11]
00689F48 2BD0 sub edx, eax ; [+11]-([+20]+offset+hash)
00689F4A 6A 00 push 0
00689F4C 54 push esp ; 用于保存计算结果的地址指针
00689F4D 8BC3 mov eax, ebx
00689F4F E8 487BBD00 call 01261A9C ; 查找API相关HASH并获取API地址
00689F54 58 pop eax ; 取出计算结果
00689F55 03C7 add eax, edi ; 计算出API实际地址
00689F57 BA 98CB6900 mov edx, 0069CB98 ; IAT基址
00689F5C B9 B8090000 mov ecx, 9B8 ; IAT长度
00689F61 3B02 cmp eax, dword ptr [edx] ; 查找IAT中与API地址相等的位置
00689F63 74 0C je short 00689F71 ; 是否找到API?
00689F65 83C2 04 add edx, 4 ; 下一个IAT地址
00689F68 83C1 FC add ecx, -4
00689F6B 85C9 test ecx, ecx
00689F6D ^ 75 F2 jnz short 00689F61 ; 查找结束?
00689F6F CD 03 int 3 ; 查找结束还未找到:出错
00689F71 8B46 04 mov eax, dword ptr [esi+4] ; 找到API时:
00689F74 0343 24 add eax, dword ptr [ebx+24] ; [+4]+baseoffset
00689F77 03C7 add eax, edi ; 计算出待修复跳转表的位置:[+4]+baseoffset+offset
00689F79 66:C700 FF25 mov word ptr [eax], 25FF ; 写入JMP [XXXXXXXX]
00689F7E 40 inc eax
00689F7F 40 inc eax
00689F80 8910 mov dword ptr [eax], edx ; 写入跳转表地址
00689F82 03B3 E4000000 add esi, dword ptr [ebx+E4] ; 取下一个数据组
00689F88 4D dec ebp ; 数量-1
00689F89 ^ EB 8A jmp short 00689F15
00689F8B 9D popfd ; 循环结束:恢复现场
00689F8C 61 popad
00689F8D ^ E9 4EFCFFFF jmp 00689BE0 ; 跳到OEP
再次跳到OEP后清除掉patch的代码,就可以DUMP了。
最后的步骤是用ImportREC写入修复后的IAT,测试运行----
运行出错!
还有暗桩?检查了一下原来还有个“暗桩”:在PE HEADER里,ASPR壳指定SizeOf Headers大小为0x400,然后又故意添加了数个段使PE HEADER的大小刚好是0x400,当用ImportREC修复好IAT后会添加一个新段,这个段就超出SizeOf Headers,导致载入失败。
顺便把重定位信息和大小清0,防止其他错误。
再次运行,一切OK! |
|