IDA 教程-隐藏 IDA 调试器

一个隐藏 IDA 调试器的小技巧
很多 IDA 使用者都向我索要一个可以隐藏调试器的插件或功能。事实上,有很多反调
试的手段,而针对每一种反调试的手段都需要对应一种处理方法。我们先从一些简单的开始,
我们的目的是让 IsDebuggerPresent 函数始终返回 0 值。
当一个调试器处于运行状态时,我们可以在反汇编窗口使用”go to the specified address”
命令进入 IsDebuggerPresent 函数。不幸的是,当前版本的 IDA(译者注:作者文章写于 2005
年)不能在名称列表中显示输入函数名字,因此我们需要在输入框中手动输入函数名字:

请注意我是如何来构造这个地址的:在 Dll 名字后面有一个下划线,之后再加上函数名。
我们在这个函数的结尾放置一个断点。这样我们就可以拦截它并修改它的返回值:

我们并不希望每次这个 IsDebuggerPresent 函数被调用时挂起程序,然后每次手动修改
这个数值,这很麻烦,我们希望它能自动完成这个操作。方法是:我可以使用条件断点,“断
点条件”通常用来确定一个断点应该被触发或抛弃,其语法为 IDC 表达式,如果表达式等
效为 0,断点就不会触发。IDA 需要执行这个表达式,以判断其结果,因此我们可以利用它
的执行结果,修改寄存器或内存为任何你需要的数值。我们编辑断点的属性如下(右击鼠标,
编辑断点):

我们设定条件为” EAX=0”。注意这里不是一个比较,而是一个赋值。当 IDA 执行它的
时候,EAX 会被附带设置为 0,这正是我们需要的。因为我们不想挂起程序,我们也清除
了这个断点的属性。以这种方式断点,就可以让我们的调试器对付 IsDebuggerPresent 的调
用了。这听起来很简单,你或许会问“如果壳作者使用的不是这种幼稚的反调试技巧该如何
应付呢?”,请不要着急,我们以后会继续这个话题。

一个隐藏调试器的插件


上次我提到了一个使用条件断点的小技巧,今天我们会给大家提供一个可以自动处理这
些断点的插件,以便可以使用 IDA 解压一些象“Zotob 蠕虫”这样的恶意软件。
如果测试一个“活”的恶意软件很危险,因此我们将在演示中使用一个示例程序。Zotob
使用 Yoda’s Protector 的一个变种来加壳(可以通过这个连接来认识它)。我们将会使用这个
示例程序,并使用 Yoda’s Protector 来保护它。首先我们尝试对它脱壳。
IDA 给出了很多关于压缩了的可执行文件的提示并尝试装载它。它找到了这个压缩器的
入口,但通常来说,当我们处理一个恶意软件的时候,推荐打开 manual load 选项,并关闭
make imports section 选项。Manual load 选项可以将输入文件的所有区段都装载到数据库中
(恶意软件通常将他们的代码隐藏在文件的任何地方)。取消 Creating the imports seciton,
则可以是 IDA 以原始方式显示整个输入表目录的内容,谁说恶意软件不能在输入表目录中
隐藏呢?

接着我们遇到的问题是,当我们在调试器中试图跟踪壳时,会有非常多的异常。你必须
非常小心的处理这些伪调用和异常。一个不留神我们就会发现已不知身在何处,程序跑飞,
崩溃甚至关闭调试器。它是壳有意这样做的-壳作者喜欢将一些事情复杂化以使其“几乎”
无法被分析。如果一个程序可以在不需要特殊的 key 或额外数据的情况下运行,那么我们可
以让它运行在一个虚拟环境下,并完整的分析它。今天我们不会虚拟化整个环境,只是其中
一小部分-我们将会处理 Windows API 以让壳无法使用他们。
好,回到我们的程序。壳在解压进程中使用 SEH(结构化异常处理),IDA 不停的报告着
每一次异常。这可能是成百上千次。默认情况下,IDA 和多数其它调试器有着类似的设置:
一旦发生异常,它就会挂起程序。通常在这种设置适用于调试“正常”程序,但对我们跟踪
恶意软件却没有任何帮助。
我们修改一下这些异常处理的设置,以让 IDA 不在每次异常时都停下来。你可以通过
用户界面(Debugger,Debugger options,Edit exceptions)或通过编辑 cfg/exceptions.cfg 文件来
进行设置。第二种方法更好些,因为设置将会应用到所有以后的调试中,而第一种方法,只
针对当前的程序有效。我们要告诉 IDA 所有的异常都应交给应用程序来处理。下面是这个
配置文件中的一行:

0xC0000005   nostop app EXCEPTION_ACCESS_VIOLATION     The instruction at 
0x%a referenced memory at 0x%a. The memory could not be %s 


这行设置表示当该异常发生时,调试器不会停止,应用程序会处理这个异常。如果你有
过一些 IDA 的使用经验,你会发现注意到,尽管有这些设置有时 IDA 仍会停止在一个异常
处。如果这是一个“Second Changce”的异常,IDA 将会停止在这个异常:一个未被处理的
“Second Changce”异常将会中止应用程序,IDA 会给你一个处理它的机会。
你可以使用这个文件替换你的配置文件,方法是打开 Debugger,debugger options 对话框
中的 Load 按钮来装载这个配置文件。
使用这个新的配置文件,你可以很容易的单步跟踪它了。你甚至可以在 4766a4 处设置
一个断点来查看它的一个小把戏-在 4766a8 处的自修改代码(就在下面的几条指令)。一旦
开始执行在 4766a5 处的’STOSB’,你就可以在 4766a6 处按 F8,接着代码就在屏幕上出现了。
我不会细说每一个壳中的小把戏,你可以参看其它现在做的非常好的站点上的介绍(译者注:
比如 pediy.com,hehe)。现在,让我们在 476854 处使用一个硬件断点,并返回到程序中。
你会看到壳愉快而又卖力的工作着,并没有发现调试器正在使用 SEH 技巧。
为什么我们要用一个硬件断点,而不是软件断点呢?原因是因为应用程序可以很容易检
测到软件断点。例如,在 4775CE 处有一个计算校验和的函数。如果你使用软件断点,这里
就会得到一个错误的校验和,随之壳就会在其后的某处崩溃。通常说来,推荐使用硬件断点,
但不幸的是,IDA 并没有自动使用它们的选项。我手动在恶意软件中使用硬件断点以让它从
开始运行到一个指定位置。错误是不可避免的,但硬件断点可以让我在整个调试过程中重复
到达上一个已知地址中。好处是我可以在几天后,甚至重启机器仍能继续调试进程

如果你在 476854 处放置一个硬件断点,你会看到下面代码:

 

我们面对的是一个间接调用。当前我们处于调试器中,因此我们可以很容易找到这个被
调用函数的地址,但是显示出来的却很丑陋。让我们使用 IDA 命令来修改它,壳使用许多
基于 EBP 寄存器的参考。很明显 EBP 寄存器并不变化。我们选择整个屏幕,使用“user-defined
offset”命令:

偏移是 EBP,它是个简单的数字(并没有保存一个地址)。因为我们选择了一个区域,
因此它还有一个对话框需要设置:  

我们让它转换在 400000..500000 范围内所有地址为偏移。结果比开始的要好多了:

 

我们看到壳用到 LoadLibrary 这个函数来访问 Windows API 函数。它会检索许多函数的
地址并创建导入表。如果你让程序运行到 476e77(你可以使用硬件断点),你将会在 476451
处看到导入表:

(默认情况下,是看不到这张表的;你需要将鼠标放置在起始位置,创建一个双字,再
创建双字数组)。这张表还不是很好,因为它包括一些名字的参考,但这些条目却没有被命
名。在导入表的每一条将会一个接着一个的被使用,但一个张没有名字的列表没有什么意义。
下面这段脚本,将会修正这张表。使用 F2 进入脚本对话框:

auto ea, name; 
for ( ea=here; ea < 0x476545; ea=ea+4 ) 
{ 
  name = Name(Dword(ea)); 
  name = substr(name, strstr(name, "_")+1, -1); 
  MakeName(ea, name); 
}


下面是脚本运行结果:

查看这张表,我们会发现很多邪恶函数。著名的 IsDebuggerPresent 也在其中,还有一
些如 SuspendThread, TerminateProcess, BlockInput,看上去也不像是好东西。
下面是我们的对策:我们在每一个危险函数上设置条件断点如下:
(EIP=address_of_ret_instruction) && (EAX=return_value)
例如,在 BlockInput 中:

条件断点应是:
(EIP=0x7D9A059B) && (EAX=0x1)
断点会跳过函数的执行并返回了一个我们预设的结果。它不会挂起运行的程序。壳将没
有机会阻止用户的输入,也无法探测调试器和终止它。即使它试图这样,也会失败。
如果每次在运行应用程序时都设置这些断点是很乏味的事情,因此我写了个插件。它非
常简单,我提供了源代码。通过这个插件,可以很容易让应用程序运行且无法检测到调试器:
只需激活插件,然后运行调试器即可。应用程序将会自加压,然后没有任何疑虑的运行。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值