Crack_Qs 发表于 2015-6-14 17:42:55

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

本帖最后由 Crack_Qs 于 2015-6-14 17:57 编辑

只是感兴趣,大牛路过.
默笙妹子发来一个被用SMC方式破解的一个软件,于是研究其SMC中的ShellCode.
//////////////////////////////////////////////////////////////////////////////////////////////////
执行流程:
1.首先得到kernel32的ImageBase为起始解析PE,得到导出表.
2.然后取出GetProcAddress函数地址,获取指定的API
3.Api hook破解该软件

分析代码:
00400380   60            pushad                                 ; 保存寄存器环境
00400381   8B4424 44       mov   eax, dword ptr
00400385   25 0000FFFF   and   eax, 0xFFFF0000                  ; 不为序号导出
0040038A   66:8138 4D5A    cmp   word ptr , 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 , al
0040045A:
    0040045A   58            pop   eax
    0040045B   870424          xchg    dword ptr , eax
    0040045E   50            push    eax
    0040045F   C3            retn

进函数时栈布局
$ ==>    > 00400465__CALL_RET_EIP -> EAX
$+4      > 0040039E_CALL_RET_EIP->
$+8      > 7C800000kernel32_ImageBase

出函数时栈布局
$ ==>    > 0040039E_CALL_RET_EIP
$+4      > 00400465__CALL_RET_EIP
$+8      > 7C800000kernel32.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       ; ecx == e_lfanew(offset)
004003A5   03C8            add   ecx, eax                         ; ecx == kernel32_Image_NT_Header
004003A7   8B51 78         mov   edx, dword ptr       ; 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 , 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       ; 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              ; ecx == Kernel32_ImageBase
00400481    8B10            mov   edx, dword ptr              ; 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:
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 , ax
004003CC    64:72 65      jb      short 00400434
004003CF    73 73         jnb   short 00400444
004003D1    0000            add   byte ptr , al
004003D3    56            push    esi
004003D4    6972 74 75616C5>imul    esi, dword ptr , 0x506>
004003DB    72 6F         jb      short 0040044C
004003DD    74 65         je      short 00400444
004003DF    637400 00       arpl    word ptr , si
004003E3    4D            dec   ebp
004003E4    61            popad
004003E5    70 56         jo      short 0040043D
004003E7    6965 77 4F66466>imul    esp, dword ptr , 0x694>
004003EE    6C            ins   byte ptr es:, dx
004003EF    65:0000         add   byte ptr gs:, al
004003F2    0043 72         add   byte ptr , al
004003F5    65:61         popad
004003F7    74 65         je      short 0040045E
004003F9    46            inc   esi
004003FA    696C65 41 00000>imul    ebp, dword ptr , 0x0
00400402    0056 69         add   byte ptr , dl
00400405    72 74         jb      short 0040047B
00400407    75 61         jnz   short 0040046A
00400409    6C            ins   byte ptr es:, dx
0040040A    41            inc   ecx
0040040B    6C            ins   byte ptr es:, dx
0040040C    6C            ins   byte ptr es:, dx
0040040D    6F            outs    dx, dword ptr es:
0040040E    6300            arpl    word ptr , ax

004003C347 65 74 50 72 6F 63 41 64 64 72 65 73 73 00 00GetProcAddress..
004003D356 69 72 74 75 61 6C 50 72 6F 74 65 63 74 00 00VirtualProtect..
004003E34D 61 70 56 69 65 77 4F 66 46 69 6C 65 00 00 00MapViewOfFile...
004003F343 72 65 61 74 65 46 69 6C 65 41 00 00 00 00 00CreateFileA.....
0040040356 69 72 74 75 61 6C 41 6C 6C 6F 63 00 00 00 00VirtualAlloc....

当前在获取GetProcAddress
0040047A    83C0 04         add   eax, 0x4                         ; 挪动指针,方便取新API
0040047D    43            inc   ebx                              ; 计数器
0040047E    8B0C24          mov   ecx, dword ptr              ; ecx == Kernel32_ImageBase
00400481    8B10            mov   edx, dword ptr              ; 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:
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:, byte ptr>; 比较是否一致
0040049C^ 75 DC         jnz   short 0040047A                   ; 不一致开始下一轮
0040049E    58            pop   eax                              ; eax == Kernel32_ImageBase
0040049F    870424          xchg    dword ptr , 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 == Kernel32_ExportTable_AddrOfFunc
004004A8    50            push    eax
004004A9    8B4C24 04       mov   ecx, dword ptr          ; 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        ; 利用计数器查表得到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                   ; 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 , al
00400438      D4 1A         aam   0x1A                           ; VirtualProtectEx addr
0040043A      807C95 B9 80    cmp   byte ptr , 0x80; MapViewOfFile addr
0040043F      7C 00         jl      short 00400441

00400350      8B4424 08       mov   eax, dword ptr
00400354      8901            mov   dword ptr , eax             ; 保存 kernel32_imagebase
00400356      8959 04         mov   dword ptr , 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                   ; hModule
00400585   FF51 04         call    dword ptr             ; kernel32.GetProcAddress

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

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

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

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

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


如何构造的shellcode已经分析完成,下面看是如何破解的:
hook:
004007CC    50            push    eax
004007CD    83C0 75         add   eax, 0x75
004007D0    B9 16924300   mov   ecx, 00439216
004007D5    2BC1            sub   eax, ecx
004007D7    C601 E8         mov   byte ptr , 0xE8
004007DA    8941 01         mov   dword ptr , eax
004007DD    C741 05 8BCEEBA>mov   dword ptr , 0xACEBCE8B
004007E4    83E9 4D         sub   ecx, 0x4D
004007E7    66:C701 EB4B    mov   word ptr , 0x4BEB
004007EC    830424 01       add   dword ptr , 0x1
004007F0    81C1 95220000   add   ecx, 0x2295
004007F6    C701 33C04083   mov   dword ptr , 0x8340C033
004007FC    81C1 D2830000   add   ecx, 0x83D2
00400802    66:C701 C390    mov   word ptr , 0x90C3
00400807    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
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

飘云 发表于 2015-6-14 18:05:17

屌炸天,值得学习!

vipcrack 发表于 2015-6-14 18:36:07

碉堡了!

vipcrack 发表于 2015-6-14 18:36:48

QS,你看下400899哪里开始的后面的KEY是怎么处理的

ppy117 发表于 2015-6-14 22:29:32

{:soso_e100:}学习一下!

Dxer 发表于 2015-6-15 12:48:09

vipcrack 发表于 2015-6-14 18:36
QS,你看下400899哪里开始的后面的KEY是怎么处理的

你又一眼看到了重点,鄙视你的智商太高了。什么时候带带我

small-q 发表于 2015-6-15 17:10:06

不错,你排版的真不错,好舒服,一下就看懂了

crackvip 发表于 2015-6-16 01:36:06

碉堡了!+1

zhgong007 发表于 2018-12-31 03:03:13

不错的技术分析
页: [1]
查看完整版本: 一段被破解程序中的shellcode分析