vm_str.hpp is a header only C++20 compile time string obfuscator.
I got this idea floating in my head about trying to do something like xorstr, but with random constexpr-chosen operations instead of just xor.
At compile time (constexpr), the library generates bytecode representing the obfuscation schema. Then, at runtime, a stack-based VM interprets this bytecode to reconstruct the original string.
The string is constructed on the stack at runtime and does not appear anywhere in the executable prior to execution.
How the string construction appears on IDA decompiler.
-
VM_CSTR(...)to get a pointer to a c-like string. -
VM_STR(...)to get a std c++ string. -
VM_W_CSTR(...)to get a pointer to a c-like wide string. -
VM_W_STR(...)to get a std c++ wide string.
#include "vm_str.hpp"
int main() {
const char *c_like_string = VM_CSTR("Hello, ");
std::string cpp_std_string = VM_STR("World!");
std::cout << c_like_string << cpp_std_string << std::endl;
const wchar_t *cw_like_string = VM_W_CSTR(L"Hello, ");
std::wstring cpp_std_wstring = VM_W_STR(L"World!");
std::wcout << cw_like_string << cpp_std_wstring << std::endl;
}- Generates different obfuscation schema for every build, making general deobfuscators like that harder to develop.
- String is constructed on the stack at runtime and does not appear in the
.datasection. - The string's runtime decryption is purposefully convoluted, making static analysis harder.
- char*
- std::string
- wchar_t*
- std::wstring
See Limitations
- msvc
See Limitations
- We currently support UTF-8 and UTF-16 strings; other encodings are not supported.
- No compiler other than MSVC will be supported.
- Builds with C++ standards earlier than C++20 will fail.
- Build time is highly affected by
vm_str.hppsince it makes extensive use ofconstexprevaluations to generate the bytecode. Based on anecdotal data, even a single character can increase build time by ~1 second. Runtime performance does not seem to be significantly affected, though.