这一个星期都在弄这个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.pediy.com/showthread.php?t=80422
在上一节修复完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
代码:
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
代码:
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
对基本数据进行分析:
基本含义:
代码:
+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值
修正跳转表时使用了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
[-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 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!!
重点分析一下这一段代码:
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
最后的步骤是用ImportREC写入修复后的IAT,测试运行----
运行出错!
还有暗桩?检查了一下原来还有个“暗桩”:在PE HEADER里,ASPR壳指定SizeOf Headers大小为0x400,然后又故意添加了数个段使PE HEADER的大小刚好是0x400,当用ImportREC修复好IAT后会添加一个新段,这个段就超出SizeOf Headers,导致载入失败。
修改Size Of Headers数值为400,顺便把重定位信息和大小清0,防止其他错误。
再次运行,一切OK!