脱壳2

 

脱壳­0.upx.exe

① 找OEP

ESP定律

跟脱aspack.exe方法差不多。

脱壳­0.exe(FSG 2.0)

① 找oep

单步跟踪

跳转到OEP代码:

观察寄存器,看是否有在获取导入表的代码附近代表快到OEP了。

就能找到 JMP DWORD PTR DS:[EBX+0xC]

 

 

 

扫描二维码关注公众号,回复: 6907927 查看本文章

② dump内存

。。

③ 修复IAT

FSG 2.0对内存中的IAT 进行了一些空隙填充,需要将其改为0 ,

否则会修复不完全。

进到oep里面,机器码为FF15或者FF25就是跟导入表有关,

 

 

右键数据窗口跟随

 

 

脱壳­2.exe(15PB pack)

① 找OEP

单步跟踪

跟到有个jmp到

 

GetVersion函数特征

 

FF15或者FF25后面跟着一般都是导入表

 

 

对着004094AC这行右键-数据窗口跟随

然后下硬件写入断点,当程序在往里写数据的时候就会断下,就能找到加密的地方。

 

② IAT加密,解密IAT

解密IAT需要先找到加密IAT的地方,然后将其删除或是能还原。

找加密IAT代码的方式

 

 

① 对IAT设置硬件写入断点

对GetVersion所在的iat设置硬件写入断点,最终可以找到填充IAT的地方

004385EE      8907            MOV DWORD PTR DS:[EDI],EAX                ; 填充IAT 函数地址

修改附近代码

 

修改前

 

修改后

 

dump的时候,入口应该用9486.

 

 

修复导入表的时候大小可以弄大点。然后再把无效的剪切掉。

 

② 对IAT相关的API设置断点

LoadLibraryA

GetProcAddress

GetModuleHandleA

VirtualProtect

脱壳中的一些问题

  1. 拿到程序怎么办?

以脱壳为目的,尽可能完成脱壳

  1. 技巧的使用?

① API下断注意的问题

API下断之后,第一应该观察的是堆栈,确定返回地址是我们要分析的模块

 

 

②注意当前分析的模块是不是主模块

 

脱壳­4.exe(未知壳)

① 找OEP

ESP定律

② IAT加密

这个壳使用一些加密技术:

 

  1. IAT函数地址是不规则的

  2. 填充IAT时有混淆代码

  3. 自己实现了一个GetProcAddress

  4. 字符串使用Hash值来存储

  5. 壳代码填充IAT的代码是在申请的内存中执行

混淆规则

  1. jmp 地址

等价于 call 地址

LEA ESP,DWORD PTR SS:[ESP+0x4]

哈希算法

edx=0, 保存计算之后的结果

LODS BYTE PTR DS:[ESI] TEST AL,AL

JE SHORT 002F1CCB ROL EDX,0x3

XOR DL,AL

手动修改填充IAT代码解密IAT

  1. 修改代码

① 保存API函数地址到EBX

 

001D14DC mov dword ptr ds:[ecx+eax-0x4],edx
改为
001D14DC mov ecx,edx

这里的修改为了能将函数地址保存到ecx中,经过测试ecx中的值没有什么用

001D0EE2 mov eax,dword ptr ss:[ebp-0x58]
改为
001D0EE2 mov eax,ecx

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

 

 

 

由于上面代码是在申请出来的地址, 所以有可能是从原程序中拷贝的, 经过搜索,可以在原代码修改

特征:FF 75 D8 E9 AD 00 00 00 C2 04 00 E9 F3 F1 FF FF 8D 64 24 04

 

② 将原CALL指令改为jmp,增加代码空间

 

 

在原代码中修改

 

③ 在原混淆指令上,添加填充IAT代码

 

 

在原代码中修改

 

 

 

寻址OEP解密IAT脚本

// 1. 定义一些必要的变量 VAR  vOldOEP
VAR  vAllocAddr
VAR  vWriteIATAddr
VAR  vGetAPIAddr
VAR  vTmp
​
MOV vOldOEP,0047148B  
MOV vAllocAddr, 0047A37F 
MOV vGetAPIAddr,  14E0 
MOV vWriteIATAddr,0897// 2. 对申请空间的地方下断,取出基址
// 3. 设置其他的断点,让程序跑起来,对每一个断点进行处理
BPHWC  // 清除硬件断点
BC    //清除所有断点 
BPHWS vOldOEP, "x" //当执行到此地址时产生中断. 
BPHWS vAllocAddr, "x" //当执行到此地址时产生中断.
​
LOOP1:
​
RUN 
​
CMP vAllocAddr,eip
JNZ CASE1
ADD vGetAPIAddr,  eax
ADD vWriteIATAddr,eax 
BPHWS vGetAPIAddr, "x" //当执行到此地址时产生中断. 
BPHWS vWriteIATAddr, "x" //当执行到此地址时产生中断.
​
JMP LOOP1
CASE1:
CMP vGetAPIAddr,eip JNZ CASE2
MOV vTmp,edx
JMP LOOP1
​
CASE2:
CMP vWriteIATAddr,eip JNZ CASE3
MOV [edx],vTmp
JMP LOOP1
​
CASE3:
MSG "到达OEP!"

寻找OEP脚本

// 1. 定义变量
VAR dwWriteIATAddr    //  填充IAT地址的下一行地址
VAR dwGetAPIAddr      //  获取到了API地址
VAR dwOEP             //  原始OEP   
VAR dwGetBaseAddr     //  申请的内存             
VAR dwTmp             //  临时变量
// 2. 初始化变了
MOV dwOEP, 0047148B 
MOV dwGetBaseAddr,0047A37F
// 0047A37F     0BC>OR EAX,EAX                            ; eax=申请 的基地址
MOV dwWriteIATAddr,0897 
 // 001D0895     890>MOV DWORD PTR DS:[EDX],EAX            ; 填充IAT             
 // 001D0897     E8 >CALL 001D08D5
 //00300895     890>MOV DWORD PTR DS:[EDX],EAX //00300897     E8 >CALL 003008D5
 MOV dwGetAPIAddr, 0828    
 //00300828   ^\E9 >JMP 00300474    ; eax=函数地址   
 // 3. 清除所有断点    
 BPHWC 
 BPMC    
 BC
 // 4. 设置断点
 BPHWS dwGetBaseAddr, "x"     BPHWS dwOEP, "x"   
 // 5. 循环判断   
 LOOP0:
 RUN  
 CMP eip,dwGetBaseAddr 
 JNZ NEXT1 
 ADD dwWriteIATAddr,eax 
 ADD dwGetAPIAddr,eax           
 BPHWS dwWriteIATAddr, "x"   
 BPHWS dwGetAPIAddr, "x"   
 JMP LOOP0
NEXT1:  
 CMP eip,dwGetAPIAddr             JNZ NEXT2
 MOV dwTmp,eax
 JMP LOOP0
NEXT2:
 CMP eip,dwWriteIATAddr             JNZ NEXT3
 MOV [edx],dwTmp  JMP LOOP0
NEXT3:
  CMP eip,dwOEP   JNZ LOOP0  
  MSG "到达OEP!"

脚本3


// 1. 定义变量
MOV dwGetAPIAddr, 14DC
MOV dwWriteIATAddr, 0895
MOV dwOEP, 0047148B
MOV dwGetBase,0047A37F 
​
​
// 2. 初始化环境
BC     // 清除软件断点
BPHWC  // 清除硬件断点
BPMC   // 清除内存断点
​
​
BPHWS dwGetBase, "x" 
BPHWS dwOEP, "x" 
​
​
// 3. 构建循环判断
LOOP0:
  RUN   //  相当于在OllyDbg中按 F9  
  
  CMP dwGetBase, eip
  JNZ case0   
  ADD dwGetAPIAddr, eax
  ADD dwWriteIATAddr, eax    
  BPHWS dwGetAPIAddr, "x" 
  BPHWS dwWriteIATAddr, "x" 
  JMP LOOP0
    
case0:
  CMP dwGetAPIAddr, eip  
  JNZ case1  
  // 修改指令  
  fill dwGetAPIAddr,4,90   
  asm dwGetAPIAddr, "mov ebx, edx"
  JMP LOOP0
​
case1:
  CMP dwWriteIATAddr, eip  
  JNZ  LOOP0  
  asm dwWriteIATAddr, "mov dword ptr [edx], ebx"   
  // 清除环境  
  BPHWC dwGetAPIAddr
  BPHWC dwWriteIATAddr     
  RUN

 

猜你喜欢

转载自www.cnblogs.com/ltyandy/p/11273679.html