annihilatorq/omni

GitHub: annihilatorq/omni

一个现代 C++23 零分配头文件库,封装了 Windows 用户态底层操作,包括 PEB 模块遍历、导出表解析、延迟导入和直接 syscall 调用。

Stars: 254 | Forks: 23

[![Windows MSVC](https://static.pigsec.cn/wp-content/uploads/repos/2026/04/ac9ab4379d090254.svg)](https://github.com/annihilatorq/shadow_syscall/actions/workflows/windows-msvc.yml) [![Windows Clang-cl](https://static.pigsec.cn/wp-content/uploads/repos/2026/04/95fcd0d705090257.svg)](https://github.com/annihilatorq/shadow_syscall/actions/workflows/windows-clang-cl.yml) [![Windows GCC](https://static.pigsec.cn/wp-content/uploads/repos/2026/04/4e1abb5894090259.svg)](https://github.com/annihilatorq/shadow_syscall/actions/workflows/windows-gcc.yml) [![Windows MSVC Without Exceptions](https://static.pigsec.cn/wp-content/uploads/repos/2026/04/560507cd4b090301.svg)](https://github.com/annihilatorq/shadow_syscall/actions/workflows/windows-msvc-no-exceptions.yml) # omni `omni` 为通常较为繁琐的 WinAPI 操作提供了现代 C++ 封装:遍历加载器列表、解析导出表、通过哈希解析导入、调用 syscall 以及读取共享用户数据。它在需要迭代的地方保持了良好的 range 兼容性,简化了常见的调用流程,并提供了类型化的封装作为可选的额外验证。 ## 核心特性 - 仅头文件的 CMake target:`omni::omni` - 通过 `omni::modules`、`omni::module` 和 `omni::module_exports` 进行加载器/模块/导出检查 - 通过简洁的自由函数重载实现延迟导入和 syscall 调用 - 通过 `omni::lazy_importer` 和 `omni::syscaller` 提供可选的类型化封装 - 支持隐式字面量友好构造函数的编译时字符串哈希 - 对模块和导出提供友好的 Ranges 迭代器 - 为 syscall ID 和延迟导入提供可选缓存 - 针对加载器语义、导出解析、缓存和 syscall 解析的 Windows 特定测试 ## 快速开始 ``` add_subdirectory(path/to/omni) target_link_libraries(your_target PRIVATE omni::omni) ``` ``` #include #include "omni/modules.hpp" #include "omni/syscall.hpp" #include #include int main() { auto kernel32 = omni::get_module(L"kernel32.dll"); auto yield_status = omni::syscall("NtYieldExecution"); std::println("module : {}", kernel32.name()); std::println("exports : {}", kernel32.exports().size()); std::println("yield : 0x{:08X}", yield_status); } ``` ## API 概览 | 区域 | 主要类型 | | --- | --- | | Syscall | `omni::syscall`、`omni::syscaller`、`omni::status` | | 延迟导入 | `omni::lazy_import`、`omni::lazy_importer` | | 加载器检查 | `omni::modules`、`omni::module`、`omni::module_export`、`omni::module_exports` | | 共享数据 | `omni::shared_user_data` | | 工具 | `omni::address`、`omni::allocator`、`omni::fnv1a32`、`omni::fnv1a64`、自定义哈希策略 | ## 示例 [`examples/`](examples) 中的每个文件都会构建为独立的可执行文件: `address` · `allocator` · `hash` · `lazy_import` · `module` · `module_exports` · `modules` · `shared_user_data` · `status` · `syscall`
examples/module.cpp — 像普通 range 一样迭代导出项 ``` #include #include "omni/module.hpp" #include "omni/modules.hpp" #include #include #include namespace { [[nodiscard]] std::string_view name_of_export(const omni::module_export& export_entry) { return export_entry.name; } } // namespace int main() { auto self = omni::base_module(); auto kernel32 = omni::get_module(L"kernel32.dll"); auto* optional_header = self.image()->get_optional_header(); std::println("Current image:"); std::println(" name : {}", self.name()); std::println(" path : {}", self.system_path().string()); std::println(" base : {:#x}", self.base_address().value()); std::println(" entry point : {:#x}", self.entry_point().value()); std::println(" size of image : {}", optional_header->size_image); std::println(" export count : {}", self.exports().size()); std::println(); std::println("Kernel32 convenience helpers:"); std::println(" name : {}", kernel32.name()); std::println(" path : {}", kernel32.system_path().string()); std::println(R"( matches "kernel32" : {})", kernel32.matches_name_hash(L"kernel32")); std::println(R"( matches "KERNEL32.DLL": {})", kernel32.matches_name_hash(L"KERNEL32.DLL")); std::println(); std::println("First five named exports from kernel32:"); auto kernel32_exports = kernel32.exports(); auto first_named_exports = kernel32_exports.named() | std::views::transform(name_of_export) | std::views::take(5); for (std::string_view export_name : first_named_exports) { std::println(" {}", export_name); } } ``` 示例输出: ``` AcquireSRWLockExclusive AcquireSRWLockShared ActivateActCtx AddAtomA AddAtomW ```
examples/lazy_import.cpp — 简单的调用优先,需要元数据时使用类型化访问 ``` #include #include "omni/lazy_import.hpp" #include #include #include namespace { using get_module_handle_w_fn = HMODULE(WINAPI*)(LPCWSTR); using get_system_directory_w_fn = UINT(WINAPI*)(LPWSTR, UINT); } // namespace int main() { auto get_module_handle = omni::lazy_importer{"GetModuleHandleW"}; HMODULE kernel32_handle = get_module_handle(L"kernel32.dll"); auto get_module_handle_export = get_module_handle.module_export(); if (kernel32_handle == nullptr || !get_module_handle_export.present()) { std::println("Failed to lazy-import GetModuleHandleW"); return 1; } std::println("Typed lazy importer:"); std::println(" result : {:#x}", reinterpret_cast(kernel32_handle)); std::println(" export address : {:#x}", get_module_handle_export.address.value()); std::println(" owning module : {}", omni::get_module(get_module_handle_export.module_base).name()); auto system_directory_buffer = std::array{}; auto system_directory_length = omni::lazy_import({"GetSystemDirectoryW", "kernel32.dll"}, system_directory_buffer.data(), static_cast(system_directory_buffer.size())); auto system_directory = std::filesystem::path{ std::wstring_view{system_directory_buffer.data(), system_directory_length}, }; std::println(); std::println("Hash-pair overload:"); std::println(" system directory : {}", system_directory.string()); auto process_id = omni::lazy_import<::GetCurrentProcessId>(); std::println(); std::println("Auto-function overload:"); std::println(" current process id : {}", process_id); omni::lazy_import("SetLastError", 0xCAFEU); auto last_error = ::GetLastError(); std::println(); std::println("Generic return-type overload:"); std::println(" GetLastError() : 0x{:X}", last_error); auto missing_export = omni::lazy_importer{"MissingExportForExamples", "kernel32.dll"}.try_invoke(); if (!missing_export) { std::println(); std::println("Failure diagnostics stay explicit:"); std::println(" {}", missing_export.error().message()); } } ``` 示例输出: ``` process id : 18432 result : 0x7ff9d3d40000 export address : 0x7ff9d3d5b7f0 ```
examples/syscall.cpp — 原生 syscall 优先,需要额外检查时使用类型化封装 ``` #include #include "omni/syscall.hpp" #include #include struct process_basic_information { void* reserved1{}; void* peb_base_address{}; void* reserved2[2]{}; std::uintptr_t unique_process_id{}; void* reserved3{}; }; using nt_query_info_process_fn = omni::status (*)(HANDLE, ULONG, void*, ULONG, ULONG*); int main() { omni::syscaller query_process{"NtQueryInformationProcess"}; process_basic_information process_info{}; ULONG return_length{}; auto query_status = query_process.try_invoke(::GetCurrentProcess(), 0U, &process_info, sizeof(process_info), &return_length); if (!query_status) { std::println("Failed to resolve NtQueryInformationProcess: {}", query_status.error().message()); return 1; } process_basic_information shortcut_process_info{}; ULONG shortcut_return_length{}; auto shortcut_status = omni::syscall("NtQueryInformationProcess", ::GetCurrentProcess(), 0U, &shortcut_process_info, sizeof(shortcut_process_info), &shortcut_return_length); std::println("Typed syscall wrapper around NtQueryInformationProcess:"); std::println(" status : 0x{:08X}", static_cast(query_status->value)); std::println(" success : {}", query_status->is_success()); std::println(" PEB : {:#x}", reinterpret_cast(process_info.peb_base_address)); std::println(" process id : {}", process_info.unique_process_id); std::println(" return length : {}", return_length); std::println(); std::println("Free overload with a typed function signature:"); std::println(" status : 0x{:08X}", static_cast(shortcut_status.value)); std::println(" same PEB : {}", shortcut_process_info.peb_base_address == process_info.peb_base_address); std::println(" same process id : {}", shortcut_process_info.unique_process_id == process_info.unique_process_id); std::println(" return length : {}", shortcut_return_length); auto yield_status = omni::syscall("NtYieldExecution"); std::println(); std::println("Generic syscall overload:"); std::println(" NtYieldExecution : 0x{:08X}", static_cast(yield_status.value)); std::println(" success : {}", yield_status.is_success()); auto not_a_syscall = omni::syscaller{"RtlGetVersion"}.try_invoke(); if (!not_a_syscall) { std::println(); std::println("Diagnostics stay explicit when an export is not a syscall stub:"); std::println(" {}", not_a_syscall.error().message()); } } ``` 示例输出: ``` status : 0x00000000 success : true typed : 0x00000000 ```
更多完整示例,请参见: - [`examples/hash.cpp`](examples/hash.cpp) - [`examples/module_exports.cpp`](examples/module_exports.cpp) - [`examples/modules.cpp`](examples/modules.cpp) - [`examples/shared_user_data.cpp`](examples/shared_user_data.cpp) ## 构建 要求: - Windows - CMake 3.21+ - C++23 编译器 构建库、所有示例和测试套件: ``` cmake -S . -B build -DOMNI_BUILD_EXAMPLES=ON -DOMNI_BUILD_TESTS=ON cmake --build build --config Release ``` 常用 CMake 选项: | 选项 | 默认值 | 含义 | | --- | --- | --- | | `OMNI_BUILD_EXAMPLES` | 顶层构建默认为 `ON` | 将 `examples/` 中的每个文件构建为独立的可执行文件 | | `OMNI_BUILD_TESTS` | 顶层构建默认为 `ON` | 构建 Windows 测试套件 | | `OMNI_DISABLE_EXCEPTIONS` | `OFF` | 禁用 C++ 异常 | ## 测试 测试套件位于 [`tests/`](tests),每个测试源文件会构建一个名为 `omni_test_` 的可执行文件,并注册到 `CTest`。 当前涵盖的测试范围包括: - 加载器迭代与查找 - `module` 标识及面向 WinAPI 的属性 - 导出表解析、按名称/序号迭代以及转发器 - 延迟导入的成功/失败路径、类型化重载及缓存 - syscall 解析、类型化/泛型封装及缓存行为 使用 CTest 运行测试套件: ``` ctest --test-dir build --output-on-failure ``` 如果你使用多配置生成器,请附加 `-C Release` 或你所选的配置。 测试使用了 [`boost.ut`](https://github.com/boost-ext/ut)。如果本地不可用,CMake 会自动拉取它。 ## 配置 `omni` 基本上是零配置的,但也提供了一些编译时开关: | 宏 | 效果 | | --- | --- | | `OMNI_DISABLE_CACHING` | 禁用延迟导入和 syscall ID 的内部缓存 | | `OMNI_ENABLE_ERROR_STRINGS` | 在非 Debug 构建中保留可读的错误字符串 | | `OMNI_DISABLE_ERROR_STRINGS` | 即使在 Debug 构建中也剥离错误字符串 | ## 备注 - `syscall` 示例假定运行在 x64 Windows 进程中。 - 函数的哈希参数确保在编译时将你传入的字符串字面量转换为数字。 - 该项目仍在不断发展中,因此在库的接口稳定之前,预计还会有 API 调整。 - 第三方声明详见 [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md)。 感谢 `receiver1`、`po0p` 和 invers1on 为本项目提供的贡献、想法和帮助。
标签:Bash脚本, C++23, CMake, C++封装库, DNS 解析, EDR绕过, Hpfeeds, PEB遍历, Ranges, Raspberry Pi, shadow_syscall, Shellcode辅助, Syscall, Web开发, Windows API, Windows开发, XML 请求, 中高交互蜜罐, 云资产清单, 内存执行, 动态解析, 头文件库, 安全工具库, 安全开发, 安全意识培训, 导出表遍历, 延迟导入, 恶意软件开发, 模块解析, 用户态, 端点可见性, 系统调用, 红队基础设施, 编译期字符串哈希, 被动侦察, 逆向工程, 零内存分配, 高交互蜜罐