反射式dll注入「建议收藏」

反射式dll注入「建议收藏」前不久实现了经典dll注入exe,实现注入到用户层面进程,比如notepad.exe和wps.exe。(像金山毒霸kxetray.exe有自我保护机制也注入不进去)。由于对会话隔离注入不太了解,怕搞坏主机,没有再去实现注入到系统进程中。最近在网上看到dll反射注入,想把学习总结的笔记给大家分享一下。首先什么是反射式注入?它和传统经典注入有什么区别呢?我这里作个比喻。经典式:在别人的内存里调用…

大家好,又见面了,我是你们的朋友全栈君。

  前不久实现了经典dll注入exe,实现注入到用户层面进程,比如notepad.exe和wps.exe。(像金山毒霸kxetray.exe有自我保护机制也注入不进去)。特此记录一下。
  首先什么是反射式注入?它和传统经典注入有什么区别呢?我这里作个比喻。

经典式
  在目标进程申请一段空间并放入恶意dll,创建远线程让目标进程调用LoadLiabrary函数加载这段内存
  先把病毒扔进邻居家,告诉邻居这是个炮仗(病毒dll),邻居误以为真,点燃导火索(创建线程执行),显然邻居被骗了
反射式:
   在别人的内存里调用自己编写的dll导出函数 ,自己dll导出函数里实现自我加载(加载PE的整个过程)
   先把病毒扔进邻居家,然后自己把它直接点燃(调用dll导出函数),病毒自己爆炸(dll内部实现自己从底层dll遍历加载函数),邻居浑然不知(没有通过系统LoadLibrary调用dll,没有记录)

区别是啥
  少了使用LoadLibrary的过程。

反射式注入dll的优点

   反射式注入方式并没有通过LoadLibrary等API来完成DLL的装载,DLL并没有在操作系统中”注册”自己的存在,因此ProcessExplorer等软件也无法检测出进程加载了该DLL。利用解密磁盘上加密的文件、网络传输等方式避免文件落地,DLL文件可以不一定是本地文件,可来自网络等,总之将数据写到缓冲区即可。
   由于它没有通过系统API对DLL进行装载,操作系统无从得知被注入进程装载了该DLL,所以检测软件也无法检测它。同时,由于操作流程和一般的注入方式不同,反射式DLL注入被安全软件拦截的概率也会比一般的注入方式低。

实现需求

一、注射器
  (将这个DLL文件写入目标进程的虚拟空间中)实现大部分和传统注入一样。但它要做一件很重要的事情,就是获得病毒dll里的一个最重要的导出函数,也即是我们要编写的反射加载自己的函数ReflectiveLoader的文件偏移。(如果你知道自己dll这个导出函数文件偏移多少其实也没必要再用程序读取)

二、编写一个邪恶的dll以及它的核心函数ReflectiveLoader
  要知道ReflectiveLoader函数运行时所在的DLL还没有被装载,它在运行时会受到诸多的限制,例如无法正常使用全局变量等。而且,由于我们无法确认我们究竟将DLL文件写到目标进程哪一处虚拟空间上,所以我们编写的ReflectiveLoader必须是地址无关的。

注射器实现

  1. 将待注入DLL读入自身内存(可以在磁盘上存放一份DLL的加密后的版本,然后将其解密之后储存在内存里)
  2. 利用VirtualAlloc和WriteProcessMemory在目标进程中写入待注入的DLL文件
  3.利用CreateRemoteThread等函数启动位于目标进程中的ReflectiveLoader(要首先获得ReflectiveLoader的文件偏移地址),获取的是DLL中反射加载函数在文件中的偏移,由于这种注入没有使用LoadLibraryA函数,所以DLL在内存中的状态和在磁盘中的状态是相同的,要想调用函数,我们就需要找到文件偏移。
  线程函数的地址=缓冲区的基地址+文件偏移

在这里插入图片描述

在这里插入图片描述
图中1264十六进制就是4F0

  4.通过DLL的导出表找到这个ReflectiveLoader并调用它
   将自身合适地展开到虚拟空间中。我们都知道在PE文件包含了许多节,而为了节省存储空间,这些节在PE文件中比较紧密地凑在一起的。而在广阔虚拟空间中,这些节就可以映射到更大的空间中去。(更不用说还存在着.bss这样的在PE文件中不占空间,而要在虚拟空间中占据位置的节)

ReflectiveLoader函数实现

实现中的问题:

  DLL中可能会用到其他DLL的函数,装载一个DLL还需要将这个DLL依赖的其他动态库装入内存,并修改DLL的IAT指向到合适的位置,这样对其他DLL函数的引用才能正确运作ReflectiveLoader的代码是地址无关的,但是该DLL的其他部分的代码却并不是这样的。在一份源代码编译、链接成为DLL时,编译器都是假设该DLL会加载到一个固定的位置,生成的代码也是基于这一个假设。在反射式注入DLL的时候,我们不太可能申请到这个预先设定好的地址,所以我们需要面对一个重定位(Rebasing)的问题。

解决方案

  1.ReflectiveLoader做的第一件事就是查找自身所在的DLL具体被写入了哪个位置
ULONG_PTR caller( VOID ) { return(ULONG_PTR)_ReturnAddress(); }
借助上文找到的地址,我们逐字节的向上遍历,当查找到符合PE格式的文件头之后,就可以认为找到了DLL文件在内存中的地址了。
Caller()函数:获得当前指令的下条指令的地址。

  2.我们需要的函数是kernel32.dll中的LoadLibraryA(), GetProcAddress(),VirtualAlloc()以及ntdll.dll中的NtFlushInstructionCache()函数。我们需要遍历已经加载的模块,从中找到我们需要的模块,获得以上几个函数的地址。
#define KERNEL32DLL_HASH 0x6A4ABC5B
#define NTDLLDLL_HASH 0x3CFA685D
#define LOADLIBRARYA_HASH 0xEC0E4E8E
#define GETPROCADDRESS_HASH 0x7C0DFCAA
#define VIRTUALALLOC_HASH 0x91AFCA54
#define NTFLUSHINSTRUCTIONCACHE_HASH 0x534C0AB8
// compute the hash values for this function name
dwHashValue = hash((char *)(uiBaseAddress + DEREF_32(uiNameArray)));
每一个线程都具有一个TEB结构,记录了相关线程的一些基本信息。线程运行时,其FS段寄存器记录了其TEB的位置。
获取PEB的方法:FS:[0x30]和GS:[0x60],前者为32位系统,后者为64位系统。
这里需要用到之前TEB定位与导出函数定位的知识。

  3. 分配一片用来装载DLL的空间。
虽然在ReflectiveLoader运行时,DLL文件已经在进程内存中了,但是要装载这个DLL,我们还需要更大的空间。借助在第2)步得到的函数VirtualAlloc(),我们可以分配一片更大的内存空间用于加载DLL。在PE头中的IMAGE_OPTIONAL_HEADER结构体中的SizeOfImage成员记载DLL被装载后的大小,我们按照这个大小分配内存即可。
uiBaseAddress=(ULONG_PTR)pVirtualAlloc(NULL, ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfImage,
MEM_RESERVE|MEM_COMMIT,
PAGE_EXECUTE_READWRITE );
uiBaseAddress记录了VirtualAlloc的返回值,也就是分配内存空间的起始地址。于是uiBaseAddress就成为了DLL被装载后的基地址。

  4.复制PE文件头和各个节
分配了用于装载的空间后,ReflectiveLoader将DLL文件的头部(也就是DOS文件头、DOS插桩代码和PE文件头)复制到新的空间的首部。再根据PE文件的节表将各个节复制到相应的位置中。

  5.根据节表加载节

  6. 处理DLL的导入表
被注入的DLL可能还依赖于其他的DLL,因此我们还需要装载这些被依赖的DLL,并修改本DLL的引入表,使这些被引入的函数能正常运行。
无论是以什么方式导入,我们都要需要找到对应的函数,然后将其地址填入FirstThunk指向的IMAGE_THUNK_DATA数组中。这个跑起来是IAT

  7.对DLL进行重定位
  由于基址改变,所以程序中的一些直接寻址等会出问题,所以要更改重定向表。
  被注入的DLL只有其ReflectiveLoader中的代码是故意写成地址无关、不需要重定位的,其他部分的代码则需要经过重定位才能正确运行。
  我们首先计算得到基地址的偏移量,也就是实际的DLL加载地址减去DLL的推荐加载地址。DLL推荐加载地址保存在NT可选印象头中的ImageBase成员中,而实际DLL加载地址则是我们在第3)步中函数VirtualAlloc()的返回值。然后我们将VirtualAddress和Typeoffset合力组成的地址所指向的双字加上这个偏移量,重定位就完成了。
(DWORD)(VirtualAddress + Typeoffset的低12位) += (实际DLL加载地址 – 推荐DLL加载地址)
  在完成所有的重定位后,我们最后调用第2)步得到的NtFlushInstructionCache()清除指令缓存以避免问题。
8. 调用DLL入口点
  至此,ReflectiveLoader的任务全部完成,最后它将控制权转交给DLL文件的入口点,这个入口点可以通过NT可选印象头中的AddressOfEntryPoint找到。一般地,它会完成C运行库的初始化,执行一系列安全检查并调用dllmain。

用到的底层C++语言编程

  dll遍历kernel32与ntdll的导出函数部分用汇编语言更加直接简短,这部分代码同样是大部分加壳程序的壳内核心代码,有时间一定会细心研究一下。
  _rotr函数,功能是value右循环移动shift位( unsigned int value, int shift );
  register 关键字请求“编译器”将局部变量存储于寄存器中——最快的关键字
  register 这个关键字请求编译器尽可能的将变量存在CPU内部寄存器,而不是通过内存寻址访问,以提高效率。注意是尽可能,不是绝对。
  数据从内存里拿出来先放到寄存器,然后CPU 再从寄存器里读取数据来处理,处理完后同样把数据通过寄存器存放到内存里,CPU 不直接和内存打交道。
内存 寄存器 CPU
  寄存器其实就是一块一块小的存储空间,只不过其存取速度要比内存快得多。CPU从寄存器里拿数据比在大内存里去寻找某个地址上的数据快多了。
  __readgsqword(0x60) 从GS寄存器里读取数值

查杀建议

  回想我们注射器实现的过程中所调用的函数,与正常的注入似乎没有太大的区别,像CreateRemoteProcess这种危险函数杀软抓的很严,可以被替换掉。整个过程没有发现LoadLibraryA函数。但这个样本有明显的特征:解析PE结构,所以当我们遇到这种样本的时候,可以考虑为反射式DLL注入。
  用IDA逆向程序时,解析PE结构的过程,编程中会出现很多+0xnumber 这里number代表十六进制数字。
  在磁盘发现某dll很可疑,如果该dll被注入到进程中已经在运行,删除或移动dll时会弹窗正在某某程序中使用,可以看到它是不是注入的dll。
  另外注入到进程的恶意Dll程序执行错误时崩溃并不会导致被注入程序实际的崩溃。

参考

来源https://bbs.pediy.com/thread-224241.htm

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

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

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

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

(0)
blank

相关推荐

  • 共享计算机没有响应,网络共享打印机出现联机无反应的处理方法

    共享计算机没有响应,网络共享打印机出现联机无反应的处理方法网络共享打印机出现联机无反应、打印乱码及无法连接共享打印机的故障处理方法1、共享打印出现乱码倘若从局域网中某一台工作站中执行共享打印操作时,网络打印机能够正常工作;而从另外一台工作站中执行共享打印操作时,网络打印机打印出来的内容全部是乱码,遇到这种故障时你该如何快速排除呢?从上面的故障现象来看,大家可以知道共享打印机在硬件方面以及网络连接方面都应该是正常的,毕竟有计算机能够通过网络正常进行打印材料…

  • 11尺寸长宽 iphone_iPhone11屏幕尺寸

    11尺寸长宽 iphone_iPhone11屏幕尺寸【iPhone11屏幕尺寸】iPhone11系列屏幕继续沿用“全面屏”设计,由苹果初代手机开始,iPhone的屏占比越做越高,同时屏幕尺寸越做越大。iPhone11屏幕尺寸是多少呢?我们一起来看看吧。iPhone11屏幕尺寸iPhone11屏幕采用6.1英寸1792*828分辨率全面屏,屏幕像素密度为326ppi,最大亮度可达625尼特,材质为LCD面板。iPhone11Pro屏幕采用5.8英寸2…

  • docker日志存放位置_oracle数据库日志文件在哪里

    docker日志存放位置_oracle数据库日志文件在哪里binlog就是binarylog,二进制日志文件,这个文件记录了mysql所有的dml操作。通过binlog日志我们可以做数据恢复,做主住复制和主从复制等等。对于开发者可能对binlog并不怎么关注,但是对于运维或者架构人员来讲是非常重要的。如何开启mysql的binlog日志呢?在my.inf主配置文件中直接添加三行log_bin=ONlog_bin_basename=/var/lib/m…

    2022年10月15日
  • Git提交(PUSH)时记住密码 – 不用每次都输入密码

    Git提交(PUSH)时记住密码 – 不用每次都输入密码

  • 计算机启动显示安装程序正在启动服务,安装程序正在启动服务需要多久

    计算机启动显示安装程序正在启动服务,安装程序正在启动服务需要多久大家好,我是时间财富网智能客服时间君,上述问题将由我为大家进行解答。安装程序正在启动服务需要多久,这个主要看软件大小,安装完成就会自动运行的,要是系统不断的提示,这个就不一定了,时间可能会很久的,需要耐心等待。程序,香港和台湾对英文procedure的中文翻译,编程语言中的procedure在大陆翻译为“过程”,在港台和其他领域则翻译为“程序”。在大陆于计算机科学、电脑工程、电子工程、电机工程、机…

  • matlab自带的插值函数interp1的四种插值方法

    matlab自带的插值函数interp1的四种插值方法分段线性插值,临近插值,球面插值,三次多项式插值!!

发表回复

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

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