• 标 题:脱Advanced Email Extractor PRO的壳 (19千字)
  • 作 者:fs0
  • 时 间:2001-8-19 19:10:30
  • 链 接:http://bbs.pediy.com

Advanced Email Extractor PRO
http://www.mailutilities.com/aee/aeepro.zip

首先说说Asprotect的反跟踪代码, SEH(Structure Exception Handling)当然是时下流行的

Exception Handler:
016F:00E6097B  MOV      EAX,[ESP+0C]              ;EAX 是指向 CONTEXT record 的指针
016F:00E6097F  ADD      DWORD [EAX+B8],BYTE +02  ; [EAX+B8] 是产生异常的地址,这里加 2 就是 XOR [EAX],EAX 的下一条指令
016F:00E60986  PUSH    ECX
016F:00E60987  XOR      ECX,ECX
016F:00E60989  MOV      [EAX+04],ECX              ;clear dr0, 也就是清除断点, 呵呵我们有 SuperBPM 就不用担心了
016F:00E6098C  MOV      [EAX+08],ECX              ;clear dr1
016F:00E6098F  MOV      [EAX+0C],ECX              ;clear dr2
016F:00E60992  MOV      [EAX+10],ECX              ;clear dr3
016F:00E60995  MOV      DWORD [EAX+18],0155      ;clear global breakpoint enable flags
016F:00E6099C  POP      ECX
016F:00E6099D  XOR      EAX,EAX                  ;eax=0 reload context and continue execution
016F:00E6099F  RET   

016F:00E609A0  XOR      EAX,EAX
016F:00E609A2  PUSH    DWORD [FS:EAX]
016F:00E609A5  MOV      [FS:EAX],ESP
016F:00E609A8  XOR      [EAX],EAX                        ;raise exception, 代码是两个字节
016F:00E609AA  POP      DWORD `DOSMGR_BackFill_Allowed`  ;从这里继续执行
016F:00E609B1  POP      EAX


好, Load AeePro.exe
bpx getprocaddress
g
F12
bd *
F12
F8
F12
F8

来到:
016F:00E616E8  PUSH    EBP
016F:00E616E9  MOV      EBP,ESP
016F:00E616EB  ADD      ESP,BYTE -0C
016F:00E616EE  CALL    00E53130
016F:00E616F3  JNZ      NEAR 00E53E0C
016F:00E616F9  CALL    00E542C8
016F:00E616FE  CALL    00E58A88
016F:00E61703  CALL    00E5941C
016F:00E61708  CALL    00E5BF00
016F:00E6170D  CALL    00E53E0C    ;<--这里下断点, F8 跟进去
016F:00E61712  MOV      ESP,EBP      ;<--不会返回到这里
016F:00E61714  POP      EBP
016F:00E61715  RET      0C


上面的CALL 00E53E0C  F8 跟进去后, 用F8一步一步的跟, 当然要小心那些Exception啦
过不了多远, 来到:
016F:00E602F7  CALL    00E60336
016F:00E602FC  PUSH    DWORD 00E60305
016F:00E60301  INC      DWORD [ESP]
016F:00E60304  RET   

016F:00E60336  XOR      EAX,EAX
016F:00E60338  JMP      SHORT 00E6033C
016F:00E6033A  INT      20
016F:00E6033C  PUSH    DWORD [FS:EAX]
016F:00E6033F  JMP      SHORT 00E60342  ;跳到下面

016F:00E60342  MOV      [FS:EAX],ESP
016F:00E60345  XOR      [EAX],EAX      ;raise exception
016F:00E60347  JMP      SHORT 00E6034A  ;exception continue execution here, 将光标移到这里按 F7

来到:
016F:00E60355  POP      EAX
016F:00E60356  PUSH    DWORD 00E5E0EC  ;<--下断点 bpx 00E5E0EC
016F:00E6035B  PUSH    DWORD 00E6043C  ;g
016F:00E60360  PUSH    DWORD 00E5FAD8
016F:00E60365  PUSH    DWORD 00E5F788
016F:00E6036A  PUSH    DWORD 00E5F15C
016F:00E6036F  PUSH    DWORD 00E5EC04
016F:00E60374  PUSH    DWORD 00E5FE90
016F:00E60379  RET   


到 00E5E0EC 后 F12, F8, 来到:
016F:00E60DDC  PUSH    DWORD E6B8DCDB
016F:00E60DE1  PUSH    DWORD 2364
016F:00E60DE6  PUSH    DWORD EA74
016F:00E60DEB  PUSH    DWORD 00016000
016F:00E60DF0  PUSH    DWORD [00E63014]
016F:00E60DF6  CALL    00E60DFC                        ;这段代码自检运行过的代码, 不是这个call, 而是后面的代码, 被花指令盖过了
016F:00E60DFB  ADD      DWORD [EBX+78E804C4],E8FFFFBB  ;应该是 00E60DFF 的 CALL 00E5C97C
016F:00E60E05  ADD      [EAX],EAX                      ;如果你改了之前的代码, 后面就会出错
016F:00E60E07  ADD      [EAX],AL
016F:00E60E09  ADD      DWORD [EBX+043104C4],0001E824
016F:00E60E13  ADD      [EAX],AL
016F:00E60E15  PUSH    DWORD 8B04C483
016F:00E60E1A  ADD      EAX,00E63014
016F:00E60E1F  CALL    00E60E26      ;<--这里下断点 F8 跟进去
016F:00E60E24  CALL    05AA9191
016F:00E60E29  ADD      [ESP],EAX
016F:00E60E2C  RET   


跟进 00E60E26 后几下 F8, ret 后来到:
016F:00E5FE78  MOV      EAX,00E639C4
016F:00E5FE7D  MOV      EDX,0A
016F:00E5FE82  CALL    00E5C288
016F:00E5FE87  CALL    00E5FC9C
016F:00E5FE8C  RET   

往上看就是: (因为按逻辑是要跟进上面的 CALL 00E5FC9C ....还有很大一堆!!! 不多写了, 自己看着办吧)
016F:00E5FE62  CMP      DWORD [EAX],BYTE +00
016F:00E5FE65  JZ      00E5FE69
016F:00E5FE67  PUSH    DWORD [EAX]
016F:00E5FE69  PUSH    DWORD [EBP-10]
016F:00E5FE6C  JMP      NEAR [EBP-14]  ;跳到 [EBP-14] 后就离 OEP 不远了, 那里是一堆“垃圾代码”, 看你的啦!

最后来到:
016F:00E76155  JC      00E7611A
016F:00E76157  POP      EBX
016F:00E76158  POP      EAX
016F:00E76159  ADD      EAX,76B922D4
016F:00E7615E  POP      ESP
016F:00E7615F  ADD      EAX,EBX
016F:00E76161  MOV      [ESP+1C],EAX
016F:00E76165  POPA   
016F:00E76166  JMP      EAX          ;Jump to EOP



;-----------------------------------------------------------------------------------
下面看看原程序的还原和Import Table的重建 (没有手动脱壳经验的, 就别往下看了, 很长的一部分!)
016F:00E5F1F0  JMP      SHORT 00E5F25C
016F:00E5F1F2  CALL    00E52568
016F:00E5F1F7  MOV      ESI,EAX
016F:00E5F1F9  MOV      EAX,[EBX]      ;[EBX]是Section RVA
016F:00E5F1FB  ADD      EAX,[EBP-14]  ;[EBP-14]是ImageBase
016F:00E5F1FE  MOV      [EBP-04],EAX
016F:00E5F201  MOV      ECX,[EBX+04]  ;[EBX+04]是Section size
016F:00E5F204  MOV      EDX,ESI
016F:00E5F206  MOV      EAX,[EBP-04]
016F:00E5F209  CALL    00E5ED00      ;还原
016F:00E5F20E  MOV      EDI,EAX
016F:00E5F210  CMP      EDI,[EBX+04]
016F:00E5F213  JZ      00E5F21F      ;还原OK就跳?
016F:00E5F215  MOV      EAX,00E5F2E0
016F:00E5F21A  CALL    00E5EB18
016F:00E5F21F  CMP      BYTE [EBP-05],00
016F:00E5F223  JNZ      00E5F243
016F:00E5F225  MOV      BYTE [EBP-05],01
016F:00E5F229  PUSH    ESI
016F:00E5F22A  MOV      ESI,[EBP-04]
016F:00E5F22D  ADD      ESI,BYTE +14
016F:00E5F230  PUSH    DWORD [ESI]
016F:00E5F232  MOV      BYTE [ESI],C3
016F:00E5F235  CALL    ESI
016F:00E5F237  POP      DWORD [ESI]
016F:00E5F239  POP      ESI
016F:00E5F23A  MOV      EDX,EDI
016F:00E5F23C  MOV      EAX,ESI
016F:00E5F23E  CALL    00E5ED20
016F:00E5F243  MOV      ECX,EDI
016F:00E5F245  MOV      EDX,ESI
016F:00E5F247  MOV      EAX,[EBP-04]
016F:00E5F24A  CALL    00E5449C      ;将还原后的data 复制到原程序的空间
016F:00E5F24F  MOV      EDX,[EBX+04]
016F:00E5F252  MOV      EAX,ESI
016F:00E5F254  CALL    00E52580
016F:00E5F259  ADD      EBX,BYTE +0C
016F:00E5F25C  MOV      EAX,[EBX+04]  ;eax = next section size
016F:00E5F25F  TEST    EAX,EAX
016F:00E5F261  JG      00E5F1F2      ;还没全部还原完就跳
016F:00E5F263  CMP      DWORD [EBP-0C],BYTE +00
016F:00E5F267  JZ      00E5F271
016F:00E5F269  MOV      EAX,[EBP-0C]
016F:00E5F26C  MOV      EDX,[EBP-10]
016F:00E5F26F  MOV      [EAX],EDX
016F:00E5F271  CALL    00E5F2B0
016F:00E5F276  PUSH    DWORD 00E5F27F
016F:00E5F27B  INC      DWORD [ESP]
016F:00E5F27E  RET   
;-----------------------------------------------------------------------------------


;===================================================================================
Import Table 的重定向
016F:00E5F962  PUSHA 
016F:00E5F963  CLD   
016F:00E5F964  MOV      ESI,[EBP-04]
016F:00E5F967  LODSD 
016F:00E5F968  OR      EAX,EAX
016F:00E5F96A  JZ      00E5F9B6        ;处理完所有DLL了吗? 是就跳
016F:00E5F96C  MOV      EDI,EAX        ;EAX --> Next IAT RVA
016F:00E5F96E  ADD      EDI,[00E63560]  ;[00E63560] --> ImageBase
016F:00E5F974  MOV      [EBP-08],EDI    ;EDI 指向该 DLL 的第一个 IAT
016F:00E5F977  MOV      EBX,ESI        ;ESI 指向 DLL Name
016F:00E5F979  XOR      ECX,ECX
016F:00E5F97B  DEC      ECX
016F:00E5F97C  XCHG    EDI,ESI
016F:00E5F97E  XOR      AL,AL
016F:00E5F980  REPNE SCASB
016F:00E5F982  XCHG    EDI,ESI
016F:00E5F984  LODSB 
016F:00E5F985  CMP      AL,00
016F:00E5F988  JZ      00E5F967      ;该DLL处理完了吗?
016F:00E5F98A  CMP      AL,06        ;特殊Import function ?  如GetVersion, 下面有列出
016F:00E5F98D  JNZ      00E5F995      ;不是就跳(本想把这里改为jmp, 就以为可以得到完整的IAT, 可惜再细看后才发现该特殊Import function name根本就没有存起来!
016F:00E5F98F  ADD      DWORD [EBP-08],BYTE +04  ;是特殊Import function就跳过不处理, 后面有说这些是怎么处理的
016F:00E5F993  JMP      SHORT 00E5F984
016F:00E5F995  PUSH    EBX          ;<--DLL name
016F:00E5F996  PUSH    ESI          ;<--Encrpyted Function Name
016F:00E5F997  PUSH    EBX
016F:00E5F998  LEA      EBX,[EBP-08]  ;<--IAT
016F:00E5F99B  PUSH    EBX
016F:00E5F99C  CMP      AL,02        ;import function by name or ord?
016F:00E5F99F  JZ      00E5F9A7
016F:00E5F9A1  MOVZX    ECX,BYTE [ESI]
016F:00E5F9A4  INC      ECX
016F:00E5F9A5  JMP      SHORT 00E5F9AC
016F:00E5F9A7  MOV      ECX,04
016F:00E5F9AC  ADD      ESI,ECX  ;esi --> end of Encrpyted Function by name or import function by ord?
016F:00E5F9AE  CALL    00E5F674  ;<--看下面的 00E5F674
016F:00E5F9B3  POP      EBX
016F:00E5F9B4  JMP      SHORT 00E5F984
016F:00E5F9B6  POPA   
016F:00E5F9B7  CALL    00E5F9F6
016F:00E5F9BC  PUSH    DWORD 00E5F9C5
016F:00E5F9C1  INC      DWORD [ESP]
016F:00E5F9C4  RET   


调用GetProcAddress, 生成重定向代码的函数:
016F:00E5F674  PUSH    EBP
016F:00E5F675  MOV      EBP,ESP
016F:00E5F677  ADD      ESP,FFFFFEFC
016F:00E5F67D  PUSH    EBX
016F:00E5F67E  PUSH    ESI
016F:00E5F67F  PUSH    EDI
016F:00E5F680  MOV      ESI,[EBP+10]
016F:00E5F683  MOV      EDI,[EBP+08]
016F:00E5F686  MOV      EAX,ESI
016F:00E5F688  DEC      EAX
016F:00E5F689  XOR      EBX,EBX
016F:00E5F68B  MOV      BL,[EAX]
016F:00E5F68D  LEA      EAX,[EBP+FFFFFEFF]
016F:00E5F693  XOR      ECX,ECX
016F:00E5F695  MOV      EDX,0100
016F:00E5F69A  CALL    00E52768      ;<--清空eax指向的空间
016F:00E5F69F  MOV      EAX,EBX
016F:00E5F6A1  DEC      EAX
016F:00E5F6A2  SUB      EAX,BYTE +02
016F:00E5F6A5  JC      00E5F700
016F:00E5F6A7  JZ      NEAR 00E5F772
016F:00E5F6AD  DEC      EAX
016F:00E5F6AE  JZ      00E5F700
016F:00E5F6B0  DEC      EAX
016F:00E5F6B1  JNZ      NEAR 00E5F77B
016F:00E5F6B7  MOV      AL,[ESI]
016F:00E5F6B9  MOV      [EBP-01],AL
016F:00E5F6BC  INC      ESI
016F:00E5F6BD  XOR      EBX,EBX
016F:00E5F6BF  MOV      BL,[EBP-01]
016F:00E5F6C2  MOV      ECX,EBX
016F:00E5F6C4  LEA      EAX,[EBP+FFFFFEFF]
016F:00E5F6CA  MOV      EDX,ESI
016F:00E5F6CC  CALL    00E5449C    ;<--Copy encrypted function name to eax 指向的空间
016F:00E5F6D1  PUSH    BYTE +0A
016F:00E5F6D3  MOV      ECX,00E639BA
016F:00E5F6D8  MOV      EDX,EBX
016F:00E5F6DA  LEA      EAX,[EBP+FFFFFEFF]
016F:00E5F6E0  CALL    00E5C3E0            ;<--还原Import Function Name
016F:00E5F6E5  LEA      ESI,[EBP+FFFFFEFF]  ;<--esi指向Import Function Name
016F:00E5F6EB  PUSH    ESI
016F:00E5F6EC  MOV      EAX,[EBP+0C]        ;<--eax 指向 dll name
016F:00E5F6EF  PUSH    EAX
016F:00E5F6F0  CALL    00E5F30C            ;<--GetProcAddress by name,在eax返回地址
016F:00E5F6F5  CALL    00E5F578            ;<--(下面有说明) 在返回的eax指向的空间生成跳到Import Function的代码?
                                            ;可以将这句 call nop 掉, 直接将 EAX 放到 [EDX] 中,
                                            ;整个输入表就差那些特殊的 Import functions 了要重建了
                                            ;(当然Import REConstructor v1.2已经可以重建改输入表了, 不用这么麻烦)
                                            ;要是真的改了该代码, 要在处理完所有的 DLL 后, 还原该代码, 因为后面有自检
016F:00E5F6FA  MOV      EDX,[EDI]
016F:00E5F6FC  MOV      [EDX],EAX          ;<-- 重定向IAT?
016F:00E5F6FE  JMP      SHORT 00E5F77B      ;<--完成

016F:00E5F700  CMP      EBX,BYTE +01      ;encrypted funciont name?
016F:00E5F703  JZ      00E5F70A
016F:00E5F705  CMP      EBX,BYTE +04      ;Import function by ord?
016F:00E5F708  JNZ      00E5F741
016F:00E5F70A  MOV      AL,[ESI]
016F:00E5F70C  MOV      [EBP-01],AL
016F:00E5F70F  INC      ESI
016F:00E5F710  XOR      ECX,ECX
016F:00E5F712  MOV      CL,[EBP-01]
016F:00E5F715  LEA      EAX,[EBP+FFFFFEFF]
016F:00E5F71B  MOV      EDX,ESI
016F:00E5F71D  CALL    00E5449C            ;copy encrypted function name to [eax]
016F:00E5F722  PUSH    BYTE +0A
016F:00E5F724  MOV      ECX,00E639B0
016F:00E5F729  XOR      EDX,EDX
016F:00E5F72B  MOV      DL,[EBP-01]
016F:00E5F72E  LEA      EAX,[EBP+FFFFFEFF]
016F:00E5F734  CALL    00E5C3E0            ;decrypt function name
016F:00E5F739  LEA      ESI,[EBP+FFFFFEFF]
016F:00E5F73F  JMP      SHORT 00E5F743
016F:00E5F741  MOV      ESI,[ESI]
016F:00E5F743  CMP      EBX,BYTE +04
016F:00E5F746  JNZ      00E5F762
016F:00E5F748  PUSH    ESI                ;<--Import function name is GetProcAddress ?
016F:00E5F749  MOV      EAX,[EBP+0C]
016F:00E5F74C  PUSH    EAX
016F:00E5F74D  CALL    00E5F30C
016F:00E5F752  MOV      [00E6355C],EAX
016F:00E5F757  MOV      EAX,00E5C490      ;<--00E5C490 处的代码自己看吧, 应该是 GetProcAddress
016F:00E5F75C  MOV      EDX,[EDI]
016F:00E5F75E  MOV      [EDX],EAX
016F:00E5F760  JMP      SHORT 00E5F77B
016F:00E5F762  PUSH    ESI            ;<--esi指向Import Function Name or esi is import function ord
016F:00E5F763  MOV      EAX,[EBP+0C]
016F:00E5F766  PUSH    EAX            ;<--eax 指向 dll name
016F:00E5F767  CALL    00E5F30C        ;<--GetProcAddress by ord,在eax返回地址
016F:00E5F76C  MOV      EDX,[EDI]
016F:00E5F76E  MOV      [EDX],EAX
016F:00E5F770  JMP      SHORT 00E5F77B
016F:00E5F772  MOV      EAX,00E5C468
016F:00E5F777  MOV      EDX,[EDI]
016F:00E5F779  MOV      [EDX],EAX

016F:00E5F77B  ADD      DWORD [EDI],BYTE +04
016F:00E5F77E  POP      EDI
016F:00E5F77F  POP      ESI
016F:00E5F780  POP      EBX
016F:00E5F781  MOV      ESP,EBP
016F:00E5F783  POP      EBP
016F:00E5F784  RET      0C



生成跳到真正Import Function地址的代码:
016F:00E5F578  PUSH    EBX
016F:00E5F579  PUSH    ESI
016F:00E5F57A  PUSH    EDI
016F:00E5F57B  PUSH    EBP
016F:00E5F57C  ADD      ESP,BYTE -10
016F:00E5F57F  MOV      [ESP],EAX
016F:00E5F582  MOV      EAX,C8
016F:00E5F587  CALL    00E52568
016F:00E5F58C  MOV      [ESP+04],EAX
016F:00E5F590  MOV      EAX,[ESP+04]
016F:00E5F594  MOV      [ESP+08],EAX
016F:00E5F598  MOV      EBP,[ESP]
016F:00E5F59B  CALL    00E5F524
016F:00E5F5A0  MOV      EBX,EAX
016F:00E5F5A2  MOV      BYTE [ESP+0C],00
016F:00E5F5A7  MOVZX    ESI,BYTE [EBX]
016F:00E5F5AA  LEA      EAX,[EBX+01]
016F:00E5F5AD  MOVZX    EDI,BYTE [EAX]
016F:00E5F5B0  LEA      EDX,[EBX+02]
016F:00E5F5B3  MOV      ECX,ESI
016F:00E5F5B5  MOV      EAX,EBP
016F:00E5F5B7  CALL    00E5BF44
016F:00E5F5BC  TEST    AL,AL
016F:00E5F5BE  JZ      00E5F5D8
016F:00E5F5C0  MOV      ECX,EDI
016F:00E5F5C2  MOV      EDX,EBP
016F:00E5F5C4  MOV      EAX,[ESP+08]
016F:00E5F5C8  CALL    00E5449C
016F:00E5F5CD  ADD      [ESP+08],EDI
016F:00E5F5D1  ADD      EBP,EDI
016F:00E5F5D3  MOV      BYTE [ESP+0C],01
016F:00E5F5D8  ADD      ESI,BYTE +02
016F:00E5F5DB  ADD      EBX,ESI
016F:00E5F5DD  CMP      BYTE [ESP+0C],00
016F:00E5F5E2  JNZ      00E5F5E9
016F:00E5F5E4  CMP      BYTE [EBX],00
016F:00E5F5E7  JNZ      00E5F5A7
016F:00E5F5E9  CMP      BYTE [ESP+0C],00
016F:00E5F5EE  JNZ      00E5F59B
016F:00E5F5F0  CALL    00E52698
016F:00E5F5F5  MOV      ESI,[ESP+08]
016F:00E5F5F9  SUB      ESI,[ESP+04]
016F:00E5F5FD  LEA      EAX,[ESI+06]
016F:00E5F600  CALL    00E52568
016F:00E5F605  MOV      EBX,EAX
016F:00E5F607  MOV      ECX,ESI
016F:00E5F609  MOV      EDI,[ESP+04]
016F:00E5F60D  MOV      EDX,EDI
016F:00E5F60F  MOV      EAX,EBX
016F:00E5F611  CALL    00E5449C
016F:00E5F616  MOV      EBP,EBX
016F:00E5F618  ADD      EBP,ESI
016F:00E5F61A  MOV      [ESP+08],EBP
016F:00E5F61E  MOV      EAX,02
016F:00E5F623  CALL    00E52788
016F:00E5F628  SUB      EAX,BYTE +01
016F:00E5F62B  JNC      00E5F647
016F:00E5F62D  MOV      EAX,[ESP+08]
016F:00E5F631  MOV      BYTE [EAX],E9  ;<--jmp的代码, 上面的不说了
016F:00E5F634  ADD      EBP,BYTE +05
016F:00E5F637  MOV      EAX,[ESP]
016F:00E5F63A  SUB      EAX,EBP
016F:00E5F63C  ADD      ESI,EAX
016F:00E5F63E  MOV      EAX,[ESP+08]
016F:00E5F642  INC      EAX
016F:00E5F643  MOV      [EAX],ESI
016F:00E5F645  JMP      SHORT 00E5F662
016F:00E5F647  MOV      EAX,[ESP+08]  ;[ESP+08]是要修改的代码的首址
016F:00E5F64B  MOV      BYTE [EAX],68  ;<--push的代码
016F:00E5F64E  ADD      ESI,[ESP]      ;[ESP] 为真正的Import Function Address, 如 [ESP] = BFF72535,
016F:00E5F651  MOV      EAX,[ESP+08]  ;而ESI就是push前的代码字节数, 如 ESI = 1
016F:00E5F655  INC      EAX            ;eax为下一个要修改的代码地址
016F:00E5F656  MOV      [EAX],ESI      ;exp: 如果 上面的ESI = 1, [ESP] = BFF72535, 则这时的 ESI = BFF72536
016F:00E5F658  MOV      EAX,[ESP+08]  ;[ESP+08]是要修改的代码的首址
016F:00E5F65C  ADD      EAX,BYTE +05  ;PUSH XXXXXXXX 为 5 个字节
016F:00E5F65F  MOV      BYTE [EAX],C3  ;ret 代码
016F:00E5F662  MOV      EAX,EDI
016F:00E5F664  CALL    00E52580
016F:00E5F669  MOV      EAX,EBX
016F:00E5F66B  ADD      ESP,BYTE +10
016F:00E5F66E  POP      EBP
016F:00E5F66F  POP      EDI
016F:00E5F670  POP      ESI
016F:00E5F671  POP      EBX
016F:00E5F672  RET   


处理特殊Import functions:
016F:00E5FA60  PUSHA 
016F:00E5FA61  PUSH    DWORD 00E621F0
016F:00E5FA66  LEA      EAX,[EBP-0C]
016F:00E5FA69  PUSH    DWORD [00E63560]
016F:00E5FA6F  CALL    NEAR [EAX]        ;call 下面的 00E71238
016F:00E5FA71  POPA   


016F:00E71238  CALL    00E7123D
016F:00E7123D  POP      EBP
016F:00E7123E  CLD   
016F:00E7123F  LEA      ESI,[EBP+2F]  ;ESI指向特殊Import function的相关信息
016F:00E71242  XOR      EAX,EAX
016F:00E71244  LODSB 
016F:00E71245  OR      AL,AL
016F:00E71247  JZ      00E71265      ;完了吗?
016F:00E71249  DEC      AL
016F:00E7124B  SHL      EAX,02
016F:00E7124E  ADD      EAX,[ESP+08]  ;[ESP+08]就是指向第一个特殊Import function的重定向地址, 我看到的就有 10 个这样的functions
016F:00E71252  MOV      EBX,[EAX]    ;EBX为该特殊Import function的重定向地址
016F:00E71254  LODSD                  ;该EBX指向的代码如: mov eax, [xxxxxxxx]
016F:00E71255  ADD      EAX,[ESP+04]  ;                  ret , 这些就是我们要手动修改的 IAT
016F:00E71259  MOV      [EAX],EBX    ;EAX指向 IAT
016F:00E7125B  XOR      EAX,EAX
016F:00E7125D  MOV      [ESI-04],EAX  ;clear
016F:00E71260  MOV      [ESI-05],AL  ;clear
016F:00E71263  JMP      SHORT 00E71244
016F:00E71265  RET      08


特殊的Import functions:
016F:00E5C7D8  PUSH    BYTE +00
016F:00E5C7DA  CALL    `KERNEL32!GetModuleHandleA`
016F:00E5C7DF  MOV      [00E635D4],EAX
016F:00E5C7E4  CALL    `KERNEL32!GetVersion`
016F:00E5C7E9  MOV      [00E635D8],EAX
016F:00E5C7EE  PUSH    DWORD 00E635E4
016F:00E5C7F3  CALL    `KERNEL32!GetVersionExA`
016F:00E5C7F8  CALL    `KERNEL32!GetCurrentProcess`
016F:00E5C7FD  MOV      [00E635DC],EAX
016F:00E5C802  CALL    `KERNEL32!GetCurrentProcessId`
016F:00E5C807  MOV      [00E635E0],EAX
016F:00E5C80C  CALL    `KERNEL32!GetCommandLineA`
016F:00E5C811  MOV      [00E63678],EAX
016F:00E5C816  RET   
016F:00E5C817  NOP   

016F:00E5C818  PUSH    EBP              ;<--第一个特殊Import function 是 KERNEL32!GetModuleHandleA
016F:00E5C819  MOV      EBP,ESP
016F:00E5C81B  MOV      EAX,[EBP+08]
016F:00E5C81E  TEST    EAX,EAX
016F:00E5C820  JNZ      00E5C829
016F:00E5C822  MOV      EAX,[00E63560]
016F:00E5C827  JMP      SHORT 00E5C82F
016F:00E5C829  PUSH    EAX
016F:00E5C82A  CALL    `KERNEL32!GetModuleHandleA`
016F:00E5C82F  POP      EBP
016F:00E5C830  RET      04
016F:00E5C833  NOP   

016F:00E5C834  MOV      EAX,[00E635D8]    ;<--第二个 KERNEL32!GetVersion
016F:00E5C839  RET   
016F:00E5C83A  MOV      EAX,EAX

016F:00E5C83C  PUSH    EBP              ;<--第三个(暂时没见过哪个被加壳的软件有用到, 不知道是什么, 知道的朋友请指出!)
016F:00E5C83D  MOV      EBP,ESP
016F:00E5C83F  PUSH    ESI
016F:00E5C840  PUSH    EDI
016F:00E5C841  MOV      EAX,[EBP+08]
016F:00E5C844  MOV      EDI,EAX
016F:00E5C846  MOV      ESI,00E635E4
016F:00E5C84B  MOV      ECX,25
016F:00E5C850  REP MOVSD
016F:00E5C852  MOV      AL,01
016F:00E5C854  POP      EDI
016F:00E5C855  POP      ESI
016F:00E5C856  POP      EBP
016F:00E5C857  RET      04
016F:00E5C85A  MOV      EAX,EAX

016F:00E5C85C  MOV      EAX,[00E635DC]    ;<--第四个 GetCurrentProcess
016F:00E5C861  RET   
016F:00E5C862  MOV      EAX,EAX

016F:00E5C864  MOV      EAX,[00E635E0]    ;<--第五个 GetCurrentProcessId
016F:00E5C869  RET   
016F:00E5C86A  MOV      EAX,EAX

016F:00E5C86C  MOV      EAX,[00E63678]    ;<--第六个 GetCommandLineA
016F:00E5C871  RET   
016F:00E5C872  MOV      EAX,EAX

016F:00E5C874  PUSH    EBP              ;<--第七个 KERNEL32!LockResource
016F:00E5C875  MOV      EBP,ESP
016F:00E5C877  POP      EBP
016F:00E5C878  RET      04
016F:00E5C87B  NOP   

016F:00E5C87C  PUSH    EBP              ;<--第八个 KERNEL32!FreeResource
016F:00E5C87D  MOV      EBP,ESP
016F:00E5C87F  POP      EBP
016F:00E5C880  RET      04
016F:00E5C883  NOP   

016F:00E5C884  PUSH    EBP              ;<--第九个(这个也不知道是什么!)
016F:00E5C885  MOV      EBP,ESP
016F:00E5C887  MOV      EAX,[EBP+0C]
016F:00E5C88A  ADD      EAX,BYTE +04
016F:00E5C88D  MOV      EAX,[EAX]
016F:00E5C88F  ADD      EAX,[EBP+08]
016F:00E5C892  POP      EBP
016F:00E5C893  RET      08
016F:00E5C896  MOV      EAX,EAX

016F:00E5C898  PUSH    EBP              ;<--第十个
016F:00E5C899  MOV      EBP,ESP
016F:00E5C89B  PUSH    EBX
016F:00E5C89C  MOV      EBX,[EBP+08]
016F:00E5C89F  MOV      EAX,[EBP+18]
016F:00E5C8A2  PUSH    EAX
016F:00E5C8A3  MOV      EAX,[EBP+14]
016F:00E5C8A6  PUSH    EAX
016F:00E5C8A7  MOV      EAX,[EBP+10]
016F:00E5C8AA  PUSH    EAX
016F:00E5C8AB  PUSH    BYTE +05
016F:00E5C8AD  MOV      EAX,[EBP+0C]
016F:00E5C8B0  PUSH    EAX
016F:00E5C8B1  PUSH    EBX
016F:00E5C8B2  CALL    `KERNEL32!FindResourceA`
016F:00E5C8B7  PUSH    EAX
016F:00E5C8B8  PUSH    EBX
016F:00E5C8B9  CALL    `KERNEL32!LoadResource`
016F:00E5C8BE  PUSH    EAX
016F:00E5C8BF  CALL    `KERNEL32!LockResource`
016F:00E5C8C4  PUSH    EAX
016F:00E5C8C5  PUSH    EBX
016F:00E5C8C6  CALL    `USER32!DialogBoxIndirectParamA`
016F:00E5C8CB  POP      EBX
016F:00E5C8CC  POP      EBP
016F:00E5C8CD  RET      14

其中最特殊的是第十个的DialogBoxIndirectParamA, 但在 AeePro 中没有用到,
要是用到的话, 可以将该段代码dump下来, 加到脱壳后的程序上去, 再改该 IAT 指向我们加上去的代码的地址。
这十个特殊函数我想在 1.2, 1.3 中是一样的。
除了上面的特殊函数以外, Asprotect 提供的 API 我们也应该注意, 这我就没仔细研究了。

用Asprotect加壳的程序, 脱壳后不能运行, 我知道的有:
1. 原程序调用Asprotect的"Export Function", 最简单的就是:
  push ..
  push -1
  call GetProcAddress
看其返回值是否为0, 为0 就出错或退出(AeePro就是这样的)

2. 原程序自检加壳后的程序(已经加壳了, 真不知道他是怎么检的)。
3. Asprotect 调用原程序的“初始化”函数, 当到达 OEP 前, 某些全局变量已经初始化了, 脱壳后运行就很可能出错,
  解决方法是, 修改脱壳后的程序, 先运行该“初始化”函数, 再跳会到 OEP 运行就可以了。
4. 再有就是DialogBoxIndirectParamA等的了。

当然应该还有其他的。
唉, 好长的一篇!(~!@#$%^&*台下的别扔果皮:)