吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

搜索
查看: 2894|回复: 40
上一主题 下一主题

[原创] 浅谈Themida 3.0.4.0 x32 IAT修复

  [复制链接]
跳转到指定楼层
楼主
ICEY 发表于 2021-1-5 21:46 回帖奖励
本帖最后由 ICEY 于 2021-1-7 10:34 编辑

前言
    首先呢,我是一个小白,也不太懂太多的专业术语或者更加好的方法,所以以下文章用的方法也是小白都会想到的方法。如果有错误或者哪里有纰漏,也请大家理解。那我们就开始吧!{:1_924:}

ThemIDA 3.0.4.0
    这个壳,在吾爱论坛上也有,
    加密方式是默认的:    

需要用到
虚拟机 XP SP3 2002版 ,OllyDbg ,LordPE , ImportREC , 一点点的小聪明 。 (亿点点的运气,这是我分析时需要的)
ps:XP系统调试这个壳真的贼爽,这个版本的Themida基本检测不到,直接在程序代码段设置内存访问运行两次就能到OEP。←亿点点的运气,不过这篇文章主要讲的也不是找OEP吧。:keai

分析
    先把要脱壳的程序运行起来,然后OD附加,分析主程序的代码段是否被更改:
我这里用了未加壳和程序和已经加壳的程序的代码进行分析,发现他并未对代码段进行更改。(这里和旧版的不同,旧版的是改了代码段的指令的, 。)而是对输入表中的API进行了重定向。接下来的事就简单了。在输入表中下写入断点。然后不就可以知道所有的API了吗?

思路是对的,但是实现起来却花了我不少时间,因为这个壳对在输入表的断点检测比较严格。(第一个难点)
你必须要卡在它要开始填充输入表的前一刻再下写入断点。我这里试了许多办法,都不怎么行,最后盯上了旧版找OEP时需要用到的函数 ZwFreeVirtualMemory ,重载程序后下这个函数断点,但这次,我们看的并不是找OEP时看的EDI,而是要盯住输入表(对易语言来说,你把程序拖进OD,下面那个窗口就是他的输入表)的内容。当按了若干次F9后,你可以注意到,输入表的内容发生了变化,从原来的乱码,变成了略有规律的代码。但并不是重定向的地址。

变化成了
这个时候,就可以在输入表下写入断点了,但不能直接下内存写入断点,因为这里往后程序还会检测内存写入断点。但是过了硬件断点检测,所以只能下硬件写入断点,但硬件写入断点最多只能下16字节,那要下在哪呢?(这是第二个难点)
但其实这个很简单,只要把程序运行起来,看看它哪些API地址没有被重定向,就是下那个地方的硬件写入断点。运行起来可以发现:
可以得到输入表表头的API就没有进行重定向,我们就在这下硬件写入断点。F9后,就可以断在写入API指令的下一行。
我们再在上一行下一个硬件执行断点,就是在写入API的那一行。然后F9一下。就到这里:(然后你多按几次F9你就可以自己发现规律了)
ps:当你到了写入API的地方时,壳对内存写入断点的检测就已经过了,你就可以在输入表所在的区段直接下一个内存写入断点。

规律:

对无需重定向的API:
第一次 mov dword ptr ds:[ecx],eax(此时eax为API,ecx为备份地址)
....(花指令) + 隐藏API + 恢复API(放回EAX)
第二次 mov dword ptr ds:[ecx],eax(此时eax为API,ecx为填充输入表的位置)
....(花指令) + 获取下一个API地址,放到eax
返回  第一次
对需要重定向的API:
第一次 mov dword ptr ds:[ecx],eax (此时eax为API,ecx为备份地址)
....(花指令) + 隐藏API + 垃圾数据放入eax
第二次 mov dword ptr ds:[ecx],eax (此时eax为垃圾数据,ecx为壳段的某个地址)
....(花指令) + 获取下一个API地址,放到eax
返回 第一次
ps1:因为 壳段的地址大小 和 输入表的地址大小 是有很大区别的,所以我们能通过第二次的 mov dword ptr ds:[ecx],eax 的ecx的值判定下一个API是否需要重定向。
ps2:当遇到第一个需要重定向的API开始,往后的API便都需要重定向。
ps3:每一个程序加壳后,所谓的 API 和 备份地址 等 出现在寄存器上的位置,不一定就是 eax 和 ecx ,有可能是其他,随机的。

由规律可以轻易知道,对无需重定向的API,获得之后就直接填入输入表。对需要重定向的API,是先不需要填入输入表的,但重定向得到的地址也迟早需要填入输入表,这就是我们后面需要在输入表所在区段下内存写入断点的原因。
(下内存写入断点后)当壳读取了API地址进行重定向之后,必定要向输入表填入重定向之后的地址,如图:
向输入表的481254位置写入重定向后的API地址 611955。
(写入的指令有好几条,但指令都是“pop dword ptr ds:[ebx]”)这里很重要,写脚本要用到。
ps:重定向API 的顺序和 此处写入输入表的顺序是相同的(别问我怎么知道,问就是发现的规律!)

写脚本
由上面的规律可以知道,不管是需要重定向的API还是无需重定向的API他都需要先放到一个备份地址。而我们就要写一个脚本,将他需要重定向的API先读取出来。脚本如下:
[Asm] 纯文本查看 复制代码
//先手动运行到第一个需要重定向的API处(方法上面有提),再运行脚本。
var api //声明一个变量,用于存放API地址
var dizhi //声明一个变量,用于存放备份地址
mov dizhi,6111AA//备份地址

mov api,[dizhi] //先把第一个被重定向的API地址输出
jmp jlapi

re:
esto
cmp eip,788930 //判断是否停在我们下硬件执行段点
je pdapi //如果是就跳
ret

pdapi:
cmp ecx,6111AA //因为当ECX值就等于备份地址时,新获得的API还未被写入6111AA
je re
mov api,[dizhi]
jmp jlapi

jlapi:
wrta "C:\Documents and Settings\Administrator\桌面\ziji\tmd3API1.txt",api //将得到的api输出到一个记事本
jmp re

接下来,我们也要读取这些API本来需要填充到的地址(上面有提到重定向的顺序和填充IAT的顺序一致),脚本如下:
[Asm] 纯文本查看 复制代码
var ad //声明一个变量,存放api真正需要填充到的地址

mov ad,ebx //上面有说,地址就是ebx的地址。
wrta "C:\Documents and Settings\Administrator\桌面\ziji\tmd3APIdy.txt",ad //将api真正需要需要填充到的地址输出
//上面是先输出当前的

jl:
esto
mov ad,ebx //将下一个填充地址放入ad
wrta "C:\Documents and Settings\Administrator\桌面\ziji\tmd3APIdy.txt",ad //输出
jmp jl //重来!

当你两个脚本都运行完后,你会得到两个TXT,一个是全都是api地址。一个全都是api需要填充到的地址。我们将两个TXT的数据放进表格。可以发现,他们的个数是一样多的,这肯定是当然的啦!
(看来被重定向的API有299个啊)
接下来,我们就要写修复脚本了,我们巧妙地利用一下表格的功能,就能很快写出一个修复脚本啦!
有点投机取巧呢,哈哈。
修复
先到达OEP,然后运行此脚本,刷刷刷!就好了。然后我们用LordPE 修复一下镜像,dump出来,然后用 ImportREC,填好OEP偏移后直接点自动搜索IAT,修复。
看到这一排函数,是不是特别激动呢!{:1_927:}
可是,可别高兴太早了,这个时候。还是不能运行!(当初分析到这里的时候差点就吐了)
我就直接把我分析的结果和 正确思路 直接和大家分享吧。
回到得到全都是API地址的表格,我们利用表格将相同的地址给标记出来,终于发现问题出在哪里了。原来是有一些函数没有经过 上面提到的 mov dword ptr ds:[ecx],eax 所以也没放进备份地址。所以导致读取了两次一样的地址:
  ,

我姑且将这些没经过 mov dword ptr ds:[ecx],eax 的函数地址称为二次加密的入口地址。由上表我们也可以知道,这些二次重定向地址 它们本应该填充到的地址分别为:
[Asm] 纯文本查看 复制代码
4812B0
481268
481224
481190
481298
4812E4
为了搞清楚这些二次重定向的API地址的真实地址到底是什么,我用了许多方法。你们可以在系统的DLL上下访问断点 然后改汇编指令 调用一下这些地址。看一下它到底调用了那些API(注意,此处要先让壳的代码先写出之后才行,因为重定向要进入壳代码。刚开始壳代码是空白)。。等等多种方法。不过一般工作量是真的大!如果有更好的方法能告诉我吗?我这里就直接把我多次分析的结论告诉你们。仅针对 VC程序(其他语言没有研究)。

被二次加密的API分别是:
1.ntdll.RtlSetLastWin32Error
2.ntdll.RtlSizeHeap
3.kernel32.ExitProcess
4.ntdll.RtlReAllocateHeap
5.ntdll.RtlGetLastWin32Error
6.ntdll.RtlUnwind
7.ntdll.RtlDeleteCriticalSection //这应该是仅针对控制台程序
总之,前6个函数必定会二次加密

这是我多次加壳后脱壳修复都会遇到的二次加密的API地址。
?什么?你问我怎么知道哪个是哪个?好家伙,上面不是提供了一种方法给你了吗?举个例子。
我想知道 4812B0 处真正的API地址是什么就直接改汇编指令,CALL他!

然后我猜他是ntdll(因为大部分是ntdll)的,直接下内存访问断点
F9运行,就直接看EIP了:

但这种方法不是万能的,因为DLL的调用就像套娃一样,相互调用。如果都行得通,我们岂不是不就可以每一个函数都这么找吗?
所以这里也是有点运气成分在。还有,我这里改的是OEP的下一行,因为到了OEP,壳代码也肯定都恢复了。其实也不一定要在这里改,你在区段的Themida段下一个内存写入断点,当他写完所有的壳代码后,应该也可以直接CALL,不过这时候是 CALL 65437F , 不是  CALL [4812B0] 。总之找个方法CALL它就行了。
方法二:在上面的函数都下一个断点,然后再CALL重定向的地址,看看程序被断在哪,就可以知道哪个重定向地址对应哪个API。(这个方法应该更加好用)


最后
费了九牛二虎之力,终于脱完了。也可以成功运行,试了一下,是可以跨平台的。
(区段也要优化一下,不然程序太大了)

课件下载:
链接:https://pan.baidu.com/s/1rXISTWf4jjHSC5d6uROOFQ
提取码:52PJ

练习下载:
链接:https://pan.baidu.com/s/15z1gRStyT61MMyTEIIxJPQ
提取码:icey

如果你觉得我这篇文章还行,请给我一个免费的热心值,求求了,这对我真的很重要!

免费评分

参与人数 27威望 +2 吾爱币 +60 热心值 +26 收起 理由
shdavid + 1 + 1 谢谢@Thanks!
w3528810 + 1 + 1 谢谢@Thanks!
dangducluan + 1 + 1 谢谢@Thanks!
fengbolee + 2 + 1 用心讨论,共获提升!
叫我女王 + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
gaosld + 1 + 1 热心回复!
ALCATEL + 1 + 1 谢谢@Thanks!
石碎大胸口 + 1 + 1 用心讨论,共获提升!
xukefei + 1 + 1 谢谢@Thanks!
yAYa + 3 + 1 硬货
Bizhi-1024 + 1 谢谢@Thanks!
dream. + 1 + 1 我很赞同!
nnelqw + 1 + 1 热心回复!
nevinhappy + 1 + 1 用心讨论,共获提升!
笙若 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
wanttobeno + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
solly + 1 + 1 用心讨论,共获提升!
ddx123 + 1 + 1 谢谢@Thanks!
evea + 1 + 1 谢谢@Thanks!
libozi + 1 + 1 用心讨论,共获提升!
FleTime + 3 + 1 用心讨论,共获提升!
冥界3大法王 + 1 用心讨论,共获提升!
gcode + 1 + 1 谢谢@Thanks!
hszt + 1 + 1 用心讨论,共获提升!
Sound + 2 + 28 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
罗萨 + 2 + 1 用心讨论,共获提升!
小朋友呢 + 2 + 1 谢谢@Thanks!

查看全部评分

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

推荐
董督秀 发表于 2021-1-7 17:06
@ICEY 楼主你好,请问这句话的断点下在那里?
输入表所在区段?下内存写入断点的原因。(下内存写入断点后)当壳读取了API地址进行重定向之后,必定要向输入表填入重定向之后的地址,如图:

我已经按照楼主的思路断在了00788930了,并且获取了ds:[006111AA]

下一步在那里下(具体是哪个地址呢) 内存写入断点呢?貌似帖子没有明确清楚。 我下断后,程序直接运行了。楼主是怎么断到0097A5A7的?
推荐
董督秀 发表于 2021-1-8 11:50
ICEY 发表于 2021-1-7 20:23
看区段,输入表所在的区段正好在代码段下面的数据段,在数据段下内存写入断点。

嗯,可以了。是在00401000下面的数据段下内存写入断点。
另外,
脚本存在执行后软件直接运行,从而执行不完全的情况。的情况,
有时候脚本让程序直接运行,执行不完全。
有时候脚本能执行完全,程序还处于暂停状态。
执行不完全的时候,获取不了全部的地址,脚本在什么时候适合执行?
沙发
罗萨 发表于 2021-1-5 21:58
3#
Sound 发表于 2021-1-5 22:04
默认保护,API的思路不错。
4#
Lixinist 发表于 2021-1-5 22:55
用用x64dbg的命令行,一边跟踪一边看寄存器是不是API就可以了
5#
chenjingyes 发表于 2021-1-5 23:01
值得学习 嘿嘿
6#
PrincessSnow 发表于 2021-1-6 00:48
谢谢大佬的教程!
7#
gcode 发表于 2021-1-6 03:56
TMD3也能脱,这也太牛逼了吧,学习学习
8#
嘟囔嘟囔 发表于 2021-1-6 07:38
学习 ,来这么就就会简单的破解。。。
9#
cjc3528 发表于 2021-1-6 08:02
在我眼中你已经是大神,谢谢分享
10#
libozi 发表于 2021-1-6 08:10
学习一下,谢谢分享

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
170077000 + 1 + 1 我很赞同!

查看全部评分

您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

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

GMT+8, 2021-1-20 17:52

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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