ShellCode详解三

直接进入正题。

在完成正式的shellcode代码导出之前,我们先手动的对代码进行导出,以使各位同学更加了解其原理。

手动注入shellcode

1、我们利用DLE工具找到上一节中我们生成的PE文件的代码段位置
在这里插入图片描述
上述图片就是我们的代码段位置
2、利用WinHex工具我们将这一段代码复制出来
在这里插入图片描述
通过以上步骤我们就已经将shellcode的代码复制到我们的剪切板了,当我们复制的代码注入到任何进程的时候它就会出现一个弹窗。
3、随便写一个可执行程序,然后将我们复制的代码注入进去,然后我们来看一下效果

#pragma comment(linker,"/entry:ShellCodeEntry")

int ShellCodeEntry()
{
	
	return 0;
}

上边是一个简单的代码,什么也不做。
然后我们来看一下上一节我们写的shellcode生成的PE文件效果
在这里插入图片描述
是一个简单的弹窗。
使用x64dbg工具打开上述写的简单程序
首先,先看一下没有注入的情况:
在这里插入图片描述
可以看到,什么也没有发生,因为我们什么也没做,啥也没有是理所当然的了。
接下来,我们将我们的shellcode代码注入进去:
在这里插入图片描述
可以看到,当我们的shellcode注入进去后,它执行的就是我们写的shellcode代码。

现在我们手动对shellcode代码段复制并随便注入到一个进程的过程已经全部结束。当然,实际应用中我们当然不可能手动复制这段shellcode的代码段了,所以接下来就是重点了,我们可以依赖程序的自动提取,把shellcode的代码段提取出来,然后直接全选就可以了。重点!重点!重点!重要的事说三遍。

自动提取程序中的shellcode代码

首先,我们需要搞清楚一个问题,我们写的函数是如何保存到生成的PE文件中的,我们可以使用IDA看一下。实际上它就是以cpp文件的从上到下函数地址保存的,所以要获取我们的shellcode代码,我们就可以这么写:

#include <Windows.h>

//定义函数入口点
#pragma comment(linker,"/entry:ShellCodeEntry")

int ShellCodeEntry()
{
	HANDLE hFile = CreateFile(L"shellcode.bin", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);

	//shellcode代码段长度
	DWORD dwShellcodeSize = (DWORD)ShellCodeEnd - (DWORD)ShellCodeStart;
	DWORD dwRetSize;

	WriteFile(hFile, ShellCodeStart, dwShellcodeSize, &dwRetSize, NULL);
	CloseHandle(hFile);
#endif

	return 0;
}

其中需要注意的是"ShellCodeStart"就是我们shellcode代码的起始函数,"ShellCodeEnd"是我们结束的代码,它实际上是没有任何功能的,只是一个shellcode结束的标志。
全部代码如下:

#include <Windows.h>
#include <winternl.h>

#pragma comment(linker,"/entry:ShellCodeEntry")

HMODULE GetKernel32BaseAddress();
FARPROC GetPorcAddressBaseAddress();

void ShellCodeStart()
{
	typedef FARPROC(WINAPI* FN_GetProcAddress)(_In_ HMODULE hModule, _In_ LPCSTR lpProcName);
	typedef HMODULE(WINAPI* FN_LoadLibraryA)(_In_ LPCSTR lpLibFileName);

	FN_GetProcAddress fn_GetProcAddress;
	fn_GetProcAddress = (FN_GetProcAddress)GetPorcAddressBaseAddress();
	if (!fn_GetProcAddress)
		return;

	FN_LoadLibraryA fn_LoadlibraryA;
	//LoadLibraryA
	char szLoadLibraryA[] = { 'L','o','a','d','L','i','b','r','a','r','y','A',0 };

	HMODULE hKernel32Address = GetKernel32BaseAddress();
	fn_LoadlibraryA = (FN_LoadLibraryA)fn_GetProcAddress(hKernel32Address, szLoadLibraryA);
	if (!fn_LoadlibraryA)
		return;

	typedef int (WINAPI* FM_MessageBoxA)(__in_opt HWND hWnd, __in_opt LPCSTR lpText, __in_opt LPCSTR lpCaption, __in UINT uType);

	char szUser32[] = { 'U','s','e','r','3','2','.','d','l','l',0 };
	char szMessageBoxA[] = { 'M','e','s','s','a','g','e','B','o','x','A',0 };
	FM_MessageBoxA fn_MessageBoxA = (FM_MessageBoxA)(fn_GetProcAddress(fn_LoadlibraryA(szUser32), szMessageBoxA));

	if (fn_MessageBoxA)
	{
		char szText[] = { 'H','e','l','l','o',0 };
		fn_MessageBoxA(NULL, szText, 0, 0);
	}
}


//获取kernel32的基址
HMODULE GetKernel32BaseAddress()
{
	HMODULE hKernel32 = NULL;

	//保存模块名
	WCHAR wszModuleName[MAX_PATH];

#ifdef _WIN64
	//获取gs偏移60h
	PPEB lpPeb = (PPEB)__readgsqword(0x60);
#else
	//获取fs偏移30h
	PPEB lpPeb = (PPEB)__readfsdword(0x30);
#endif

	//模块列表
	PLIST_ENTRY pListHead = &lpPeb->Ldr->InMemoryOrderModuleList;
	PLIST_ENTRY pListData = pListHead->Flink;

	while (pListData != pListHead)
	{
		PLDR_DATA_TABLE_ENTRY pLDRData = CONTAINING_RECORD(pListData, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);

		//模块路径字符串数量
		DWORD dwLen = pLDRData->FullDllName.Length / 2;
		if (dwLen > 12)
		{
			for (size_t i = 0; i < 12; i++)
			{
				wszModuleName[11 - i] = pLDRData->FullDllName.Buffer[dwLen - 1 - i];
			}

			//kernel32.dll
			if ((wszModuleName[0] == 'k' || wszModuleName[0] == 'K') &&
				(wszModuleName[1] == 'e' || wszModuleName[1] == 'E') &&
				(wszModuleName[2] == 'r' || wszModuleName[2] == 'R') &&
				(wszModuleName[3] == 'n' || wszModuleName[3] == 'N') &&
				(wszModuleName[4] == 'e' || wszModuleName[4] == 'E') &&
				(wszModuleName[5] == 'l' || wszModuleName[5] == 'L') &&
				wszModuleName[6] == '3' &&
				wszModuleName[7] == '2' &&
				wszModuleName[8] == '.' &&
				(wszModuleName[9] == 'd' || wszModuleName[9] == 'D') &&
				(wszModuleName[10] == 'l' || wszModuleName[10] == 'L') &&
				(wszModuleName[11] == 'l' || wszModuleName[11] == 'L'))
			{
				//kernel32.dll在进程中的基址
				hKernel32 = (HMODULE)pLDRData->DllBase;
				break;
			}
		}
		pListData = pListData->Flink;
	}

	return hKernel32;
}

//获取GetPorcAddress地址
FARPROC GetPorcAddressBaseAddress()
{
	FARPROC pGetPorcAddress = NULL;

	HMODULE hKernel32 = GetKernel32BaseAddress();
	if (!hKernel32)
		return pGetPorcAddress;

	//获取Dos头
	PIMAGE_DOS_HEADER lpDosHeader = (PIMAGE_DOS_HEADER)hKernel32;
	//获取NT头
	PIMAGE_NT_HEADERS lpNtHeader = (PIMAGE_NT_HEADERS)((unsigned char*)hKernel32 + lpDosHeader->e_lfanew);

	if (!lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size &&
		!lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress)
	{
		return pGetPorcAddress;
	}

	//导出表
	PIMAGE_EXPORT_DIRECTORY lpExports = (PIMAGE_EXPORT_DIRECTORY)((unsigned char*)hKernel32 + lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
	//函数名
	PDWORD lpdwFunName = (PDWORD)((unsigned char*)hKernel32 + lpExports->AddressOfNames);
	//函数序号
	PWORD lpdwOrd = (PWORD)((unsigned char*)hKernel32 + lpExports->AddressOfNameOrdinals);
	//函数地址
	PDWORD lpdwFunAddr = (PDWORD)((unsigned char*)hKernel32 + lpExports->AddressOfFunctions);

	for (DWORD dwLoop = 0; dwLoop < lpExports->NumberOfNames; dwLoop++)
	{
		char* pFunName = (char*)(lpdwFunName[dwLoop] + (unsigned char*)hKernel32);

		//GetProcAddress
		if (pFunName[0] == 'G' && pFunName[1] == 'e' &&
			pFunName[2] == 't' && pFunName[3] == 'P' &&
			pFunName[4] == 'r' && pFunName[5] == 'o' &&
			pFunName[6] == 'c' && pFunName[7] == 'A' &&
			pFunName[8] == 'd' && pFunName[9] == 'd' &&
			pFunName[10] == 'r' && pFunName[11] == 'e' &&
			pFunName[12] == 's' && pFunName[13] == 's')
		{
			pGetPorcAddress = (FARPROC)(lpdwFunAddr[lpdwOrd[dwLoop]] + (unsigned char*)hKernel32);
			break;
		}
	}

	return pGetPorcAddress;
}


void ShellCodeEnd()
{
}

int ShellCodeEntry()
{
	HANDLE hFile = CreateFile(L"shellcode.bin", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);

	DWORD dwShellcodeSize = (DWORD)ShellCodeEnd - (DWORD)ShellCodeStart;
	DWORD dwRetSize;

	WriteFile(hFile, ShellCodeStart, dwShellcodeSize, &dwRetSize, NULL);
	CloseHandle(hFile);

	return 0;
}

如此,运行程序之后,我们的shellcode代码段就直接保存到"shellcode.bin"文件中了。
生成的文件内容如下:
在这里插入图片描述
可以看到,这个文件和我们的shellcode代码完全一样。

到这里,我们的shellcode生成基础基本就完事了。感谢大家的阅读,后边可能还会出一些高级的,大家期待吧… ^ _ ^

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Shellcode downloader(壳代码下载器)是一种恶意软件的一部分,用于在受感染的系统上下载和执行恶意shellcode。它通常由黑客或攻击者利用系统的弱点,如漏洞或错误配置,将其注入到受感染系统的进程中。 Shellcode downloader的主要目的是在感染的系统上建立一个后门,以便攻击者能够以后访问并对系统进行进一步的攻击。通过下载和执行远程恶意shellcode,攻击者可以获取系统上的敏感信息、执行远程命令、安装其他恶意软件以及执行各种潜在攻击。 Shellcode downloader通常通过各种方式传播,比如利用社交工程、垃圾邮件、恶意网站或网络钓鱼攻击等。一旦感染了一个系统,shellcode downloader将执行以下一些步骤: 1. 首先,shellcode downloader会与其指定的远程服务器建立连接,以获取后续恶意代码的位置和执行指令。 2. 下载恶意的shellcode文件到受感染系统中,并将其写入指定的文件或内存位置。 3. 执行shellcode,使其在系统的特定进程中运行。shellcode的目标是通过利用系统或应用程序的弱点来获取系统权限并执行恶意操作。 4. 一旦shellcode成功运行,它可能会执行许多不同的操作,比如建立远程访问通道、搜集系统信息、窃取敏感信息或执行其他攻击。 为了保护系统免受shellcode downloader的入侵,用户应该始终注意不点击垃圾邮件或未知来源的链接,并保持系统和应用程序的更新,以修复任何发现的漏洞。此外,安装有效的防病毒和防火墙软件也是防止shellcode downloader侵入的关键步骤。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值