查看原文
其他

Windows 网络编程:破解与调试API函数

计算机与网络安全 计算机与网络安全 2022-06-01

一次性进群,长期免费索取教程,没有付费教程。

教程列表见微信公众号底部菜单

进微信群回复公众号:微信群;QQ群:460500587



微信公众号:计算机与网络安全

ID:Computer-network

调试API是系统留给用户进行程序调试的接口,其功能非常强大。在介绍调试API以前,先来介绍一下OD的使用。OD是强大的用来调试应用程序的工具。为了容易理解,这里我们自己写一个简单程序,用OD来进行调试。除了介绍调试API以外,还会介绍一些简单的与破解相关的内容。当然,破解是一个技术的积累,也是要靠多方面技术的综合应用,希望这些简单的基础知识能给大家起到一个抛砖引玉的作用。


一、CrackMe程序


下面将写一个CrackMe程序,CrackMe的意思就是“来破解我”的意思。这里提到的破解是针对软件方面来说的,不是网络中的破解。对于软件的破解来说,主要是取消软件中的各种限制,比如时间限制、序列号限制……对于破解来说,无疑与逆向工程有着密切的关系,想要突破任何一种限制都要去了解该种限制的保护方式或保护机制。


破解别人的软件属于侵权行为,尽管有很多人在做这样的事情,但是大多人是为了进行学习研究而非用于牟取商业利益。但是,为了尊重他人的劳动成果,也为了避免给自己带来不必要的麻烦,大家尽可能找一些CrackMe来进行学习和研究。


下面来写一个非常简单的CrackMe程序供我们学习研究,并进行“破解”。自己写CrackMe并自己破解,虽然这样省去了很多问题的思考,但是对于初学者来说这仍然是一件非常有乐趣的事情。


这个程序使用MFC来编写,界面如图1所示。

图1  自己编写的CrackMe程序

从图1中可以看出,整个程序只有两个可以输入内容的编辑框,和两个可以单击的按钮,除此之外什么都没有了,更不会有什么提示。基本上这就是一个CrackMe的样子。不过有的人习惯在CrackMe中添加一个美女的照片,让界面显得美观诱惑,有的人喜欢给CrackMe加层壳来增加破解的难度,不过这些对于我们都不重要,关键是要进行学习。在界面上输入一个账号和一个密码,当单击“确定”按钮后,该按钮会执行以下代码:

void CEasyCrackMeDlg::OnBtnReg() {   // TODO: Add your control notification handler code here  char szUser[MAXBYTE] = { 0 };   char szPassword[MAXBYTE] = { 0 };   char szTmpPassword[MAXBYTE] = { 0 };   // 获取输入的账号和密码  GetDlgItemText(IDC_EDIT_USER, szUser, MAXBYTE);   GetDlgItemText(IDC_EDIT_PASSWORD, szPassword, MAXBYTE);   // 判断账号是否为空  if ( strlen(szUser) == 0 )   {     return ;   }  // 判断密码是否为空  if ( strlen(szPassword) == 0 )   {     return ;   }   // 判断账号长度是否小于7  if ( strlen(szUser) < 7 )   {    return ;   }   // 根据账号生成密码  for ( int i = 0; i < strlen(szUser); i ++ )   {     if ( szUser[i] == 'Z'       || szUser[i] == 'z'      || szUser[i] == '9' )     {       szTmpPassword[i] = szUser[i];     }     else    {       szTmpPassword[i] = szUser[i] + 1;     }   }  // 把生成的密码和输入的密码进行匹配  if ( strcmp(szTmpPassword, szPassword) == 0 )   {     MessageBox("密码正确");   }   else  {    MessageBox("密码错误");   } }

整个代码非常简单。这段代码是通过输入的账号来生成密码的,而不是有固定的账号和固定的密码进行一一对应的。生成密码的算法非常简单,把输入的账号的每一个ASCII码进行加1运算,但是有几个ASCII值除外。如果该ASCII码是字符大写“Z”、小写“z”或者是数字“9”,那么,就不会进行加1运算。除了这点外,要求账号的长度必须大于7位,这也算是一个小小的要求了。


测试一下。输入一个小于7位的账号,再随便输入一个密码,单击“确定”按钮,这时程序不会有任何反应。那么,这次输入一个超过7位的账号,单击“确定”按钮来试试,如图2所示。

图2  CrackMe提示错误

CrackMe提示“密码错误”。当然了,密码是根据账号算出来的,而且跟账号的长度是相等的。那么,该如何获得这个CrackMe的密码呢?如果这个CrackMe不是我们写的,那我们该怎么办?接下来的工作,就交给OD来完成吧。


二、用OD破解CrackMe

对于破解来说,总是要找到一个突破点的。而对于这个简单的CrackMe来说,突破点是非常多的。下面会以不同的方式来开始这次破解之旅,不需要有太多的汇编知识,毕竟这里是基础性的知识,要想深入学习破解,对破解有所了解的话,那么学习和掌握汇编是必修课。


1、破解方法一


现在用OD打开所编写的CrackMe,如图3所示。

图3  用OD打开CrackMe后的界面

用OD打开CrackMe以后会看到很多汇编代码,这部分内容大家可以通过学习汇编语言和逆向知识来进行学习。在这里会介绍一些基本的破解技巧,通过这些技巧同样可以完成破解工作。


首先来梳理一下思路,梳理思路的时候可以参考上面写的代码来进行梳理。输入了“账号”及“密码”后,首先程序会从编辑框处获得“账号”的字符串及“密码”的字符串,然后进行一系列的比较验证,再通过“账号”来计算出正确的“密码”,最后来匹配正确的“密码”与输入的“密码”是否一致,根据匹配结果,给出相应的提示。


上面是编写代码的流程和思路,我们也可根据这个思路合理地设置断点(设置断点也叫下断点)。“断点”就是产生中断的位置。通过下断点,可以让程序中断在需要调试或分析的地方。下断点在调试中起着非常大的作用,学会在合理的地方下断点也是一个技巧性的知识,合理地下断点有助于对软件进行分析和调试,大家应该学着掌握它。断点的分类很多,有内存断点、硬件断点、INT 3断点……


现在就可以选择合适的地方设置断点了。可以在API函数上设置断点,比如在GetDlgItemText()行设置断点,也可以选择在strlen()上设置断点,还可以在strcmp()上设置断点,甚至可以在MessageBox()上设置断点。上面的这些API函数都是可以设置断点的,但是对于GetDlgItemText()和MessageBox()这两个API函数来说,需要下断点的时候指定是ANSI版本,还是UNICODE版本。也就是说系统中是没有这两个函数的,根据版本的不同存在系统的函数只有GetDlgItemTextA()、GetDlgItemTextW()、MessageBoxA()和MessageBoxW()这样的函数。通常使用ANSI版本的即可。


上面有如此多的API函数可供我们设置断点,那么要选择哪个进行设置呢?最好的选择是strcmp()这个函数,因为在比较函数处肯定会出现正确的“密码”。而在GetDlgItemTextA()和strlen()上设置断点,需要使用F8进行跟踪。如果在MessageBoxA()上设置断点,那么就不容易找到正确的“密码”存放的位置了。所以选择在strcmp()上设置断点。在“命令”窗口中输入“bp strcmp”,然后按回车键,如图4所示。

图4  在“命令”窗口设置断点

如何知道断点是否设置成功呢?按下Alt + B组合键打开断点窗口可以查看,如图5所示。

图5  在断点窗口查看所下断点

断点已经设置好了,那么就按F9键来运行程序吧。CrackMe启动了,输入一个长度大于等于7位的“账号”为“testtest”,然后随便输入一个“密码”为“123456”,单击“确定”按钮,OD中断在断点,如图6所示。

图6  OD断下响应了断点

从图6中可以看到,OD断在了strcmp这个函数的首地址处,地址为10217570。断在这里如何找到真正的密码呢?其实在提示的地方已经显示出了正确的密码,我们可以看栈窗口。函数参数的传递是依赖于栈的,对于C语言来说,函数的参数是从右往左依次入栈的。对于strcmp()函数来说,该函数有两个参数,这两个参数分别是要进行比较的字符串。那么在栈窗口中可以看到输入的密码及正确的密码,如图7所示。

图7  栈窗口中显示出的两个密码

可以看到,在调用strcmp()时,传递的两个参数的值分别是“123456”和“uftuuftu”两个字符串。前面的字符串肯定是输入的密码,那么后面的字符串肯定就是正确的密码了。按F9键运行程序,会出现那个错误对话框,提示密码错误。现在关闭OD,直接打开CrackMe,现在仍然用刚才的账号“testtest”,然后输入密码“uftuuftu”,单击“确定”按钮,会提示“密码正确”,如图8所示。

图8  密码正确

这样就完成了破解,这种方法比较简单。只要在strcmp()函数处设置断点即可。大家可以试着在其他几个API函数处设置断点,然后试着找到正确的注册码。接下来,尝试使用另外的方法来对CrackMe进行破解。


2、破解方法二


在上一种方法中通过对API函数设置断点找到了正确的密码,现在通过提示字符串来完成破解。在不知道正确密码的情况下输入密码,通常会得到的提示字符串是“密码错误”,只要在程序中寻找该字符串,并且查看是何处使用了该字符串,那么就可以对破解起到提示性的作用。


用OD打开CrackMe程序,然后在反汇编界面处单击鼠标右键,在弹出的菜单中依次选择“超级字串参考”->“查找ASCII”命令,会出现“超级字串参考”窗口,如图9所示。

图9  超级字串参考

在“超级字串参考”窗口中可以看到两个非常熟悉的字符串,双击“密码正确”这个字符串,来到004024de地址处,该地址内容如图10所示。

图10  004024DE地址处反汇编代码

从图10中可以看到3处比较关键性的内容,第一个是可以看到strcmp()函数,第二个是可以看到字符串“密码正确”,第三个是可以看到字符串“密码”错误。由这3个内容可以让我们联想到这岂不是和C代码基本上是对应的啊。根据strcmp()的比较结果,if……else……会选择不同的流程进行执行。也就是说,只要改变比较的结果,或者更换比较的条件,都可以改变程序的流程。下面主要讲述一下修改比较条件的方法,拿具体的例子来解释一下,在代码中是这么一个情况,代码如下:

但是对于反汇编应该如何做呢?其实非常简单,我们再回过头来看一下图10中的那几条反汇编代码。想要修改其判断条件,那么只要修改004024D8处的指令代码JNZ SHORTEasyCrac.004024ED即可,该指令的意思是如果比较结果不为0,则跳转到004024ED处执行。JNZ结果不为0则跳转,只要把JNZ修改为JZ即可,JZ的意思刚好与JNZ相反。修改方法很简单,选中004024D8地址所在的行,按下空格键即可进行编辑,如图11所示。

图11  在OD中修改反汇编代码

单击窗口上的“汇编”按钮,然后按F9键运行,随便输入一个长度大于7位的账号,再输入一个密码,然后单击“确定”按钮,会提示“密码正确”,如图12所示。

图12  修改指令后的流程

关掉OD和CrackMe,然后直接运行CrackMe,随便输入账号和密码,单击“确定”按钮后提示密码错误。为什么呢?因为刚才只是在内存中进行了修改,需要对文件进行存盘在以后运行时我们的修改才有效。修改后的存盘方法为:选中修改的反汇编代码(可以多选几行,只要修改的那行被选中即可),然后单击右键,在弹出的菜单中选择“复制到可执行文件”->“选定内容”命令,会出现“文件”对话框,如图13所示。

图13“文件”对话框

在出现的这个对话框中单击鼠标右键,在弹出的菜单中选择“保存文件”命令,然后进行保存。这样我们的修改就存盘了,下次在执行该程序时,随便输入大于7位的账号和密码都会提示“密码正确”了。如果你输入了正确的密码,那么会提示“密码错误”。


上面就是两种破解该CrackMe的方法,这两种方法都是极其简单的方法,这里是为了学习,为了提高动手能力,而采用了这两种方法。

微信公众号:计算机与网络安全

ID:Computer-network

【推荐书籍】

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存