【转帖】浅析CTF中的反静态调试(一)
# **开始**------
在CTF比赛中,出题人总是会用各种手段来阻扰选手们解题的速度,其中最常用的手段就是采用反调试技术,让选手无法舒舒服服的调试程序。倘若想要在比赛中愉快的度过,那么明白怎样处理反调试,理解反调试的原理,将是我们在比赛中“羞辱”出题人最好的利器。
# **前言**
什么是反调试?反调试有什么作用?带着这两个问题,我们开始学习CTF中的反调试手段,并会在后文中用真实的CTF比赛题目来阐述反调试机制和怎样处理反调试。
首先回答什么是反调试?
反调试大致可以分为反静态调试和反动态调试两大类。反静态调试就是阻扰逆向人员静态分析,而反动态调试便是阻扰动态调试。今天我们主要还是弄懂一下反静态调试技术,循序渐进,逐个击破。
反调试有什么作用呢?
程序的开发人员意识到恶意人员经常利用调试器来观察程序的运行结果,从而利用开发的程序,因此他们使用反调试技术尽可能的延长调试的时间。为了阻止调试器的分析,当程序意识到自己被调试时,它可能会改变正常的执行路径或者修改自身程序让自己崩溃,从而增加调试的时间和复杂度。
# **准备的工具**
------
1、 IDA Pro
2、 Ollybug
3、 Peid(查壳工具)
# **正文**
## **一、栈指针平衡**
------
要想彻底的弄明白这个问题,首先至少要明白什么是栈,对于栈的描述和解释,在此推荐《程序员的自我修养——链接、装载与库》和《逆向工程核心原理》这两本书。我在这里就不讲栈的知识。
为了让读者更加清楚,我就画了一个栈的示意图。
!(https://xzfile.aliyuncs.com/media/upload/picture/20190715170827-1babd17c-a6e0-1.png)
在我们做题的时候,用IDA静态分析,想用“F5大法”查看伪代码,结果会出现下面这种情况:
!(https://xzfile.aliyuncs.com/media/upload/picture/20190715170853-2af98d18-a6e0-1.png)
你无法查看伪代码,做题时就很费时间,如果不解决这个问题,我们就只能分析汇编代码,对于逻辑简单的题目来说还可以理解,对于复杂点的题目就只能望洋兴叹。因此。在这一节中我们就解决这个问题,并熟悉其原理,好好的“羞辱”一下出题人。
我们以安恒杯九月赛题为例子:
首先,我们找到是什么地方导致栈指针不平衡,IDA会有提示是
!(https://xzfile.aliyuncs.com/media/upload/picture/20190715170922-3c6d7eb0-a6e0-1.png)
我们找到这个地方,就要分析栈指针
这里,我们要设置一下IDA,让它显示出栈指针
设置前:
!(https://xzfile.aliyuncs.com/media/upload/picture/20190715170958-51922e58-a6e0-1.png)
设置后:(Options-General-Disassembly-"Stack pointer")
!(https://xzfile.aliyuncs.com/media/upload/picture/20190715171030-64d2f4ca-a6e0-1.png)
根据前面的图,我们知道栈在结束后,esp和ebp的值回事一样的。但是我们看这个pop指令后的栈指针与入栈的栈指针根本就不一致。
!(https://xzfile.aliyuncs.com/media/upload/picture/20190715171057-7514348e-a6e0-1.png)
这就引起了栈指针不平衡(原因我们会在第二节中花指令中解释)
因此我们需要手动调节栈指针,让其恢复平衡
注意:每条语句前的栈指针是这条语句未执行的栈指针。
我们在IDA中使用Ait+K就可以修改栈指针
!(https://xzfile.aliyuncs.com/media/upload/picture/20190715171140-8e5b5d78-a6e0-1.png)
因为我们要修改最后两句的栈指针,因此,我们要在这两句之前修改。
!(https://xzfile.aliyuncs.com/media/upload/picture/20190715171152-95b855da-a6e0-1.png)
我们要填入多少呢?
0X21E-0X4 = 0X21A
!(https://xzfile.aliyuncs.com/media/upload/picture/20190715171205-9dabbbce-a6e0-1.png)
!(https://xzfile.aliyuncs.com/media/upload/picture/20190715171216-a422f72e-a6e0-1.png)
这样就栈指针平衡了。
!(https://xzfile.aliyuncs.com/media/upload/picture/20190715171236-b026145c-a6e0-1.png)
就可以反汇编出伪代码了。不过这题是两层加密,具体的做法可以研究一下。知识点挺不错的。
## **二、花指令**
------
为什么会产生栈指针不平衡呢?这可能就是IDA的一个漏洞吧,但是又无可避免。在IDA官网上有这么一段解释:
!(https://xzfile.aliyuncs.com/media/upload/picture/20190715171311-c48afe58-a6e0-1.png)
IDA有栈跟踪的功能,它在函数内部遇到ret(retn)指令时会做判断:栈指针的值在函数的开头/结尾是否一致,如果不一致就会在函数的结尾标注"sp-analysis failed"。一般编程中,不同的函数调用约定(如stdcall&_cdcel call)可能会出现这种情况;另外,为了实现代码保护而加入代码混淆(特指用push/push+ret实现函数调用)技术也会出现这种情况。
想要保护自己的代码可以加入花指令混淆或者垃圾代码,除了花指令外,给软件加壳也是一种混淆代码的方式,但在这里并不讨论壳的问题(以后会分析壳)。
那么,花指令又是怎样影响栈指针的呢?
首先,我们来写一个简单的花指令,我们来分析是怎样影响栈指针的。
!(https://xzfile.aliyuncs.com/media/upload/picture/20190715171427-f243fa0c-a6e0-1.png)
**asm的作用:用于调用内联汇编程序,并且可在 C 或 C++ 语句合法时出现,** asm后跟一个程序集指令、一组括在大括号中的指令或者至少一对空大括号。
emit指令的作用:
1. 编译器不认识的指令,拆成机器码来写。
2. 插入垃圾字节来反跟踪,又称花指令。
用emit就是在当前位置直接插入数据(实际上是指令),一般是用来直接插入汇编里面没有的特殊指令,多数指令可以用asm内嵌汇编来做,没有必要用emit来做,除非你不想让其它人看懂你的代码。
我们来看用IDA反汇编的效果吧。
!(https://xzfile.aliyuncs.com/media/upload/picture/20190715171625-38687e22-a6e1-1.png)
完美显示,但是当我们访问第二个函数的时候就会出现这样的情况
!(https://xzfile.aliyuncs.com/media/upload/picture/20190715171636-3ecbc4e0-a6e1-1.png)
这就是我们想要的结果,我们用花指令成功影响了栈指针平衡。
同样,我们跟踪到出现栈指针不平衡的地方去看看,同时开启栈指针
!(https://xzfile.aliyuncs.com/media/upload/picture/20190715171648-45f9d59a-a6e1-1.png)
在这个图中有两个地方,前面是我们加入的花指令,加入花指令改变了esp的空间而实际有效代码的空间并没有这么大,在esp恢复时(出栈),会加上比实际值大的数字,从而导致栈指针不平衡。这样也就可以达到反跟踪的目的。
在某些CTF出题中,也会有人为的改变esp的值,让esp不正常,从而达到无法静态分析的目的。
小提醒:花指令是一个比较庞大的体系,学习花指令,巧妙的利用花指令,是一个很重要的技巧,不管是在软件开发还是软件调试过程中,都是很重要的。当然,今天分享的知识只是花指令应用的冰山一角,后面会分享一下花指令的鬼斧神工。
# **总结**
------
这次的知识点就是栈指针平衡和花指令的小尝试。同样也是反静态分析中比较基础的两种手段,CTF比赛只会中等难度的题目中遇到。不过这也算是反静态分析体系之中的吧。想要命吧是反静态分析,还是要从基础入手,循序渐进。
在后面几节中,我们会涉及到以下内容:
1、 SMC自解码问题
2、 OLLVM混淆
3、 MOV混淆
4、 还有一些其他反静态分析的技巧。
技术大神,谢谢分享 感谢大牛,受益匪浅 好好学习,天天向上 不错,学习了 麻烦楼主转文章的时候请标注文章来自先知社区好不好,尊重版权 学习了!!!!! 学到了谢谢楼主 非常有用的教程,谢谢分享
页:
[1]