小生我怕怕 发表于 2009-1-14 22:20

ASPR学习笔记(二):还原跳转表 作者:lelfei

这一个星期都在弄这个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

请关注上一节:ASPR学习笔记(一):修复IAThttp://bbs.unpack.cn/viewthread.php?tid=31713

在上一节修复完IAT后可以看出OEP=289BE0,RVA=29CB98,SIZE=9B8
修复IAT还不能算完成,因为ASPR把程序中的跳转表JMP 替换成了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
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 , 0
012609B1    837F 08 00      cmp   dword ptr , 0
012609B5    0F84 DF010000   je      01260B9A
012609BB    8D47 5C         lea   eax, dword ptr
012609BE    BA 0A000000   mov   edx, 0A
012609C3    E8 FC27FFFF   call    012531C4                                 ; 初始化随机序列数据
012609C8    8D47 5C         lea   eax, dword ptr
012609CB    BA 0A000000   mov   edx, 0A
012609D0    E8 A327FFFF   call    01253178                                 ; 生成随机序列保存到
012609D5    33ED            xor   ebp, ebp
012609D7    8A442F 5C       mov   al, byte ptr
012609DB    8D57 40         lea   edx, dword ptr
012609DE    03D5            add   edx, ebp
012609E0    8802            mov   byte ptr , al
012609E2    45            inc   ebp
012609E3    83FD 0A         cmp   ebp, 0A
012609E6^ 75 EF         jnz   short 012609D7                           ; copy随机序列到
012609E8    8B77 08         mov   esi, dword ptr
012609EB    BD 0A000000   mov   ebp, 0A
012609F0    8A1E            mov   bl, byte ptr                      ; 取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
01260A18    83C6 04         add   esi, 4
01260A1B    33D2            xor   edx, edx
01260A1D    8AD3            mov   dl, bl
01260A1F    8D1452          lea   edx, dword ptr
01260A22    894497 6C       mov   dword ptr , eax
01260A26    3D 00200000   cmp   eax, 2000
01260A2B    0F87 69010000   ja      01260B9A
01260A31    8B16            mov   edx, dword ptr
01260A33    895424 04       mov   dword ptr , edx
01260A37    83C6 04         add   esi, 4
01260A3A    33D2            xor   edx, edx
01260A3C    8AD3            mov   dl, bl
01260A3E    8D1452          lea   edx, dword ptr
01260A41    8B4C24 04       mov   ecx, dword ptr
01260A45    894C97 70       mov   dword ptr , ecx
01260A49    33D2            xor   edx, edx
01260A4B    8AD3            mov   dl, bl
01260A4D    8D1452          lea   edx, dword ptr
01260A50    897497 68       mov   dword ptr , esi
01260A54    03F0            add   esi, eax
01260A56    4D            dec   ebp
01260A57^ 75 97         jnz   short 012609F0                           ; 循环生成函数随机入口
01260A59    8D47 4A         lea   eax, dword ptr
01260A5C    B9 09000000   mov   ecx, 9
01260A61    8BD6            mov   edx, esi
01260A63    E8 2C4FFEFF   call    <CopyStringByByte>                     ; 复制9字节到
01260A68    83C6 09         add   esi, 9
01260A6B    8A06            mov   al, byte ptr
01260A6D    8847 20         mov   byte ptr , al                  ; 标志位
01260A70    46            inc   esi
01260A71    8B06            mov   eax, dword ptr
01260A73    8987 E4000000   mov   dword ptr , eax                  ; 数据组的长度
01260A79    83C6 04         add   esi, 4
01260A7C    8B06            mov   eax, dword ptr
01260A7E    8987 E0000000   mov   dword ptr , eax                  ; 待修正代码的偏移
01260A84    83C6 04         add   esi, 4
01260A87    BA 54652601   mov   edx, 1266554
01260A8C    8902            mov   dword ptr , eax
01260A8E    8B06            mov   eax, dword ptr
01260A90    8947 18         mov   dword ptr , eax                  ; 待修正代码的数据组的数量
01260A93    83C6 04         add   esi, 4
01260A96    837F 2C 00      cmp   dword ptr , 0                  ; 生成4个新段并把入口放入开始的位置中
01260A9A    74 0D         je      short 01260AA9                           ; 段1是否已经生成?
01260A9C    8D47 2C         lea   eax, dword ptr
01260A9F    E8 0C99FFFF   call    0125A3B0
01260AA4    33C0            xor   eax, eax
01260AA6    8947 2C         mov   dword ptr , eax
01260AA9    8BC7            mov   eax, edi
01260AAB    E8 74F6FFFF   call    01260124                                 ; 生成段1并生成代码数据
01260AB0    8947 2C         mov   dword ptr , eax                  ; 保存段1入口地址
01260AB3    837F 30 00      cmp   dword ptr , 0
01260AB7    74 0D         je      short 01260AC6                           ; 段2是否已经生成?
01260AB9    8D47 30         lea   eax, dword ptr
01260ABC    E8 EF98FFFF   call    0125A3B0
01260AC1    33C0            xor   eax, eax
01260AC3    8947 30         mov   dword ptr , eax
01260AC6    8BC7            mov   eax, edi
01260AC8    E8 87F9FFFF   call    01260454                                 ; 生成段2并生成代码数据
01260ACD    8947 30         mov   dword ptr , eax                  ; 保存段2入口地址
01260AD0    837F 34 00      cmp   dword ptr , 0
01260AD4    74 0D         je      short 01260AE3                           ; 段3是否已经生成?
01260AD6    8D47 34         lea   eax, dword ptr
01260AD9    E8 D298FFFF   call    0125A3B0
01260ADE    33C0            xor   eax, eax
01260AE0    8947 34         mov   dword ptr , eax
01260AE3    8BC7            mov   eax, edi
01260AE5    E8 4AFBFFFF   call    01260634                                 ; 生成段3并生成代码数据
01260AEA    8947 34         mov   dword ptr , eax                  ; 保存段3入口地址
01260AED    837F 38 00      cmp   dword ptr , 0
01260AF1    74 0D         je      short 01260B00                           ; 段4是否已经生成?
01260AF3    8D47 38         lea   eax, dword ptr
01260AF6    E8 B598FFFF   call    0125A3B0
01260AFB    33C0            xor   eax, eax
01260AFD    8947 38         mov   dword ptr , eax
01260B00    8BC7            mov   eax, edi
01260B02    E8 D1FCFFFF   call    012607D8                                 ; 生成段4并生成代码数据
01260B07    8947 38         mov   dword ptr , eax                  ; 保存段4入口地址
01260B0A    8977 54         mov   dword ptr , esi                  ; 修正跳转表所用的数据组基址
01260B0D    8B47 18         mov   eax, dword ptr
01260B10    F7AF E4000000   imul    dword ptr                      ; 数据组数量*数据组长度
01260B16    03F0            add   esi, eax
01260B18    8B06            mov   eax, dword ptr
01260B1A    8947 1C         mov   dword ptr , eax                  ; 0
01260B1D    83C6 04         add   esi, 4
01260B20    8977 58         mov   dword ptr , esi                  ; 数据组的结束地址
01260B23    8B87 E0000000   mov   eax, dword ptr
01260B29    50            push    eax
01260B2A    68 00030000   push    300
01260B2F    8B47 2C         mov   eax, dword ptr
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 , ebx                  ; save hash
01260B41    53            push    ebx
01260B42    68 00030000   push    300
01260B47    8B47 30         mov   eax, dword ptr
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 , esi                  ; save hash
01260B59    56            push    esi
01260B5A    68 00030000   push    300
01260B5F    8B47 34         mov   eax, dword ptr
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 , ebx                  ; save hash
01260B71    53            push    ebx
01260B72    68 00030000   push    300
01260B77    8B47 38         mov   eax, dword ptr
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 , esi                  ; save hash
01260B89    56            push    esi
01260B8A    57            push    edi
01260B8B    E8 3C1B0000   call    012626CC                                 ; hash(数据组)
01260B90    8987 04010000   mov   dword ptr , eax               ; save hash
01260B96    C60424 01       mov   byte ptr , 1
01260B9A    8A0424          mov   al, byte ptr
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
012624AE    85D2            test    edx, edx
012624B0    0F84 0D020000   je      012626C3
012624B6    83BB E4000000 0>cmp   dword ptr , 0
012624BD    0F84 00020000   je      012626C3
012624C3    837B 18 00      cmp   dword ptr , 0
012624C7    0F84 F6010000   je      012626C3
012624CD    837B 24 00      cmp   dword ptr , 0
012624D1    0F84 EC010000   je      012626C3
012624D7    837B 2C 00      cmp   dword ptr , 0
012624DB    0F84 E2010000   je      012626C3
012624E1    837B 30 00      cmp   dword ptr , 0
012624E5    0F84 D8010000   je      012626C3
012624EB    8BF2            mov   esi, edx
012624ED    8B43 18         mov   eax, dword ptr
012624F0    890424          mov   dword ptr , eax
012624F3    8B83 E0000000   mov   eax, dword ptr
012624F9    894424 14       mov   dword ptr , eax
012624FD    8D7B 40         lea   edi, dword ptr
01262500    833C24 00       cmp   dword ptr , 0
01262504    0F86 AB010000   jbe   012626B5
0126250A    33C0            xor   eax, eax
0126250C    8A07            mov   al, byte ptr                      ; 取函数入口index0
0126250E    8D0440          lea   eax, dword ptr
01262511    8B6C83 68       mov   ebp, dword ptr             ; 函数入口:
01262515    8BC6            mov   eax, esi
01262517    FFD5            call    ebp                                    ; 函数功能:mov eax,
01262519    8BE8            mov   ebp, eax                                 ; 取出的值为待修正地址的偏移
0126251B    036B 24         add   ebp, dword ptr                   ; +基址
0126251E    03AB E0000000   add   ebp, dword ptr                   ; +段偏移
01262524    EB 01         jmp   short 01262527                           ; 结果为待修正的地址入口
01262526    90            nop
01262527    33C0            xor   eax, eax
01262529    8A47 09         mov   al, byte ptr                      ; 取函数入口index9
0126252C    8D0440          lea   eax, dword ptr
0126252F    8B5483 68       mov   edx, dword ptr             ; 函数入口:
01262533    8BC6            mov   eax, esi
01262535    FFD2            call    edx                                    ; 函数功能:mov eax,byte ptr
01262537    807B 20 00      cmp   byte ptr , 0                     ; 取出的值为待修正地址的标志位
0126253B    0F85 3D010000   jnz   0126267E                                 ; 总标志位:是否进行修正?
01262541    3C 01         cmp   al, 1
01262543    0F85 35010000   jnz   0126267E                                 ; 数据组标志位:是否进行修正?
0126267E    8B43 2C         mov   eax, dword ptr                   ; 取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 , 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                   ; 复制的长度:随机多复制几个字节
01262699    8BD6            mov   edx, esi
0126269B    8BC3            mov   eax, ebx
0126269D    E8 BAE6FFFF   call    01260D5C                                 ; copy一段代码到一个段中
012626A2    FF0C24          dec   dword ptr                         ; 循环次数-1
012626A5    03B3 E4000000   add   esi, dword ptr                   ; +数据组长度:取下一个数据组
012626AB    833C24 00       cmp   dword ptr , 0
012626AF^ 0F87 55FEFFFF   ja      0126250A                                 ; 继续循环
012626B5    53            push    ebx
012626B6    E8 5D000000   call    01262718                                 ; 校验hash:是否修改代码?
012626BB    0183 EC000000   add   dword ptr , 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*0Anot 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:dwordhash? 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                      ; 取函数入口index0
0126250E    8D0440          lea   eax, dword ptr
01262511    8B6C83 68       mov   ebp, dword ptr             ; 函数入口:
01262515    8BC6            mov   eax, esi
01262517    FFD5            call    ebp                                    ; 函数功能:mov eax,
功能只相当于一句:mov eax,
index=9时:
01262527    33C0            xor   eax, eax
01262529    8A47 09         mov   al, byte ptr                      ; 取函数入口index9
0126252C    8D0440          lea   eax, dword ptr
0126252F    8B5483 68       mov   edx, dword ptr             ; 函数入口:
01262533    8BC6            mov   eax, esi
01262535    FFD2            call    edx                                    ; 函数功能:mov eax,byte ptr
功能只相当于一句:mov eax,byte ptr
再来看看程序调用修复后的CALL 1410000是怎么变成API地址执行的?
在call 1410000有大量的花指令和无效指令(我所说的无效意思是指令的计算结果完全没有使用),删除掉这些垃圾指令后代码就是这样子:
push    edx
pushfd
sub   esp, 20
lea   edx, dword ptr
push    edi
pop   dword ptr
push    eax
pop   dword ptr
or      eax, edi
mov   dword ptr , ebp
push    esi
pop   dword ptr
mov   esi, 42AFF2
push    ebx
pop   dword ptr
mov   ebx, 4716BE
push    ecx
pop   dword ptr
mov   edi, esp
lea   edi, dword ptr
push    edi
push    edx
push    edx
pop   edi
add   edi, 20
mov   edi, dword ptr
push    edi
push    edx
pop   edi
lea   edi, dword ptr
push    dword ptr
pop   edi
lea   edi, dword ptr
lea   edi, dword ptr
push    edi
push    0
pop   edi
push    dword ptr fs:
push    1210620
lea   edx, dword ptr
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:            异常入口
[-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 , eax
01261F8E    8945 D8         mov   dword ptr , eax
01261F91    8945 E0         mov   dword ptr , eax
01261F94    8B5D 08         mov   ebx, dword ptr          ; ebx=1210620,基本数据基址
01261F97    33C0            xor   eax, eax
01261F99    55            push    ebp
01261F9A    68 54222601   push    1262254
01261F9F    64:FF30         push    dword ptr fs:
01261FA2    64:8920         mov   dword ptr fs:, esp
01261FA5    EB 01         jmp   short 01261FA8
01261FA7    90            nop
01261FA8    A1 54672601   mov   eax, dword ptr
01261FAD    C600 C9         mov   byte ptr , 0C9
01261FB0    A1 A8672601   mov   eax, dword ptr
01261FB5    C600 72         mov   byte ptr , 72
01261FB8    33D2            xor   edx, edx
01261FBA    55            push    ebp
01261FBB    68 FB212601   push    12621FB
01261FC0    64:FF32         push    dword ptr fs:
01261FC3    64:8922         mov   dword ptr fs:, esp
01261FC6    A1 20672601   mov   eax, dword ptr          ; =012679D4
01261FCB    8B00            mov   eax, dword ptr              ; =01210000
01261FCD    FFD0            call    eax                              ; 功能:mov eax,+34]
01261FCF    8945 F0         mov   dword ptr , eax
01261FD2    EB 01         jmp   short 01261FD5
01261FD4    90            nop
01261FD5    8B45 1C         mov   eax, dword ptr
01261FD8    83E8 08         sub   eax, 8
01261FDB    8B00            mov   eax, dword ptr              ; 入口时的EDX值
01261FDD    50            push    eax
01261FDE    8A8B 16010000   mov   cl, byte ptr
01261FE4    8B55 18         mov   edx, dword ptr
01261FE7    8BC3            mov   eax, ebx
01261FE9    E8 7EFAFFFF   call    01261A6C                         ; 保存EDX值
01261FEE    8B45 1C         mov   eax, dword ptr
01261FF1    50            push    eax                              ; 返回时的地址指针
01261FF2    B1 04         mov   cl, 4
01261FF4    8B55 18         mov   edx, dword ptr
01261FF7    8BC3            mov   eax, ebx
01261FF9    E8 6EFAFFFF   call    01261A6C                         ; 保存返回时的地址指针
01261FFE    A1 DC672601   mov   eax, dword ptr
01262003    8B40 34         mov   eax, dword ptr           ; GetCurrentProcessId
01262006    FFD0            call    eax                              ; 获取线程ID
01262008    2945 10         sub   dword ptr , eax          ; 计算出调用CALL 1410000时的指令地址codeaddr
0126200B    8B45 10         mov   eax, dword ptr
0126200E    2B43 14         sub   eax, dword ptr           ; codeaddr-baseaddr,相对地址
01262011    8B55 10         mov   edx, dword ptr
01262014    2B53 24         sub   edx, dword ptr           ; codeaddr-codebase,代码段地址偏移
01262017    2B93 E0000000   sub   edx, dword ptr           ; codeaddr-codebase-offset
0126201D    8955 F8         mov   dword ptr , edx
01262020    3B43 28         cmp   eax, dword ptr
01262023    0F83 B2010000   jnb   012621DB                         ; 代码超出范围?
01262029    8D53 40         lea   edx, dword ptr
0126202C    8955 E8         mov   dword ptr , edx
0126202F    EB 01         jmp   short 01262032
01262031    90            nop
01262032    8B53 18         mov   edx, dword ptr           ; 取出待修正跳转表的总数
01262035    8955 F4         mov   dword ptr , edx
01262038    8B55 10         mov   edx, dword ptr
0126203B    83C2 05         add   edx, 5
0126203E    8A12            mov   dl, byte ptr                ; 取出调用的跳转表代码的后一字节数据codeextra
01262040    3293 E0000000   xor   dl, byte ptr             ; 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          ; 异或出的结果为当前API所用数据组的组号
01262058    0F87 9F000000   ja      012620FD
0126205E    8B83 E4000000   mov   eax, dword ptr           ; 取出每组数据的长度
01262064    F7EF            imul    edi
01262066    0343 54         add   eax, dword ptr           ; 获取当前API所用数据组地址
01262069    8945 FC         mov   dword ptr , eax
0126206C    EB 01         jmp   short 0126206F
0126206E    90            nop
0126206F    8B45 E8         mov   eax, dword ptr
01262072    0FB600          movzx   eax, byte ptr
01262075    8D0440          lea   eax, dword ptr
01262078    8B7483 68       mov   esi, dword ptr
0126207C    8B45 FC         mov   eax, dword ptr
0126207F    FFD6            call    esi                              ; mov eax,
01262081    8BF0            mov   esi, eax
01262083    3B75 F8         cmp   esi, dword ptr          ; 校验codeaddr-codebase-offset
01262086    75 63         jnz   short 012620EB
01262088    807B 20 00      cmp   byte ptr , 0             ; 检测总标志位
0126208C    74 3C         je      short 012620CA
0126208E    8B45 E8         mov   eax, dword ptr
01262091    0FB640 09       movzx   eax, byte ptr
01262095    8D0440          lea   eax, dword ptr
01262098    8B5483 68       mov   edx, dword ptr
0126209C    8B45 FC         mov   eax, dword ptr
0126209F    FFD2            call    edx                              ; mov eax,byte ptr
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
012620A9    50            push    eax                              ; 数据组地址指针
012620AA    8B45 14         mov   eax, dword ptr
012620AD    50            push    eax                              ; 状态寄存器
012620AE    8B45 18         mov   eax, dword ptr
012620B1    50            push    eax                              ; 返回程序时的堆栈指针
012620B2    8B45 0C         mov   eax, dword ptr
012620B5    50            push    eax                              ; fs:
012620B6    8B45 F0         mov   eax, dword ptr
012620B9    50            push    eax                              ; +34]
012620BA    8B4D 1C         mov   ecx, dword ptr           ; 返回程序的地址指针
012620BD    8B55 10         mov   edx, dword ptr           ; 调用的跳转表地址指针
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 , ecx
01262290    8955 F0         mov   dword ptr , edx
01262293    8945 F4         mov   dword ptr , eax
01262296    8B75 18         mov   esi, dword ptr           ; 当前API所用的数据组指针
01262299    8B45 F4         mov   eax, dword ptr          ; 基本数据
0126229C    8D58 40         lea   ebx, dword ptr           ; 基本数据+40,随机函数index
0126229F    EB 01         jmp   short 012622A2
012622A1    90            nop
012622A2    A1 54672601   mov   eax, dword ptr
012622A7    C600 DD         mov   byte ptr , 0DD
012622AA    33C0            xor   eax, eax
012622AC    8A43 07         mov   al, byte ptr              ; index7
012622AF    8D0440          lea   eax, dword ptr
012622B2    8B55 F4         mov   edx, dword ptr
012622B5    8B7C82 68       mov   edi, dword ptr
012622B9    8B06            mov   eax, dword ptr
012622BB    FFD7            call    edi                              ; mov eax,
012622BD    8945 EC         mov   dword ptr , eax          ; 保存
012622C0    33C0            xor   eax, eax
012622C2    8A43 08         mov   al, byte ptr              ; index8
012622C5    8D0440          lea   eax, dword ptr
012622C8    8B55 F4         mov   edx, dword ptr
012622CB    8B7C82 68       mov   edi, dword ptr
012622CF    8B06            mov   eax, dword ptr
012622D1    FFD7            call    edi                              ; mov eax,
012622D3    8945 E8         mov   dword ptr , eax          ; 保存
012622D6    EB 01         jmp   short 012622D9
012622D8    90            nop
012622D9    33C0            xor   eax, eax
012622DB    8A43 02         mov   al, byte ptr              ; index2
012622DE    8D0440          lea   eax, dword ptr
012622E1    8B55 F4         mov   edx, dword ptr
012622E4    8B7C82 68       mov   edi, dword ptr
012622E8    8B06            mov   eax, dword ptr
012622EA    FFD7            call    edi                              ; mov eax,
012622EC    8BF8            mov   edi, eax
012622EE    33C0            xor   eax, eax
012622F0    8A43 06         mov   al, byte ptr              ; index6
012622F3    8D0440          lea   eax, dword ptr
012622F6    8B55 F4         mov   edx, dword ptr
012622F9    8B5482 68       mov   edx, dword ptr
012622FD    8B06            mov   eax, dword ptr
012622FF    FFD2            call    edx                              ; mov eax,byte ptr
01262301    8845 DF         mov   byte ptr , al            ; 保存
01262304    8B45 F4         mov   eax, dword ptr          ; 基本数据
01262307    03B8 E0000000   add   edi, dword ptr           ; 计算代码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             ; [+0]
01262316    05 FF000000   add   eax, 0FF                         ; [+0]+0xFF
0126231B    50            push    eax                              ; 计算代码hash的长度:[+0]+0xFF
0126231C    8B45 F4         mov   eax, dword ptr
0126231F    E8 4CFCFFFF   call    01261F70                         ; 计算代码hash的基址:fixaddr=126099C
01262324    8BC8            mov   ecx, eax
01262326    8B45 F4         mov   eax, dword ptr
01262329    8B50 10         mov   edx, dword ptr           ; 计算代码段HASH时使用的代码起止位置数据表指针
0126232C    8B45 F4         mov   eax, dword ptr          ; 基本数据
0126232F    E8 70EAFFFF   call    01260DA4                         ; hash(fixaddr+[+2C]+offset,[+0]+0xFF)
01262334    8945 D8         mov   dword ptr , eax          ; 保存hash结果
01262337    EB 01         jmp   short 0126233A
01262339    90            nop
0126233A    33C0            xor   eax, eax
0126233C    8A43 03         mov   al, byte ptr              ; index3
0126233F    8D0440          lea   eax, dword ptr
01262342    8B55 F4         mov   edx, dword ptr
01262345    8B7C82 68       mov   edi, dword ptr
01262349    8B06            mov   eax, dword ptr
0126234B    FFD7            call    edi                              ; mov eax,
0126234D    8BF8            mov   edi, eax
0126234F    8B45 F4         mov   eax, dword ptr
01262352    03B8 E0000000   add   edi, dword ptr           ; [+20]+offset
01262358    8B45 EC         mov   eax, dword ptr           ; [+9]
0126235B    03C7            add   eax, edi                         ; [+20]+offset+[+9]
0126235D    0345 D8         add   eax, dword ptr           ; [+20]+offset+[+9]+hash
01262360    8945 EC         mov   dword ptr , eax          ; API所用的DLL名称HASH:[+20]+offset+[+9]+hash
01262363    8B45 E8         mov   eax, dword ptr           ; [+11]
01262366    2BC7            sub   eax, edi                         ; [+11]-([+20]+offset)
01262368    2B45 D8         sub   eax, dword ptr           ; [+11]-([+20]+offset)-hash
0126236B    8945 E8         mov   dword ptr , eax          ; API名称字符串HASH:[+11]-([+20]+offset)-hash
0126236E    33C0            xor   eax, eax
01262370    8A43 01         mov   al, byte ptr              ; index1
01262373    8D0440          lea   eax, dword ptr
01262376    8B55 F4         mov   edx, dword ptr
01262379    8B5482 68       mov   edx, dword ptr
0126237D    8B06            mov   eax, dword ptr
0126237F    FFD2            call    edx                              ; mov eax,byte ptr
01262381    8BD8            mov   ebx, eax
01262383    EB 01         jmp   short 01262386
01262385    90            nop
01262386    8D45 E4         lea   eax, dword ptr
01262389    50            push    eax                              ; 用于保存计算结果的地址指针
0126238A    66:8B4D EC      mov   cx, word ptr             ; API所用的DLL名称HASH
0126238E    66:8B55 E8      mov   dx, word ptr             ; API名称字符串HASH
01262392    8B45 F4         mov   eax, dword ptr          ; 基本数据
01262395    E8 02F7FFFF   call    01261A9C                         ; 查找API相关HASH并获取API地址
0126239A    84C0            test    al, al
0126239C    8B45 F4         mov   eax, dword ptr
0126239F    8B80 E0000000   mov   eax, dword ptr           ; offset
012623A5    0345 E4         add   eax, dword ptr           ; 计算结果+offset:API实际地址
012623A8    8945 FC         mov   dword ptr , 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,
8:mov eax,
2:mov eax,
6:mov eax,byte ptr
3:mov eax,
1:mov eax,byte ptr
分析到这里就可以得到还原跳转表的思路了:对每一个数据组计算出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
00689F07    8B18            mov   ebx, dword ptr              ; 基本数据
00689F09    8BBB E0000000   mov   edi, dword ptr           ; offset
00689F0F    8B6B 18         mov   ebp, dword ptr           ; 待修正跳转表地址数量
00689F12    8B73 54         mov   esi, dword ptr           ; 修正跳转表所用的数据组的基址
00689F15    83FD 00         cmp   ebp, 0
00689F18    74 71         je      short 00689F8B                   ; 循环结束?
00689F1A    8B46 2C         mov   eax, dword ptr           ; [+2C]
00689F1D    03C7            add   eax, edi                         ; [+2C]+offset
00689F1F    50            push    eax
00689F20    33C0            xor   eax, eax
00689F22    8A06            mov   al, byte ptr                ; [+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           ; 计算代码段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           ; [+20]+offset+hash
00689F40    8B4E 09         mov   ecx, dword ptr
00689F43    03C8            add   ecx, eax                         ; [+9]+[+20]+offset+hash
00689F45    8B56 11         mov   edx, dword ptr
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              ; 查找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          ; 找到API时:
00689F74    0343 24         add   eax, dword ptr           ; [+4]+baseoffset
00689F77    03C7            add   eax, edi                         ; 计算出待修复跳转表的位置:[+4]+baseoffset+offset
00689F79    66:C700 FF25    mov   word ptr , 25FF             ; 写入JMP
00689F7E    40            inc   eax
00689F7F    40            inc   eax
00689F80    8910            mov   dword ptr , edx             ; 写入跳转表地址
00689F82    03B3 E4000000   add   esi, dword ptr           ; 取下一个数据组
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!

iawen 发表于 2009-1-14 22:36

这么精彩的文章,还是让小生哥给转过来了,呵呵

:D

石头学破解 发表于 2009-1-15 00:02

好文,又长知识了,谢谢小生!

小生我怕怕 发表于 2009-1-15 15:33

原帖由 chenguo 于 2009-1-14 22:36 发表 http://www.52pojie.cn/images/common/back.gif
这么精彩的文章,还是让小生哥给转过来了,呵呵

:D
这文的确写得很好啊!

qifeon 发表于 2009-1-15 17:13

精彩,真辛苦啊。
页: [1]
查看完整版本: ASPR学习笔记(二):还原跳转表 作者:lelfei