首页
社区
课程
招聘
[原创]脱壳实践笔记-动态空间填充IAT
发表于: 2020-2-25 13:31 11602

[原创]脱壳实践笔记-动态空间填充IAT

2020-2-25 13:31
11602

F8过PUSHFD、esp右键-HW break、F9

单步几下到达:有个sub esp,0x58,下面还有一个call(一般就是GetVersion),故可判定VC 6.0

image-20191122185855905

下面的WinMain也算是Vc6.0的特征<!--more-->

image-20191122185927427

若pushad与pushfd连着,则fd之后再下断

暂停至popfd后,是一个call,enter过去是lea esp

call xxx + lea esp [esp+4] = jmp xxx(混淆指令-化简为繁

有些call不是真正的函数,要F7,而非F8

FF 15那个call IAT的地方,数据窗跟随,IAT处异常,IAT被壳修改了

image-20191122190023454

IAT处下硬件写入断点,重新运行,检查断下的地方是否正确(有时没有那么准确,一下就到断在理想位置;通过上面的地址和值判断

第一次断在rep movs那,硬件写入为陷阱类,指向下一条,故rep movs的上一条才是;rep movs 物理上一条为JB语句,也不可能是其他地方jmp过来的,jmp指令不可能触发硬件写入,故舍去

image-20191122191018196

再一次断在call处,目的地址同1中都是475080,故这就是(源地址不同,但都是xx5039,可能是一个偏移

image-20191122191140575

在mov 上设置硬件执行断点,去掉原来的硬件写入,重新运行,发现有时会断下,有时断不下;而硬件写入时,每次都会准确断下,推测此指令所在地址是动态变化的

重复1-5,反复测试,发现mov这条填充IAT的指令地址是不确定的,但是后面那个0895是确定的,应该是一个偏移,所以推测:壳代码填充IAT的代码是在申请的内存中执行 (偏移+申请内存的首地址 = 最终地址

验证上述猜想

调用VirtualAlloc的地方0047A37D CALL EAX ,此处下断,运行至此时F8,得到eax即基地址 0x1F0000

image-20191120191855196

基地址+填充IAT指令的偏移,0x1F0000 + 0x0895 = 0x1F0895,跳到此处,下硬件执行(此时刚申请完内存,具体代码还没有拷过去,所以是一堆00,不打紧,照样下断

image-20191120191920293

F9运行,发现断在0x1F0895(此时就有代码了

image-20191120191815132

这样就可保证,每次都会断在填充IAT处(不像一开始有时候断成功,有时候失败

每次运行,都要获取壳代码申请的内存空间的首地址,此时为1f0000(有随机性,每次申请的都不一样,故如此(系统有伪随机性,何况是在虚拟中,尽管如此,也要获取,确保万无一失

image-20191122192636153

填充IAT的位置偏移0895+基地址1f0000=1f0895,下硬件执行,运行到此

image-20191122193041387

image-20191122193108680

F7单步向下执行,发现进入循环,暂不看代码窗口,只关注堆栈窗口,发现是挨个字符的判断(一个函数名中全部字符的循环

运行到向上跳的jmp时,就是循环语句,在本jmp指令与它跳往的地方,二者之间,找JXX条件跳转语句,JXX一般就是跳出循环的

image-20191120202646938

在跳出的xx1ccc下断,F9测试一下,发现就不是一个函数名中各个字符的循环了,而是一个个函数名的循环,表示确实是跳出了内层的循环

在4的基础上继续F7单步,继续找负责本层循环的jxx条件跳转语句(这一个逻辑正好与4相反,4:跳则出循环,5:不跳才是出循环,但实质相同

image-20191120203141485

4的循环时一个函数名字符串中各个字符的循环,5的循环是多个函数名的循环,猜测,接下来就是多个dll的循环了(函数名称字符串有多个字符、一个dll有多个函数、一个exe有多个dll)

在5的基础上,继续F7单步,此时就要慢点了,快要到关键点了,要时刻关注寄存器窗口,肯定会出现xxx.yyy此种形式;发现1911执行后,eax中出现xxx.yyy

image-20191120204525809

这就是所谓获取API地址的地方(不管这个值是怎么出来的,我只知道,运行到此时,eax寄存器中有我想要的东西:原始的API地址)

(将真实API的地址添加到IAT,而非壳加密后的值

(要运行至壳OEP时再执行脚本,前面那个系统断点用OD的F9跳过

如图,修复完成(OEP是结束条件,所以正好运行至OEP

image-20191122213958158

此时IAT表是正常的,dump下来后,通过此正常的IAT来修复输入表

image-20191122214212076

image-20191122215400920

脱壳成功

image-20191122215429251

 
 
 
 
// 基础模版

// 1. 找到三个地址
MOV dwGetAPIAddr,004385BF
MOV dwWriteIATAddr, 004385F0
MOV dwOEP,00409486

// 2. 设置断点(设置之前先清除所有
BC    // 清除所有软件断点
BPHWC // 清除所有硬件断点
BPMC  // 清除所有内存断点

BPHWS dwGetAPIAddr, "x" //当执行到此地址时产生中断.
BPHWS dwWriteIATAddr, "x" //当执行到此地址时产生中断.
BPHWS dwOEP, "x" //当执行到此地址时产生中断.

// 3. 循环
LOOP_START:
  RUN   // 运行,即F9
  CMP dwGetAPIAddr,eip
  JNZ case1
  MOV dwTmp,eax// 将真实API地址保存至临时变量
  JMP LOOP_START
case1:
  CMP dwWriteIATAddr,eip  
  JNZ case2  
  MOV [edi],dwTmp// 将真实API地址填充至IAT表
  JMP LOOP_START
case2:
  CMP dwOEP,eip  
  JNZ LOOP_START  // 继续循环
  MSG "到达OEP!脚本结束"// 若达到OEP则结束

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 3
支持
分享
最新回复 (1)
雪    币: 83
活跃值: (1087)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
2
MOV dwBase,0047A37F                    // 壳申请的内存空间首地址(真实地址
这个每次都不一样 你怎么可以写成固定的呢?
wei为啥要运行至壳OEP时再执行脚本?运行到oep的时候 iat 都被壳处理完了 你此时运行脚本 根本硬断断不下来吧?
2020-2-25 23:47
0
游客
登录 | 注册 方可回帖
返回
//