SharpSploit.Execution.DynamicInvoke

SharpSploit 中很有趣的一部分是 SharpSploit.Execution.DynamicInvoke,我通常只需要这一部分并不需要整个库,本文记录一些阅读 SharpSploit 代码并提取其核心部分的过程。

以作者给出的例子为基础:

从这个例子出发,将依赖的方法依次填充进去。

整理了一下方法间的调用关系和依赖,得到了奇怪的东西,我依赖我自己。

DynamicInvoke

然后重读了 GetLibraryAddress 函数,整理了新的调用流程:

这个函数是判断模块是否已经加载,根据给定参数选择是否从磁盘加载 DLL。

Rtl 和 Ldr 这两个函数是 ntdll 的导出函数,默认加载进每个进程的,所以在调用这两个方法的时候不会用到 LoadModuleFromDisk。

实际的调用逻辑如下:

DynamicInvoke

DynamicInvoke

通常来说,我不需要 LoadModuleFromDisk,我在我自己的版本中去除了这个方法。

然后整理了一些不必要的包装,得到 3 个方法:

GetModuleAddress:获取模块基地址

GetFunctionAddress:解析导出表获取函数指针

GetFunctionDelegate:将函数指针转化为委托

用法:

局限性:

当我想用分配堆内存的方式代替 VirtualAlloc 时,遇到了 HeapAlloc 始终无法调用成功的问题,在反复检查不是我的代码逻辑问题后,我就把这个问题搁置了。

直到在 http://www.exploit-monday.com/2013/08/writing-optimized-windows-shellcode-in-c.html 的评论区中找到了问题的原因:

DynamicInvoke

在 DLL 中有一类不同于常规导出函数的函数,叫做 forwarder,这种函数的作用就是指示调用这个函数的代码转到其他 DLL 的导出函数。

https://devblogs.microsoft.com/oldnewthing/20060719-24/?p=30473

当 DInvoke 获取函数地址后,这个地址定位的并不是可执行代码而是字符串。

解决这个问题需要获取 kernel32.dll 的导出信息:dumpbin /EXPORTS kernel32.dll > k32.txt

DynamicInvoke

可以看到 HeapAlloc 后跟着 forwarded to NTDLL.RtlAllocateHeap,用 RtlAllocateHeap 代替 HeapAlloc 即可解决问题。

使用这种技术写了一个 shellcode 加载器:

DynamicInvoke

计划通 ψ(`∇´)ψ

https://github.com/TheWover/DInvoke

https://blog.nviso.eu/2020/11/20/dynamic-invocation-in-net-to-bypass-hooks/