一段被破解程序中的shellcode分析

只是感兴趣,大牛路过.
默笙妹子发来一个被用SMC方式破解的一个软件,于是研究其SMC中的ShellCode.

//////////////////////////////////////////////////////////////////////////////////////////////////

执行流程:
1.首先得到kernel32的ImageBase为起始解析PE,得到导出表.
2.然后取出GetProcAddress函数地址,获取指定的API
3.Api hook破解该软件


分析代码:

00400380     60              pushad                                   ; 保存寄存器环境
00400381     8B4424 44       mov     eax, dword ptr [esp+0x44]
00400385     25 0000FFFF     and     eax, 0xFFFF0000                  ; 不为序号导出
0040038A     66:8138 4D5A    cmp     word ptr [eax], 0x5A4D           ; 判断MZ
0040038F     74 07           je      short 00400398                   ; 该判断成立即意味着已经得到kernel32的imageBase
00400391     2D 00100000     sub     eax, 0x1000                      ; 内存中4K对齐,挪动到kernel32 dll的头部
00400396   ^ EB F2           jmp     short 0040038A                   ; 循环得到kernel32 imagebase

获得一个存放kernel32_ImageBase的指针:
00400398     50              push    eax                              ; eax == kernel32_ImageBase
00400399     E8 C2000000     call    00400460                         ; push 0x0040039E
0040039E     59              pop     ecx
0040039F     58              pop     eax
00400460:
    00400460     E8 F5FFFFFF     call    0040045A
    00400465     0000            add     byte ptr [eax], al
0040045A:
    0040045A     58              pop     eax
    0040045B     870424          xchg    dword ptr [esp], eax
    0040045E     50              push    eax
    0040045F     C3              retn

进函数时栈布局
$ ==>    > 00400465  __CALL_RET_EIP -> EAX
$+4      > 0040039E  _CALL_RET_EIP  -> 
$+8      > 7C800000  kernel32_ImageBase

出函数时栈布局
$ ==>    > 0040039E  _CALL_RET_EIP
$+4      > 00400465  __CALL_RET_EIP
$+8      > 7C800000  kernel32.7C800000
得出的结论即是,mov ecx,00400465(kernel32_ImageBase),其他忽略不谈

通过PE结构的固定偏移算出kernel32.dll的导出表,为后面顺利取出WINAPI做准备
004003A0     8BD8            mov     ebx, eax                         ; ebx == kernel32_ImageBase(SAVE)
004003A2     8B48 3C         mov     ecx, dword ptr [eax+0x3C]        ; ecx == e_lfanew(offset)
004003A5     03C8            add     ecx, eax                         ; ecx == kernel32_Image_NT_Header
004003A7     8B51 78         mov     edx, dword ptr [ecx+0x78]        ; edx == Kernel32_Export_Table(offset)
004003AA     03D0            add     edx, eax                         ; EDX == Kernel32_ExportTable_VA

同上冲定位函数,直接给出结果 mov ecx,00400465
004003AC     50              push    eax
004003AD     E8 AE000000     call    00400460
004003B2     59              pop     ecx
004003B3     58              pop     eax
004003B4     83C1 08         add     ecx, 0x8                         ; ecx == pNewEipAddr
004003B7     50              push    eax                              ; kernel32_ImageBase
004003B8     51              push    ecx                              ; ecx == pNewEipAddr
004003B9     E8 9C000000     call    0040045A
0040045A:
    0040045A     58              pop     eax
    0040045B     870424          xchg    dword ptr [esp], eax
    0040045E     50              push    eax
    0040045F     C3              retn

有意思的在于下面的一句,之前没注意看,此时才发现&pKernel32 + 8的位置是接下来运算的中的shellcode的一部分
004003B4    83C1 08         add     ecx, 0x8                         ; ecx == 0040046D(pKernel32)
004003B7    50              push    eax                              ; kernel32_ImageBase
004003B8    51              push    ecx                              ; ecx == pUnKnowAddr
004003B9    E8 9C000000     call    0040045A

0040046D    59              pop     ecx
0040046E    58              pop     eax                              ; eax == Kernel32_ImageBase
0040046F    8B4A 20         mov     ecx, dword ptr [edx+0x20]        ; ecx == Kernel32_ExprotTable_AddrOfNames(offset)
00400472    52              push    edx                              ; edx == Kernel32_ExportTable_VA
00400473    03C1            add     eax, ecx                         ; eax == Kernel32_ExprotTable_AddrOfNames
00400475    53              push    ebx                              ; ebx == Kernel32_ImageBase(SAVE)
00400476    33DB            xor     ebx, ebx
00400478    EB 04           jmp     short 0040047E
0040047A    83C0 04         add     eax, 0x4
0040047D    43              inc     ebx
0040047E    8B0C24          mov     ecx, dword ptr [esp]             ; ecx == Kernel32_ImageBase
00400481    8B10            mov     edx, dword ptr [eax]             ; api offset
00400483    03D1            add     edx, ecx                         ; edx == API Addr
00400485    8BFA            mov     edi, edx                         ; Sava Api Addr
00400487    33C9            xor     ecx, ecx
00400489    50              push    eax                              ; Kernel32_ExprotTable_AddrOfNames(Save)
0040048A    33C0            xor     eax, eax
0040048C    41              inc     ecx                              ; 计数器(API Name Len)
0040048D    AE              scas    byte ptr es:[edi]
0040048E  ^ 75 FC           jnz     short 0040048C
00400490    49              dec     ecx
00400491    E8 28FFFFFF     call    004003BE

004003BE    E8 97000000     call    0040045A
004003C3    47              inc     edi                              ;看不懂正常,因为是字符串
004003C4    65:74 50        je      short 00400417
004003C7    72 6F           jb      short 00400438
004003C9    6341 64         arpl    word ptr [ecx+0x64], ax
004003CC    64:72 65        jb      short 00400434
004003CF    73 73           jnb     short 00400444
004003D1    0000            add     byte ptr [eax], al
004003D3    56              push    esi
004003D4    6972 74 75616C5>imul    esi, dword ptr [edx+0x74], 0x506>
004003DB    72 6F           jb      short 0040044C
004003DD    74 65           je      short 00400444
004003DF    637400 00       arpl    word ptr [eax+eax], si
004003E3    4D              dec     ebp
004003E4    61              popad
004003E5    70 56           jo      short 0040043D
004003E7    6965 77 4F66466>imul    esp, dword ptr [ebp+0x77], 0x694>
004003EE    6C              ins     byte ptr es:[edi], dx
004003EF    65:0000         add     byte ptr gs:[eax], al
004003F2    0043 72         add     byte ptr [ebx+0x72], al
004003F5    65:61           popad
004003F7    74 65           je      short 0040045E
004003F9    46              inc     esi
004003FA    696C65 41 00000>imul    ebp, dword ptr [ebp+0x41], 0x0
00400402    0056 69         add     byte ptr [esi+0x69], dl
00400405    72 74           jb      short 0040047B
00400407    75 61           jnz     short 0040046A
00400409    6C              ins     byte ptr es:[edi], dx
0040040A    41              inc     ecx
0040040B    6C              ins     byte ptr es:[edi], dx
0040040C    6C              ins     byte ptr es:[edi], dx
0040040D    6F              outs    dx, dword ptr es:[edi]
0040040E    6300            arpl    word ptr [eax], ax

004003C3  47 65 74 50 72 6F 63 41 64 64 72 65 73 73 00 00  GetProcAddress..
004003D3  56 69 72 74 75 61 6C 50 72 6F 74 65 63 74 00 00  VirtualProtect..
004003E3  4D 61 70 56 69 65 77 4F 66 46 69 6C 65 00 00 00  MapViewOfFile...
004003F3  43 72 65 61 74 65 46 69 6C 65 41 00 00 00 00 00  CreateFileA.....
00400403  56 69 72 74 75 61 6C 41 6C 6C 6F 63 00 00 00 00  VirtualAlloc....

当前在获取GetProcAddress
0040047A    83C0 04         add     eax, 0x4                         ; 挪动指针,方便取新API
0040047D    43              inc     ebx                              ; 计数器
0040047E    8B0C24          mov     ecx, dword ptr [esp]             ; ecx == Kernel32_ImageBase
00400481    8B10            mov     edx, dword ptr [eax]             ; api offset
00400483    03D1            add     edx, ecx                         ; edx == API Addr
00400485    8BFA            mov     edi, edx                         ; Sava Api Addr
00400487    33C9            xor     ecx, ecx
00400489    50              push    eax                              ; Kernel32_ExprotTable_AddrOfNames(Save)
0040048A    33C0            xor     eax, eax
0040048C    41              inc     ecx                              ; 计数器(API Name Len)
0040048D    AE              scas    byte ptr es:[edi]
0040048E  ^ 75 FC           jnz     short 0040048C
00400490    49              dec     ecx
00400491    E8 28FFFFFF     call    004003BE
00400496    5E              pop     esi                              ; esi == "GetProcAddress"
00400497    58              pop     eax                              ; eax == Kernel32_ExprotTable_AddrOfNames
00400498    8BFA            mov     edi, edx                         ; 当前遍历出的API
0040049A    F3:A6           repe    cmps byte ptr es:[edi], byte ptr>; 比较是否一致
0040049C  ^ 75 DC           jnz     short 0040047A                   ; 不一致开始下一轮
0040049E    58              pop     eax                              ; eax == Kernel32_ImageBase
0040049F    870424          xchg    dword ptr [esp], eax             ; 与Kernel32_Export_Table_VA交换
004004A2    90              nop
004004A3    83C0 1C         add     eax, 0x1C                        ; eax == Kernel32_ExportTable_AddrOfFunc(offset)
004004A6    8B00            mov     eax, dword ptr [eax]             ; eax == Kernel32_ExportTable_AddrOfFunc
004004A8    50              push    eax
004004A9    8B4C24 04       mov     ecx, dword ptr [esp+0x4]         ; ecx == Kernel32_ImageBase
004004AD    8BFF            mov     edi, edi
004004AF    58              pop     eax
004004B0    03C1            add     eax, ecx                         ; eax == Kernel32_ExportTable_AddrOfFunc(VA)
004004B2    8B0498          mov     eax, dword ptr [eax+ebx*4]       ; 利用计数器查表得到API offset
004004B5    03C1            add     eax, ecx                         ; 得到API
004004B7    50              push    eax                              ; push api addr
004004B8    E8 A3FFFFFF     call    00400460                         ; 执行

004004C8    59              pop     ecx
004004C9    58              pop     eax
004004CA    83C1 10         add     ecx, 0x10                        ; 取自定义API名字表中的下一项(VirtualProtect)
004004CD    51              push    ecx
004004CE    8BD0            mov     edx, eax
004004D0    E8 8BFFFFFF     call    00400460

004004D5    59              pop     ecx
004004D6    58              pop     eax
004004D7    50              push    eax                              ; push lpProcName
004004D8    FF31            push    dword ptr [ecx]                  ; hModule
004004DA    FFD2            call    edx                              ; edx == GetProcAddress
004004DC    50              push    eax                              ; api(VirtualProtect) addr
004004DD    E8 4EFEFFFF     call    00400330

00400330     8BF8            mov     edi, eax
00400332     50              push    eax
00400333     54              push    esp
00400334     6A 40           push    0x40                            ; VirtualProtect 参数 PAGE_EXECUTE_READWRITE
00400336     68 00010000     push    0x100                           ; VirtualProtect 参数 Size
0040033B     E8 F3000000     call    00400433

00400436      0000            add     byte ptr [eax], al
00400438      D4 1A           aam     0x1A                             ; VirtualProtectEx addr
0040043A      807C95 B9 80    cmp     byte ptr [ebp+edx*4-0x47], 0x80  ; MapViewOfFile addr
0040043F      7C 00           jl      short 00400441

00400350      8B4424 08       mov     eax, dword ptr [esp+0x8]
00400354      8901            mov     dword ptr [ecx], eax             ; 保存 kernel32_imagebase
00400356      8959 04         mov     dword ptr [ecx+0x4], ebx         ; 保存GetProcAddress
00400359      E8 D5000000     call    00400433
0040035E      59              pop     ecx
0040035F      C3              retn

00400580     59              pop     ecx
00400581     58              pop     eax
00400582     50              push    eax                              ; push lpProcName(MapViewOffile)
00400583     FF31            push    dword ptr [ecx]                  ; hModule
00400585     FF51 04         call    dword ptr [ecx+0x4]              ; kernel32.GetProcAddress

保存了前五字节,应是要进入HOOK:
004005B8     59              pop     ecx
004005B9     58              pop     eax
004005BA     83C1 14         add     ecx, 0x14
004005BD     8B10            mov     edx, dword ptr [eax]
004005BF     66:8B58 04      mov     bx, word ptr [eax+0x4]
004005C3     8911            mov     dword ptr [ecx], edx
004005C5     66:8959 04      mov     word ptr [ecx+0x4], bx
004005C9     C3              retn

HOOK操作:
00400606     59              pop     ecx
00400607     58              pop     eax
00400608     C600 68         mov     byte ptr [eax], 0x68
0040060B     8948 01         mov     dword ptr [eax+0x1], ecx
0040060E     C640 05 C3      mov     byte ptr [eax+0x5], 0xC3
00400612     C3              retn

恢复环境:
00400598     61              popad
00400599     830424 07       add     dword ptr [esp], 0x7
0040059D     C3              retn

CreateFile挂后:
7C801A28 >  68 8F074000     push    0x40078F                         ; ASCII "PQ?"
7C801A2D    C3              retn

MapViewOffile挂后:
7C80B995 >  68 38064000     push    0x400638
7C80B99A    C3              retn

 

Patch Code(只是简单跟了下,估计不全只简单跟了下hook createfile的部分,没测试过):

1.
004391c9:
     jmp PatchAddr
PatchAddr:
    call PatchFun(00400810)
恢复原流程:
    mov     ecx, esi
    jmp     004391CB
2.
0043B45E  |.  8B07          mov     eax, dword ptr [edi]
0043B460  |.  48            dec     eax                              ;  Switch (cases 1..C)
0043B461  |.  83F8 0B       cmp     eax, 0xB
0043B464  |.  0F87 95020000 ja      0043B6FF

0043B45E  |.  33C0          xor     eax, eax
0043B460  |.  40            inc     eax                              ;  Switch (cases 1..C)
0043B461  |.  83F8 0B       cmp     eax, 0xB
0043B464  |.  0F87 95020000 ja      0043B6FF
3.
00443830   .  6A FF         push    -0x1

00443830   .  C3            retn
00443831   ?  90            nop

  

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。