ShellCode注入

注意点:

1. 不能有全局变量

2. 不能使用常量字符串 ,可以使用这种形式 szTitle = {'a', 'b', 'c', 0};

3. 不能使用系统调用,比如不能直接使用MessageBox,因为生成的汇编是 Call [0xxxxxx],这个0xxxxx是导入表的地址,注入的程序导入表地址不同而且导入表中不一定有这个函数,可以使用LoadLibrary配合GetProcAddress,但是LoadLibrary和GetProcAddress也是系统调用,也依赖导入表需要通过PEB的模块链,找到Kernel32.dll的模块句柄,然后找到Kernel32.dll的导出表,然后找到LoadLibrary和GetProcAddress的函数地址

4. 不能嵌套调用其他函数,注入后函数地址变化了

 

头文件,结构体定义

#pragma once

#include <windows.h>

typedef struct _UNICODE_STR
{
	USHORT Length;
	USHORT MaximumLength;
	PWSTR pBuffer;
} UNICODE_STR, *PUNICODE_STR;

typedef struct _RTL_USER_PROCESS_PARAMETERS {
	BYTE			Reserved1[16];
	PVOID			Reserved2[10];
	UNICODE_STR		ImagePathName;
	UNICODE_STR		CommandLine;
} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;

typedef struct _LDR_DATA_TABLE_ENTRY
{
	LIST_ENTRY InMemoryOrderModuleList;
	LIST_ENTRY InInitializationOrderModuleList;
	PVOID DllBase;
	PVOID EntryPoint;
	ULONG SizeOfImage;
	UNICODE_STR FullDllName;
	UNICODE_STR BaseDllName;
	ULONG Flags;
	SHORT LoadCount;
	SHORT TlsIndex;
	LIST_ENTRY HashTableEntry;
	ULONG TimeDateStamp;
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;

typedef struct _PEB_LDR_DATA
{
	DWORD dwLength;						//结构体大小
	DWORD dwInitialized;				//进程是否初始化完成
	LPVOID lpSsHandle;
	LIST_ENTRY InLoadOrderModuleList;
	LIST_ENTRY InMemoryOrderModuleList;
	LIST_ENTRY InInitializationOrderModuleList;
	LPVOID lpEntryInProgress;
} PEB_LDR_DATA, *PPEB_LDR_DATA;

//PEB
typedef struct __PEB
{
	BYTE Reserved1[2];
	BYTE BeingDebugged;
#ifdef _WIN64
	BYTE Reserved2[21];
#else
	BYTE Reserved2[9];
#endif
	PPEB_LDR_DATA pLdr;
	PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
	BYTE Reserved3[520];
	BYTE Reserved4[136];
	ULONG SessionId;
} _PEB, *_PPEB;

cpp文件

#include "ShellCode.h"

typedef PVOID(__stdcall *MyGetProcAddress)(HMODULE hModule, LPCSTR lpProcName);
typedef HMODULE(__stdcall *MyLoadLibraryA)(LPCSTR lpLibFileName);
typedef int (__stdcall *MyMessageBoxA)(HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType);

void ShellCode()
{
	//获取peb地址  fs:[0x30]
#ifdef _WIN64
	DWORD64 dwPeb = __readgsqword(0x60);
#else
	DWORD dwPeb = __readfsdword(0x30);
#endif

	//unicode格式
	wchar_t szKernel32[] = { L'K', L'E', L'R', L'N' , L'E' , L'L' , L'3' , L'2' , L'.', L'D', L'L', L'L', 0, 0 };
	char szUser32[] = { 'U', 'S', 'E', 'R', '3', '2', '.', 'D', 'L', 'L', 0 };

	char szGetProcAddr[] = { 'G', 'e', 't', 'P', 'r', 'o', 'c', 'A', 'd', 'd', 'r', 'e', 's', 's', 0 };
	char szLoadLibrary[] = { 'L', 'o', 'a', 'd', 'L', 'i', 'b', 'r', 'a', 'r', 'y', 'A', 0 };
	char szMessageBox[] = { 'M', 'e', 's', 's', 'a', 'g', 'e', 'B', 'o', 'x', 'A', 0 };

	PVOID pKernelBase = nullptr;
	MyGetProcAddress pMyGetProcAddress = nullptr;
	
	//遍历Dll模块
	PLDR_DATA_TABLE_ENTRY pDataTable = (PLDR_DATA_TABLE_ENTRY)((PPEB_LDR_DATA)((_PPEB)dwPeb)->pLdr)->InMemoryOrderModuleList.Flink;
	while (pDataTable)
	{
		//找到kernel32模块
		LPTSTR lpDllName = (LPTSTR)pDataTable->BaseDllName.pBuffer;
		wchar_t*  pTemp = szKernel32;
		while (*pTemp && *pTemp == *lpDllName)
		{
			pTemp++;
			lpDllName++;
		}
		if (*pTemp == 0)
		{
			pKernelBase = pDataTable->DllBase;
			break;
		}

		//双向链表的下一个
		pDataTable = (PLDR_DATA_TABLE_ENTRY)pDataTable->InMemoryOrderModuleList.Flink;
	}

	if (pKernelBase == nullptr)
	{
		return;
	}

	//定位到PE指纹
	UINT_PTR pSignature = (UINT_PTR)pKernelBase + ((PIMAGE_DOS_HEADER)pKernelBase)->e_lfanew;
	//定位到导出表
	UINT_PTR pExportTable = (UINT_PTR)&((PIMAGE_NT_HEADERS)pSignature)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
	pExportTable = (UINT_PTR)pKernelBase + ((PIMAGE_DATA_DIRECTORY)pExportTable)->VirtualAddress;
	
	//函数名表
	UINT_PTR pNameArray = (UINT_PTR)pKernelBase + ((PIMAGE_EXPORT_DIRECTORY)pExportTable)->AddressOfNames;
	//函数地址表
	UINT_PTR pAddressArray = (UINT_PTR)pKernelBase + ((PIMAGE_EXPORT_DIRECTORY)pExportTable)->AddressOfFunctions;
	//函数序号表
	UINT_PTR pNameOrdinals = (UINT_PTR)pKernelBase + ((PIMAGE_EXPORT_DIRECTORY)pExportTable)->AddressOfNameOrdinals;
	//导出函数个数
	DWORD dwExportFunCount = ((PIMAGE_EXPORT_DIRECTORY)pExportTable)->NumberOfNames;
	//遍历导出函数
	for (int i = 0; i < dwExportFunCount; i++)
	{
		//导出函数名
		char* pFunName = (char*)((UINT_PTR)pKernelBase + ((UINT_PTR*)pNameArray)[i]);
		//找到GetProcAddress
		char* pTemp = szGetProcAddr;
		while (*pTemp && *pTemp == *pFunName)
		{
			pTemp++;
			pFunName++;
		}
		if (*pTemp == 0)
		{
			//从序号表中取出地址表中的索引
			unsigned int nIndex = ((unsigned short*)pNameOrdinals)[i];
			//根据索引获取函数地址
			pMyGetProcAddress = MyGetProcAddress((UINT_PTR)pKernelBase + ((UINT_PTR*)pAddressArray)[nIndex]);
			break;
		}
	}

	//用GetProcAddress获取到LoadLibraryA的地址
	MyLoadLibraryA pMyLoadLibraryA = (MyLoadLibraryA)pMyGetProcAddress((HMODULE)pKernelBase, szLoadLibrary);

	HMODULE hUser32 = pMyLoadLibraryA(szUser32);
	MyMessageBoxA pMyMessageBox = (MyMessageBoxA)pMyGetProcAddress(hUser32, szMessageBox);
	pMyMessageBox(0, 0, 0, 0);
}

int main()
{
	ShellCode();
}
 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值