
Непрямые системные вызовы + DInvoke — это просто.
Непрямые системные вызовы + DInvoke без лишних сложностей.
Разработанная для прямого импорта в ваши собственные проекты на Nim, nimvoke использует макросы, чтобы абстрагировать детали выполнения непрямых системных вызовов и объявлений делегатов в стиле DInvoke. Эта библиотека проста в использовании и относительно безопасна с точки зрения OPSEC прямо из коробки. Имена функций и библиотек, используемые в макросах, хэшируются на этапе компиляции, а SSN и адреса инструкции syscall извлекаются независимо от каких-либо хуков. Все системные вызовы проходят через корректную инструкцию syscall в ntdll.dll.
Установите с помощью nimble (nimble install https://github.com/nbaertsch/nimvoke), затем просто импортируйте нужную библиотеку и вызовите соответствующий макрос. Подробности см. в examples.
DInvoke:
import winim/lean
import nimvoke/dinvoke
dinvokeDefine(
ZwAllocateVirtualMemory,
"ntdll.dll",
proc (ProcessHandle: Handle, BaseAddress: PVOID, ZeroBits: ULONG_PTR, RegionSize: PSIZE_T, AllocationType: ULONG, Protect: ULONG): NTSTATUS {.stdcall.}
)
var
hProcess: HANDLE = 0xFFFFFFFFFFFFFFFF
shellcodeSize: SIZE_T = 1000
baseAddr: PVOID
status: NTSTATUS
status = ZwAllocateVirtualMemory(
hProcess,
&baseAddr,
0,
&shellcodeSize,
MEM_RESERVE or MEM_COMMIT,
PAGE_READWRITE)
Системные вызовы:
import winim/lean
import nimvoke/syscalls
var
hProcess: HANDLE = 0xFFFFFFFFFFFFFFFF
shellcodeSize: SIZE_T = 1000
baseAddr: PVOID
status: NTSTATUS
status = syscall(NtAllocateVirtualMemory,
hProcess,
&baseAddr,
0,
&shellcodeSize,
MEM_RESERVE or MEM_COMMIT,
PAGE_READWRITE
)
Все бинарные файлы Nim импортируют набор базовых функций Win32. Все остальные функции Win32 разрешаются через dynlib, который использует GetProcAddress и LoadLibraryA для разрешения функций во время выполнения. Эта реализация DInvoke может предотвратить раскрытие новых функций, которые не используются другим кодом (будь то среда выполнения Nim/GC или код стандартной библиотеки, импортируемый через dynlib), но не может удалить основные импорты Nim или изменить поведение стандартных и сторонних библиотек.
При импорте nimvoke/syscalls анализирует EAT библиотеки ntdll.dll, чтобы найти все системные вызовы и извлечь необходимые данные. Информация обо всех системных вызовах хранится в памяти.
type
Syscall* = object
pName*: PCHAR
ord*: WORD
pFunc*: PVOID
pSyscall*: PVOID = NULL
ssn*: WORD
hooked*: bool
...
syscallSeq: seq[Syscall] # stores all syscall data
syscallTable* = initTable[string, ptr Syscall]() # maps syscall `Zw` hashed-name to `Syscall` object's in the `syscallSeq`
Получение SSN выполняется путём сортировки всех системных вызовов по их адресу и их подсчёта. Этот метод должен работать независимо от наличия хуков. В памяти не хранятся строки с именами функций, но для вычисления хэшей удерживается указатель на строки имён функций в EAT библиотеки ntdll.dll.
Системные вызовы используют один трамплин (из FreshyCalls) для перемещения SSN в eax, подготовки аргументов и перехода к корректной инструкции syscall в ntdll.dll. Этот трамплин размещается в новой приватной куче.
Если вы хотите выполнить код до этого кода инициализации системных вызовов (например, для обхода песочницы или environmental keying), вам нужно вызвать его до оператора import nimvoke/syscalls в вашем коде.
Есть предложения? Открывайте issue! PR тоже приветствуются.