【前言】

by hkfans

这个壳的这个版本主要以TLS为主线展开的... 两个TLS函数的调用完成了壳大部分过程

第一个TLS回调函数: 解压各个区段的数据,修改E8 E9 的偏移量,再获取几个API函数的地址,如GetModuleHandleA...
第二个TLS回调函数: 加载部分IAT的数据。。因为这个壳可以支持动态Import。。所以部分在这个TLS函数处理。。另外部分动态加载,也就是当调用到的时候在获取(只获取一次)

当两个TLS回调函数执行完毕后,就进入EP处代码... 所以EP处的代码是会被执行的.....

另外,这个壳有很多检测INT3断点的代码。。会检测EP处, VMOEP处, TLS回调函数 等函数地址处的INT3断点..
检测API函数的全部指令是否被设软件断点....通过 SEH 检测硬件断点.

ps:  有个不理解的问题.. 有的地方设置硬件断点不会被检测到。。有的设置硬件断点会被检测到。。SOD照样还是那样设置。。。呵呵

OK.. 下面就按照每个TLS进行分析

【分析过程】

【第一个TLS回调函数】

代码:
对第一个TLS回调函数下段点.. 断到这里  ===> 然后就是后面的内容了...

00628BEF    E8 53F4FFFF       call    00628047


===========================================================================

1.  检测了TLS第一个回调函数头部是否设置了 INT3 软件断点。。。

              
// [00628BEF] = E8 CALL   ----> 计算公式:  ([00628BEF] - 0x99) * [00628BEF] = (0xe8 - 0x99 ) * 0xe8 = 0x98 (一个字节)

// 如果是 INT3断点的话 ---> (0xCC - 0x99) * 0xCC = 0xA4



0062804B   0F89 35030000         jns     00628386
006288D7                         push    ebp                               Morph instruction
006285B8   0F89 7CFAFFFF         jns     0062803A
0062803A   8BEC                  mov     ebp, esp
0062803F                         push    ecx                               Morph instruction
00628D79   8D05 EF8B6200         lea     eax, dword ptr [628BEF]
0062985C                         push    00629505                          Morph instruction
0062890F                         push    ebp                               Morph instruction
00628912   8BEC                  mov     ebp, esp
00628096                         push    ecx                               Morph instruction
00628099   8945 FC               mov     dword ptr [ebp-4], eax
0062809C                         mov     eax, FFFFFFFC                     eax = FFFFFFFC
00629479   03C5                  add     eax, ebp
00629481   8B00                  mov     eax, dword ptr [eax]
00629298   8A00                  mov     al, byte ptr [eax]
0062929A   2C 99                 sub     al, 99
0062929C                         mov     edx, D4237042                     edx = D4237042
006295FA   F7C2 00040000         test    edx, 400
00629688   0F84 95FBFFFF         je      00629223
006288FB   81F2 53E2FF84         xor     edx, 84FFE253
00628901   03D5                  add     edx, ebp
006284AD   81C2 EB6D23AF         add     edx, AF236DEB
006284B3   8B12                  mov     edx, dword ptr [edx]
006284B5   F62A                  imul    byte ptr [edx]
0062888B   3C A4                 cmp     al, 0A4
0062888D   0F85 EA0D0000         jnz     0062967D
00629682                         pop    ecx                                Morph instruction
00629448                         pop    ebp                                Morph instruction
00629449   C3                    retn


// codeclean 之后返回到这里 ..  ==> 006293D0 返回到TLS处理完毕收尾的地方...

00628B21                         push    006293D0                   Morph instruction    

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

这里修改指令为 0xC3 retn 是有目的的... TLS回调函数会被调用2次..  所以.. 这里修改为 0xC3
的目的就是区别第一次和第二次的流程。。不可能都走一样的路线的。。。

所以,这个 C3很关键...

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

// 自己指令的EIP ---> 填充为 0xC3  retn 指令....       
006297C2   8D05 C2976200         lea     eax, dword ptr [6297C2]  // 这里会变为 retn
0062950F   C600 C3               mov     byte ptr [eax], 0C3

================================================

00555108  00 10 40 00 1E 04 10 40 00 03 07 42 6F 6F 6C 65  .@.@.Boole

=================================================

00629512   B8 08515500           mov     eax, 00555108       // 存放压缩后的数据

00629517   0F83 67FAFFFF         jnb     00628F84      // 这里的很多 jnb js 指令其实是垃圾代码来着。只是不知道怎么确定
0062951D   0F88 42EDFFFF         js      00628265

00628815   8B10                  mov     edx, dword ptr [eax]    // edx = 00401000 --> 代码段起始地址
0062919F   09D2                  or      edx, edx
006291A1   0F84 9BF9FFFF         je      00628B42


00628549          push    edx    // edx = 00401000  
0062854C   57                    push    edi    // edi = 00400000


006290FF                         mov     edi, 00000004                     edi = 00000004
00628063   03C7                  add     eax, edi  // eax ==> 存放代码段压缩后的数据
00629468   5F                    pop     edi    
 

// 返回地址...                                                     
006281E0                         push     0062920A                        ; Morph instruction                             
00628630                         push     00627F50                        ; Morph instruction
00628633    C3                   retn                                    



3.  解压 被保护程序的代码段数据.... (下面的函数和前面调用的一样)....


//=============================================
// 比较执行该代码之前,都是0.。。 执行后 有被保护程序字符串数据。。。所以这段代码是解压被保护程序的代码
//

00627F50    56              push    esi
00627F51    57              push    edi
00627F52    53              push    ebx
00627F53    31DB            xor     ebx, ebx
00627F55    89C6            mov     esi, eax
00627F57    89D7            mov     edi, edx
00627F59    0FB606          movzx   eax, byte ptr [esi]
00627F5C    89C2            mov     edx, eax
00627F5E    83E0 1F         and     eax, 1F
00627F61    C1EA 05         shr     edx, 5
00627F64    74 2D           je      short 00627F93
00627F66    4A              dec     edx
00627F67    74 15           je      short 00627F7E
00627F69    8D5C13 02       lea     ebx, dword ptr [ebx+edx+2]
00627F6D    46              inc     esi
00627F6E    C1E0 08         shl     eax, 8
00627F71    89FA            mov     edx, edi
00627F73    0FB60E          movzx   ecx, byte ptr [esi]
00627F76    46              inc     esi
00627F77    29CA            sub     edx, ecx
00627F79    4A              dec     edx
00627F7A    29C2            sub     edx, eax
00627F7C    EB 32           jmp     short 00627FB0
00627F7E    C1E3 05         shl     ebx, 5
00627F81    8D5C03 04       lea     ebx, dword ptr [ebx+eax+4]
00627F85    46              inc     esi
00627F86    89FA            mov     edx, edi
00627F88    0FB70E          movzx   ecx, word ptr [esi]
00627F8B    29CA            sub     edx, ecx
00627F8D    4A              dec     edx
00627F8E    83C6 02         add     esi, 2
00627F91    EB 1D           jmp     short 00627FB0
00627F93    C1E3 04         shl     ebx, 4
00627F96    46              inc     esi
00627F97    89C1            mov     ecx, eax
00627F99    83E1 0F         and     ecx, 0F
00627F9C    01CB            add     ebx, ecx
00627F9E    C1E8 05         shr     eax, 5
00627FA1    73 07           jnb     short 00627FAA
00627FA3    43              inc     ebx
00627FA4    89F2            mov     edx, esi
00627FA6    01DE            add     esi, ebx
00627FA8    EB 06           jmp     short 00627FB0
00627FAA    85DB            test    ebx, ebx
00627FAC    74 0E           je      short 00627FBC
00627FAE  ^ EB A9           jmp     short 00627F59
00627FB0    56              push    esi
00627FB1    89D6            mov     esi, edx
00627FB3    89D9            mov     ecx, ebx
00627FB5    F3:A4           rep     movs byte ptr es:[edi], byte ptr>
00627FB7    31DB            xor     ebx, ebx
00627FB9    5E              pop     esi
00627FBA  ^ EB 9D           jmp     short 00627F59

00627FBC    89F0            mov     eax, esi    // 结构指针向下移动
00627FBE    5B              pop     ebx
00627FBF    5F              pop     edi
00627FC0    5E              pop     esi
00627FC1    C3              retn

===========================================================================

4. 解压完代码段数据后返回  0062920A

**************************************************************************
压缩数据的结构布局:

struct stCompressData
{
   DWORD  dest;      // 释放压缩数据的内存地址  --> eg. 00401000 -->(如果为0, 所以区段解压处理完毕)
   char  pData[MAX];    // 压缩后的数据
  
   DWORD sectionRawDataSize;  // 下面两个参数为了修复E8 E9的偏移量 (如果为0,解压下一个区段数据)
   DWORD sectionRVA;   
};

所以解压完一个段的数据后,eax 指针自动指向第二个结构的起始地址

00401000
data




***************************************************************************

// 005BC0A5 内存数据

005BC0A5  00 08 0C 00 00 20 4C 00 1B 32 13 8B C0 02 00 8B  .... L.2.
005BC0B5  C0 00 8D 40 00 E0 03 11 B4 49 A0 03 E0 00 01 1D  ?.???


// eax = 005BC0A5
0062920A    8B10               mov     edx, dword ptr [eax]  ; eax = 005BC0A5  edx = 000C0800
0062920C    52                 push    edx

// 安装 SEH..

0062920D    E8 CCF7FFFF           call    006289DE                        
006289DE    67:64:FF36 0000       push    dword ptr fs:[0]                
006287C9    67:64:8926 0000       mov     dword ptr fs:[0], esp    

// 一下修改 EFLAGS -->        TF标志位 --> 造成单步异常 -> 等同于指令 int1 --> 如果单步跟踪下去的话,程序运行..
// 因为正确的流程是设置了TF标志后,就相当于INT1指令.. INT1下面的代码不会被指令,会被执行就是错误的。。

006283BE    9C                    pushfd                                  
00629746    870424                xchg    dword ptr [esp], eax            
00629749    81C8 00010000         or      eax, 100                     ; TF = 1   
0062974F    870424                xchg    dword ptr [esp], eax     

// 这条指令造成单步异常...       
00629752    9D                    popfd     


// 直接 F4 到这里程序运行??? 流程是正确的走向???? [ 这里应该是错误的..刚好往下走是到退SEH的地方。。而且EBP可能修正。。所以才没出错 ]
//????????????????????????????????????????????????????????????????????????????????????                     
00628253    81D5 1D83E636         adc     ebp, 36E6831D                   
00627FF1    81CD B403DF7F       or      ebp, 7FDF03B4    ; ebp = 7FFF7FFF
00627FF7    C1E9 0C             shr     ecx, 0C
00627FFA   /0F8C 34070000       jl      00628734
//?????????????????????????????????????????????????????????????????????????????????????


// 退掉SEH....

00628000   |67:64:8F06 0000     pop     dword ptr fs:[0]            
00628006   |870424                xchg    dword ptr [esp], eax
00628009   |58                    pop     eax



0062891F    81E2 410EE038         and     edx, 38E00E41                   
00628925    81C2 5D2AEDAE         add     edx, AEED2A5D                   
0062892B    F7C2 40000000         test    edx, 40                         
0062807F    0F84 4F150000         je      006295D4                        
006295D4    81F2 9A328DBF         xor     edx, BF8D329A                   
006295E4    03C2                  add     eax, edx        ; edx = 4  eax = 005BC0A5 处的结构数据              
006295E6    5A                    pop     edx             ; edx = 000C0800

// 中间的SEH被codeclean...

00628F7C    870424                xchg    dword ptr [esp], eax            
006295A5    09D2                  or      edx, edx                        
006295A7    0F84 AB010000         je      00629758                        
00628786    0F85 000C0000         jnz     0062938C    

// 中间的SEH被codeclean...

00628027                          mov     esi, 629758                     ; esi = 629758  ==> 返回地址
006290A6    873424                xchg    dword ptr [esp], esi            
00628E56                          push    005550E0                        ; Morph instruction
00628E59    C3                    retn                                    
   

==================================================================

4. 返回到 005550E0.... 修正 被保护程序中所有的 E9 指令的偏离量...  


参数:

edx = 000C0800 (区段的RawDataSize)   eax = 00401000  ( 区段RVA )


<<<< 注意:  005550E0的计算方法:  --> E8 E9 都满足条件... >>>

 005550E0    56              push    esi
005550E1    51              push    ecx
005550E2    89C6            mov     esi, eax
005550E4    89D1            mov     ecx, edx
005550E6    83E9 04         sub     ecx, 4
005550E9    FC              cld


// 循环查找   所有的 E9 --> far jmp 指令

005550EA    AC              lods    byte ptr [esi]

005550EB    D0E8            shr     al, 1        
005550ED    80F8 74         cmp     al, 74    // 0xE9 / 2 = 0x74
005550F0    75 0E           jnz     short 00555100

// 如果是 jmp --> 处理跳转偏移量... 

005550F2    8B06            mov     eax, dword ptr [esi]  // [esi] --> 四字节偏离量..

// 交换32位寄存器内的字节顺序 比如:[EAX]=0123 4567H,执行指令: BSWAP EAX ;使[EAX]=6745 2301H .

005550F4    0FC8            bswap   eax
005550F6    01C8            add     eax, ecx    
005550F8    8906            mov     dword ptr [esi], eax  // 填充正确的偏离量数值
005550FA    83C6 04         add     esi, 4      // 
005550FD    83E9 04         sub     ecx, 4
00555100    49              dec     ecx        // ecx = C0800 --> 被保护程序代码段大小


00555101  ^ 7F E7           jg      short 005550EA
00555103    59              pop     ecx
00555104    5E              pop     esi
00555105    C3              retn


==================================================================

5. 返回到 00628B3C

005BC099                                      00 08 0C 00              ..
005BC0A9  00 20 4C 00 1B 32 13 8B C0 02 00 8B C0 00 8D 40  . L.2..




// 代码段大小 = 000C8000
// 第一个区段的开始地址= 004C2000

// eax = 005BC0A9

00628B3C                          pop    eax                              ; Morph instruction
00629517    0F83 67FAFFFF         jnb     00628F84                        
0062951D    0F88 42EDFFFF         js      00628265                        
00628815    8B10                  mov     edx, dword ptr [eax]            
0062919F    09D2                  or      edx, edx          ; edx = 004C2000                    
006291A1    0F84 9BF9FFFF         je      00628B42                        

006291A1    0F84 9BF9FFFF         je      00628B42                        
00628549                          push    edx                             ; Morph instruction
0062854C    57                    push    edi                             
006290FF                          mov     edi, 00000004                   ; edi = 00000004
00628063    03C7                  add     eax, edi               ; eax = 005BC0AD       
00629468    5F                    pop     edi                             
006281E0                          push    0062920A                        ; 这个是返回地址 --> 下面进入一个函数

// 跳去该函数
00628630                          push    00627F50                        ; Morph instruction
00628633    C3                    retn                                    


// 跳到这里..

00627F50    56                push    esi
00627F51    57                push    edi
00627F52    53                push    ebx
00627F53    31DB              xor     ebx, ebx


************************************************

注意和前面的是同一个函数.... 所以这个函数被调用了  多次。。解压多个区段<具体说是前几个区段>..

************************************************ 

// 解压缩数据到 004C2000  --> 压缩算法和前面的一样。。 (前面解压 00401000处的数据)...  (下面的函数和前面调用的一样)....

00627F55    89C6              mov     esi, eax      ; esi = eax = 005BC0AD
00627F57    89D7              mov     edi, edx      ; edi = 004C2000 


00627F59    0FB606            movzx   eax, byte ptr [esi]
00627F5C    89C2              mov     edx, eax
00627F5E    83E0 1F           and     eax, 1F
00627F61    C1EA 05           shr     edx, 5
00627F64    74 2D             je      short 00627F93
00627F66    4A                dec     edx
00627F67    74 15             je      short 00627F7E
00627F69    8D5C13 02         lea     ebx, dword ptr [ebx+edx+2]
00627F6D    46                inc     esi
00627F6E    C1E0 08           shl     eax, 8
00627F71    89FA              mov     edx, edi
00627F73    0FB60E            movzx   ecx, byte ptr [esi]
00627F76    46                inc     esi
00627F77    29CA              sub     edx, ecx
00627F79    4A                dec     edx
00627F7A    29C2              sub     edx, eax
00627F7C    EB 32             jmp     short 00627FB0
00627F7E    C1E3 05           shl     ebx, 5
00627F81    8D5C03 04         lea     ebx, dword ptr [ebx+eax+4]
00627F85    46                inc     esi
00627F86    89FA              mov     edx, edi
00627F88    0FB70E            movzx   ecx, word ptr [esi]
00627F8B    29CA              sub     edx, ecx
00627F8D    4A                dec     edx
00627F8E    83C6 02           add     esi, 2
00627F91    EB 1D             jmp     short 00627FB0
00627F93    C1E3 04           shl     ebx, 4
00627F96    46                inc     esi
00627F97    89C1              mov     ecx, eax
00627F99    83E1 0F           and     ecx, 0F
00627F9C    01CB              add     ebx, ecx
00627F9E    C1E8 05           shr     eax, 5
00627FA1    73 07             jnb     short 00627FAA
00627FA3    43                inc     ebx
00627FA4    89F2              mov     edx, esi
00627FA6    01DE              add     esi, ebx
00627FA8    EB 06             jmp     short 00627FB0
00627FAA    85DB              test    ebx, ebx
00627FAC    74 0E             je      short 00627FBC
00627FAE  ^ EB A9             jmp     short 00627F59
00627FB0    56                push    esi
00627FB1    89D6              mov     esi, edx
00627FB3    89D9              mov     ecx, ebx
00627FB5    F3:A4             rep     movs byte ptr es:[edi], byte ptr [esi]
00627FB7    31DB              xor     ebx, ebx
00627FB9    5E                pop     esi
00627FBA  ^ EB 9D             jmp     short 00627F59
00627FBC    89F0              mov     eax, esi
00627FBE    5B                pop     ebx
00627FBF    5F                pop     edi
00627FC0    5E                pop     esi
00627FC1    C3                retn

===================================================================

6.  返回到 0062920A  (上面也有调用这个函数...  有个异常)

0062920A    8B10              mov     edx, dword ptr [eax]    ; eax --> 前面解压缩数据接下来的地址  eax = 005D9272
0062920C    52                    push    edx                             
0062920D    E8 CCF7FFFF           call    006289DE           ; 第二类 SEH安装函数

// SEH 执行完返回到这里                 

006295E4    03C2                  add     eax, edx         ; eax  = 005D9276                 
006295E6    5A                    pop     edx                             
00628F7C    870424                xchg    dword ptr [esp], eax            
006295A5    09D2                  or      edx, edx  

$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$


// <<<< 这里下断点                ---> 判断所有区段是否都已解压数据完毕 >>>>
//  Exectryptor 把所有的数据全部压缩到 最后一个区段中..... -----------------------> 外壳的代码也是在最后一个区段中  /////


// 而且每次解压数据都是  eax --> 存放压缩后数据的内存地址    edx ---> 目的内存地址...

// 0062920A --> 解压完数据的出口
// 00629758 --> 修复E8 E9后的出口...


流程:

--> 循环结构获取结构数据  stCompressData --> 获取区段开始地址 ---> 判读是否为0 --> 不为0 调用 00627F50 解压数据函数 ---> 返回到 0062920A

--> 获取区段的大小  ---> 判段是否为0 --> 不为0 调用 00629758 修复 E8 E9  --> 返回到 00629758  ---> 再循环这个过程...

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


006295A7    0F84 AB010000         je      00629758         // 这个是判断每个区段是否有数据需要解压缩的... << PEID 查看区段信息 >>>


// eax = 005D9276   跳到这里...

00628F8A    8B10                  mov     edx, dword ptr [eax]     // edx = 004E7000       
00628E18    09D2                  or      edx, edx                        
00628E1A    0F84 22FDFFFF         je      00628B42                        
                 
00629017    9D                    popfd                                   
00629018    871424                xchg    dword ptr [esp], edx        // 返回地址:  006283C4    
00628F20    9C                    pushfd                                  
00628645    9D                    popfd                                   
00628646                          push    00627F50                        ; 这个是解压函数....
00628649    C3                    retn                                    


// 解压后返回到到  006283C4   --> 之前是 0062920A

006283C4    8B10                  mov     edx, dword ptr [eax]           ; eax = 005D9A0D 
006296DE    52                    push    edx                             
006296DF                          mov     edx, BCE8D362                   ; edx = BCE8D362
006296F7    F7C2 00000008         test    edx, 8000000                    
00629080    0F85 C2F7FFFF         jnz     00628848                        
00628848    81F2 66D3E8BC         xor     edx, BCE8D366                   
0062959F    03C2                  add     eax, edx                ; edx = 4          
006295A1    5A                    pop     edx                           ; edx = 0x3000 <<< 区段大小>>    
006295A2    870424                xchg    dword ptr [esp], eax            
006295A5    09D2                  or      edx, edx                        
006295A7    0F84 AB010000         je      00629758     


<<<< 注意:  005550E0的计算方法:  --> E8 E9 都满足条件... >>>

// 接下来调用 005550E0 --> 修复区段 004E7000 的 所有 jmp 和 call 的偏移量数值...
                 
00628786    0F85 000C0000         jnz     0062938C                        
006290A6                          push    00629758                        ; Morph instruction
00628E56                          push    005550E0                        ; Morph instruction
00628E59    C3                    retn                                    

//

006291FE    0F84 3EF9FFFF         je      00628B42                        
00629204    52                    push    edx                             
00628936    51                    push    ecx                             
00628937    E8 84010000           call    00628AC0                        


==================================================================================================

7. 所有区段的数据解压和修复完毕后返回到这里...  ==> 处理外壳自己的输入表..s获取外壳自己需要的一些API函数地址 


// 此时  eax = 00627F0D

00627F0D  00 00 00 00 00 00 00 00                          ........

006297A6    8B10                  mov     edx, dword ptr [eax]       ; eax =  00627F0D    
006297A8    56                    push    esi                             
006297A9                          mov     esi, 00000004                   ; esi = 00000004
006280FD    03C6                  add     eax, esi                        
006280FF    5E                    pop     esi                             
00628100    870424                xchg    dword ptr [esp], eax            
00628103    09D2                  or      edx, edx                        
00628105    0F84 4D160000         je      00629758                        
00628B3C                          pop    eax                              ; Morph instruction
00629517    0F83 67FAFFFF         jnb     00628F84                        
00628F84    0F88 DBF2FFFF         js      00628265                        
00628F8A    8B10                  mov     edx, dword ptr [eax]            
00628E18    09D2                  or      edx, edx                        
00628E1A    0F84 22FDFFFF         je      00628B42          ; = 0    
                
00628B42    E8 4A0E0000           call    00629991                      // 所有区段数据全部解压和修复完毕后返回到这
00629991    C3                    retn                                    

// 返回到 00628B47

00628B47                          mov     edx, 00627F40                   ; edx = 00627F40
00629714    8B02                  mov     eax, dword ptr [edx]            
00628671    68 5E7A4FB5           push    B54F7A5E                        
00628676    5A                    pop     edx                             
00628677    81C2 50E1FFBB         add     edx, BBFFE150                   
006284EC    0F85 61100000         jnz     00629553                        
00629553    81EA 788AA43C         sub     edx, 3CA48A78                   
00629589    81C2 9E43A3CB         add     edx, CBA3439E                   
0062958F    8902                  mov     dword ptr [edx], eax            ; EDX = 004E14D4 EAX = 0
0062949D    E8 21040000           call    006298C3                        


{
// 这个函数很好读。。哈哈

006298C3    55                    push    ebp
006298C4    8BEC                  mov     ebp, esp
006298C6    83C4 F4               add     esp, -0C
006298C9    56                    push    esi
006298CA    57                    push    edi
006298CB    53                    push    ebx

// esi = 004A7EEF

006298CC    BE EF7E4A00           mov     esi, 004A7EEF
006298D1    B8 00004000           mov     eax, 00400000                 ; ASCII "MZP"
006298D6    8945 FC               mov     dword ptr [ebp-4], eax
006298D9    89C2                  mov     edx, eax


//---------------------------------------------------------------
esi = 004A7EEF 数据结构 --> 壳的输入表结构s

struct stImport
{
   DWORD  IAT;


   DWORD  DLLname;
   DWORD  INT;

};

004A7EFF  83 7F 0A 00 C7 7F 0A 00 00 00 00 00 FF FF FF FF  ?..?......
004A7F0F  A7 7F 0A 00 C3 7F 0A 00 00 00 00 00 00 00 00 00  ?..?..........
004A7F1F  00 00 00 00 00 00 00 00 00 00 00 00 6B 65 72 6E  ............kern
004A7F2F  65 6C 33 32 2E 64 6C 6C 00 00 00 00 00 00 47 65  el32.dll......Ge
004A7F3F  74 4D 6F 64 75 6C 65 48 61 6E 64 6C 65 41 00 00  tModuleHandleA..
004A7F4F  00 00 4C 6F 61 64 4C 69 62 72 61 72 79 41 00 00  ..LoadLibraryA..
004A7F5F  00 00 47 65 74 50 72 6F 63 41 64 64 72 65 73 73  ..GetProcAddress
004A7F6F  00 00 00 00 00 00 45 78 69 74 50 72 6F 63 65 73  ......ExitProces
004A7F7F  73 00 00 00 3B 7F 0A 00 4F 7F 0A 00 5F 7F 0A 00  s...;..O.._..
004A7F8F  73 7F 0A 00 3B 7F 0A 00 4F 7F 0A 00 5F 7F 0A 00  s..;..O.._..
004A7F9F  73 7F 0A 00 00 00 00 00 75 73 65 72 33 32 2E 64  s......user32.d
004A7FAF  6C 6C 00 00 00 00 4D 65 73 73 61 67 65 42 6F 78  ll....MessageBox




//------------------------------------------------------------------
// [esi + c] = 000A7F2B


006298DB    8B46 0C               mov     eax, dword ptr [esi+C]
006298DE    09C0                  or      eax, eax
006298E0    0F84 99000000         je      0062997F
006298E6    01D0                  add     eax, edx  ; EAX = 00400000  EDX = 000A7F2B

006298E8    89C3                  mov     ebx, eax
006298EA    50                    push    eax
006298EB    FF15 94505500         call    dword ptr [<&kernel32.GetModu>; kernel32.GetModuleHandleA

006298F1    09C0                  or      eax, eax
006298F3    0F85 0F000000         jnz     00629908


// LoadLibrayA

006298F9    53                    push    ebx
006298FA    FF15 98505500         call    dword ptr [<&kernel32.LoadLib>; kernel32.LoadLibraryA


00629900    09C0                  or      eax, eax
00629902    0F84 62000000         je      0062996A

00629908    8945 F8               mov     dword ptr [ebp-8], eax
0062990B    6A 00                 push    0
0062990D    8F45 F4               pop     dword ptr [ebp-C]
00629910    8B06                  mov     eax, dword ptr [esi]
00629912    09C0                  or      eax, eax
00629914    8B55 FC               mov     edx, dword ptr [ebp-4]
00629917    0F85 03000000         jnz     00629920
0062991D    8B46 10               mov     eax, dword ptr [esi+10]
00629920    01D0                  add     eax, edx
00629922    0345 F4               add     eax, dword ptr [ebp-C]
00629925    8B18                  mov     ebx, dword ptr [eax]
00629927    8B7E 10               mov     edi, dword ptr [esi+10]
0062992A    01D7                  add     edi, edx
0062992C    037D F4               add     edi, dword ptr [ebp-C]
0062992F    09DB                  or      ebx, ebx
00629931    0F84 4F000000         je      00629986
00629937    F7C3 00000080         test    ebx, 80000000
0062993D    0F85 04000000         jnz     00629947
00629943    8D5C13 02             lea     ebx, dword ptr [ebx+edx+2]
00629947    81E3 FFFFFF0F         and     ebx, 0FFFFFFF
0062994D    53                    push    ebx
0062994E    FF75 F8               push    dword ptr [ebp-8]
00629951    FF15 9C505500         call    dword ptr [<&kernel32.GetProc>; kernel32.GetProcAddress
00629957    09C0                  or      eax, eax
00629959    0F84 0B000000         je      0062996A

// edi = 004A7F83  ===>  存到这里。。

0062995F    8907                  mov     dword ptr [edi], eax
00629961    8345 F4 04            add     dword ptr [ebp-C], 4
00629965  ^ E9 A6FFFFFF           jmp     00629910
0062996A    6A 10                 push    10
0062996C    6A 00                 push    0
0062996E    53                    push    ebx
0062996F    6A 00                 push    0
00629971    FF15 D4505500         call    dword ptr [<&user32.MessageBo>; user32.MessageBoxA
00629977    6A FF                 push    -1
00629979    FF15 A0505500         call    dword ptr [<&kernel32.ExitPro>; kernel32.ExitProcess
0062997F    5B                    pop     ebx
00629980    5F                    pop     edi
00629981    5E                    pop     esi
00629982    8BE5                  mov     esp, ebp
00629984    5D                    pop     ebp
00629985    C3                    retn

}  

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// 返回到  006294A2 ---> 修改 EP处的指令... <<< 这下面的几个地址都是关键地址???? >>>>
// 去掉OD下的EP软件断点,让OD在EP处段不下来.. 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

006294A2    C605 59946200 0F      mov     byte ptr [<ModuleEntryPoint>], 0F

// 修改第一个 TLS回调函数指令.. (去INT3断点)
006294A9    C605 EF8B6200 E8      mov     byte ptr [628BEF], 0E8

//
006294B0    C605 47806200 87      mov     byte ptr [628047], 87
006294B7    C605 4A806200 5E      mov     byte ptr [62804A], 5E
006294BE    C605 4B806200 0F      mov     byte ptr [62804B], 0F
006294C5    C3                    retn


// 返回到这里

006293D0    C745 FC 01000000      mov     dword ptr [ebp-4], 1
006293D7    E8 85F5FFFF           call    00628961

006293D0    C745 FC 01000000      mov     dword ptr [ebp-4], 1            
00628965                          mov     eax, B2DFBF52                   ; eax = B2DFBF52
00629720    D1C0                  rol     eax, 1                          
00628D5C    03C5                  add     eax, ebp                        
00628CEC    8B00                  mov     eax, dword ptr [eax]            ; eax= 0012F9C3  [eax] = 1
00628CF3                          pop    ecx                              ; Morph instruction
006297BE    5D                    pop     ebp     


// 这里返回到 系统调用 TLS 回调函数的代码处..                        
006297BF    C2 0C00               retn    0C            

{
7C92118A  |.  8BE6          mov     esp, esi
7C92118C  |.  5B            pop     ebx
7C92118D  |.  5F            pop     edi
7C92118E  |.  5E            pop     esi
7C92118F  |.  5D            pop     ebp
7C921190  \.  C2 1000       retn    10

}
【第二个回调函数】

============================================================================================================================

代码:
一些用到结构的定义:

第一张表的格式

struct stIatThunk
{
  DWORD  thunkOffset;    // 当前IAT块相对于前一个 IAT块的偏移 (第一个该结构的该数值就是IAT起始地址)
  DWORD  apiCount;    // 该IAT块对应的导入函数个数
};

第二张表的格式:

struct stTable2
{
  BYTE   by1;      // 索引第三张表用?
  BYTE   by2;      // 
  WORD   wd;      // 辅助获取API函数地址用?
  DWORD  ApiNameHashVal;  
};


第三张表的格式:

struct stDllEntry
{
  DWORD   dllModuleHandle;  // 模块基地址
  BYTE  encryptedDllName[n];  // 动态库名称字符串..加密后的.. 加载时会先解密..加载完动态库后又重新加密回去..
};


//
// 最最重要的修改IAT的代码:   ==> 对这个地址下段点拦截...
// 

0053210A    8902                  mov     dword ptr [edx], eax            ; 修改IAT的数据.. 说明已经加载了IAT项目的数据


00541A2F    8378 04 00      cmp     dword ptr [eax+4], 0    ; 处理每一个DLL的数据
00541A33  ^ 0F87 0CA8FEFF   ja      0052C245        ; 如果 = 0的话, 全部处理完毕?
00541A39  - E9 F4C5FAFF     jmp     004EE032



// 这里看到的是 GDI32.DLL oleaut32.DLL comctl32.dll 没有动态IAT, 而且每个API函数都有一个编号.. 按其在IAT表中的位置递增。。
//
//

=================================================================================================================================

1. 第二个TLS函数调用函数 0052F6DD..  ==> 这个函数的目的就是加载那些不需要动态Import的API函数


[ebp-4]      ==> 0051FF48 => BYTE* pIatThunk 指针..指向 stIatThunk结构数值
[ebp-8]    ==> 00542940  
[ebp-C]    ==> 00542D14

[ebp-28]    ==> curIatThunkFirstAddress 这个是当前IAT块的第一个项的地址.. 后一个Iat 块的地址就是这个数值 + 后一个stIatThunk.thunkOffset..
[ebp-2C]  ==> 当前stIatThunk结构的 apiCount

[ebp-18]  ==> curIatEntryAddress 存储每个IAT项的地址,区别于[ebp-28],因为[ebp-28] 只存储IAT块里面的第一个地址..
[ebp-20]  ==> 需要动态加载的API的个数..这个变量在这里没用..


            
0052F6DD    55                    push    ebp                             
0052F6DE    8BEC                  mov     ebp, esp                        
0052F6E0    0F83 F7FCFEFF         jnb     0051F3DD                        
0051F3DD    83C4 D0               add     esp, -30     
                   
0051F3E0    B8 48FF5100           mov     eax, 0051FF48                   
00550620    8945 FC               mov     dword ptr [ebp-4], eax          
00550623    B8 40295400           mov     eax, 00542940                   
00550628    8945 F8               mov     dword ptr [ebp-8], eax          
0055062B    B8 142D5400           mov     eax, 00542D14                   
00550630    8945 F4               mov     dword ptr [ebp-C], eax  
       
00550633    8D05 DDF65200         lea     eax, dword ptr [52F6DD]         ; 这里修改0052F6DD 为retn指令..第二次调用TLS函数的时候就不会在执行一次
00550639    C600 C3               mov     byte ptr [eax], 0C3             

0053BD05    33C0                  xor     eax, eax                        
0053BD07    8945 D8               mov     dword ptr [ebp-28], eax         

0053BD10                          mov     eax, -4                         ; eax = -4
00513A52    03C5                  add     eax, ebp                        
00513A5A    8B00                  mov     eax, dword ptr [eax]            ; [ebp-4]
00513A5C    8378 04 00            cmp     dword ptr [eax+4], 0            ; 比较当前stIatThunk.apiCount 是否大于0  (即是否包含了导出函数)
0052C5F3    0F87 4CFCFFFF         ja      0052C245          
              

==============================================> 从这里往下循环处理每个IAT Thunk

0052C245    8B45 FC               mov     eax, dword ptr [ebp-4]          
0052C248    8B00                  mov     eax, dword ptr [eax]            ; stIatThunk.thunkOffset (相对curIatThunkAddress的偏移量)
0052C24A    0145 D8               add     dword ptr [ebp-28], eax         ; curIatThunkFirstAddress

0052C24D    8B45 D8               mov     eax, dword ptr [ebp-28]         
0052C250    8945 E8               mov     dword ptr [ebp-18], eax         


0054B8A3                          mov     eax, -4                         ; eax = -4
0051C8FA    03C5                  add     eax, ebp                        
0051C902    8B00                  mov     eax, dword ptr [eax]            
005387AE    8B40 04               mov     eax, dword ptr [eax+4]          ; stIatThunk.apiCount
005387B1    85C0                  test    eax, eax                        
005387B3    0F8E E4D4FBFF         jle     004F5C9D                        ; 判段 stIatThunk.apiCount 是否小于等于0,如果是的话, pIatThunk += 8;
00527C5C    0F8F E51AFFFF         jg      00519747                        

00519747    53                    push    ebx                             
00519748                          mov     ebx, -2C                        ; ebx = -2C
0054B50D    03DD                  add     ebx, ebp                        
0054B515    8903                  mov     dword ptr [ebx], eax            ; 保存 当前stIatThunk.apiCount
0054B517    5B                    pop     ebx                             

00525B7C    C745 E0 01000000      mov     dword ptr [ebp-20], 1           

00541124                          mov     eax, -18                        ; eax = -18
0053AC3B    03C5                  add     eax, ebp                        
0053AC43    8B00                  mov     eax, dword ptr [eax]            
0054B321    F700 0000FFFF         test    dword ptr [eax], FFFF0000       ; 测试该IAT块的每个存放API的地址是否是正常的地址,如果是表示需要动态加载..这里不处理
0054B327    0F85 DF6DFEFF         jnz     0053210C                        ; 如果不是的话,由这里加载对应的API函数地址


0053210C    8345 E8 04            add     dword ptr [ebp-18], 4           ; 下一个IAT项地址
00532110    FF45 E0               inc     dword ptr [ebp-20]              ; 
00546A33    FF4D D4               dec     dword ptr [ebp-2C]              ; 初始为.stIatThunk.apiCount ==> while (count < stIatThunk.apiCount )
00546A36    0F85 47F1FDFF         jnz     00525B83                    ; 等于0.. 处理完当前的IAT块..
0052A0F8    0F84 9FBBFCFF         je      004F5C9D                        
004F5C9D    8345 FC 08            add     dword ptr [ebp-4], 8            ; 处理完该IAT块的所有IAT项后,处理下一个 stIatThunk结构


0052C30E                          mov     eax, -4                         ; eax = -4
00541A25    03C5                  add     eax, ebp                        
00541A2D    8B00                  mov     eax, dword ptr [eax]            
00541A2F    8378 04 00            cmp     dword ptr [eax+4], 0            ; stIatThunk.apiCount 是否大于0
00541A33    0F87 0CA8FEFF         ja      0052C245                        ; 拦截这个ja才能跟踪直到每个IAT块都处理完毕.. 前面那个ja不可以

00547994  ^\0F86 A248FEFF       jbe     0052C23C        // 所有IAT块都处理完毕后返回..退出函数
0052C23C    8BE5                mov     esp, ebp
0052C23E    5D                    pop     ebp
0052C23F    C3                    retn

0052C245    8B45 FC               mov     eax, dword ptr [ebp-4]          ; 否则的话..跳到前面的 0052C245 继续循环..


====================================================================================================================

2. 不是动态加载,即现在加载的IAT项的处理方法


// 变量

[ebp-24]  ==> 存储指向第二张表内数据项的地址 (通过Iat的数值<<8,计算得到)

[ebp-1C]  ==> 结构stDllEntry的地址.... (由IAT项的数值计算索引得到的)

[ebp-14]  ==> 保存获取到的第三张表的数据 

[ebp-10]  ==> 存储stDllEntry.encryptedDllName地址


// 数据个数下面.. 每个IAT的数值是一个编号数值..用于索引另外两张表

004E7238  00000000
004E723C  00000001
004E7240  00000002
004E7244  00000003
004E7248  00000004
004E724C  00000005
004E7250  00000006


005408EB                          mov     eax, -18                        ; eax = -18
0051A8B0    03C5                  add     eax, ebp                        
0051A8B8    8B00                  mov     eax, dword ptr [eax]            ; curIatEntryAddress
0051A8BA    8B00                  mov     eax, dword ptr [eax]            ; 取该IAT项存储的数值 IatValue..

0051A8BC    C1E0 03               shl     eax, 3                          ; Tab2Index = IatValue << 3 (左移三位得到的数值索引第二张表)
0051A8BF    0345 F8               add     eax, dword ptr [ebp-8]          ; Tab2Addr = Tab2Index + Tab2StartAddr;

004A93EC    8945 DC               mov     dword ptr [ebp-24], eax         
004A93EF                          mov     eax, -24                        ; eax = -24
004F8260    03C5                  add     eax, ebp                        
004F8268    8B00                  mov     eax, dword ptr [eax]            ; 

004F826A    0FB700                movzx   eax, word ptr [eax]             ; 取第二张表的2个字节( 这个结构估计是每个字节为一个单位的)
0053770C    25 FF7FFFFF           and     eax, FFFF7FFF                   ; Tab3Index = [Tab2Index] & 0xFFFF7FFF
00546515    52                    push    edx                             
00546516                          mov     edx, -C                         ; edx = -C
004F81B7    03D5                  add     edx, ebp                        
0054A072    8B12                  mov     edx, dword ptr [edx]            ; 第三张表的地址 [epb-C]
0054A074    03C2                  add     eax, edx                        ; 第三张表的首地址 + 
0054A076    5A                    pop     edx                             


0054A077    56                    push    esi                             
0054A078                          mov     eax, B55071C                    ; eax = B55071C
0053DB46    03F5                  add     esi, ebp                        
0053DB48    50                    push    eax                             
0053DB49                          mov     eax, 6D52304A                   ; eax = 6D52304A
0052CB2A    03F0                  add     esi, eax                        
0052CB2C    58                    pop     eax                             
0052CB2D    8906                  mov     dword ptr [esi], eax            
004F129E                          pop     esi                             ; Morph instruction
004F129F    9C                    pushfd                                  
004F12A0                          mov     eax, -1C                        ; eax = -1C
005517F5    03C5                  add     eax, ebp                        
0051E6DF    8B00                  mov     eax, dword ptr [eax]            
0051E6E1    9D                    popfd                                   

0051E6E2    8B00                  mov     eax, dword ptr [eax]           ; 索引获取到第三表中的数据

0051E6E4    53                    push    ebx                             
0051E6E5                          mov     ebx, 29CFE5C3                   ; ebx = 29CFE5C3
0051BFEC    03DD                  add     ebx, ebp                        
0051BFEE    57                    push    edi                             
0051BFEF                          mov     edi, D6301A29                   ; edi = D6301A29
0053A7C6    03DF                  add     ebx, edi                        
0053A7C8    5F                    pop     edi                             
0053A7C9    8903                  mov     dword ptr [ebx], eax            ; 保存获取到的第三张表的数据 [ebp-14] -->也是DLL模块的基地址
0053A7CB    5B                    pop     ebx                             

004A8082    837D EC 00            cmp     dword ptr [ebp-14], 0           ; 如果模块的基地址为0的话..则加载该DLL
004A8086    0F85 FCF80700         jnz     00527988                        
00513070    0F84 98FB0300         je      00552C0E                        

 
00552C0E    8B45 E4               mov     eax, dword ptr [ebp-1C]         
00552C11    83C0 04               add     eax, 4                          
00552C14    8945 F0               mov     dword ptr [ebp-10], eax         ; 保存stDllEntry.encryptDllName地址
00552C17                          mov     eax, -10                        ; eax = -10
0054E0C4    03C5                  add     eax, ebp                        
005524D2    8B00                  mov     eax, dword ptr [eax]            

0051AAA6                          push    eax                             ; Morph instruction
0051AAB1    873C24                push    eax          ; stDllEntry.encryptDllName字符串地址作为参数..

//////////////////////////////////////////////////////////////////
//
//  下面调用一个加解密字符串的函数.. 函数过程放到后面分析 ==> 名称: enDeCodeString() ==> 0051866C
//  eax: 待加密或者待解密的字符串的内存地址
//
/////////////////////////////////////////////////////////////////

0053599B                          push    004A94AF                        ; 返回地址
0051866C                                        ; enDeCodeString();  // 调用解密出Dll库文件名

// 结果如下:
00542D14  00 00 00 00 6F 6C 65 61 75 74 33 32 2E 64 6C 6C  ....oleaut32.dll

004A94AF    8B05 BCF35100         mov     eax, dword ptr [51F3BC]         
004A94B5    FF10                  call    dword ptr [eax]                  ; GetModuleHandleA函数,尝试调用该函数..如果不行再调用 LoadLibraryA

004A94B7    09C0                  or      eax, eax                        
004A94B9    0F85 4ACB0400         jnz     004F6009                        ; 这里返回0.. 因为  oleaut32.dll未被加载
0054D5C7    0F84 F1AEFFFF         je      005484BE                        
005484BE    8B0424                mov     eax, dword ptr [esp]            
005484C4                          push    eax                             ; eax ==> "oleaut32.dll"字符串内存地址

==> 堆栈如下:
0012F968   00542D18  ASCII "oleaut32.dll"
0012F96C   00542D18  ASCII "oleaut32.dll"


==> 这个函数是调用函数004F7609 来获取Kernel32模块的基地址,然后再获取LoadLibraryA函数地址,
==> 然后调用LoadLibraryA函数加载其他模块,如这里的oleaut32.dll

004F6004    E8 3F820500           call    0054E248                        

{

===> 函数 0054E248

005475AC    55                    push    ebp                             
005475AD    8BEC                  mov     ebp, esp                        
005475AF    51                    push    ecx                             
005475B0    833D C0F35100 00      cmp     dword ptr [51F3C0], 0           ; 判断LoadLibrayA函数是否已经获取..如果是的话就直接调用

0054A784    0F85 9C64FAFF         jnz     004F0C26                        
0053C126    0F84 08C5FFFF         je      00538634                ; 如果是的话,接下面的过程..              

004EE987                          push    0051AC80                        ; 入栈返回地址
00516CFF    0F85 F6B80000         jnz     005225FB                        
005225FB    8D05 FF6C5100         lea     eax, dword ptr [516CFF]         
00522601    C600 C3               mov     byte ptr [eax], 0C3             ; 防止下次再被执行

==> 这个函数先判断kernel32模块地址是否已经获取..如果没有的话..调用GetModuleHandleA获取

00522604    E8 0050FDFF           call    004F7609                        ; getKernel32Module();
00522609    BA 708A2FA2           mov     edx, A22F8A70                  ; DebugBreak -->API函数的HASH值
0052260E    E8 E8960100           call    0053BCFB                       ; 调用自己的 myGetProcAddress() [00516067] , 获取函数..
00522613    A3 0C245200           mov     dword ptr [52240C], eax         ; eax = 7C85AB46 ==> DebugBreak

==> 再获取ExitProcess函数地址

00522618    E8 EC4FFDFF           call    004F7609                     ; getKernel32Module()
004EE1C9    BA D959CDA2           mov     edx, A2CD59D9                  ; 
004EE1E4                          push    0051577E                        ; Morph instruction
00516067    55                    push    ebp                             ; 再次调用00516067 myGetProcAddress()

0051577E    A3 706F5100           mov     dword ptr [516F70], eax         ; eax = 7C81CB12 ==> ExitProcess
00515783    C3                    retn                                    

0051AC80    E8 84C9FDFF           call    004F7609                        ; getKernel32Module()

0051AC85    BA F68201CF           mov     edx, CF0182F6                   ; LoadLibraryA -> Hash值
0051BB57                          push    0051216F                        ; myGetProcAddress()
00516067    55                    push    ebp                             

0051216F    57                    push    edi                             ; eax = 7C801D7B ==> LoadLibraryA 
00512170                          mov     edi, 51F3C0                     ; edi = 51F3C0
004F0C23    8907                  mov     dword ptr [edi], eax            
004F0C25    5F                    pop     edi                             
004F0C26    A1 C0F35100           mov     eax, dword ptr [51F3C0]         ; 存储LoadLibraryA函数


==> 这个函数是关键.. 检测API函数的所有指令是否被下断点 ==> 不单单是首地址..
==>  checkFunctionBreakpoint();

004F0C2B    E8 2B8A0400           call    0053965B                        ; 详细分析见后面

004F0C30    89EC                  mov     esp, ebp                        
004F0C32    870424                xchg    dword ptr [esp], eax            
004F0C35    8BE8                  mov     ebp, eax                        
004F0C37    873424                xchg    dword ptr [esp], esi            
00529B2D    8BC6                  mov     eax, esi                        
00529B2F    5E                    pop     esi                             
005341A2    52                    push    edx                             
005341A3                          mov     edx, 51F3C0                     ; edx = 51F3C0
004EF644    8B12                  mov     edx, dword ptr [edx]            
004EF646    871424                xchg    dword ptr [esp], edx            ; 入栈API函数 LoadLibraryA地址
0053965A    C3                    retn                                    ; retn返回去执行

==> 堆栈
0012F960   7C801D7B  kernel32.LoadLibraryA
0012F964   004F6009  返回到 EXECrypt.004F6009 来自 EXECrypt.0054E248
0012F968   00542D18  ASCII "oleaut32.dll"
0012F96C   00542D18  ASCII "oleaut32.dll"
==

004F6009    870424                xchg    dword ptr [esp], eax            ; eax = 770F0000 oleaut32 模块基地址
004F600C    E8 5B260200           call    0051866C                        ; 重新加密字符串函数 enDecodeString() "oleaut32.dll"

004F6016                          pop     eax                             ; eax = 770F0000 oleaut32 模块基地址
005195C2    52                    push    edx                             
005195C3                          mov     edx, -14                        ; edx = -14
004A8AA4    03D5                  add     edx, ebp                        
004A8AAC    8902                  mov     dword ptr [edx], eax            ; [ebp-14] ==> 存储到 ebp-14
004A8AAE    5A                    pop     edx                             
00527980    8B45 E4               mov     eax, dword ptr [ebp-1C]         ; stDllEntry结构地址( 如这里是oleaut32.dll对应的stDllEntry结构地址)
00527983    8B55 EC               mov     edx, dword ptr [ebp-14]         ; stDllEntry.dllModuleHandle
00527986    8910                  mov     dword ptr [eax], edx            ; 保存
00527988    0F88 11F00100         js      0054699F                        

00548519    8B45 DC               mov     eax, dword ptr [ebp-24]         
0054851C    F640 01 80            test    byte ptr [eax+1], 80            
00548520    0F85 80D7FAFF         jnz     004F5CA6                        

0055380F    0F84 3AF1FCFF         je      0052294F                        
00550610                          mov     eax, -24                        ; eax = -24
0053E11E    03C5                  add     eax, ebp                        
0053E126    8B00                  mov     eax, dword ptr [eax]            
0054698D    8B48 04               mov     ecx, dword ptr [eax+4]          
00546990    8B45 DC               mov     eax, dword ptr [ebp-24]         
00546993    66:8B50 02            mov     dx, word ptr [eax+2]            
00546997    8B45 EC               mov     eax, dword ptr [ebp-14]         
00514C01    E8 12650000           call    0051B118                        ; 这个函数通过查dll导出表,比较API函数名称字符串HASH值来获取API函数地址


0054094E                          mov     edx, -18                        ; edx = -18
00532100    03D5                  add     edx, ebp                        
00532108    8B12                  mov     edx, dword ptr [edx]            ; edx ==> IAT地址
0053210A    8902                  mov     dword ptr [edx], eax            ; 最关键的一句话.. 填充IAT的数据 

0053210C    8345 E8 04            add     dword ptr [ebp-18], 4           ; 继续处理下一个IAT项数据
00532110    FF45 E0               inc     dword ptr [ebp-20]              ;
00546A33    FF4D D4               dec     dword ptr [ebp-2C]              ; 此IAT块待处理总数减去1
00546A36    0F85 47F1FDFF         jnz     00525B83                        ; 继续循环。。回到最最上面的.



@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

==> 整个IAT的处理过程完毕后返回到这里...  从这个函数0052F6DD返回..


0052C23C    8BE5                  mov     esp, ebp                        
0052C23E    5D                    pop     ebp                             
0052C23F    C3                    retn                                    
                     
==> 第二个TLS回调函数处理完毕.. 返回到系统 。。

0052CEE8    C745 FC 01000000      mov     dword ptr [ebp-4], 1            
0052CEEF                          mov     eax, -4                         ; eax = -4
0054A2BF    03C5                  add     eax, ebp                        
0054A2C7    8B00                  mov     eax, dword ptr [eax]            
0054A2C9    59                    pop     ecx                             
00540540                          pop     ebp                             ; Morph instruction
00540541    C2 0C00               retn    0C                              












=============================================================================================
10. 函数 0053965B 

==> checkFunctionBreakpoint()  ==> 检测整个函数的所有指令是否被下软件断点.. <没有跟进CALL的>

==> 参数: eax  ==> 需要被检测的API函数的地址

==> 返回: 0 或 1


==> 检测结束的条件:

a. 遇到会改变程序流程的指令如  jmp  retn   jmp dword ptr [eax]  iretd
b. 计算出的本条指令长度为0..



00533FEB                          push    ebp                             ; Morph instruction
00533FEE    8BEC                  mov     ebp, esp                        
00533FF0    83C4 F8               add     esp, -8                         
00551D58    8945 FC               mov     dword ptr [ebp-4], eax          
00551D5B                          mov     eax, -4                         ; eax = -4
00532AFC    03C5                  add     eax, ebp                        
004EF2FC    8B00                  mov     eax, dword ptr [eax]            ; eax ==> LoadLibrary函数地址(7C801D7B)
0054D2EB    9C                    pushfd                                  
0053BA44    9D                    popfd                      
             

========> 从这里开始循环检测每条指令...

0053BA45                          push    005238D5                        ; 下面到 retn是垃圾代码
005427CD    E8 0F95FFFF           call    0053BCE1                        ; 

{

0053BCE1    64:FF35 00000000      push    dword ptr fs:[0]                ; 这里的SEH估计是防止读取出现异常用的 
0053BCE8    64:8925 00000000      mov     dword ptr fs:[0], esp           
0053BCEF    8B00                  mov     eax, dword ptr [eax]            ; 这个读取系统API函数的代码可能会发生异常..(这里不会)
0053BCF1    B8 01000000           mov     eax, 1                          
0053BCD6    64:8F05 00000000      pop     dword ptr fs:[0]                
0053BCDD    83C4 04               add     esp, 4                          
0053BCE0    C3                    retn                                    

005238D5    84C0                  test    al, al                          
005238D7    0F85 0E020100         jnz     00533AEB                        


00533AEB                          mov     eax, -4                         ; eax = -4
0052815B    03C5                  add     eax, ebp                        
00536FE5    8B00                  mov     eax, dword ptr [eax]            
00536FE7    8A00                  mov     al, byte ptr [eax]              
00536FE9    2C 99                 sub     al, 99                          ; 准备检测API函数的首字节是否是 0xCC

00536FEB    8B55 FC               mov     edx, dword ptr [ebp-4]          
00536FEE    F62A                  imul    byte ptr [edx]                  
00529F40    3C A4                 cmp     al, 0A4                         ; 如果相等说明被下段点了...
00529F42    0F85 7CAE0000         jnz     00534DC4                        


00551B85    8B45 FC               mov     eax, dword ptr [ebp-4]          
005385D3                          push    005216B5                        ; Morph instruction

-------------------------------------
==> 这里调用函数 0052DED6
==> 这个函数是判段一条指令是否是 改变EIP的指令等
==> isInstructionChangeEip();

0052DED6    55                    push    ebp                             ; isInstructionChangeEip();  

005216B5    84C0                  test    al, al                          
005216B7    0F85 9E9F0000         jnz     0052B65B                        ; 如果是的话从这个函数返回 ==> pop ebp (检测结束)
00542093    0F84 5B04FBFF         je      004F24F4                        ; 如果不是的话.. 继续检测

004F24F4    8B45 FC               mov     eax, dword ptr [ebp-4]          
00553C24    8038 E8               cmp     byte ptr [eax], 0E8             ; 是否是E8 --> Call
00553C27    0F85 1C48FAFF         jnz     004F8449                        ; 

004F8449    0F85 218C0400         jnz     00541070                        
00541070                          mov     eax, -4                         ; eax = -4
004F197C    03C5                  add     eax, ebp                        
004F1984    8B00                  mov     eax, dword ptr [eax]            ; 


==>
==> 返回当前指令的长度  如这里 eax = 2

004F124B    E8 5C330400           call    005345AC                        ; 返回当前指令的长度 ==> 这里 eax = 2

}

004F1250    56                    push    esi                             
004F1251                          mov     esi, B36F99E                    ; esi = B36F99E
005192E7    03F5                  add     esi, ebp                        
005192E9    81C6 5A06C9F4         add     esi, F4C9065A                   
005192EF    8906                  mov     dword ptr [esi], eax            
005192F1    5E                    pop     esi                             
004EEF46    837D F8 00            cmp     dword ptr [ebp-8], 0            
004EEF4A    0F8E 0BC70300         jle     0052B65B                        ; 指令长度如果小等于0, 函数返回... (检测结束 )

0052CB9D    0F8F BF180100         jg      0053E462                        
0053E462                          mov     eax, -4                         ; eax = -4
0051CD0A    03C5                  add     eax, ebp                        
0051CD12    8B00                  mov     eax, dword ptr [eax]            
0051CD14    33D2                  xor     edx, edx                        
0051CD16    52                    push    edx                             

0051CD17    50                    push    eax                            ; 前一条指令的首地址.. 
0051E44B    8B45 F8               mov     eax, dword ptr [ebp-8]         ; [ebp-8] ==> 指令长度
 
0051E44E    99                    cdq                                     
0053C2E4    030424                add     eax, dword ptr [esp]           ; 加上前一条指令的首地址 + 该指令的长度 (如这里的: eax=7C801D7D)
00530DBE    135424 04             adc     edx, dword ptr [esp+4]         ; 
00530DC2    83C4 08               add     esp, 8                          

00530DC5    53                    push    ebx                             
00530DC6                          mov     ebx, -4                         ; ebx = -4
0053459C    03DD                  add     ebx, ebp                        
005345A4    8903                  mov     dword ptr [ebx], eax            ; [ebp-4] ==> 下一条需要被检测CC断点的指令的起始地址
005345A6    5B                    pop     ebx                             

00551D5B                          mov     eax, -4                         ; eax = -4
00532AFC    03C5                  add     eax, ebp                        
004EF2FC    8B00                  mov     eax, dword ptr [eax]            


0053BA45                          push    005238D5                        ; (循环) 重复前面的代码,检测下一条指令是否被设置断点..
005427CD    E8 0F95FFFF           call    0053BCE1                        ; ....



==>  循环检测完毕后返回到这里

0052B665                          pop     eax                             ; Morph instruction
0052B666    59                    pop     ecx                             
00533ADF                          pop     ebp                             ; Morph instruction
00533AE0    C3                    retn                                    










============================================================================================
11. 函数 005345AC 


==>  005345AC 获取当前指令的长度?

                      
005345AC    55                    push    ebp                             
0052525C    8BEC                  mov     ebp, esp                        
0052525E    83C4 D8               add     esp, -28                        
00525261    8945 E0               mov     dword ptr [ebp-20], eax         
00525264    8B45 E0               mov     eax, dword ptr [ebp-20]         
004EE878    8945 D8               mov     dword ptr [ebp-28], eax         
004EE87B    C745 EC 04000000      mov     dword ptr [ebp-14], 4           
004EE882    8B45 EC               mov     eax, dword ptr [ebp-14]         
004EE885    8945 FC               mov     dword ptr [ebp-4], eax          
004EE888    8B45 EC               mov     eax, dword ptr [ebp-14]         
004EE88B    8945 F4               mov     dword ptr [ebp-C], eax          
0054A32E    8B45 E0               mov     eax, dword ptr [ebp-20]         
0054A331    0FB600                movzx   eax, byte ptr [eax]             
0054A334    8945 E4               mov     dword ptr [ebp-1C], eax         
0054A337    FF45 E0               inc     dword ptr [ebp-20]              
0054A33A    8B45 E4               mov     eax, dword ptr [ebp-1C]         

0054A33D    8B0485 7C6F5100       mov     eax, dword ptr [eax*4+516F7C]   ; 查表0x516F7C 获取该指令的长度...
0051190E    8945 F8               mov     dword ptr [ebp-8], eax          
00511911    837D F8 00            cmp     dword ptr [ebp-8], 0            
00511915    0F85 EB730000         jnz     00518D06                        


004F0D10    837D E4 0F            cmp     dword ptr [ebp-1C], 0F          ; 是否是双字节指令.. 0x0F
004F0D14    0F85 DA140400         jnz     005321F4                        ; 

005321FA    F645 F8 02            test    byte ptr [ebp-8], 2             ; [ebp-8] --> 从表获取到指令长度值
00512A95    0F84 A6770200         je      0053A241                        ; 

00512A9B    55                    push    ebp                             
00512A9C    8B45 E0               mov     eax, dword ptr [ebp-20]         
00523690    E8 4121FFFF           call    005157D6                        ; 定位到下一条指令..

{

==> 函数 005157D6

005157D6    55                    push    ebp                             
005157D7    8BEC                  mov     ebp, esp                        
005157D9    83C4 EC               add     esp, -14                        
005157DC    8945 FC               mov     dword ptr [ebp-4], eax          
005157DF    8B45 FC               mov     eax, dword ptr [ebp-4]      

    
004F2F74    0FB600                movzx   eax, byte ptr [eax]               ; ApiAddr

004F2F77    8B55 08               mov     edx, dword ptr [ebp+8]            ; 上一个函数的堆栈地址
004F2F7A    8942 F0               mov     dword ptr [edx-10], eax           ; 这里子函数来修改调用函数的变量数值..
                    ; 等同于修改调用函数的 [ebp-10] .. 


004F2F7D    FF45 FC               inc     dword ptr [ebp-4]                 ; 下一个字节..

004F2F80    8B45 08               mov     eax, dword ptr [ebp+8]            
004F2F83    8B40 F0               mov     eax, dword ptr [eax-10]           ; 0xFF ==> LoadLibraryA函数的第二个字节

00527828    C1E8 06               shr     eax, 6                            ; (0xFF >> 6) = 3
0052782B    8945 F0               mov     dword ptr [ebp-10], eax           ; value1

0052782E    8B45 08               mov     eax, dword ptr [ebp+8]          
00527831    8B40 F0               mov     eax, dword ptr [eax-10]         
00527834    83E0 07               and     eax, 7                            ; (0xFF & 7 )
00527837    8945 EC               mov     dword ptr [ebp-14], eax           ; value2


0052783A    837D F0 03            cmp     dword ptr [ebp-10], 3             ; if(value == 3 )
0052783E    0F83 B7340200         jnb     0054ACFB                        
0054ACFB    0F85 91F4FDFF         jnz     0052A192                        

0051BDA2    8B45 08               mov     eax, dword ptr [ebp+8]            ; 这里 value == 3
0051BDA5    8178 E4 F6000000      cmp     dword ptr [eax-1C], 0F6           ; if(ApiByte == 0xF6 ) 调用函数里的变量 [ebp-1C] API函数的每个字节 ApiByte.
0051BDAC    0F84 89C00000         je      00527E3B                          ; 这里 = 0x8B

0051BDB2    8B45 08               mov     eax, dword ptr [ebp+8]          
0051BDB5    8178 E4 F7000000      cmp     dword ptr [eax-1C], 0F7           ; if(ApiByte == 0xF7 ) ==> 字节是F6 / F7 

0052A187    0F85 EED0FCFF         jnz     004F727B                        
004F727B    8B45 FC               mov     eax, dword ptr [ebp-4]            ; 

004F727E    8945 F8               mov     dword ptr [ebp-8], eax            ; 
0054DEFE    8B45 F8               mov     eax, dword ptr [ebp-8]            ; EAX = 7C801D7D ==> 指向LoadLibraryA函数的第二条指令..
0054DF01    8BE5                  mov     esp, ebp                        
0054DF03    5D                    pop     ebp                             
0054DF04    C3                    retn     


}

00523695    59                    pop     ecx                             
0053A23E    8945 E0               mov     dword ptr [ebp-20], eax         
0053A241    0F84 5183FDFF         je      00512598                        
004F89B0    F645 F9 08            test    byte ptr [ebp-7], 8             
004F89B4    0F84 A0850300         je      00530F5A               
         
00530F5A    F645 F8 20            test    byte ptr [ebp-8], 20            
00530F5E    0F84 0F91FEFF         je      0051A073                   
     
0051A073    F645 F8 08            test    byte ptr [ebp-8], 8             
00540245    0F84 4E98FEFF         je      00529A99                        

00529A99    0F83 C4120200         jnb     0054AD63                        
0054AD63    F645 F8 40            test    byte ptr [ebp-8], 40            
0054AD67    0F84 17F5FDFF         je      0052A284                        

0052A284    8B45 E0               mov     eax, dword ptr [ebp-20]         
005379B0    2B45 D8               sub     eax, dword ptr [ebp-28]         
005379B3    8945 DC               mov     dword ptr [ebp-24], eax         
005379B6    8B45 DC               mov     eax, dword ptr [ebp-24]         
005379B9    8BE5                  mov     esp, ebp                        
005379BB    5D                    pop     ebp                             
005379BC    C3                    retn                                    






==============================================================================================
12. 函数 0052DED6  ==> 判断当前指令是不是 iretd  jmp retn jmp dword ptr [reg] 等指令..如果是返回1.. 否则返回0..

=> 这里用到一张表..好像是查询指令opCode对应的指令长度.. 如 0x8B --> 2





==>  bool isInstructionChangeEip();

==> 参数: 指令起始地址

==> 返回值: 该条指令的长度

如: LoadLibraryA函数

7C801D7B >/$  8BFF          mov     edi, edi


[ebp-4]  ==> BYTE* pCode



0052DED6    55                    push    ebp                             
004F1C76    8BEC                  mov     ebp, esp                        
004F1C78    83C4 F8               add     esp, -8                         
004F1C7B    8945 FC               mov     dword ptr [ebp-4], eax            ; [ebp-4] ==> 指针指向函数中的代码...
004F1C7E    0F81 4DBC0500         jno     0054D8D1                        
0053F846    8B45 FC               mov     eax, dword ptr [ebp-4]          
0053F849    0FB600                movzx   eax, byte ptr [eax]               ; 一个字节指令值 作为索引值?

0053F84C    833C85 7C6F5100 00    cmp     dword ptr [eax*4+516F7C], 0       ; 表0x516F7C --> 每个项是一个DWORD
0053F854    0F84 6B2F0000         je      005427C5                          ; 表中对应的值是0 的话..则继续下一个字节..


===> 如果是下面这5种情况之一的话.. 则该函数返回 1.. 否则返回0

0053F85A    8B45 FC               mov     eax, dword ptr [ebp-4]            ; 
0053F85D    8038 CF               cmp     byte ptr [eax], 0CF               ; iretd 异常返回指令
0051EE88    0F84 30390200         je      005427BE                        

0051EE8E    8B45 FC               mov     eax, dword ptr [ebp-4]          
0051EE91    8038 E9               cmp     byte ptr [eax], 0E9               ; 0xE9 长跳转指令
0051EE94    0F84 24390200         je      005427BE                        

00540C91    8B45 FC               mov     eax, dword ptr [ebp-4]          
00540C94    8038 EB               cmp     byte ptr [eax], 0EB               ; 0xEB 短跳转指令
00540C97    0F84 211B0000         je      005427BE                        


00540C9D    8B45 FC               mov     eax, dword ptr [ebp-4]          
00540CA0    8A00                  mov     al, byte ptr [eax]              
00541EEE    24 F6                 and     al, 0F6                         
00541EF0    3C C2                 cmp     al, 0C2                           ; 0xC2 或者 0xC3 返回指令
004F0E17    0F84 A1190500         je      005427BE                        


004F0E1D    8B45 FC               mov     eax, dword ptr [ebp-4]          
004F0E20    66:8B00               mov     ax, word ptr [eax]              
004F0E23    66:25 FF38            and     ax, 38FF                        
004F0E27    66:3D FF20            cmp     ax, 20FF                          ; FF21 FF22 FF23 FF24 FF25 FF26 FF27 
0052E772    0F84 46400100         je      005427BE                          ; jmp dword ptr [eax] / jmp dword ptr [ebx] 等

0052E778    33C0                  xor     eax, eax                        
00537B61    8845 FB               mov     byte ptr [ebp-5], al            
00537B64    8A45 FB               mov     al, byte ptr [ebp-5]            
00537B67    59                    pop     ecx                             
00537B68    59                    pop     ecx                             
00537B69    5D                    pop     ebp                             
005427BD    C3                    retn                                    













=============================================================================================
13. 函数 004F7609 

==> getKernel32Module()

==> 这个参数是先判断 51778C 处是否已经存储了 kernel32模块的地址..如果不是的话就调用GetModuleHandle获取

004A8D82    55                    push    ebp                             
004A8D83    8BEC                  mov     ebp, esp                        
004A8D85    51                    push    ecx                             
004A8D86    833D 8C775100 00      cmp     dword ptr [51778C], 0          ; 判段kernel32模块基地址是否已经获取
004A8D8D    0F85 C6F40900         jnz     00548259                        
0051533F    0F84 D3A90100         je      0052FD18                        
0052FD18    B8 F0235200           mov     eax, 005223F0                  ; 005223F0 存储"kernel32.dll"加密后的字符串
0052FD1D    E8 4A89FEFF           call    0051866C                       ; 解密字符串函数enDecodeString()

00530429                          push    005223F0                        ; Morph instruction
0053B916    81C0 3AE75098         mov     eax, 0051F3BC                   

0053B91C    8B00                  mov     eax, dword ptr [eax]            ; Kernel32.GetModuleHandlerA
0053B91E    FF10                  call    dword ptr [eax]                 ; 调用GetModuleHandle()
0054824A    A3 8C775100           mov     dword ptr [51778C], eax         ; 保存到 51778C

0054824F    B8 F0235200           mov     eax, 005223F0                   
00548254    E8 1304FDFF           call    0051866C                        ; 重新加密"kernel32.dll"字符串

00548259    A1 8C775100           mov     eax, dword ptr [51778C]         ; 返回 kernel32基地址 7C80000
00518663    8945 FC               mov     dword ptr [ebp-4], eax          
00518666    8B45 FC               mov     eax, dword ptr [ebp-4]          
00518669    59                    pop     ecx                             
0051866A    5D                    pop     ebp                             
0051866B    C3                    retn                                    






=============================================================================================

14. 加解密字符串函数 enDecodeString()
 eax: 参数  ==> 待加密或者待解密的字符串的内存地址

 返回: 直接修改待加密或解密地址处的数据..

 函数地址: 0051866C



0051866C    55                    push    ebp                             
0051888F    8BEC                  mov     ebp, esp                        
00518891    83C4 F8               add     esp, -8                   
      
00518894    8945 FC               mov     dword ptr [ebp-4], eax          
00518897    A0 00245200           mov     al, byte ptr [522400]           
0051889C    8845 FA               mov     byte ptr [ebp-6], al           
 

//
//  循环解密 dll库名称字符串... 如 "kernel32.dll"
//
//
0051889F    0F83 E01A0300         jnb     0054A385                        

004F41F9    8B45 FC               mov     eax, dword ptr [ebp-4]          ; 加密后的DLL库名称地址
00531AB6    8038 00               cmp     byte ptr [eax], 0               ; 判断字符是否为0,0解密完成..
00531AB9    0F85 B0EAFFFF         jnz     0053056F                        ; 循环解密dll库名称的每个字符串.. 直到为0

0053056F                          mov     eax, -4                         ; eax = -4
00530584    03C5                  add     eax, ebp                        
0051681F    8B00                  mov     eax, dword ptr [eax]            
00516821    8A00                  mov     al, byte ptr [eax]              ; [ebp-4]

00516823    8845 FB               mov     byte ptr [ebp-5], al            ; 保存到 [ebp-5]

00516826    51                    push    ecx                             
004F543A                          mov     ecx, -6                         ; ecx = -6
00549743    03CD                  add     ecx, ebp                        
0054974B    8A01                  mov     al, byte ptr [ecx]              ; [ebp-6]
0054974D    59                    pop     ecx    
                         
005155CB    24 07                 and     al, 7               ; and al, 7
                  
005155CD    52                    push    edx                             
005155CE                          mov     edx, -7                         ; edx = -7
00526506    03D5                  add     edx, ebp                        
0052650E    8802                  mov     byte ptr [edx], al              ; 保存到 [ebp-7]  = [ebp-6] & 7;
005493DF    5A                    pop     edx    

                         
005493E0    33C0                  xor     eax, eax           ; 只要最后一个字节。。清0 first
                    
005493E2    51                    push    ecx                             
005493E3                          mov     ecx, 10A510AB                   ; ecx = 10A510AB
00515530    03CD                  add     ecx, ebp                        
00515532    52                    push    edx                             
00515533                          mov     edx, EF5AEF4E                   ; edx = EF5AEF4E
00515545    03CA                  add     ecx, edx                        
0051C2B6    5A                    pop     edx                             
0051C2B7    8A01                  mov     al, byte ptr [ecx]              ; [ecx] = [ebp - 7]
0051C2B9    59                    pop     ecx                             


0051C2BA    9C                    pushfd                                  
0051C2BB                          mov     ecx, 8                          ; ecx = 8
00520396    9D                    popfd                                   

00520397    2BC8                  sub     ecx, eax                        ; 8 - [ebp-5]
0053E887    33C0                  xor     eax, eax                        

0053E889    8A45 FB               mov     al, byte ptr [ebp-5]            
0053E88C    D3E0                  shl     eax, cl                         
0053E88E    8A4D F9               mov     cl, byte ptr [ebp-7]            
0053E891    33D2                  xor     edx, edx                        
0053E893    8A55 FB               mov     dl, byte ptr [ebp-5]            
0052A463    D3EA                  shr     edx, cl                         
0052A465    0BC2                  or      eax, edx                        ; ([ebp-5] >> [ebp-7]) | ([ebp-5] << 8- [ebp-7)

0052A467    8B55 FC               mov     edx, dword ptr [ebp-4]          ; 
0052A46A    8802                  mov     byte ptr [edx], al              ; 解密dll名称字符串的一个字符

0052A46C    8B45 FC               mov     eax, dword ptr [ebp-4]          
0052A46F    8A00                  mov     al, byte ptr [eax]        ; 前面解密出来的一个字符...
          
0052A471    55                    push    ebp                             
004F7F8D    53                    push    ebx        
                     
004F7F8E                          mov     ebx, 804D5D50                   ; ebx = 804D5D50
005220E6    03EB                  add     ebp, ebx                        
005220E8    81C5 AAA2B27F         add     ebp, 7FB2A2AA                   ; ebx = 0xFFFFFFFA
005220EE    8BDD                  mov     ebx, ebp                        
005220F0    8B1B                  mov     ebx, dword ptr [ebx]             ; [ebx] = [ebp-6]
   
00514F7F    32D8                  xor     bl, al                          ; 修改字符解密key Byte
00514F81    885D 00               mov     byte ptr [ebp], bl              

00516CF5    5B                    pop     ebx                             
00516CF6    5D                    pop     ebp                             
00516CF7    FF45 FC               inc     dword ptr [ebp-4]               ; 继续下一个dllName字符..        dataPtr ++;
0051889F    0F83 E01A0300         jnb     0054A385                        ; 


0054A385    8B45 FC               mov     eax, dword ptr [ebp-4]          
0054A388    8038 00               cmp     byte ptr [eax], 0               ; 这里才是解密完成的出口..shit
0054A38B    0F85 DE61FEFF         jnz     0053056F                        ; 跳到前面循环处理下一个字符
0052B4AD   /0F84 0CCB0100       je      00547FBF



//------------------
// 字符串的所有字符都解密完成后跳到这里...
//-----------------
0052B4AD    0F84 0CCB0100         je      00547FBF                        
00547FC4                          pop     ecx                             ; Morph instruction
00547FC5    59                    pop     ecx                             
00547FC6    5D                    pop     ebp                             
00547FC7    C3                    retn         


  
===============================================================================================================

15. 函数 00516067 ===> myGetProcAddress                  

==> 过程就是先访问动态库PE文件选项头中 导出表的地址..然后就是循环每个 导出函数.. 将他们的数值HASH化.. 比较和传递进来的
==> 是不是相等的.. 是的话就是找到了.. 再处理下获取API函数地址..


00516067    55                    push    ebp                             
00516068    8BEC                  mov     ebp, esp                        
0051606A    83C4 E4               add     esp, -1C                        
0051606D    8955 F8               mov     dword ptr [ebp-8], edx          
00516070    8945 FC               mov     dword ptr [ebp-4], eax          
00516073                          mov     eax, -4                         ; eax = -4
00542887    03C5                  add     eax, ebp                        
0054288F    8B00                  mov     eax, dword ptr [eax]      
【返回到EP处】

代码:
00629459    0F89 2EFDFFFF         jns     0062918D                        
00629548                          push    00628134                        ; Morph instruction
006297C2    C3                    retn   

//  检测EP处是否有 INT3断点...
                                 
00628305    8D05 59946200         lea     eax, dword ptr [<ModuleEntryPoint>]
006282F7                          push    006295BC                        ; Morph instruction
00629128                          push    ebp                             ; Morph instruction
0062912B    8BEC                  mov     ebp, esp                        
00629130                          push    ecx                             ; Morph instruction
00629133    8945 FC               mov     dword ptr [ebp-4], eax          
00628117    8B45 FC               mov     eax, dword ptr [ebp-4]    
      
0062811A    8A00                  mov     al, byte ptr [eax]              ; EP处的第一个字节.. 
0062811C    2C 99                 sub     al, 99          
                
00629358    8B12                  mov     edx, dword ptr [edx]            ; [edx] = 0x00629459
006287F7    F62A                  imul    byte ptr [edx]                  
006287F9    3C A4                 cmp     al, 0A4                    ; 等于就出错。。         
006287FB    0F85 09030000         jnz     00628B0A                        
006287FB    0F85 09030000         jnz     00628B0A      

                  
00628B0A    59                    pop     ecx                             
00628B10                          pop    ebp                              ; Morph instruction
00628B11    C3                    retn                                    

// 这里两次PUSH都是作为 返回地址
// 
// push 4C1460
// push 628A7B
//
//
00628516                          mov     eax, 4C1460                     ; eax = 4C1460 ==> 4C1460就是 VM-OEP处了..
00628DB2                          push    eax                             ; 先入栈.. 等下就返回到VMOEP...

// push 628A7B

00628DB5    57                    push    edi                             
00628DB6                          mov     edi, 628A7B                     ; edi = 628A7B
00628B63    873C24                xchg    dword ptr [esp], edi           
 
00628A84                          push    ebp                             ; Morph instruction
00628A87    8BEC                  mov     ebp, esp                        
00628A89    51                    push    ecx    
                         
00628832    56                    push    esi                             
006292F1                          mov     esi, -4                         ; esi = -4
00629309    03F5                  add     esi, ebp                        [ebp-4]

// eax = 004C1460 
0062882B    8906                  mov     dword ptr [esi], eax            ; mov dword ptr [ebp-4], eax
00628D49    5E                    pop     esi   
         

00628D4A    8B45 FC               mov     eax, dword ptr [ebp-4]          
00628D4D    8A00                  mov     al, byte ptr [eax]         ; [EAX] = [004C1460] =  0xE9     
00628D4F    2C 99                 sub     al, 99                          
00628D51                          mov     edx, -4                         ; edx = -4
00628DE2    03D5                  add     edx, ebp                        
0062931F    8B12                  mov     edx, dword ptr [edx]            
00629321    F62A                  imul    byte ptr [edx]                  
00629323    3C A4                 cmp     al, 0A4                  ; 检测VmOep处是否有CC断点..         
00629325    0F85 56040000         jnz     00629781                       ; 这句下面有个 SEH..



00628441                          pop    ecx                              ; Morph instruction
00628442    5D                    pop     ebp                             
00628F0F    C3                    retn            
                        
00628A7B    C3                    retn                                    ; 从这里就是跳到Vm-Oep了...