yangjt 发表于 2009-8-15 12:01

NoobyProtect SE Demo 1.6.1.0 IAT加密初探

本帖最后由 yangjt 于 2009-8-15 12:15 编辑

【文章标题】: NoobyProtect SE Demo 1.6.1.0 IAT加密初探
【文章作者】: yangjt
【作者邮箱】: yangjietao123@163.com
【作者QQ号】: 325002492
【下载地址】: 附件里
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
非常感谢这两天帮助过我的所有人……特别感谢下Nooby指点,还有HyperChem和Hmily的帮助

首先载入壳,Demo版可以来到VirtualProtect在那里的
E8 75FFFFFF   call    VirtualProtectEx处下断点,然后看堆栈,当堆栈变成这样的时候

0012FF48   FFFFFFFF|hProcess = FFFFFFFF
0012FF4C   00401000|Address = 复件_未?00401000
0012FF50   00004000|Size = 4000 (16384.)
0012FF54   00000040|NewProtect = PAGE_EXECUTE_READWRITE
0012FF58   0012FF84\pOldProtect = 0012FF84

再按一遍F9,这个时候代码段就已经解码了。然后取消断点,来到00401000段……因为我们的目的只是分析IAT,所以找到入口对我们来说并没有太多的作用,Ctrl+B搜索E8 ?? ?? 0A 00搜索不到就更改0A的值,增加或减少,对于这个程序是这个
可以来到这个地方:

004010C7    000D 0A00002A   add   byte ptr , cl
004010CD    8BEC            mov   ebp, esp
004010CF    83EC 44         sub   esp, 44
004010D2    56            push    esi
004010D3    E8 E3BE0A00   call    004ACFBB;这就是被加密的API调用,可以搜索到这里,直接Enter进入
004010D8^ 7D 8B         jge   short 00401065
004010DA    F0:8A00         lock mov al, byte ptr [eax]
004010DD    3C 22         cmp   al, 22
004010DF    75 1B         jnz   short 004010FC
004010E1    56            push    esi
004010E2    E8 D6AF0A00   call    004AC0BD

;call来自004010D3:

004ACFBB    90            nop;直接在这里下断点,运行断下
004ACFBC    68 A448416D   push    6D4148A4                        ;IAT索引?后面用来储存所调用的API需要的地址
004ACFC1    9C            pushfd
004ACFC2    814424 04 341DA>add   dword ptr [esp+4], 74AB1D34      ;修改IAT索引为E1EC65D8
004ACEBA    60            pushad
004AC71C    E8 00000000   call    004AC721
004AC721    58            pop   eax
004AC722    81E8 79C386D7   sub   eax, D786C379                ;貌似是GetModuleHandleA的定位
004AC644   ?E8 0D000000   call    004AC656
004AC649   .6B 65 72 6E 6>ascii   "kernel32.dll",0
004AC656    FF90 CD8286D7   call    dword ptr [eax+D78682CD]         ; kernel32.GetModuleHandleA
004AC362    85C0            test    eax, eax                         ; kernel32.7C800000
004AC364^ 0F84 0CFDFFFF   je      004AC076                        ;不成功?就得到自己的句柄……Nooby说是为了支持插件
004AC01A      E8 10000000   call    004AC02F
004AC01F   .47 65 74 43 6>ascii   "GetCommandLineA",0                ;其实这里已经看到API的名字了……
004ABFF8    50            push    eax                              ;下面的一坨代码是用来模拟GetProcAddress的…
004AC055    E8 B089F6FF   call    00414A0A
00414A0A    E8 F7A90600   call    0047F406
0047F406    50            push    eax
0047F40C    9C            pushfd
0047D183    E8 00000000   call    0047D188
0047D188    E9 902A0000   jmp   0047FC1D
0047FC1D    58            pop   eax
0047FC8B    81E8 81A56389   sub   eax, 8963A581
0047FC91    81C0 5AC66389   add   eax, 8963C65A                ;定位SEH异常处理流程
0047FC97    874424 04       xchg    dword ptr [esp+4], eax      ;充当SEH handler
0047FC9B    9D            popfd
0047FC9C    64:FF35 0000000>push    dword ptr fs:
0047FC25    64:8925 0000000>mov   dword ptr fs:, esp      ;建立异常处理
0047D161    CC            int3                              ;邪恶的CC 9D
0047D162    9D            popfd                              ;Nooby说这里本来是用于猥琐OD的一个Bug,后来因为StrongOD,OD都不吃这套了

;异常类型,STATUS_BREAKPOINT
;到异常处理流程里看看去

0047F261    60            pushad;这里下int3断点
0047F262    8B45 08         mov   eax, dword ptr [ebp+8]      ;pEXCEPTION_RECORD
0047F265    EB 5F         jmp   short 0047F2C6                ;= =SEH处理过程也被猥琐了……
0047F2C6    8B4D 10         mov   ecx, dword ptr [ebp+10]      ;ecx:pContext
0047F270    8B00            mov   eax, dword ptr [eax]      ;eax = dwExceptionCode
0047F2D2    8061 18 F0      and   byte ptr [ecx+18], 0F0      ;iDr7清零
0047F27B    80E8 03         sub   al, 3
0047F2FC^\70 FA         jo      short 0047F2F8                ;这样可以用来判断异常类型,不是不处理,交给上一层SEH
0047F33F    8B99 C1000000   mov   ebx, dword ptr [ecx+C1]      ;ebx=Eflag+1
0047F450    80E3 01         and   bl, 1                        ;TF标志判断
0047F34A    3AC3            cmp   al, bl                        ;猥琐单步用
0047F429^\0F85 C9FEFFFF   jnz   0047F2F8                        ;做个标记了……免得下次再走进去……
0047F3B8    8381 B8000000 0>add   dword ptr [ecx+B8], 0D      ;计算返回位置,加13个字节
0047F3BF    8B81 B8000000   mov   eax, dword ptr [ecx+B8]      ;返回点 = 0047D16E
0047F3C5    0FB600          movzx   eax, byte ptr [eax]                ;返回点的第一个字节
0047F3C8    81C0 9F109961   add   eax, 6199109F
0047F391    81F8 6B119961   cmp   eax, 6199116B                ;判断是否是CC……跳转Demo里没有……
0047F3F0    61            popad
0047F3F1    C7C0 00000000   mov   eax, 0                        ;EXCEPTION_CONTINUE_EXECTION
0047F337    C2 1000         retn    10                              ;安全返回……

;从0047F2FC跳出来的分支
;死亡谷……
0047F2F8    61            popad
0047F331    C7C0 FFFFFFFF   mov   eax, -1                        ;EXCEPTION_CONTINUE_SEARCH
0047F337    C2 1000         retn    10

;返回后:

0047D16E   /E9 5F220000   jmp   0047F3D2
0047F3D2    64:8F05 0000000>pop   dword ptr fs:               ; 解除异常处理,其实可以跑到这个地方下Int3 断点,这样不会被SEH里的检测猥琐
0047F3FC    8D6424 08       lea   esp, dword ptr [esp+8]      ;平衡堆栈
0047F45A    55            push    ebp
0047F4FE    8BEC            mov   ebp, esp
0047F500    81EC 0C010000   sub   esp, 10C
0047F506    53            push    ebx
0047F507    8B5D 08         mov   ebx, dword ptr [ebp+8]      ;dll image base
0047F50A    85DB            test    ebx, ebx
0047F50C    56            push    esi                              ;什么玩艺?
0047F4E1    57            push    edi
0047F515   /74 1D         je      short 0047F534                ;不太可能出问题吧……
0047F738    8BCB            mov   ecx, ebx                  ;这里的代码猥琐程度终于降低了
0047F73A    33FF            xor   edi, edi
0047F73C    E8 F2D2FCFF   call    0044CA33;这里算是比较远的Call,跟进……
0047F741    8B48 7C         mov   ecx, dword ptr [eax+7C]
0047F744    8B70 78         mov   esi, dword ptr [eax+78]
0047F747    03F3            add   esi, ebx
0047F749    85C9            test    ecx, ecx


;call 来自0047F73C:

0044CA33    50            push    eax                              ; kernel32.7C800000
0044CA36    9C            pushfd
00449DE3    E8 00000000   call    00449DE8
00449DE8    E9 BD2C0000   jmp   0044CAAA
0044CAAA    58            pop   eax                              ; 复件_未?00449DE8
0044CAAB    81E8 6C21BA96   sub   eax, 96BA216C
0044CAB1    81C0 C24CBA96   add   eax, 96BA4CC2
0044CAB7    874424 04       xchg    dword ptr [esp+4], eax
0044CABB    9D            popfd
0044CABC    64:FF35 0000000>push    dword ptr fs:
0044CB07    64:8925 0000000>mov   dword ptr fs:, esp
00449C38    CC            int3                              ;这个壳考验的是人的耐心……
00449C39    9D            popfd


;SEH

0044C93E    60            pushad
0044C9B8    8B45 08         mov   eax, dword ptr [ebp+8]
0044C9BB    8B4D 10         mov   ecx, dword ptr [ebp+10]
0044C9BE    8B00            mov   eax, dword ptr [eax]
0044C9C0    8061 18 F0      and   byte ptr [ecx+18], 0F0
0044C9C4    80E8 03         sub   al, 3
0044C9C7^ 0F80 78FFFFFF   jo      0044C945

;下面代码同上一个SEH……代码核心完全一样……只是猥琐程度不同……懒得分析了……


;返回

00449C3D   /E9 BA2D0000   jmp   0044C9FC
0044CA56    64:8F05 0000000>pop   dword ptr fs:
0044CA26    8D6424 04       lea   esp, dword ptr [esp+4]
00413BC4    E8 3A1A0600   call    00475603
00413BC9    1ACA            sbb   cl, dl
00413BCB    53            push    ebx
00413BCC    C3            retn

;call来自00413BC4
;……接下来省略一些猥琐代码……= =还是老一套……

;返回到

00475062   /E9 2E050000   jmp   00475595
00475549    66:8139 4D5A    cmp   word ptr [ecx], 5A4D;终于到了激动人心的时刻……
004755B8^\74 B0         je      short 0047556A      ;是PE文件?
0047556A    8B41 3C         mov   eax, dword ptr [ecx+3C];e_lfanew
004755CD    03C1            add   eax, ecx                ;定位Signature PE
0047F741    8B48 7C         mov   ecx, dword ptr [eax+7C];size of Export Directory
0047F744    8B70 78         mov   esi, dword ptr [eax+78];RVA of Export Directory
0047F747    03F3            add   esi, ebx;VA of Export Directory
0047F749    85C9            test    ecx, ecx;有导出表吗?
0047F6F2    894D F8         mov   dword ptr [ebp-8], ecx;输出表大小保存
0047F6F5^\0F84 39FEFFFF   je      0047F534;没有还扯什么……
0047F6FB    3BF3            cmp   esi, ebx
0047F6BD^\0F86 71FEFFFF   jbe   0047F534;导出表怎么会在PE头前面?
0047F713    8B55 0C         mov   edx, dword ptr [ebp+C];哪个API?EDX=API名称
0047F6CD    81FA 00000100   cmp   edx, 10000;?
0047F762^\73 B4         jnb   short 0047F718;堆栈怎么会用那么多?
0047F718    8B46 20         mov   eax, dword ptr [esi+20];定位export name table
0047F7E0    8A0A            mov   cl, byte ptr [edx]
0047F84D    03C3            add   eax, ebx;VA of export name table
0047F84F    80F9 40         cmp   cl, 40;大于等于'@'?
0047F852    8945 FC         mov   dword ptr [ebp-4], eax
0047F855^ 7E 8E         jle   short 0047F7E5
0047F857    80F9 53         cmp   cl, 53;大于等于'S'?
0047F85A^ 7E D1         jle   short 0047F82D
0047F82D    217D 08         and   dword ptr [ebp+8], edi;清零?
0047F880    397E 18         cmp   dword ptr [esi+18], edi;NumberOfNames
0047F883^ 0F86 E6FEFFFF   jbe   0047F76F;不能是是负数或者0
0047F860    8B4D 08         mov   ecx, dword ptr [ebp+8];ecx=计数器
0047F958    8B0488          mov   eax, dword ptr [eax+ecx*4]
0047F894    03C3            add   eax, ebx;第N个export name
0047F896    E8 80D3FCFF   call    0044CC1B;不是这个函数吗?
0047F89B    85C0            test    eax, eax;返回1继续,返回0找到
0047F8B8   /74 1E         je      short 0047F8D8;是
0047F8BA   |EB 6D         jmp   short 0047F929;下一个
0047F929    FF45 08         inc   dword ptr [ebp+8]
0047F8FF    8B45 08         mov   eax, dword ptr [ebp+8]
0047F938    3B46 18         cmp   eax, dword ptr [esi+18]
0047F906^\72 83         jb      short 0047F88B
0047F88B    8B55 0C         mov   edx, dword ptr [ebp+C]
0047F88E    8B45 FC         mov   eax, dword ptr [ebp-4]
0047F860    8B4D 08         mov   ecx, dword ptr [ebp+8]
0047F958    8B0488          mov   eax, dword ptr [eax+ecx*4]
0047F894    03C3            add   eax, ebx
0047F896    E8 80D3FCFF   call    0044CC1B
0047F89B    85C0            test    eax, eax

;找到所需API的时候

0047F8D8    8B46 24         mov   eax, dword ptr [esi+24];AddressOfNameOrdinals
0047F90B    8B4D 08         mov   ecx, dword ptr [ebp+8]
0047F8E1    8D0448          lea   eax, dword ptr [eax+ecx*2]
0047F9B7    0FB70418      movzx   eax, word ptr [eax+ebx]
0047FB1F    8B4E 1C         mov   ecx, dword ptr [esi+1C];AddressOfFunctions
0047FB22    8D0481          lea   eax, dword ptr [ecx+eax*4]
0047F7B6    8B3C18          mov   edi, dword ptr [eax+ebx];RAV of func
0047FAA0    03FB            add   edi, ebx;VA
0047F76F    3BFE            cmp   edi, esi;这里的EDI就是需要的API                         ; kernel32.7C80262C
0047FAC9^\72 AF         jb      short 0047FA7A
0047FACB    8B45 F8         mov   eax, dword ptr [ebp-8]
0047FACE    03F0            add   esi, eax
0047FAD0    3BFE            cmp   edi, esi
0047FAD2^ 73 A6         jnb   short 0047FA7A
0047FA7A    8BC7            mov   eax, edi                         ; kernel32.GetCommandLineA
0047FC47    E8 51D7FCFF   call    0044D39D;后面省略N多猥琐代码
0044D059   /E9 6C030000   jmp   0044D3CA
004149D0    E8 70A50600   call    0047EF45;继续猥琐
0047D104   /E9 6E1D0000   jmp   0047EE77
0047EF33    E8 57A0F9FF   call    00418F8F;VM Check?
0047EF3C    C3            retn;直接在这里下断点吧……

0047FC4C^\E9 46FFFFFF   jmp   0047FB97
0047FB97    5F            pop   edi
0047FB98^ E9 E4FEFFFF   jmp   0047FA81
0047FA81    5E            pop   esi
0047FA82    E9 5C010000   jmp   0047FBE3
0047FBE3    5B            pop   ebx
0047FBE4    C9            leave
0047FBE5    C2 0800         retn    8
;返回以后的最后一段代码……光明就在眼前了……
004AC05A^\EB A3         jmp   short 004ABFFF
004ABFFF    E8 00000000   call    004AC004
004AC004    EB 30         jmp   short 004AC036
004AC036    59            pop   ecx                              ; 复件_未?004AC004
004AC037    E9 56010000   jmp   004AC192
004AC192    81E9 04C04A00   sub   ecx, 004AC004
004AC198    8981 BDCF4A00   mov   dword ptr [ecx+4ACFBD], eax
004AC19E    C781 C2CF4A00 F>mov   dword ptr [ecx+4ACFC2], 82444FF
004AC1A8^ EB BF         jmp   short 004AC169
004AC169    66:C781 C6CF4A0>mov   word ptr [ecx+4ACFC6], 0C39D
004AC088    0FB618          movzx   ebx, byte ptr [eax]      ;检测API开头的1个字节
004AC13E    81C3 58363566   add   ebx, 66353658
004AC0E2    81FB 24373566   cmp   ebx, 66353724      ;是CC吗?
004AC0E8    74 5C         je      short 004AC146      ;是就猥琐你
004AC0AC    894424 24       mov   dword ptr [esp+24], eax    ;不是就可以转到真正的API了……
004AC0B0    61            popad
004AC0B1    FF4424 08       inc   dword ptr [esp+8];返回地址修正
004AC0B5    90            nop
004AC0B6    9D            popfd
004AC0B7    C3            retn;光明了……
;啊!终于到站了……晕死我了……把我猥琐坏了……
004010D9    8BF0            mov   esi, eax
004010DB    8A00            mov   al, byte ptr [eax]
004010DD    3C 22         cmp   al, 22

返回,IAT分析告一段落……有一些地方有些疑问…欢迎大家指正错误……
--------------------------------------------------------------------------------
【经验总结】
总结下:追踪NP的IAT加密的时候能用Int3断点尽量用……因为整个程序对硬件断点的猥琐很严格……
我一开始以为要用GetProcAddress的……后来发现其实GetProcAddress他是自己实现的……具体步骤就是找到需要Dll的导
出表,然后再挨个找……
写个脚本吧……自己太菜……写不出来……0047F76F每次停在这一行就可以得到地址了,至于调用地址可以读堆栈,修正下
就可以了……

跟以前版本相比的区别……
1.整个流程显得非常猥琐,Demo版本的不足也很容易看到……比较完了不给你跳……囧
2.自己实现了GetProcAddress,这期间没有调用系统API。
3.ZP和VMP的优点融合的非常融洽……搞得那个貌似VM_Check的函数进去直接跟晕了……所以这个函数的功能只是猜测……
具体作用等待Nooby作解析
4.那个貌似IAT索引的东西到底是什么?是为了后面函数返回所Push的一个随即值?程序里好像没有对他进行读取……等待
Nooby作解析



VM+乱续+SEH除了猥琐……还能怎么评价?

--------------------------------------------------------------------------------
【版权声明】: 转载请注明作者并保持文章的完整, 谢谢!

                                                       2009年08月15日 11:39:57

小马甲 发表于 2009-8-15 14:37

太强了,做我的师傅把

wuhanqi 发表于 2009-8-15 15:14

LZ很好很强大..

Hmily 发表于 2009-8-15 16:29

毅力很足,搞完了问一句,累吗?:lol

yangjt 发表于 2009-8-15 17:03

毅力很足,搞完了问一句,累吗?:lol
Hmily 发表于 2009-8-15 16:29 http://www.52pojie.cn/images/common/back.gif
:lol 还行……有点累……

shsww 发表于 2009-8-16 16:00

你也太强悍了吧!厉害

wyg5858 发表于 2009-8-16 17:24

毅力很足,搞完了问一句,累吗

小生我怕怕 发表于 2009-8-16 17:42

楼主好问彩,膜拜加学习~

ZeNiX 发表于 2009-8-17 08:45

注解寫得很不錯.
學習了

20010501 发表于 2009-8-17 20:01

给你加分支持
页: [1] 2 3
查看完整版本: NoobyProtect SE Demo 1.6.1.0 IAT加密初探