
استدعاءات النظام غير المباشرة + DInvoke بكل بساطة.
استدعاءات النظام غير المباشرة + DInvoke ببساطة.
صُمم ليُستورد مباشرة في مشاريع Nim الخاصة بك، nimvoke يستخدم وحدات الماكرو (macros) لتجريد تفاصيل إجراء استدعاءات النظام غير المباشرة وإعلانات المندوبين بنمط DInvoke. تهدف هذه المكتبة إلى أن تكون سهلة الاستخدام وصديقة نسبيًا للأمن التشغيلي (op-sec) افتراضيًا. تُجزَّأ أسماء الدوال والمكتبات المستخدمة في الماكرو في وقت الترجمة، كما يتم استرجاع أرقام SSN وعناوين تعليمات syscall بغض النظر عن أي خطافات (hooks). جميع استدعاءات النظام تمر عبر تعليمة 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)
Syscalls:
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.
يتم تخصيص هذا الترامبولين في كومة خاصة جديدة.
إذا كنت تريد تشغيل كود قبل كود تهيئة استدعاءات النظام هذا (مثلًا لمراوغة بيئات العزل (sandbox evasion) أو المفاتيح البيئية environmental keying)، يجب استدعاؤه قبل عبارة import nimvoke/syscalls في كودك.
لديك اقتراحات؟ افتح Issue! كما نرحب بـ PRs أيضًا.