首页
社区
课程
招聘
[原创]ASPack脱壳详细分析
发表于: 2009-8-31 23:56 15080

[原创]ASPack脱壳详细分析

2009-8-31 23:56
15080

【文章标题】: ASPack脱壳详细分析
【文章作者】: index09
【作者邮箱】: cradiator@gmail.com
【作者主页】: http://hi.baidu.com/index09
【软件名称】: OD + ASPack
--------------------------------------------------------------------------------
【详细过程】
  上次简单分析了UPX的解压过程。这次我们再分析一个简单的压缩壳ASPack。
  使用ASPack压缩记事本,然后调试开始。
  
  用OD载入后
  01013001 >  60              PUSHAD                                             ; ////////////////////////////////////
  01013002    E8 03000000     CALL NOTEPAD.0101300A
  01013007  - E9 EB045D45     JMP 465E34F7
  0101300C    55              PUSH EBP                                           ; 花指令 在1013015设置断点就可以通过
  0101300D    C3              RETN                                               ; 隐含了call和pop 代码重定位指令
  0101300E    E8 01000000     CALL NOTEPAD.01013014
  01013013    EB 5D           JMP SHORT NOTEPAD.01013072
  01013015    BB EDFFFFFF     MOV EBX,-13
  0101301A    03DD            ADD EBX,EBP                                        ; ebx是用于代码重定位的指针
  0101301C    81EB 00300100   SUB EBX,13000                                      ; ......................................
  这段代码中的JMP是一个花指令,不过使用F7 F8就很容易了解其中隐含的指令。
  这段指令的作用是使用 CALL和POP获得重定位指针。
  
  
  01013022    83BD 7D040000 0>CMP DWORD PTR SS:[EBP+47D],0
  01013029    899D 7D040000   MOV DWORD PTR SS:[EBP+47D],EBX                     ; [ebp+47D] = 重定位指针
  0101302F    0F85 C0030000   JNZ NOTEPAD.010133F5                               ; never jmp
  01013035    8D85 89040000   LEA EAX,DWORD PTR SS:[EBP+489]                     ; eax = kernel32.dll
  0101303B    50              PUSH EAX
  0101303C    FF95 090F0000   CALL DWORD PTR SS:[EBP+F09]                        ; getmodulehandle
  01013042    8985 81040000   MOV DWORD PTR SS:[EBP+481],EAX                     ; [ebp+481] = kernel32 handle
  01013048    8BF0            MOV ESI,EAX                                        ; esi = kernel32 handle
  0101304A    8D7D 51         LEA EDI,DWORD PTR SS:[EBP+51]                      ; ////////////////////////////////////
  这段代码提供了Kernel32.dll的句柄,并存入[ebp+418]中
  
  

  0101304D    57              PUSH EDI                                           ; function name
  0101304E    56              PUSH ESI                                           ; kernel32 handle
  0101304F    FF95 050F0000   CALL DWORD PTR SS:[EBP+F05]                        ; getprocaddress
  01013055    AB              STOS DWORD PTR ES:[EDI]                            ; [ebp+51] = virtualalloc
  01013056    B0 00           MOV AL,0
  01013058    AE              SCAS BYTE PTR ES:[EDI]                             ; 这个循环,获取了VirtualAlloc  VirtualFree
  01013059  ^ 75 FD           JNZ SHORT NOTEPAD.01013058                         ; VirtualProtect三个函数的地址
  0101305B    3807            CMP BYTE PTR DS:[EDI],AL                           ; 分别放在[ebp+51] [ebp+5E] [ebp+6A]
  0101305D  ^ 75 EE           JNZ SHORT NOTEPAD.0101304D                         ; ....................................
  到达这里代码使用GetProcAddress函数,获得了VirtualAlloc、VirtualFree和VirtualProtect三个函数地址。
  并且把它们分别存放在[ebp+51]、[ebp+5E]、[ebp+6A]中。
  这三个函数是解压缩时必须用到的。
  
  
  0101305D  ^\75 EE           JNZ SHORT NOTEPAD.0101304D                         ; ....................................
  0101305F    8D45 7A         LEA EAX,DWORD PTR SS:[EBP+7A]
  01013062    FFE0            JMP EAX                                            ; 跳到下面~~~~~~~~~~~~
  01013064  ^ E1 9A           LOOPDE SHORT NOTEPAD.01013000
  01013066    807C75 61 6C    CMP BYTE PTR SS:[EBP+ESI*2+61],6C
  0101306B    41              INC ECX
  0101306C    6C              INS BYTE PTR ES:[EDI],DX                           ; I/O 命令
  0101306D    6C              INS BYTE PTR ES:[EDI],DX                           ; I/O 命令
  0101306E    6F              OUTS DX,DWORD PTR ES:[EDI]                         ; I/O 命令
  0101306F    6300            ARPL WORD PTR DS:[EAX],AX
  01013071  ^ 74 9B           JE SHORT NOTEPAD.0101300E
  01013073    807C75 61 6C    CMP BYTE PTR SS:[EBP+ESI*2+61],6C
  01013078    46              INC ESI
  01013079    72 65           JB SHORT NOTEPAD.010130E0
  0101307B    65:00D4         ADD AH,DL                                          ; 多余的前缀
  0101307E    1A80 7C75616C   SBB AL,BYTE PTR DS:[EAX+6C61757C]
  01013084    50              PUSH EAX
  01013085    72 6F           JB SHORT NOTEPAD.010130F6
  01013087    74 65           JE SHORT NOTEPAD.010130EE
  01013089    637400 00       ARPL WORD PTR DS:[EAX+EAX],SI
  这是一大段花指令,不过貌似没做好。完全没有达到混淆汇编器的效果。通过JMP EAX直接跳到下面的解压代码。
  
  
  0101308D    8B9D 8D050000   MOV EBX,DWORD PTR SS:[EBP+58D]                     ; 跳到这里~~~~~~~~~~~~~  ebx = [ebp+58D] ???
  01013093    0BDB            OR EBX,EBX
  01013095    74 0A           JE SHORT NOTEPAD.010130A1                          ; always jmp
  01013097    8B03            MOV EAX,DWORD PTR DS:[EBX]
  01013099    8785 91050000   XCHG DWORD PTR SS:[EBP+591],EAX
  0101309F    8903            MOV DWORD PTR DS:[EBX],EAX
  010130A1    8DB5 BD050000   LEA ESI,DWORD PTR SS:[EBP+5BD]                     ; esi = ebp+5BD  point to RAV   RAWSIZE
  010130A7    833E 00         CMP DWORD PTR DS:[ESI],0
  010130AA    0F84 15010000   JE NOTEPAD.010131C5                                ; never jmp
  010130B0    6A 04           PUSH 4                                             ; PAGE_READWRITE
  010130B2    68 00100000     PUSH 1000                                          ; MEM_COMMIT
  010130B7    68 00180000     PUSH 1800                                          ; size
  010130BC    6A 00           PUSH 0                                             ; addr
  010130BE    FF55 51         CALL DWORD PTR SS:[EBP+51]                         ; virtualalloc
  
  .......
  
  0101325C   /74 11           JE SHORT NOTEPAD.0101326F
  0101325E   |03F2            ADD ESI,EDX
  01013260   |AD              LODS DWORD PTR DS:[ESI]
  01013261   |0BC0            OR EAX,EAX
  01013263   |74 0A           JE SHORT NOTEPAD.0101326F
  01013265   |03C2            ADD EAX,EDX
  01013267   |8BF8            MOV EDI,EAX
  01013269   |66:AD           LODS WORD PTR DS:[ESI]
  0101326B   |66:AB           STOS WORD PTR ES:[EDI]
  0101326D  ^|EB F1           JMP SHORT NOTEPAD.01013260
  这便是ASPack的解压指令了。
  这里 [ebp+5BD] 是一个很关键的内存区域,这里面存储了一个结构数组
  struct{
      DWORD dwSecRav;          //原程序段的RVA
      DWORD dwSecRawSize;      //源程序各段的RawSize
  }
  解压过程大致如下:
  1. 然后程序分配了0x1800的解压缓冲空间。
  2. 并且为每个段分配dwSecRawSize大的缓冲空间。
  3. 010130F6    E8 2D050000     CALL NOTEPAD.01013628   将部分数据释放到为每个段分配的缓冲中
  4. 使用缓冲中的数据与对应的段进行运算完成解压过程
  
  
  继续往下面看便是填充IAT的代码了
  0101326F    BE 04760000     MOV ESI,7604                                       ; /////////////////////填写IAT//////////////////
  01013274    8B95 7D040000   MOV EDX,DWORD PTR SS:[EBP+47D]                     ; edx = 重定位指针
  0101327A    03F2            ADD ESI,EDX                                        ; esi 指向结构 IMAGE_IMPORT_DIRECTORY
  0101327C    8B46 0C         MOV EAX,DWORD PTR DS:[ESI+C]
  0101327F    85C0            TEST EAX,EAX
  01013281    0F84 0D010000   JE NOTEPAD.01013394                                ; 这里跳走说明IAT全部填写完成
  01013287    03C2            ADD EAX,EDX
  01013289    8BD8            MOV EBX,EAX
  0101328B    50              PUSH EAX                                           ; eax = lib name
  0101328C    FF95 090F0000   CALL DWORD PTR SS:[EBP+F09]                        ; GetModuleHandle
  01013292    85C0            TEST EAX,EAX
  01013294    75 07           JNZ SHORT NOTEPAD.0101329D
  01013296    53              PUSH EBX
  01013297    FF95 0D0F0000   CALL DWORD PTR SS:[EBP+F0D]                        ; LoadLibrary??
  0101329D    8985 A1050000   MOV DWORD PTR SS:[EBP+5A1],EAX                     ; [ebp+5A1] = lib handle
  
  .....
  
  01013379  ^\E9 2FFFFFFF     JMP NOTEPAD.010132AD                               ; 跳到读取下一个函数
  0101337E    8906            MOV DWORD PTR DS:[ESI],EAX
  01013380    8946 0C         MOV DWORD PTR DS:[ESI+C],EAX
  01013383    8946 10         MOV DWORD PTR DS:[ESI+10],EAX
  01013386    83C6 14         ADD ESI,14
  01013389    8B95 7D040000   MOV EDX,DWORD PTR SS:[EBP+47D]
  0101338F  ^ E9 E8FEFFFF     JMP NOTEPAD.0101327C                               ; ...............................................
  步骤基本如下:
  1. esi指向源程序的 IMAGE_IMPORT_DIRECTORY
  2. 使用GetModuleHandle或LoadLibrary获得DLL的handle
  3. 最后程序破坏了IMAGE_IMPORT_DIRECTORY的OriginFirstThunk等信息,应该是用来防止Dump的。不过这基本没有用处。
  
  
  之后是对文件头的一些修改,因为牵扯到DOS头部,有些东西还没弄明白。
  然后便是
  0101340A    61              POPAD
  0101340B    75 08           JNZ SHORT NOTEPAD.01013415                         ; jmp to OEP
  这两句恢复了寄存器数据,并且JMP到OEP
  
  至此解压完毕,从刚才的过程中我们可以获得IAT的首地址等信息来修复IAT。
  
老规矩,放上加壳和未加壳的Notepad,UDD调试文件。
简单说明一下UDD的使用方法。
用WinHex等32位编辑器打开UDD文件,可以看到里面包含了调试文件的路径。
把它们改成你调试的Notepad的路径,然后把UDD文件考到OD的UDD目录就OK啦~~
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!

                                                       2009年08月31日 23:52:52


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 7
支持
分享
最新回复 (14)
雪    币: 229
活跃值: (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
跟着学习了....辛苦了哇
2009-9-5 19:35
0
雪    币: 229
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3

哈哈,早知道我就把我电脑的几篇文章发出来,也“骗”个精。
2009-9-6 11:21
0
雪    币: 433
活跃值: (1870)
能力值: ( LV17,RANK:1820 )
在线值:
发帖
回帖
粉丝
4
support!
2009-9-6 16:27
0
雪    币: 280
活跃值: (19)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
辛苦辛苦
支持支持
2009-9-6 16:31
0
雪    币: 257
活跃值: (28)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
6
支持支持,学习了!

另外,感觉楼主可能看漏了一个字符“E”,那不是DOS头部的e_crlc,而貌似取PE头的NumberOfSections和SizeOfOptionalHeader、数据表目录Bound Import及代码段大小等,对各段进行了写保护(取消了写权限),然后跳往OEP。不知是否正确?
你提供的UDD文件不用改路径直接放UDD目录中即可用了。
2009-9-6 22:39
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
tkb
7
很好 学习了~
2009-9-7 20:46
0
雪    币: 215
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
学习脱壳
2009-9-8 11:15
0
雪    币: 203
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
楼主难道没有遇到ANTI?昨天看了一个就是ASPack的变形,搞了好久才搞定。楼主的分析过程还是很详细。谢谢。
2009-9-8 12:30
0
雪    币: 46
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
学习了,跟着学习
2009-9-8 14:48
0
雪    币: 16
活跃值: (100)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
11
我怎么就跟不上啊
2009-9-9 16:26
0
雪    币: 206
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
大虾,我参照您下面几句话:
继续往下面看便是填充IAT的代码了
  0101326F    BE 04760000     MOV ESI,7604                                       ; /////////////////////填写IAT//////////////////
  01013274    8B95 7D040000   MOV EDX,DWORD PTR SS:[EBP+47D]                     ; edx = 重定位指针
  0101327A    03F2            ADD ESI,EDX                                        ; esi 指向结构 IMAGE_IMPORT_DIRECTORY

找到我要破解的程序里有这么几句:

00822278    MOV ESI, 33E000                                       ; /////////////////////填写IAT//////////////////
0082227D    MOV EDX,DWORD PTR [EBP+422]              ; edx = 重定位指针
00822283    ADD ESI,EDX                                              ; esi 指向结构 IMAGE_IMPORT_DIRECTORY

我想问问,我让这个程序跑起来后,用Import ReconStructor选择上他,IAT需要的信息----OEP、RVA和大小都该填什么啊?我现在看大虾们写的文章,跟着摸索摸索好困难啊,还请指教。
2009-9-9 23:08
0
雪    币: 257
活跃值: (28)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
13
0101340A    61                popad
0101340B    75 08             jnz short NOTEPAD.01013415          ; jmp to OEP(注意:这里不是直接跳往OEP,是中转站)
0101340D    B8 01000000       mov eax,1
01013412    C2 0C00           retn 0C
01013415    68 9D730001       push NOTEPAD.0100739D
0101341A    C3                retn                                                     ;这里才是去OEP

0100739D    6A 70             push 70                             ; 这里就是真正的OEP了!直接用OD插件Dump,修复输入表时不用修改IAT需要的信息----OEP、RVA和大小,都是正确的,直接抓取脱壳文件就能运行了!
0100739F    68 98180001       push NOTEPAD.01001898
010073A4    E8 BF010000       call NOTEPAD.01007568
010073A9    33DB              xor ebx,ebx
010073AB    53                push ebx
010073AC    8B3D CC100001     mov edi,dword ptr ds:[10010CC]      ; kernel32.GetModuleHandleA
010073B2    FFD7              call edi
2009-9-9 23:50
0
雪    币: 206
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
不是阿,我就是retn后面的位置Dump的,但是程序跑不起来,异常。再说Dump那个对话框上那个是IAT的RVA和大小啊?
2009-9-10 19:25
0
雪    币: 206
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
这是我的问题:高人们帮着看看http://bbs.pediy.com/showthread.php?t=96422
2009-9-10 20:46
0
游客
登录 | 注册 方可回帖
返回
//