黑客学徒日记-DInvoke (二)
上一篇:黑客学徒日记-DInvoke
我们已经在上一篇中了解了DInvoke和Pinvoke的区别,为什么不使用Pinvoke,而要使用Dinvoke。
本篇讨论Dinvoke在实战中的使用。
编译方式
要使用Dinvoke,必须编译或者下载该项目。
下载链接如下:https://github.com/TheWover/DInvoke/releases/download/v1.0.4/DInvoke.dll
在源码中要这样写,代表着使用Dinvoke using DynamicInvoke = DInvoke.DynamicInvoke;
在编译的时候需要引用DInvoke.dll
以下是使用Pinvoke的典型案例
案例一 解析托管代码导出的API
下面的示例演示如何使用 DInvoke 动态查找和调用 DLL 的导出。
获取 ntdll.dll 的基地址。 它在初始化时被加载到每个 Windows 进程中,因此我们知道它已经被加载。
因此,我们可以安全地搜索 PEB 的已加载模块列表以找到对其的引用。 一旦我们从 PEB 中找到它的基地址,我们就打印该地址。
使用 GetLibraryAddress 在 ntdll.dll 中按名称查找导出。
使用 GetLibraryAddress 按序号在 ntdll.dll 中查找导出。
使用 GetLibraryAddress 通过键控哈希在 ntdll.dll 中查找导出。
给定我们之前找到的 ntdll.dll 的基地址,使用 GetExportAddress 在内存中按名称查找模块内的导出。
1 |
|
编译以上的源码
1 |
|
执行编译后的exe
可以看到,程序运行后,定位到了dll的base address基址
案例二 调用open process, bypass api hooking
c:\windows\Microsoft.NET\Framework\v4.0.30319\csc.exe -lib:C:\Users\Local\Desktop\Tools\evasion\DInvoke -reference:DInvoke.dll test2.cs
在下面的示例中,我们首先使用 PInvoke 正常调用 OpenProcess。
然后,我们将使用 DInvoke 以多种方式调用它,以证明每种机制都成功执行了非托管代码并规避了 API hooking。
1 |
|
案例三
https://klezvirus.github.io/RedTeaming/Development/From-PInvoke-To-DInvoke/ (该文的代码有些许错误的地方,在本文中调整过了)
Pinvoke调用的远程线程注入代码
以下代码是使用Pinvoke进行Process Injection的案例。为了学习,我们要将这个代码改写为使用Dinvoke。
代码使用了这些api,OpenProcess \ VirtualAllocEx \ WriteProcessMemory \ CreateRemoteThread
1 |
|
编译以上程序
c:\windows\Microsoft.NET\Framework\v4.0.30319\csc.exe test6.cs
执行程序。程序从参数中读取pid,然后调用这四个API OpenProcess \ VirtualAllocEx \ WriteProcessMemory \ CreateRemoteThread,将shellcode注入到该进程当中。
P/Invoke 使用“签名”,D/Invoke 使用“ 委托 ”,它允许在类中包装方法。 因此,我们现在可以将任何 API 视为一个类或类型。 为了使用这些类,我们当然需要声明它们。
注意:我已经习惯了,但对我来说这仍然像魔术一样有效。
那么让我们看看上面的例子将如何变化。
来自 P/Invoke 的每个签名在新程序中都会有一个并行委托:
1 |
|
现在,要调用委托,需要三个步骤:
- 获取DLL中函数的指针
- 将指针编组到代表我们目标 API 的委托中(并转换它)
- 实例化委托(调用 API)
1 |
|
Dinvoke调用的远程线程注入代码
最终,我们将拥有完整的程序
编译程序
c:\windows\Microsoft.NET\Framework\v4.0.30319\csc.exe -lib:C:\Users\Local\Desktop\Tools\evasion\DInvoke -reference:DInvoke.dll test7.cs
1 |
|
可见, GetLibraryAddress
和 GetDelegateForFunctionPointer
以一种模式重复。 然后我们可以稍微“改进”代码,将两个调用包装在一个新方法中 ChaseFunction
. 当所有委托都来自同一个非托管 DLL 时,此技术特别有用:
1 |
|
这样可以让Main中的代码更精炼
1 |
|
我发现这个例子比前一个更简洁易读,特别是对于长程序。