{"id":26600770,"url":"https://github.com/nbaertsch/nimvoke","last_synced_at":"2025-04-09T12:08:12.530Z","repository":{"id":229113258,"uuid":"774950466","full_name":"nbaertsch/nimvoke","owner":"nbaertsch","description":"Indirect syscalls + DInvoke made simple.","archived":false,"fork":false,"pushed_at":"2024-10-17T21:10:57.000Z","size":42,"stargazers_count":82,"open_issues_count":0,"forks_count":8,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-10-20T08:00:55.905Z","etag":null,"topics":["nim-lang","syscalls"],"latest_commit_sha":null,"homepage":"","language":"Nim","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nbaertsch.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-03-20T13:51:45.000Z","updated_at":"2024-10-17T21:11:01.000Z","dependencies_parsed_at":null,"dependency_job_id":"a23cacf8-56d6-4980-bc36-fdde39b9eb04","html_url":"https://github.com/nbaertsch/nimvoke","commit_stats":null,"previous_names":["nbaertsch/nimvoke"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nbaertsch%2Fnimvoke","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nbaertsch%2Fnimvoke/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nbaertsch%2Fnimvoke/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nbaertsch%2Fnimvoke/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nbaertsch","download_url":"https://codeload.github.com/nbaertsch/nimvoke/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248036067,"owners_count":21037092,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["nim-lang","syscalls"],"created_at":"2025-03-23T18:35:02.002Z","updated_at":"2025-04-09T12:08:12.514Z","avatar_url":"https://github.com/nbaertsch.png","language":"Nim","funding_links":[],"categories":[],"sub_categories":[],"readme":"# nimvoke\nIndirect syscalls + DInvoke made simple.\n\nDesigned to be imported directly into your own Nim projects, _nimvoke_ uses macros to absract away the details of making indirect system calls and DInvoke-style delegate declarations. This library is meant to be easy to use and relatively op-sec friendly out-of-the-box. Function and library names used in the macro's are hashed at compile-time, and SSN's and `syscall` instruction addresses are retrieved regardless of any hooks. All syscalls go through the correct `syscall` instruction in `ntdll.dll`.\n\n## Usage\n\nInstall with nimble (`nimble install https://github.com/nbaertsch/nimvoke`), then simply import the relevant library and call the corresponding macro. See `examples` for more details.\n\nDInvoke:\n```nim\nimport winim/lean\nimport nimvoke/dinvoke\n\ndinvokeDefine(\n        ZwAllocateVirtualMemory,\n        \"ntdll.dll\",\n        proc (ProcessHandle: Handle, BaseAddress: PVOID, ZeroBits: ULONG_PTR, RegionSize: PSIZE_T, AllocationType: ULONG, Protect: ULONG): NTSTATUS {.stdcall.}\n    )\n\nvar\n        hProcess: HANDLE = 0xFFFFFFFFFFFFFFFF\n        shellcodeSize: SIZE_T = 1000\n        baseAddr: PVOID\n        status: NTSTATUS\n\nstatus = ZwAllocateVirtualMemory(\n    hProcess,\n    \u0026baseAddr,\n    0,\n    \u0026shellcodeSize,\n    MEM_RESERVE or MEM_COMMIT,\n    PAGE_READWRITE)\n```\n\nSyscalls:\n```nim\nimport winim/lean\nimport nimvoke/syscalls\n\nvar\n        hProcess: HANDLE = 0xFFFFFFFFFFFFFFFF\n        shellcodeSize: SIZE_T = 1000\n        baseAddr: PVOID\n        status: NTSTATUS\n\nstatus = syscall(NtAllocateVirtualMemory,\n            hProcess,\n            \u0026baseAddr,\n            0,\n            \u0026shellcodeSize,\n            MEM_RESERVE or MEM_COMMIT,\n            PAGE_READWRITE\n        )\n```\n\n## Important Op-Sec Notes\n\n### DInvoke\nAll Nim binaries will import a set of core Win32 functions. All other Win32 functions are resolved via `dynlib` which usus `GetProcAddress` and `LoadLibraryA` to resolve functions at runtime. This DInvoke implementation can prevent exposing _new_ functions that aren't used by other code (be that the nim runtime/GC or stdlib code importing via dynlib), but cannot remove Nim's core imports or alter the behavior of the std or 3rd party libraries.\n\n### Syscalls\nOn import, `nimvoke/syscalls` will parse the EAT of `ntdll.dll` to find all syscall's and extract the needed data. Information on all syscalls is stored in memory. \n```nim\ntype\n    Syscall* = object\n        pName*: PCHAR\n        ord*: WORD\n        pFunc*: PVOID\n        pSyscall*: PVOID = NULL\n        ssn*: WORD\n        hooked*: bool\n...\nsyscallSeq: seq[Syscall] # stores all syscall data\nsyscallTable* = initTable[string, ptr Syscall]() # maps syscall `Zw` hashed-name to `Syscall` object's in the `syscallSeq`\n```\n\nSSN retrival is done by sorting all syscalls by their address and counting them. This method should work regardless of any hooking. No function name strings are stored in memory, but a pointer to the function name strings in the EAT of `ntdll.dll` is held for calculating hashes.\n\nSyscalls use a single trampoline (from [FreshyCalls](https://github.com/crummie5/FreshyCalls)) to move the SSN to `eax`, prepare the arguments, and jump to the correct `syscall` instruction in `ntdll.dll`.\nThis trampoline is allocated on a new private heap.\n\nIf you want to run code before this syscall initialization code (like for sandbox evasion or enviornmental keying), you need to call it before the `import nimvoke/syscalls` statement in your code.\n\n# Future Work\n- [ ] x86 support\n- [ ] add more robust error handling and load libraries if they are missing from the process\n- [ ] include synthetic stack-frame spoofing\n\nGot suggestions? Open an issue! PR's also welcome.\n\n# Shoutouts\n- [FreshyCalls](https://github.com/crummie5/FreshyCalls) and [rust_syscalls](https://github.com/janoglezcampos/rust_syscalls) for providing 'arg-shifting' syscall trampolines.\n- [S3cur3Th1sSh1t](https://twitter.com/ShitSecure) for the idea\n- [MrUn1k0d3r](https://twitter.com/MrUn1k0d3r) for the great learning material and community\n- [Sektor7](https://institute.sektor7.net/) for solid training\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnbaertsch%2Fnimvoke","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnbaertsch%2Fnimvoke","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnbaertsch%2Fnimvoke/lists"}