吾爱汇编

 找回密码
 立即注册

QQ登录

绑定QQ避免忘记帐号

查看: 9668|回复: 11

[转载技术] 第十九章-OllyDbg反调试之IsDebuggerPresent

[复制链接]
Shark恒 发表于 2015-1-20 16:19 | 显示全部楼层 |阅读模式

                 第十九章-OllyDbg反调试之IsDebuggerPresent
本章开始,我们将讨论反调试的相关话题,包括手工以及通过OD插件来绕过对应的反调试的技巧。很多程序会检测自身是否正在被调试,如果检测到正在被调试的话,就会结束自身进程或者不按常规流程运行。所以绕过程序对OD的检测是很有必要的。
本章就介绍使用API函数-IsDebuggerPresent检测OD,这也是最常用的检测调试器的方法。
这里,我们使用Crackme1.exe来讲解,用OD加载它。
image002.jpg
我们记得我们的OD只安装了命令栏插件,并没有安装绕过IsDebuggerPresent检测的插件,那么是如何使用IsDebuggerPresent来检测OD的呢?
image004.jpg
如果我们按F9键让程序运行起来,我们会发现并没有弹出CrackMe窗口,程序直接终止了。
image006.jpg
OD的左下方显示程序已经终止,所以,我们看不到窗口出现,嘿嘿。该CrackMe可能使用的是最常见的API函数IsDebuggerPresent来检测是否被调试的。
重启该CrackMe,通过单击鼠标右键选择Searchfor-Name(label) in current module查看API函数列表,看看是否使用了IsDebuggerPresent。
image008.jpg
我们看看API函数列表
image010.jpg
使用了IsDebuggerPresent,嘿嘿。
我们对该函数设置一个断点,看看该CrackMe哪里使用了这个函数。
image012.jpg
我们运行起来,马上就断在该函数的入口处了。
image014.jpg
image016.jpg
根据堆栈窗口中的信息来看,该API函数没有参数,它干的唯一的事情就是检测当前程序是否正在被调试,如果你对该函数还有什么疑问,可以查看MSDN。
image018.jpg
这里解释了该函数的功能,我们来翻译一下。
IsDebuggerPresent表示在被调试器调试情况下,调用该函数会返回正在被调试。
并且该函数是被Kernel32.dll导出的,该函数没有参数,如果当前程序正在被调试的话,返回值为1,没有被调试的话,返回值为0。
这是非常重要的信息,我们执行到返回,看看返回值是多少。
image020.jpg
我们停在了RET指令处,看看寄存器的情况。
image022.jpg
image024.jpg
EAX的值变成了粉红色,表示EAX的值被修改过,跟其他API函数一样,IsDebuggerPersent的返回值也保存在EAX中,这里EAX为1,表示当前程序正在被调试。
我们尝试手动将EAX修改为0,表示当前程序没有被调试,看看会发生什么。
image026.jpg
运行起来。
image028.jpg
再次断在了该API函数入口处,我们执行到返回,然后将EAX的值修改为0。
image030.jpg
我们可以看到该程序启动时的检测是基于IsDebuggerPresent这个API函数的,我们重新运行CrackMe,会断在IsDebuggerPersent处,相应返回值的解释可以参考MSDN。
image032.jpg
我们可以执行到返回,也可以直接F8单步到RET指令,因为这个函数很简短,就几条指令。
image034.jpg
这里到了RET指令处,EAX的值为1,按F8键返回。
image036.jpg
这里我们可以看到,IsDebuggerPersent的调用是位于uxtheme.dll模块中的,我们运行起来,会第二次断在IsDebuggerPresent的入口处。
image038.jpg
这是第二次断在这里了,我们执行到返回,接着F8键返回到上层调用处。
image040.jpg
我们可以看到返回到了4011A9地址处,这里有一个条件跳转JE指令,判断EAX的值是否为0。
image042.jpg
可以看到如果EAX不等于0,跳转将不会发生。如果EAX为0,条件跳转发生,程序将继续执行GetDlgItem函数,读取CrackMe窗口的信息。
在这里条件跳转不会发生,接着执行后面的无条件跳转JMP指令。
image044.jpg
继续跟,我们到了这里。
image046.jpg
这里调用了PostQuitMessage这里API函数,我们看下MSDN中关于该函数的说明。
image048.jpg
MSDN上说该API函数给线程消息队列发送一个WM_QUIT消息来关闭窗口。
执行完该函数后返回:
image050.jpg
如果大家耐心的继续跟的话,就会发现该程序会调用ExitProcess函数来结束进程。(如果大家不想一步步的跟的话,可以直接给ExitProcess函数设置一个断点,然后运行起来,会发现断在了ExitProcess函数处)
image052.jpg
所以,我们可以看出IsDebuggerPresent的返回值决定了程序是继续运行还是结束。重新运行程序又到了该条件跳转指令JE处,一种方案是我们可以给该程序打补丁。
image054.jpg
这里,我们可以将条件跳转JE指令改为无条件跳转JMP指令,即JMP 4011B2(在该指令上单击空格键)。
image056.jpg
这里,我们可以看到JMP指令跳过了关闭程序的代码,程序将继续运行。
我们将该修改保存到文件并且重命名一下,我们单击鼠标右键。
image058.jpg
选择Copy to executable-Selection。
image060.jpg
在新窗口中再次单击鼠标右键选择-Save file。
image062.jpg
image064.jpg
我们将该文件命名为Crackme1p并保存,现在我们就有了原始版本和修改版本了。
现在我们用OD加载刚刚修改过的程序,不设置任何断点,直接运行起来。
image066.jpg
image068.jpg
程序完美运行,所以我们知道了可以通过修改IsDebuggerPersent的返回值EAX来让程序运行,也知道了该如何给程序打补丁而不必每次都手工修改。
对于该CrackMe我们可以打补丁的方法让程序运行起来,但是,还有更简单的方法,直接使用插件,我们就可以避免这些麻烦。不过,我们首先还是有必要知道该插件的原理是什么。
我们依然是给IsDebuggerPersent设置断点。
image070.jpg
该函数由3条不伦不类的MOV指令组成,由该函数判断当前程序是否正在被调试。我们可以想到的第一点就是,当前正在被调试程序不能执行这3条指令,如果被调试的程序执行了这3条指令并且EAX返回1表示当前程序正在被调试。我们现在重新运行该CrackMe,并且在入口点处输入这3条指令。
image072.jpg
我们可以一行一行的复制过去。
image074.jpg
image076.jpg
3条指令都写入了。
image078.jpg
可以看到单步执行这3条指令后,跟IsDebuggerPresent函数一样EAX的值被置为了1。
image080.jpg
尽管当前IsDebuggerPresent函数并没有被调用,程序也没有中断下来,我们依然检测到了当前程序正在被调试。
因此,真正关键的不是IsDebuggerPresent这个API函数,而是该函数所包含的这3条指令。
当前程序开始运行的时候,在内存的某处存放在一个特殊的标志,通过该标志来检测当前程序是否正在被调试,如果该标志为1-当前程序正在被调试,如果该标志为0-当前程序没有被调试。这个特殊的字节的值可以通过IsDebuggerPresent或者上面3条指令读取出来。
我们怎样才能找到这个字节呢?让我们来分析一下这3条指令都干了些什么。
第1条指令:
image082.jpg
我们简单介绍一下有关的理论知识,我们首先在OD中看到这里。
image084.jpg
在这个窗口中我们可以看到一个非常重要的寄存器FS的值,不要把FS想的很复杂,其实该FS的值就是指向了一个结构体,该结构体包含了有关正在运行的程序的一些非常重要的信息。我们在数据窗口中定位到这个地址(你机器上的地址可能与我机器上的地址不同,以你机器上的值为准)。
image086.jpg
该结构被称为TEB或者TIB(线程环境块),该结构保存了有关当前程序的非常重要的信息。例如,TIB被存储在哪里,程序堆栈从哪里开始以及到哪里结束。
image088.jpg
我们单击工具栏中的M按钮打开内存列表窗口,看看堆栈所在的区段。
image090.jpg
可以看到堆栈开始于12d000,下一个区段开始于130000。
该结构里面还有一些有趣的值值得我们研究,比如异常处理相关的东西,这里我们可以看到12FFE0这个地址(我的机器上是12FFE0)。
image092.jpg
在堆栈中定位到该地址。
image094.jpg
可以看到该地址被标识为End of SEH chain。所以我们看不出什么来,但是我们可以确定该地址是与异常相关的。
对于TIB比较有意思的一点是可以通过相应的方式获取自身的值,例如:可以通过FS:[0]的方式获取。
image096.jpg
我们在命令栏中输入? FS:[0]可以获取到该值,如果我们输入? FS:[1]可以得到:
image098.jpg
因此:
FS:[0] 我的机器上对应的值为7FFDF000
FS:[1] 我的机器上对应的值为7FFDF001
......................................
......................................
FS:[18] 我的机器上对应的值为7FFDF018
如果我们还记得,该值其实就是IsDebuggerPresent这个API函数第1条指令读取的值。
image100.jpg
我们可以看到FS:[18]的值为77FFDF018。
image102.jpg
这里就保存着TIB的值,FS:[18]标识的就是TIB的指针。
因此,第1条指令执行后,EAX就保存了TIB的指针,该值在不同的机器上可能会不同。我们按F8键执行该指令。
image104.jpg
好了,现在EAX就保存了TIB的指令。
image106.jpg
现在我们看下一条指令。
image108.jpg
这里EAX + 30,我的机器上计算的结果为7FFDF000+ 30 = 7FFDF030。
对应为FS:[30]。
image110.jpg
这里EAX将保存7FFDF030或者FS:[30]内存单元中的值,在我的机器上该值为7FFDC000,不要与前面的TIB的值弄混淆了。
image112.jpg
这是一个指针,指向了别的东西,我们在数据窗口中定位该地址。
image114.jpg
最后一条指令:
image116.jpg
EAX + 2 即:
7FFDC000+ 2= 7FFDC002
7FFDC002(我的机器上)这个地址处的字节值被保存到了EAX中,这就是我们需要找的字节值。
image118.jpg
这个特殊字节值可以通过IsDebuggerPresent这个API函数读取到。可能在你的机器的该特殊字节保存的地址与我机器的地址不同,但是你可以通过上面的方法很容易的定位到该字节。用OD重新加载该CrackMe。
image120.jpg
这里我们跟上面一样来手工定位到该特殊字节。
首先找到FS寄存器中保存的TIB的指针。
image122.jpg
接着在数据窗口中定位到TIB。
image124.jpg
我们找到FS:[30]即TIB的指针偏移30,我们找到的内容如下:
image126.jpg
该内容为7FFDE000,我们继续在数据窗口中定位到该地址。
image128.jpg
偏移2处的字节就是我们需要找的特殊字节。(我们可以看到EBX的值也指向了该区域,所以如果程序启动的时候,EBX就指向了该区域的话,那么EBX =FS:[30])。
image130.jpg
好了,该方法在程序刚刚启动的时候就可以定位到该特殊字节。现在我们将该字节修改为0。
image132.jpg
现在我们给IsDebuggerPresent设置一个断点。运行起来看看接下来会发生什么。
image134.jpg
执行到返回。
image136.jpg
可以看到EAX的值为0,因为我们修改了那个特殊字节的值,所以当前程序认为它没有被调试。
image138.jpg
可以看到,程序正常运行起来了。
当然,有很多插件,为我们做了上面的事情,HideDebugger1.24就是其中之一。
下载该插件,然后将DLL文件复制到OD的插件目录下。
image140.jpg
复制,嘿嘿。
image142.jpg
重新重启OD。
image144.jpg
选择该插件并进行设置。
image146.jpg
勾选中IsDebuggerPresent,其他的选项我们后面详细介绍到了再勾选。
单击Save。
image148.jpg
我们重新加载CrackMe,可以注意到EBX指向得到区域就是特殊字节的区域。
image150.jpg
我们在EBX的值上面单击鼠标右键选择-Followin Dump。
image152.jpg
可以看到该插件将该特殊字节清零了,从而绕过这个保护。可能这个过程比较简单,但是我认为了解IsDebuggerPresent反调试的原理以及如何绕过这个检测的来龙去脉对大家是大有裨益的。

本系列文章汉化版转载看雪论坛

感谢原作者:RicardoNarvaja(西班牙人)
原作者个人主页:http://www.ricardonarvaja.info/

感谢热心翻译的朋友:
1~3章译者:BGCoder
4~58章译者:安于此生

全集配套程序下载地址:
链接: http://pan.baidu.com/s/1eQzTWfo 密码: vytv



评分

参与人数 12HB +9 THX +6 收起 理由
花盗睡鼠 + 2 + 1 [吾爱汇编论坛52HB.COM]-学破解防破解,知进攻懂防守!
Jawon + 1
一路走来不容易 + 1
Soul1999 + 1
af521 + 1
消逝的过去 + 1
l278785481 + 1
jaunic + 2
成丰羽 + 1 [吾爱汇编论坛52HB.COM]-感谢楼主热心分享,小小评分不成敬意!
sm5186 + 1 [吾爱汇编论坛52HB.COM]-学破解防破解,知进攻懂防守!
hetao8003200 + 1
lies + 1

查看全部评分

吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
saozui324 发表于 2021-11-7 18:58 | 显示全部楼层
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
ghostxu 发表于 2022-1-20 05:01 | 显示全部楼层

全论坛发来贺电
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
莫大 发表于 2022-1-20 09:32 | 显示全部楼层
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
xujinwen 发表于 2022-1-20 12:16 | 显示全部楼层

谢谢大佬!
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
hetao8003200 发表于 2022-1-20 12:27 | 显示全部楼层
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
hackysh 发表于 2022-1-26 17:03 | 显示全部楼层

Searchfor-Name(label) in current module
查看当前模块API函数列表
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
头像被屏蔽
别管我了行 发表于 2022-3-1 03:38 | 显示全部楼层

提示: 作者被禁止或删除 内容自动屏蔽
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
曾经沧海 发表于 2022-11-19 17:31 | 显示全部楼层

大佬太强了
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
曾经沧海 发表于 2023-4-4 10:12 | 显示全部楼层

感谢大佬分享,吾爱因你而精彩!
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

警告:本站严惩灌水回复,尊重自己从尊重他人开始!

1层
2层
3层
4层
5层
6层
7层
8层
9层
10层

免责声明

吾爱汇编(www.52hb.com)所讨论的技术及相关工具仅限用于研究学习,皆在提高软件产品的安全性,严禁用于不良动机。任何个人、团体、组织不得将其用于非法目的,否则,一切后果自行承担。吾爱汇编不承担任何因为技术滥用所产生的连带责任。吾爱汇编内容源于网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除。如有侵权请邮件或微信与我们联系处理。

站长邮箱:SharkHeng@sina.com
站长QQ:1140549900


QQ|RSS|手机版|小黑屋|帮助|吾爱汇编 ( 京公网安备11011502005403号 , 京ICP备20003498号-6 )|网站地图

Powered by Discuz!

吾爱汇编 www.52hb.com

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