危险漫步博客
新鲜的“黑客思维”就是从全新的角度看待黑客技术,从更高的层面去思考;专注于黑客精神及技术交流分享的独立博客。
文章2306 浏览20581277

破解零起步——认识断点

在我们逆向分析一个程序的时候,程序的二进制代码往往是很多的,而危险漫步要分析的代码是其中具体的一部分,怎么在茫茫的代码海洋中一下就找到我们需要分析的代码呢?这就用到了断点技术,用户需要系统在设置断点处停下来后再进行调试,适当的利用中断来控制程序流程,使我们尽快定位到我们需要分析的代码。

断点是调试器的功能之一,可以让程序中断在需要的地方,从而方便其分析。也可以在一次调试中设置断点,下一次只需让程序自动运行到设置断点位置,便可在上次设置断点的位置中断下来,极大的方便了操作,同时节省了时间。

一般来说断点根据原理和用途不同又分为指软件断点和硬件断点两种。

软件断点是相对于硬件断点来说的,它不需要硬件的支持,只是简单的通过在代码中设置特征值的方式来实现。当需要在某地址代码处设置软件断点的时候,仿真器会先将此处代码进行备份保护,然后将预先设定好的断点特征值(一般为Ox0000、OxCC等不易与代码混淆的值)写入此地址,覆盖原来的代码数据。当程序运行到此特征值所在的地址时,仿真器识别出此处是一个软断点,便会产生中断。当取消断点时,之前受保护的代码信息会被自动恢复。

int3断点是软件断点的一种,在OD中的快捷键是F2,是一种很常用的断点类型。为什么叫int3断点呢?int3其实是一条汇编指令,int3指令的机器码为OxCC.所以通常也称之为CC指令,程序在执行过程中如果遇到int3指令则会触发异常导致中断。用int3断点的好处是可以设置无数个断点,缺点是改变了原程序指令,容易被软件检测到。

在调试程序的时候如果在某一句设置了一个int3断点,刚这一句在内存中对应的代码就会被修改为CC,当被调试进程执行int3指令的时候就会触发一个异常,接着调试就会捕捉这个异常从而停止在断点处,然后将断点处的指令恢复成原来的指令。

普通的int3断点在OD里只要选中需要设置断点的那一句代码,然后按快捷键F2既可,然后被设置断点的那条语句会高亮显示。

这里来看一个简单的例子,这个程序要求你输入一个字符串。如果你输入的字符串不正确则会弹出一个对话框提示你“Sorry,your stringincorrect”。

现在打开OD,加载这个程序,这里向大家介绍OD的一款插件,叫“Ultra String Reference”,顾名思义它是一个关于字符串参考的插件,其实OD本身是带有的字符串参考功能的,但是相对而言对于中文的支持比较差,因此这个插件诞生了,它对中文的支持效果比较好,有ASCII和UNICODE两种模式。

单击菜单栏里的“插件”,然后选“Ultra String  Reference”菜单,接下来选择“Find ASCII”或者“Find UNICODE”,具体使用哪个请自行决定,打开插件以后,这里看到了刚才输入字符串错误的时候提示的信息“Sorry, your string incorrect!”,双击这一句就会来到对应的代码处。

这段代码很简洁,清楚明了,这里的push语句都是向调用的过程传递参数,这里主要看的是第二句,这里是test指令,前面讲过test指令可以用来判断参数是不是O,再看下一句,这里是jnz选择跳转,jnz的意思可以简单理解成not zero,也就是通过上面的比较,不为零则执行跳转,否则向下执行。这里可以看出如果向下执行则会提示“yes,you got it!”,如果跳转被执行了就会提示“sorry, your string incorrect!”,而这里跳转不跳转全是由第二句test指令的参数eax说了算,如果eax是O则提示“yes,you got it!”,否则提示“sorry, your string incorrect!”,那eax的值是怎么得来的,就要看看上面的代码了。上面的代码是这样的:

可以看到这里调用了GetDlgItemTextW函数,调用这个函数用来获得与对话框中的控件相关的标题或文本,这里可以理解成获取我们输入到编辑框里的内容,那下面这个函数是什么呢?这里就需要断点功能了,选中这一句,按快捷键F2,然后可以看到这一句变成了红色。现在按F9让程序运行起来,然后随便输入一个字符串,这里假设是“abcdefg”,然后按“CHECK”按钮,接着程序就被中断了,中断以后按快捷键F8步过,然后下面是1ea指令,lea指令用来传递有效指针,这里继续F8步过,前面说过一般来说函数的返回值是通过eax寄存器传出的,那我们现在看看寄存器里的数据,eax和ecx现在是都是指针,分别指向字符串“monster”和“abcdefg”,我们知道字符串“abcdefg”是我们输入的值,那“monster”是什么呢,看看下面的代码就知道了。

仔细分析一下逻辑就可以看出这里的代码是用来比较两个字符串是不是相同的,我们可以理解成这里把我们输入的字符串和正确的字符串比较,而我们输入的字符串是“monster”,那么程序真正需要的字符串就是“monster”了。运行程序测试一下,输入字符串“monster”,按“CHECK”按钮,可以看到程序弹出了对话框提示“yes,you got it!,测试成功。

但是有些代码在程序运行过程可能会被执行多次,但是我们不需要它每次都被中断,这时就需要用到条件断点了。条件断点,就是在设置断点的时候再给OD-个条件,只有这个条件被满足的时候才会执行中断。在OD里设置一个普通的条件断点只要按快捷键SHIFT+F2既可。

把刚才的CrackMe稍微做一下修改,把字符串比较的代码放到一个函数里,看看反汇编代码,与上一节的就有一点不同:

刚才调用GetDlgltemTextW函数来获取编辑框里的内容,然后通过调用002F1000处的过程来获取正确的字符串,接下来把从编辑框里获取的字符串和正确的字符串进行比较,通过比较结果来弹出不同的对话框。而看到本节的代码,调用GetDlgItemTextW函数来获取编辑框里的内容,然后通过调用002F1000处的过程来获取正确的字符串,但是接下来就不一样了,看这里的第三句代码,把eax的值传给edx,eax是前面调用的过程的返回值,也就是正确的字符串的指针,第四句,传指针,把esp+4传给eax然后调用过程002F1050,而esp+4是通过调用GetDlgItemTextW函数获取到的编辑框里的字符串,过程002F1050则是比较两个字符串的函数,这里通过寄存器来向函数传递参数。

按快捷键CTRL+G,在弹出的对话框中输入002F1050然后按“确定”就会看到002F1050处的代码,我们需要在这里设置一个断点,这样当程序猎取编辑框里的字符串后拿来和正确的字符串比较的时候就会被中断,但是字符串比较的函.数会在程序中使用多次,如果每一次都中断,那么对新手来说就会迷失在茫茫的代码海洋中。这时候就需要用到条件断点了,选中这一句代码,然后按SHIFT+F2,在弹出的对话框里输入需要追加的条件,这里输入的条件是“unicode[eax]=”abcdefg””,意思是当eax指向一个unicode字符串“abcdefg”时满足条件,通过前面的代码可以知道eax是指向从编辑框里获取的代码的指针,而我们在测试的时候输入的字符串就是“abcdefg”。这里简述一下常用的条件断点的设置方法:操作符(和C语言基本一致):

还有一种稍微高级一点的条件断点,称为条件记录断点,按快捷键SHIFT+F4既可,使用方法和条件断点大致相同。

程序在执行过程中为了实现某些功能(比如弹出对话框)通常会调用一些Windows API函数,而函数断点就是在对应的函数的入口点设置一个int3断点,每当程序要调用这个函数的时候就会中断。

看个简单的例子,程序只有一个按钮,但是按钮是灰色的,按不了,这里我们就来充当一回灰色按钮克星。首先来了解一下,让按钮变成灰色一般会用到一个API函数EnableWindow,看看MSDN里给出的解释。函数原型如下:

这个函数有两个参数:hWnd  指向将要禁止或者激活的窗口的句柄bEnable  禁止或者激活的标志。如果该参数的值为TRUE则激活,如果为FALSE则为禁止。

这个函数的返回值为BOOL,如果窗口原来就是被禁止的,返回值为非零,如果窗口原来不是被禁止的,返回值为零。

知道了这些以后打开OD加载这个程序,然后按CT RL-G输入“EnableWindow”,然后就会显示EnableWindow函数的代码,可以在这里按F2设置一个断点,一般来说很多朋友更倾向于一种更加简便的方法,直接在OD命令行插件中输入命令“BP EnabIeWicdow”按回车既可。设置好断点后按F9让程序运行起来,接下来程序就会被中断在EnableWindow函数里,看看这时候堆栈里的信息:

可以看到这里调用了EnableWindow函数,hWncd的值为“CHECK”按钮的句柄,bEnable参数的值为FALSE,通过上面可以知道如果bEnable参数的值为FALSE则为禁止。因为可以确定下来这里的代码就是要使按钮变成灰色了。再注意标记部分,当前执行的代码并非位于程序的模块,而在user32,而我们要分析程序的代码,要返回程序领空才可以,按快捷键ALT+F9让程序执行到用户代码。

这里还调用了另外一个API函数FindWindowExW,这个函数不是我们分析的关键,我们只要知道它的作用就行,它在这里的作用是获取子窗口“CHECK”按钮的句柄然后作为hWnd参数传递给EnableWindow函数,而第一句的“push0”则是向EnableWindow函数传递bEnable参数,0就是FAL SE。我们想要让“CHECK”按钮变为可用状态只要将第一句的“push O”改为“push 1”既可。双击这一句代码,就会弹出汇编窗口,在这里输入“push l”然后点汇编按钮就可以修改此处的汇编代码,修改以后按“取消”,然后在反汇编窗口中点击鼠标右键,选择“复制到可执行文件”-“所有修改”,然后OD会提示你“要把选中内容复制到可执行文件中吗?”,这里选择“全部复制”既可,然后还会弹出一个新的窗口,在这个窗口中再点击鼠标右键,选择“保存文件”,保存修改过的文件后运行测试一下,按钮已经变为可用状态。这里是常用的函数中断方法:

禁止菜单条目EnableMenultem

禁止子窗口  EnableWindow

创建文件句柄CreateFileW(A)

打开文件OpenFile

读取文件    ReadFile

写文件WriteFile

调整文件指针SetFilePointor

退出进程    ExitProcess

创建进程    CreateProcessW(A)

打开注册表项RegOpenKeyW(A)

创建注册表项RegCreateKeyW(A)

删除注册表值RegDeleteValueW(A)

设置注册表值RegSetValueW(A)

获取系统时间GetSysterrTime

发送消息    SendMessageW(A)

传统万能断点hmemcpy

相关推荐