
D/Invoke реализация на Nim
Реализация D/Invoke на Nim
Все Nim-бинары обычно экспортируют одни и те же 58–60 функций Windows API:
Все остальные функции Windows API обычно разрешаются во время выполнения через GetProcAddress и LoadLibraryA, как упоминается в OffensiveNim или этой записи в блоге.
Таким образом, скрыть импорты API (полностью) через DInvoke в Nim невозможно, если только кто-то, например, не использует эту реализацию DInvoke для изменения компилятора Nim под использование DInvoke вместо Dynlib.
Ручной разбор функций из PEB вместо использования GetProcAddress и LoadLibraryA всё равно более незаметен, чем поведение Nim по умолчанию. Чтобы также избежать инлайн-хуков, например, потребовалось бы ручное сопоставление (manual mapping) свежей копии DLL, как упоминается в записи в блоге TheWovers о DInvoke:
Это, однако, здесь не реализовано . В данный момент я использую только для загрузки новых DLL в память.
yetLdrLoadDllЭтот проект был сильно вдохновлён кодом D/Invoke из NanoDump.
Затем функцию можно использовать следующим образом:
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/main/processID)
)
В ходе своих тестов я столкнулся со странным поведением некоторых API-функций, для которых требуются особые случаи, чтобы найти правильный относительный адрес. Моё замешательство можно найти в комментариях. Может, это просто мой дерьмовый стиль кодинга — кто знает.
Пример при успешном выполнении выглядит следующим образом: