修改jar 注入_反射型DLL注入工具-sRDI

c9613a78c96e941a56a671c43b34a3e6.png

反射型DLL注入

DLL 注入

首先,我们需要了解什么是反射型DLL注入。

DLL 注入
就是将 DLL(动态链接库,是一个包含可由多个程序,同时使用的代码和数据的库。例如,在 Windows 操作系统中,Comdlg32.dll 执行与对话框有关的常见函数。)放进某个进程的地址空间里,让它成为那个进程的一部分。要实现 DLL 注入,首先需要打开目标进程。

DLL 注入也被很多合法软件广泛的使用,但恶意软件通常采用 DLL 注入在另一进程的存储空间内伪装其操作。DLL 注入是一个过程,该过程使另一个正在运行的进程加载并执行注入者的任何代码。看上去相当的危险,但它也有很多合法用途。例如,没有它,debug 调试器就不能运行。

9942edc0f36f2b359d24fb669a27124e.png

实现 DLL 注入可参考:http://blog.opensecurityresearch.com/2013/01/windows-dll-injection-basics.html

反射型 DLL 注入

反射DLL注入用于将DLL加载到进程中,而不必将其放置在主机的文件系统上。

反射 DLL 注入的过程如下:

  1. 使用 RWX 权限打开目标进程,并为 DLL 分配足够大的内存。
  2. 将 DLL 复制到分配的内存空间中。
  3. 计算 DLL 中用于执行反射加载的导出的内存偏移量。
  4. 使用反射性加载器函数的偏移地址作为入口,调用 CreateRemoteThread(或等效的未公开的 API 函数,如 RtlCreateUserThread)开始在远程进程中执行。
  5. 反射式加载器功能使用适当的 CPU 寄存器查找目标进程的进程环境块(PEB),并使用该寄存器在内存 kernel32.dll 和任何其他所需库中查找地址。
  6. 解析的 KERNEL32 出口目录中找到所需的 API 功能,如内存地址 LoadLibraryA,GetProcAddress和VirtualAlloc。
  7. 然后使用这些函数将 DLL(自身)正确加载到内存中,并调用其入口点 DllMain。

这一过程比较复杂,值得深思。

反射型 DLL 注入: https:// github.com/stephenfewer /ReflectiveDLLInjection

反射型 DLL 注入的假设是,调用 DLL 的入口点足以执行 DLL 的全部功能。但是,往往并非如此。Microsoft 建议开发人员尽量减少在 DllMain 中的工作量,并进行“延迟初始化”,避免加载其他库或创建新线程。然后,主要入口点位于另一个函数中,该函数在 DLL 加载后将单独调用。

有人提出一种更强大的 DLL 注入技术,该技术试图遵循 Microsoft 概述的 DLL 最佳实践。它通过向目标进程动态写入一些引导程序 Shellcode 来实现此目的,该进程将加载 DLL(使用LoadLibraryA),然后查找并调用另一个导出的入口点函数(使用 GetProcAddress)。尽管这是对传统 DLL 注入的重大改进,但不是反射型的。

因此,将这一技术进行改进,来实现更完美的反射型 DLL 注入。

来源: https:// disman.tl/2015/01/30/an -improved-reflective-dll-injection-technique.html

怎样实现反射型 DLL 注入?

其基本过程如下:

  1. 打开目标进程并分配内存。
  2. 将 DLL 复制到分配的内存中。
  3. 将入口点函数名称的哈希值和该函数的所有参数复制到 DLL 之后的内存空间中。
  4. 复制一些引导程序的 shellcode,该 shellcode 调用带有指向在第3步中复制的数据的指针的修改的反射式加载器。
  5. 使用 shellcode 开头的地址作为入口点,在目标进程中创建一个远程线程。

需要引导程序 Shellcode 的原因是由于我们能够使用 Stephen Fewer 的原始反射 DLL 注入技术传递给反射加载器的数据量有限。

CreateRemoteThread 具有以下声明:

HANDLE WINAPI CreateRemoteThread(
  _In_   HANDLE hProcess,
  _In_   LPSECURITY_ATTRIBUTES lpThreadAttributes,
  _In_   SIZE_T dwStackSize,
  _In_   LPTHREAD_START_ROUTINE lpStartAddress,
  _In_   LPVOID lpParameter,
  _In_   DWORD dwCreationFlags,
  _Out_  LPDWORD lpThreadId
);

其中 LPTHREAD_START_ROUTINE lpStartAddress 是所创建的线程的执行入口点。该函数的原型为:

typedef DWORD (__stdcall *LPTHREAD_START_ROUTINE) (
[in] LPVOID lpThreadParameter
);

如上,这仅需要一个 LPVOID 参数。反射型 DLL 注入技术将反射型加载器的地址 CreateRemoteThread 作为 lpStartAddress 参数传递,因此它只能传递单个 void 指针。这将有利于反射型加载器仅调用 DllMain,而后者将 void 指针作为其 lpvReserved 参数。

但是,如果我们希望反射型加载器在加载 DLL 之后调用其他导出,则需要为其提供更多信息!我们将通过使用一些引导程序 Shellcode 将其他参数传递给反射型加载器函数来实现。因此反射型加载器函数将声明:

DWORD WINAPI ReflectiveLoader( LPVOID lpParameter, LPVOID lpLibraryAddress, DWORD dwFunctionHash, LPVOID lpUserData, DWORD nUserdataLen );

在这里的 dwFunctionHash 是要调用的导出函数名称的哈希值,lpUserData 是一堆数据(大小为nUserdataLen),当反射加载程序调用导出函数时,我们将其传递给该函数。

下面,我们不仅要在 DLL 的远程进程中分配内存,我们还要包括用于 shellcode(64字节就足够了)和一定的数据空间:

DWORD nBufferSize = dwLength // size of the DLL
    + nUserdataLen
    + 64; // shellcode buffer

// alloc memory (RWX) in the host process for the image...
lpRemoteLibraryBuffer = VirtualAllocEx(hProcess, NULL, nBufferSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (!lpRemoteLibraryBuffer)
    break;
printf("Allocated memory address in remote process: 0x%pn", lpRemoteLibraryBuffer);

// write the image into the host process...
if (!WriteProcessMemory(hProcess, lpRemoteLibraryBuffer, lpBuffer, dwLength, NULL))
    break;

ULONG_PTR uiReflectiveLoaderAddr = (ULONG_PTR)lpRemoteLibraryBuffer + dwReflectiveLoaderOffset;

// write our userdata blob into the host process
ULONG_PTR userdataAddr = (ULONG_PTR)lpRemoteLibraryBuffer + dwLength;
if (!WriteProcessMemory(hProcess, (LPVOID)userdataAddr, lpUserdata, nUserdataLen, NULL))
    break;

ULONG_PTR uiShellcodeAddr = userdataAddr + nUserdataLen;

Shellcode 将有两个目标:

  1. 使用我们的附加参数调用反射型加载器函数
  2. ExitThread() 进行适当的清理,以便我们可以从调用过程中获取线程的退出代码。

首先,我们获得的内存地址 ExitThread,该内存地址对于每个进程都应该相同(因为大多数(几乎所有)进程都加载了 kernel32.dll)。

HMODULE kernel32 = LoadLibraryA("kernel32.dll"); 
FARPROC exitthread = GetProcAddress(kernel32, "ExitThread");

接下来,我们将引导程序 Shellcode 写入缓冲区,然后将其写入分配的远程进程内存空间。shellcode 的 x86 版本很简单,因为我们只需要在调用反射加载程序之前以相反的顺序(按照__stdcall 调用约定)将参数推入堆栈即可,x64 shellcode 更为复杂,因为调用约定要求使用寄存器来传递参数。

最后,我们将 shellcode 写入远程进程,并创建一个使用 shellcode 地址作为入口点的远程线程:

// finally, write our shellcode into the host process
if (!WriteProcessMemory(hProcess, (LPVOID)uiShellcodeAddr, bootstrap, i, NULL))
    break;

// Make sure our changes are written right away
FlushInstructionCache(hProcess, lpRemoteLibraryBuffer, nBufferSize);

// create a remote thread in the host process to call the ReflectiveLoader!
hThread = CreateRemoteThread(hProcess, NULL, 1024 * 1024, (LPTHREAD_START_ROUTINE)uiShellcodeAddr, lpParameter, (DWORD)NULL, &dwThreadId);

反射型加载器功能本身与 Fewer 的原始版本相比没有太大变化,除了传递给它的附加参数以及随后在 DLL 中调用选择的导出的部分外。加载 DLL 之后,它将调用 DllMain(理想情况下为null),然后调用我们的导出。

下面就介绍今天的主角:

sRDI✨(Shellcode反射DLL注入)

它可以基于 Shellcode 实现反射型 DLL 注入,并且能够将 DLL 转换为独立的 Shellcode。

项目地址:https://github.com/monoxgas/sRDI

如果我们不想接触磁盘,则需要某种注入技术。可以写一个反射型加载的 DLL,但是反射性 DLL 注入会留下可以检测到的内存伪像。

而 sRDI 可以把一个普通的 DLL 文件转换为一段不依赖任何位置的 Shellcode。

相对于标准 RDI,使用 sRDI 的一些优点:

  • 你可以转换任何 DLL为无位置依赖的 shellcode,并且可以使用标准的 shellcode 注入技术来使用它。
  • 你的 DLL 中不需要写任何反射加载器代码,因为反射加载器是在 DLL 外部的 shellcode 中实现的。
  • 合理使用权限,没有大量的 RWX 权限数据。
  • 还可以根据选项,抹掉 PE 头特征。

组成简介

sRDI 的所有功能基于以下两个组件:

  1. 一个C语言项目,可将 PE Loader 编译为 Shellcode
  2. 转换代码负责将 DLL、RDI 和用户数据进行绑定

由以下元素组成:

  • ShellcodeRDI:编译 DLL 加载器的 Shellcode
  • NativeLoader:需要时,将 DLL 转换为 shellcode,然后注入内存
  • DotNetLoader:NativeLoader 的 C# 实现
  • Python ConvertToShellcode.py:将 DLL 转换为 shellcode
  • Python EncodeBlobs.py:对已编译的 sRDI 进行编码,进行静态嵌入
  • PowerShell ConvertTo-Shellcode.ps1:将 DLL 转换为 shellcode
  • FunctionTest:导入 sRDI 的 C 函数,进行调试测试
  • TestDLL:示例DLL,包括两个导出函数,用于后续的加载和调用
DLL 不需要使用 RDI 进行编译,但是该技术具有交叉兼容性。

优势

#1 – 隐秘的持久性

  • 使用服务器端 Python 代码(sRDI)将 RAT 转换为 shellcode
  • 将 shellcode 写入注册表
  • 设置计划的任务以执行基本的加载程序 DLL
  • 加载程序读取 shellcode 并注入(少于20行C代码)

优点: RAT 或加载器都不需要了解 RDI 或使用 RDI 进行编译。装载机可以保持小巧而简单,避免警告。

#2 – 侧面加载

  • 让你的 RAT 在内存中运行
  • 编写 DLL 以执行额外的功能
  • 将 DLL 转换为 shellcode(使用 sRDI)并本地注入
  • 使用 GetProcAddressR 查找导出的函数
  • 执行 X 次附加功能,而无需重新加载 DLL

优点: 使您的初始工具更轻巧,并根据需要添加功能。加载一次 DLL 并像使用其他任何 DLL 一样使用它。

#3 – 依赖关系

  • 从磁盘读取现有的合法 API DLL
  • 将 DLL 转换为 shellcode(使用 sRDI)并将其加载到内存中
  • 使用 GetProcAddress 查找所需的功能

优点: 避免使用监视工具来检测 LoadLibrary 调用。访问 API 函数而不会泄漏信息。(WinInet,PSApi,TlHelp32,GdiPlus)

使用✔

使用 python 将 DLL 转换为 shellcode

from 

使用 C# 加载程序将 DLL 加载到内存中

DotNetLoader

使用 python 脚本转换 DLL 并使用本机 EXE 加载

python 

使用 powershell 转换 DLL 并使用 Invoke-Shellcode 加载

Import-Module .Invoke-Shellcode.ps1
Import-Module .ConvertTo-Shellcode.ps1
Invoke-Shellcode -Shellcode (ConvertTo-Shellcode -File TestDLL_x64.dll)

搭建

sRDI 是使用Visual Studio 2015(v140)和 Windows SDK 8.1 构建的。python 脚本是使用 Python 3 编写的。

Python和Powershell脚本位于:

  • PythonConvertToShellcode.py
  • PowerShellConvertTo-Shellcode.ps1

构建项目后,其他二进制文件将位于:

  • binNativeLoader.exe
  • binDotNetLoader.exe
  • binTestDLL_<arch>.dll
  • binShellcodeRDI_<arch>.bin

测试test⌛

让我们编译一个简单的 x86 DLL,执行弹出 2 个记事本进程:

cbaee09543c3713ef9d5d843ad0aadd6.png

将 DLL 转换为 shellcode。我们将得到一个以十进制值表示的 shellcode 字节数组:

$sc = ConvertTo-Shellcode VBOXSVRExperimentsmessageboxmessageboxDebugmessagebox.dll

a23fd62e9ff08cfe0bfe1beb7f5898b0.png

让我们将它们转换为十六进制:

$sc2 = $sc | % { write-output ([System.String]::Format('{0:X2}', $_)) }

76a5ef1a346ca22e7d5c08dc6e88d4f6.png

将它们全部加入并打印到文本文件:

$sc2 -join "" > shell.txt

e9f06cf792f80bf1c2ad1f58248523c1.png

使用我们之前获得的 shellcode 创建一个新的二进制文件:

c4465301e28e28e14f5555855e58fb0f.png

为了加载和执行 shellcode,我们将把它作为资源放入二进制文件中。从 PE 资源加载和执行 Shellcode:

5c7da2d9a7ebb0e3addf53e7bb1f4331.png

编译并运行二进制文件。如果 shellcode 成功运行,我们应该会看到两个 notepad.exe 进程弹出窗口:

966fed53cb0f05715992bcfc21074f6b.gif

有关 sRDI 的内容就简单介绍到这里。更多有关 CTF 的内容请前往 二向箔安全 进行学习,最近推出了一系列免费的网络安全技能包,有关CTF、渗透测试、网络攻防、黑客技巧尽在其中,学它涨姿势 。

47f1d5b529daa2b734bb1432e5d8432d.png
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值