吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2902|回复: 12
收起左侧

[原创] 脱壳之未知加密壳

  [复制链接]
Nattevak 发表于 2021-12-23 21:15
本帖最后由 Nattevak 于 2021-12-23 21:30 编辑

一、简单分析
1.大致浏览寻找OEP地址,填充IAT的地址,获取API的地址,初步编写通用脚本
①OEP

1.1

1.1


②填充IAT地址

1.2

1.2


③获取API地址

1.3

1.3


将地址填入脚本,进行测试

1.4

1.4

1.5

1.5

[Asm] 纯文本查看 复制代码
// 1.定义变量
MOV dwOEP,0047148B 
MOV dwGetAPI,001E1914 
MOV dwWriteIAT,001E0897 

// 2. 清除环境
BC    // 清除所有软件断点
BPHWC // 清除所有硬件断点
BPMC  // 清除内存断点

// 3. 设置断点
BPHWS dwOEP, "x" //当执行到此地址时产生中断.
BPHWS dwGetAPI, "x" //当执行到此地址时产生中断.
BPHWS dwWriteIAT, "x" //当执行到此地址时产生中断.

// 4. 循环
LOOP0:
  RUN // F9  
  CMP dwGetAPI,eip  
  JNZ CASE1  
  MOV dwTMP,eax
  JMP LOOP0
CASE1:
  CMP dwWriteIAT,eip    
  JNZ CASE2
  MOV [edx],dwTMP       //MOV DWORD PTR DS:[EDX],EAX
  JMP LOOP0
CASE2:
  CMP dwOEP,eip  
  JNZ LOOP0  
  MSG "OEP已到达"

2.再次运行脚本,发现获取API和填充IAT的地址无效了,说明代码地址发生变化。
一般来说,地址随机又两种情况,一是随机基址,二是代码所在处是在申请的内存空间中,这种情况下解决方法就是找到代码基址,然后计算偏移,根据偏移在代码处下断点。
显然这个地方地址随机是因申请了内存导致的。

1.6

1.6


所以可以在VirtualAlloc处下断点,经过动态调试,发现在VirtualAlloc处断下的位置有很多出,最开始的一处栈回溯之后,代码地址是程序的模块中,推测这个地方申请的内存空间就是修复IAT代码的基地址,将之前的代码偏移,减去基址之后加上偏移,代码与之前一样,所以这个地方就是获取代码基址的地方。

1.7

1.7

1.8

1.8

1.9

1.9


分析后故修改脚本如下:

1.10

1.10

[Asm] 纯文本查看 复制代码
// 1.定义变量
MOV dwOEP,0047148B 
MOV dwGetAPI,1914 
MOV dwWriteIAT,0897
MOV dwBase,0047A37F  

// 2. 清除环境
BC    // 清除所有软件断点
BPHWC // 清除所有硬件断点
BPMC  // 清除内存断点

// 3. 设置断点
BPHWS dwOEP, "x" //当执行到此地址时产生中断.
BPHWS dwBase, "x" //当执行到此地址时产生中断.

// 4. 循环
LOOP0:
  RUN // F9     
  CMP dwBase,eip  
  JNZ CASE0    
  ADD dwGetAPI,eax      // 加上基地址
  ADD dwWriteIAT,eax    // 加上基地址              
  BPHWS dwGetAPI, "x"   // 下断点
  BPHWS dwWriteIAT, "x" // 下断点     
  BPHWC dwBase          // 清除硬件断点
  JMP LOOP0    
CASE0:
  CMP dwGetAPI,eip  
  JNZ CASE1  
  MOV dwTMP,eax
  JMP LOOP0
CASE1:
  CMP dwWriteIAT,eip    
  JNZ CASE2
  MOV [edx],dwTMP       //MOV DWORD PTR DS:[EDX],EAX
  JMP LOOP0
CASE2:
  CMP dwOEP,eip  
  JNZ LOOP0  
  MSG "OEP已到达"

3.其他方法
先获取以下基地址,在我们已知的填充IAT和获取API的地址下硬件执行断点

1.11

1.11


程序断下后,发现EAX中保存的是API地址

1.12

1.12


设置RUN跟踪,让EIP等于填充IAT的时候暂停,Ctrl+F7自动步入

1.13

1.13


查看RUN跟踪

1.14

1.14


重点关注7开头的数据,可能就是一个AIP地址

1.15

1.15


直到这个位置EDX中仍然保存的是API地址

1.16

1.16


解密思路:将API地址保存到某一个不用的寄存器中,然后在填充IAT的时候,把IAT直接填到EDX指向的内存中

1.17

1.17

修改代码:
[Asm] 纯文本查看 复制代码
001E14DC       8BDA        MOV EBX,EDX          user32.BeginPaint
001E14DE        90             NOP
001E14DF        90             NOP

001E0895       891A        MOV DWORD PTR DS:[EDX],EBX

下断点运行

1.18

1.18

1.19

1.19

1.20

1.20


DUMP文件并使用IMPREC修复

1.21

1.21


将手工操作转为脚本
[Asm] 纯文本查看 复制代码
// 1.定义变量
MOV dwOEP,0047148B
MOV dwPatch1,14DC 
MOV dwPatch2,0895 
MOV dwBase,0047A37F  

// 2. 清除环境
BC    // 清除所有软件断点
BPHWC // 清除所有硬件断点
BPMC  // 清除内存断点

// 3. 设置断点
BPHWS dwOEP, "x" //当执行到此地址时产生中断.
BPHWS dwBase, "x" //当执行到此地址时产生中断.

// 4. 循环
LOOP0:
  RUN // F9     
  CMP dwBase,eip  
  JNZ CASE0    
  ADD dwPatch1,eax      // 加上基地址
  ADD dwPatch2,eax    // 加上基地址              
  BPHWS dwPatch1, "x"   // 下断点  
  BPHWC dwBase          // 清除硬件断点
  JMP LOOP0    
CASE0:
  CMP dwPatch1,eip  
  JNZ CASE1  
  FILL dwPatch1,4,90           //NOP 4个字节    
  ASM dwPatch1,"MOV EBX,EDX" //将当前指令修改为 MOV DWORD PTR DS:[EDI],EAX
  ASM dwPatch2,"MOV DWORD PTR DS:[EDX],EBX"    
  BPHWC dwPatch1
  JMP LOOP0
CASE1:
  CMP dwOEP,eip  
  JNZ LOOP0  
  MSG "OEP已到达"


二、单步跟踪
将程序载入OD,先查看程序入口,发现有标准的push指令(pushad/pushfd),故采用ESP定律寻找OEP

2.1

2.1


使用ESP定律单步至470A036,就对ESP下断点,然后将程序运行起来

2.2

2.2


程序断在popfd下面,之后一般单步几下就可以到达OEP

2.3

2.3


到达OEP,根据经验可以看出这应该是VC6.0或者易语言程序,向下看可以发现第一个调用的函数CALL[XXX]中的函数地址被加密了,即IAT被加密了

2.4

2.4


而解密IAT的一般方法就是在IAT函数表上下硬件写入断点。
观察OEP附件的函数调用,根据经验来说,VC6.0程序调用的第一个函数应该是GetVersion,但现在能看到的是一个随机的函数地址,像是在申请内存地址

2.5

2.5


F7步入,继续单步跟踪275039地址中的代码,可以发现,原本IAT的函数地址被存放到了一个地址中,代码通过计算地址,获取到了GetVersion的函数地址,之后调用了GetVersion函数

2.6

2.6

2.7

2.7


程序的加密函数,GetVersion
[Asm] 纯文本查看 复制代码
00275039      68 0A000080     PUSH 0x8000000A      ;push一个随机数,占位,到时会存储API地址
0027503E      53              PUSH EBX             ;保存寄存器环境
0027503F      57              PUSH EDI             ;保存寄存器环境  
00275040      E8 00000000     CALL 00275045
00275045      5B              POP EBX
00275046      81EB 0C104000   SUB EBX,0x40100C    ;
0027504C      81C3 24104000   ADD EBX,0x401024    ;SUB和ADD可以化解为一条指令
00275052      8BFB            MOV EDI,EBX         ; EDI=EBX=0027505D
00275054      8B3F            MOV EDI,DWORD PTR DS:[EDI] ; 从EDI中获取 API地址
00275056      897C24 08       MOV DWORD PTR SS:[ESP+0x8],EDI  ; 将API地址存入堆栈,修改的是刚才的占位地址
0027505A      5F              POP EDI             ;恢复寄存器
0027505B      5B              POP EBX             ;恢复寄存器
0027505C      C3              RETN                ;返回到api地址
0027505D      C744F6 76 00000>MOV DWORD PTR DS:[ESI+ESI*8+0x76],>    ;存储的API地址

有些指令可以化解,比如
00275046      81EB 0C104000   SUB EBX,0x40100C
0027504C      81C3 24104000   ADD EBX,0x401024
化解之后就是 ADD EBX,0x18

生成加密的IAT函数大概步骤如下:
1.获取原始IAT函数地址,存放在一定位置
使用LoadLibraryA/W,GetProcAddress函数
2.申请空间,构造新的IAT函数
使用VirtualAlloc申请空间,拷贝代码
3.根据原始IAT函数地址计算加密值,隐藏真实地址
计算类似GetVersion函数中的代码中的x值
   sub edx,x;
   add ebc,x;
4.将新IAT函数地址写入IAT
填充地址到IAT

加密函数
[Asm] 纯文本查看 复制代码
00274986    / EB 73           JMP SHORT 002749FB
002749FB      4C              DEC ESP
002749FC      E8 DBFFFFFF     CALL 002749DC
002749DC      8D6424 04       LEA ESP, DWORD PTR SS : [ESP + 0x4]
002749E0      4C              DEC ESP
002749E1      EB 51           JMP SHORT 00274A34
00274A34      4C              DEC ESP
00274A35      E8 D1FFFFFF     CALL 00274A0B
00274A0B      8D6424 04       LEA ESP, DWORD PTR SS : [ESP + 0x4]
00274A0F      4C              DEC ESP
00274A10    ^ EB E4           JMP SHORT 002749F6
002749F6      83EC 04         SUB ESP, 0x4
002749F9      EB 2A           JMP SHORT 00274A25
00274A25      50              PUSH EAX
00274A26    ^ EB DD           JMP SHORT 00274A05
00274A05      51              PUSH ECX
00274A06      E8 12000000     CALL 00274A1D
00274A1D      8D6424 04       LEA ESP, DWORD PTR SS : [ESP + 0x4]
00274A21      8BC8            MOV ECX, EAX
00274A23    ^ EB B3           JMP SHORT 002749D8
002749D8      03C4            ADD EAX, ESP
002749DA      EB 36           JMP SHORT 00274A12
00274A12      2BC1            SUB EAX, ECX
00274A14      E8 0F000000     CALL 00274A28
00274A28      8D6424 04       LEA ESP, DWORD PTR SS : [ESP + 0x4]
00274A2C      8958 08         MOV DWORD PTR DS : [EAX + 0x8] , EBX
00274A2F    ^ E9 6EFFFFFF     JMP 002749A2
002749A2      59              POP ECX
002749A3      E9 92000000     JMP 00274A3A
00274A3A      58              POP EAX
00274A3B      E8 85FFFFFF     CALL 002749C5
002749C5      8D6424 04       LEA ESP, DWORD PTR SS : [ESP + 0x4]
002749C9      6A 00           PUSH 0x0
002749CB    ^ EB D2           JMP SHORT 0027499F
0027499F      50              PUSH EAX
002749A0      EB 50           JMP SHORT 002749F2
002749F2      03C4            ADD EAX, ESP
002749F4    ^ EB 9B           JMP SHORT 00274991
00274991      2B0424          SUB EAX, DWORD PTR SS : [ESP]
00274994      E8 EFFFFFFF     CALL 00274988
00274988      8D6424 04       LEA ESP, DWORD PTR SS : [ESP + 0x4]
0027498C      8978 04         MOV DWORD PTR DS : [EAX + 0x4] , EDI
0027498F      EB 41           JMP SHORT 002749D2
002749D2      58              POP EAX
002749D3      E8 0B000000     CALL 002749E3
002749E3      8D6424 04       LEA ESP, DWORD PTR SS : [ESP + 0x4]
002749E7      E8 00000000     CALL 002749EC
002749EC      5B              POP EBX
002749ED      E8 C7FFFFFF     CALL 002749B9
002749B9      8D6424 04       LEA ESP, DWORD PTR SS : [ESP + 0x4]
002749BD      81EB 66104000   SUB EBX, 0x401066
002749C3      EB 54           JMP SHORT 00274A19
00274A19      8BFB            MOV EDI, EBX
00274A1B    ^ EB 8B           JMP SHORT 002749A8
002749A8      81C7 C0104000   ADD EDI, 0x4010C0
002749AE      EB 51           JMP SHORT 00274A01
00274A01      8B3F            MOV EDI, DWORD PTR DS : [EDI]
00274A03    ^ EB AB           JMP SHORT 002749B0
002749B0      897C24 08       MOV DWORD PTR SS : [ESP + 0x8] , EDI
002749B4      E9 87000000     JMP 00274A40
00274A40      5F              POP EDI
00274A41    ^ E9 53FFFFFF     JMP 00274999
00274999      5B              POP EBX
0027499A      E8 2E000000     CALL 002E49CD
002749CD      8D6424 04       LEA ESP, DWORD PTR SS : [ESP + 0x4]
002749D1      C3              RETN

根据推测以及对壳shell部分IAT的操作,我们大致可以推出,无论加密不加密IAT,壳其实都会填充IAT,只是加密IAT会填充加密之后的函数。
所以现在只要能找到加密前IAT函数地址以及填充IAT的地方,并且能够在填充IAT时将加密前的函数地址写入,那IAT就相当于完成了解密。
故我们接下来分析的两个关键点就是写入IAT的地方和加密前IAT函数地址出现的地方,对这两个关键点进行破解和解密即可。

综上所诉,下面就从写入IAT的地方开始分析。
首先,在原始OEP处,GetVersion函数的IAT处下写入断点,重新运行程序。

2.8

2.8


程序断下,找到了填充IAT的位置

2.9

2.9


一般来说,写入IAT的地方应该是一个循环,在这个循环中应该包括加载模块、获取函数地址等操作。
所以我们可以在LoadLiibraryA/W和GetProcAddress两个函数上下软件断点,在写入IAT处下一行代码下硬件执行断点。
注:壳中的代码一般都是解压、解密出来的,一般地址不可靠

继续单步跟踪分析,发现代码计算出了一个地址,从这个地址获取了一个4字节的数,且没有规律,一般来说,这种值就是hash值了。

2.10

2.10


继续单步跟踪分析,发现其获取了Kernel32模块基地址

2.11

2.11


继续单步跟踪分析,访问了数据目录表

2.12

2.12


继续单步跟踪分析,又发现获取了导出函数字符串,结合上下文分析,推测代码是在获取导出函数字符串,求字符串的hash值,再与刚才获取的hash值进行对比。

2.13

2.13


继续跟踪发现程序加载了函数字符串的每一个字节,并且进行了计算

2.14

2.14


程序求函数字符串的hash函数
[Asm] 纯文本查看 复制代码
00311CB2      33D2              XOR EDX,EDX
00311CB4     /EB 1E             JMP SHORT 00311CD4
00311CD4      FC                CLD
00311CD5    ^\EB AA             JMP SHORT 00311C81
00311C81      AC                LODS BYTE PTR DS:[ESI]
00311C82      E8 13000000       CALL 00311C9A
00311C9A      8D6424 04         LEA ESP,DWORD PTR SS:[ESP+0x4]
00311C9E      84C0              TEST AL,AL
00311CA0      E8 EDFFFFFF       CALL 00311C92
00311C92      8D6424 04         LEA ESP,DWORD PTR SS:[ESP+0x4]
00311C96      74 33             JE SHORT 00311CCB
00311C98      EB 29             JMP SHORT 00311CC3
00311CC3      C1C2 03           ROL EDX,0x3
00311CC6      E8 0C000000       CALL 00311CD7
00311CD7      8D6424 04         LEA ESP,DWORD PTR SS:[ESP+0x4]
00311CDB      32D0              XOR DL,AL
00311CDD    ^ EB AF             JMP SHORT 00311C8E
00311C8E    ^\EB F1             JMP SHORT 00311C81
化简为
START:
   LODS BYTE PTR DS:[ESI]
   TEST AL,AL
   JE SHORT 00311CCB
   ROL EDX,0x3
   XOR DL,AL
   JMP START
求完之后,hash值保存在了EDX中

当计算完hash值后,会进行比较

2.15

2.15


直接在1A28的位置下断点,运行至此,即hash相等时情况

2.16

2.16


继续单步跟踪分析,找到了获取函数地址的地方

2.17

2.17


继续单步跟踪分析,发现函数地址被处理,使用memcpy拷贝出了一段代码,函数地址被写入到了代码中。而新的函数地址就是memcpy拷贝的首地址,这个地址被写入到了IAT中。

2.18

2.18

2.19

2.19

2.20

2.20


至此,我们已经知道程序在写入一个IAT函数地址时的操作过程,概括为以下步骤。
1.获取预先计算好的hash值
2.循环获取当前正在获取的模块中的导出函数名称,计算hash值,与预存的比较,如果失败继续循环获取
3.如果正确,获取导出函数的地址
4.拷贝预存的代码到缓冲区,将导出函数地址写入到缓冲区中
5.将缓冲区首地址写入IAT处,完成填充IAT的操作

如何解密IAT?此处从函数地址入手,如果当我们获取了原始函数地址,且在写入IAT时,寄存器中还保存的是原始函数地址,那解密IAT就会变得很容易完成。如果代码是线性执行,我们只需改一下跳转应该就可以完成了,但是现在代码混淆度比较高,比较难找到规律,虽然说只要足够耐心,更改跳转应该可以实现,仔细跟踪代码,可以发现其实函数地址最初保存在EAX中,而后保存在EDX中,之后EDX被修改为IAT地址,EAX修改为加密的地址,在这个过程中,只要我们能做到EAX最后是函数地址即可。

经过分析,修改两处代码即可。
第一处代码:

2.21

2.21

这里的修改是为了将函数地址保存到EBX中,因为EBX看起来没有实际使用用处

第二处代码:

2.22

2.22

这里的修改为了将函数地址保存到EAX中,因为最后填充IAT的代码使用的是EAX

2.23

2.23

2.24

2.24


这里也可以改为脚本,与上文方法3类似,更改地址与部分代码即可
[Asm] 纯文本查看 复制代码
  FILL dwPatch1,4,90           //NOP 4个字节    
  ASM dwPatch1,"MOV EBX,EDX" 
  FILL dwPatch2,2,90           //NOP 2个字节    
  ASM dwPatch2,,"MOV EAX,ECX" 

尝试直接修改壳代码
8D642404895401FC
在内存窗口中搜索,定位到地址
[Asm] 纯文本查看 复制代码
0047BB6C      8D6424 04      LEA ESP,DWORD PTR SS:[ESP+0x4]
0047BB70      895401 FC      MOV DWORD PTR DS:[ECX+EAX-0x4],EDX                ; user32.BeginPaint

计算另一个地址
地址=0047BB70-(002214DC-00220895)

2.25

2.25

[Asm] 纯文本查看 复制代码
0047AF29      8902           MOV DWORD PTR DS:[EDX],EAX

(对0047BB70 和0047AF29 两个地址下硬件执行断点)
修改为
[Asm] 纯文本查看 复制代码
0047BB70 mov ebx,edx
0047AF29 MOV DWORD PTR DS:[EDX],EBX

2.26

2.26

2.27

2.27

2.28

2.28


同样可脚本。。。
[Asm] 纯文本查看 复制代码
  FILL dwPatch1,4,90           //NOP 4个字节    
  ASM dwPatch1,"MOV EBX,EDX" 
  ASM dwPatch2,,"MOV DWORD PTR DS:[EDX],EBX" 

2.29

2.29


       未知加密壳的分析至此结束。

附件图片

附件图片


未知加密壳.zip (1.24 MB, 下载次数: 103)

免费评分

参与人数 6威望 +1 吾爱币 +26 热心值 +5 收起 理由
Hmily + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
LegendSaber + 1 + 1 我很赞同!
一块砖头 + 2 + 1 我很赞同!
笙若 + 1 + 1 谢谢@Thanks!
小小沫涵 + 1 用心讨论,共获提升!
KylinYang + 1 + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

是荞麦呀 发表于 2021-12-24 08:49
谢谢大佬分享
jy04468108 发表于 2021-12-24 08:56
这帖子有点技术含量啊,基本上把脱加密壳的步骤都来了一遍。。。
ggyynxj 发表于 2021-12-24 10:24
煎饼果子 发表于 2021-12-24 11:59
谢谢分享
ricroon 发表于 2021-12-24 13:15
非常详细,消化需要时间,感谢大佬!
RatCreak 发表于 2021-12-24 13:33
很详细 不错
Borisding18 发表于 2021-12-24 17:52

非常详细,感谢大佬!
CD3 发表于 2021-12-24 20:26
看看学习
XzeroX 发表于 2021-12-25 21:35
下载失败,可否修复
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-12-25 13:23

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表