
D/Invoke implementation in Nim
Nim 中的 D/Invoke 实现
所有 Nim 二进制文件通常都会暴露相同的 58-60 个 Windows API 函数:
所有其他 Windows API 函数通常会在运行时通过 GetProcAddress 和 LoadLibraryA 解析,如 OffensiveNim 或 这篇博客文章 中所述。
因此,在 Nim 中通过 DInvoke(完全)隐藏 API 导入是不可能的,除非有人例如使用这个 DInvoke 实现来修改 Nim 编译器,使其使用 DInvoke 而不是 Dynlib。
相对于使用 GetProcAddress 和 LoadLibraryA,手动从 PEB 解析函数仍然比 Nim 的默认行为更隐蔽。为了避免内联挂钩,例如还需要手动映射一份新的 DLL 副本,如 TheWovers DInvoke 博客文章 中所述:
然而,这在此处尚未实现。我目前只使用 LdrLoadDll 将新的 DLL 加载到内存中。
这个项目很大程度上受到了 NanoDump 的 D/Invoke 代码的启发。
该函数可以像这样使用:
const
KERNEL32_DLL* = "kernel32.dll"
const
OpenProcess_FuncName * = "OpenProcess"
type
OpenProcess_t* = proc (dwDesiredAccess: DWORD, bInheritHandle: WINBOOL, dwProcessId: DWORD): HANDLE {.stdcall.}
MyOpenProcess = cast[OpenProcess_t](cast[LPVOID](get_function_address(cast[HMODULE](get_library_address(KERNEL32_DLL, FALSE)), OpenProcess_FuncName, 0)))
echo "[*] Calling OpenProcess via D/Invoke"
let pHandle = MyOpenProcess(
PROCESS_ALL_ACCESS,
false,
cast[DWORD](https://github.com/s3cur3th1ssh1t/nim_dinvoke/blob/HEAD/processID)
)
在测试中,我遇到了一些 API 函数的奇怪行为,这些函数需要特殊处理才能找到正确的相对地址。我的困惑可以在注释中找到。也许这也只是我糟糕的编码风格——谁知道呢。
成功时的示例如下: