网络安全课程作业-RE

根据 crackme,overflow,overflow2,overflow3 的二进制程序,复现授课中的利用过程, 并将详细步骤整理(重要步骤的截图要清晰)到报告中;

Crackme.c

先用codeblock编写crackme.c代码。用release版本编译,然后IDA32位打开编译好的exe文件。

先实验一下代码。

F5反编译主函数。发现主函数逻辑比较好认得。

打开汇编目录,找到关键跳转。只需将jnz改成jz,便成功。

Ctrl + Alt + K 修改此处代码。

Edit -> Program File -> Apply patches to input files. 点击OK。

完成了对程序的修改,再打开试一下。成功。

Overflow1.c

写出代码,用debug版本编译。

用OD打开,找到主函数,下好断点。
先输入qqqqqqq。进入verify_password函数。观察其栈帧变化。


先运行完strcmp函数,发现其返回值放在EBP – 0XC 位置,跟踪其位置。此时为1。


再运行完strcpy函数,其将复制的字符串放在EBP-0X14位置。看到其并未覆盖EBP-0XC。


所以程序会直接返回1,输出错误

现在输入qqqqqqqq。发现EBP-0XC的位置为1

运行完strcpy函数,发现EBP-C的位置已经被’/0’的00所替换。所以返回0。输出正确。


然后输入 11111111。发现此时EBP-0XC的位置是0xFFFFFFFF。

执行完strcpy函数。发现EBP-0XC位置被填充,但是未被填充完。

所以函数返回值仍不是0.
输出仍错误。

Overflow2

先写代码。用debug版本编译。然后用IDA打开。

找到了关键跳转位置,是在 0x0040140A 的地方。
然后打开OD,观察栈针。
经过观察,并且根据上个实验,很快就找到了相应的位置。根据代码,我们要从ebp-0x14的地方开始填字符串,填到ebp + 0x4的地方,并且将关键跳转位置覆盖。


这其中有七个字节,所以我们选择3组12345678 + 跳转位置。
这里有个小问题,就是0A是换行符,所以保存成HEX没法读进去。这里采用的解决方法是在程序的无用的地方开辟一个跳转。让程序先return到跳转处,再跳转到成功位置。

选择的位置是 0x401337 。所以填入 401337。 完成输入。

完成后开始试验。
进入函数。

经过strcpy。成功修改返回地址。



成功实现栈溢出

Overflow3

首先输入代码。用debug版本编译。

用OD进行动态调试,进入关键函数。发现在函数结束会多个栈检查函数。这里影响到栈溢出。就直接nop掉。
观察栈帧,是从EBP-30处开始填入字符串,我们这里构造字符串,一直溢到EBP+4处。多余部分用nop(90)代替。
需要找到MessageBoxA的函数地址。用下面代码可以找到其函数地址。

      #include <stdio.h>  
      #include <windows.h>  
      typedef void (*FuncPointer)(LPTSTR);  // 函数指针    
      int main()  
      {     
	    HINSTANCE LibHandle;  
	    FuncPointer GetAddr;  
	    // 加载成功后返回库模块的句柄   
	    LibHandle = LoadLibrary("user32");    
	    printf("user32 LibHandle = 0x%X\n", LibHandle);  
	    // 返回动态链接库(DLL)中的输出库函数地址  
	    GetAddr=(FuncPointer)GetProcAddress(LibHandle,"MessageBoxA");     
	    printf("MessageBoxA = 0x%X\n", GetAddr);  
	    return 0;  
	}  
构造出汇编代码。这里用visual studio写汇编代码,用微软的_as函数可以直接在C语言中嵌入我们要的汇编代码。编译出exe,然后用OD看他的机器码。


OD打开后找到关键代码,然后手动拿出其机器码。

用010editor将机器码敲入password.txt文件。将多余部分用90填充。

然后用OD调试。首先查看函数的栈针。用EBP作为基址方便我们查询。

运行程序,发现函数返回地址已经被修改。

F8一直到RET,发现成功跳转到我们之前写入的机器码处。

运行代码。发现成功弹窗了。

进一步。按照上面的方法,重新构造。加上调用exit()函数的代码。
先找到exit()函数的入口地址。

1.	#include <stdio.h>  
2.	#include <windows.h>  
3.	  
4.	typedef void (*FuncPointer)(LPTSTR);  // 函数指针    
5.	  
6.	int main()  
7.	{     
8.	    HINSTANCE LibHandle;  
9.	    FuncPointer GetAddr;  
10.	    // 加载成功后返回库模块的句柄   
11.	    LibHandle = LoadLibrary("kernel32");    
12.	    printf("kernel32 LibHandle = 0x%X\n", LibHandle);  
13.	    // 返回动态链接库(DLL)中的输出库函数地址  
14.	    GetAddr=(FuncPointer)GetProcAddress(LibHandle,"ExitProcess");     
15.	    printf("ExitProcess = 0x%X\n", GetAddr);  
16.	    return 0;  
17.	}  


编写汇编代码。同样按照上面方法重复操作。

在OD中打开,找到机器码。

敲入password文件中。最后敲入要返回的栈的地址,也就是我们开始数据溢出的位置。这里是0x0012FAF0。

进入程序,先把检查栈底的保护函数nop掉。

运行程序,成功溢出到想要的位置。

运行到第一个call eax,调用messageBoxA函数。成功弹窗。

点击确定,继续F8单步走。

发现可以调用exit()函数。继续F8。发现程序没有报错,同时程序正常推出了,实验完成。

posted @ 2020-12-22 16:23  Evening_Breeze  阅读(586)  评论(0编辑  收藏  举报