Warning codes and precautions
Precautions
Code obfuscation tools cannot accurately understand all contexts. Therefore, users must protect their code by being alert to dangerous situations. When using code obfuscation and virtualization, be mindful of the following situations.
Compiler Optimization Considerations
If you’re using the VxLang SDK to obfuscate or virtualize your code, ensure that you check the compiler optimization settings. When compiler optimization is enabled, your code might be merged in ways that differ from how you originally wrote it. If VxLang SDK functions are referenced within this merged code, the Begin/End positions might change, resulting in less obfuscation than intended.
- Here’s how to fix the problem:
- Turn off compiler optimization.
- Disable code optimization for specific functions or pages at the code level.
#pragma optimize("", off) /// turn off optimization .. void ObfuscationTest() { VL_OBFUSCATION_BEGIN; // ... VL_OBFUSCATION_END; return; }
- Use MAP/PDB-based obfuscation/virtualization.
- It is described in the next chapter.
Potential Code Generation
Be aware of the following code pattern that may occur during the obfuscation and virtualization process:
- In this example, the jmp rax instruction causes a jump from the VxLang region back to the original code. This type of code can occur when table-based operations are used in a switch-case statement.
...
call _VXLANG_BEGIN
jmp L1
L0:
jmp EXIT
L1:
lea rax, $L0
jmp rax
EXIT:
call _VXLANG_END
...
Here’s how to get around this:
/*
For switch-case statements, it is very dangerous to obfuscate the entire syntax.
When compiled, it is moved to an unknown location (jmp reg), as shown below, and the obfuscation tool interprets it as it is,
so the code is moved to the original location where it was erased.
*** Therefore, for switch-case statements, it is safe to obfuscate the case internals as shown in the sample.
*/
/*
sub rsp,28
dec ecx
cmp ecx,E
ja tutorial64.vxm.7FF6E9C4133F
;
movsxd rax,ecx
lea rdx,qword ptr ds:[7FF6E9C40000]
mov ecx,dword ptr ds:[rdx+rax*4+3710]
add rcx,rdx
jmp rcx ; ***** Danger code ..
;
lea rdx,qword ptr ds:[<"Case 1"...>]
jmp tutorial64.vxm.7FF6E9C41346
lea rdx,qword ptr ds:[<"Case 2"...>]
jmp tutorial64.vxm.7FF6E9C41346
lea rdx,qword ptr ds:[<"Case 3"...>]
jmp tutorial64.vxm.7FF6E9C41346
lea rdx,qword ptr ds:[<"Case 4"...>]
jmp tutorial64.vxm.7FF6E9C41346
lea rdx,qword ptr ds:[<"Case 5"...>]
jmp tutorial64.vxm.7FF6E9C41346
lea rdx,qword ptr ds:[<"Case 6"...>]
jmp tutorial64.vxm.7FF6E9C41346
lea rdx,qword ptr ds:[<"Case 7"...>]
jmp tutorial64.vxm.7FF6E9C41346
lea rdx,qword ptr ds:[<"Case 8"...>]
jmp tutorial64.vxm.7FF6E9C41346
lea rdx,qword ptr ds:[<"Case 9"...>]
jmp tutorial64.vxm.7FF6E9C41346
lea rdx,qword ptr ds:[<"Case 10"...>]
jmp tutorial64.vxm.7FF6E9C41346
lea rdx,qword ptr ds:[<"Case 11"...>]
jmp tutorial64.vxm.7FF6E9C41346
lea rdx,qword ptr ds:[<"Case 12"...>]
jmp tutorial64.vxm.7FF6E9C41346
lea rdx,qword ptr ds:[<"Case 13"...>]
jmp tutorial64.vxm.7FF6E9C41346
lea rdx,qword ptr ds:[<"Case 14"...>]
jmp tutorial64.vxm.7FF6E9C41346
lea rdx,qword ptr ds:[<"Case 15"...>]
jmp tutorial64.vxm.7FF6E9C41346
lea rdx,qword ptr ds:[<"Default case"...>]
mov rcx,qword ptr ds:[<class std::basic_ostream<char, struct std::char_traits<char>> std::cout>]
call <tutorial64.vxm.class std::basic_ostream<char, struct std::char_traits<char>> & __cdecl std::operator<<<struct std::char_traits<char>>(class std::basic_ostream<char, struct std::char_traits<char>> &, char const *)>
lea rdx,qword ptr ds:[<class std::basic_ostream<char, struct std::char_traits<char>> & __cdecl std::endl<char, struct std::char_traits<char>>(class std::basic_ostream<char, struct std::char_traits<char>> &)>]
mov rcx,rax
add rsp,28
jmp qword ptr ds:[<public: class std::basic_ostream<char, struct std::char_traits<char>> & __cdecl std::basic_ostream<char, struct std::char_traits<char>>::operator<<(class std::basic_ostream<char, struct std::char_traits<char>> & (__cdecl *)(class std::basic_ostream<char, >]
*/
#pragma optimize("", off)
void Warning_SwitchCaseTest(int value) {
switch (value) {
case 1:
VL_VIRTUALIZATION_BEGIN;
std::cout << " Case 1" << std::endl;
VL_VIRTUALIZATION_END;
break;
case 2:
VL_VIRTUALIZATION_BEGIN;
std::cout << " Case 2" << std::endl;
VL_VIRTUALIZATION_END;
break;
case 3:
VL_VIRTUALIZATION_BEGIN;
std::cout << " Case 3" << std::endl;
VL_VIRTUALIZATION_END;
break;
case 4:
VL_VIRTUALIZATION_BEGIN;
std::cout << " Case 4" << std::endl;
VL_VIRTUALIZATION_END;
break;
case 5:
VL_VIRTUALIZATION_BEGIN;
std::cout << " Case 5" << std::endl;
VL_VIRTUALIZATION_END;
break;
case 6:
VL_VIRTUALIZATION_BEGIN;
std::cout << " Case 6" << std::endl;
VL_VIRTUALIZATION_END;
break;
case 7:
VL_VIRTUALIZATION_BEGIN;
std::cout << " Case 7" << std::endl;
VL_VIRTUALIZATION_END;
break;
case 8:
VL_VIRTUALIZATION_BEGIN;
std::cout << " Case 8" << std::endl;
VL_VIRTUALIZATION_END;
break;
case 9:
VL_VIRTUALIZATION_BEGIN;
std::cout << " Case 9" << std::endl;
VL_VIRTUALIZATION_END;
break;
case 10:
VL_VIRTUALIZATION_BEGIN;
std::cout << " Case 10" << std::endl;
VL_VIRTUALIZATION_END;
break;
case 11:
VL_VIRTUALIZATION_BEGIN;
std::cout << " Case 11" << std::endl;
VL_VIRTUALIZATION_END;
break;
case 12:
VL_VIRTUALIZATION_BEGIN;
std::cout << " Case 12" << std::endl;
VL_VIRTUALIZATION_END;
break;
case 13:
VL_VIRTUALIZATION_BEGIN;
std::cout << " Case 13" << std::endl;
VL_VIRTUALIZATION_END;
break;
case 14:
VL_VIRTUALIZATION_BEGIN;
std::cout << " Case 14" << std::endl;
VL_VIRTUALIZATION_END;
break;
case 15:
VL_VIRTUALIZATION_BEGIN;
std::cout << " Case 15" << std::endl;
VL_VIRTUALIZATION_END;
break;
default:
VL_VIRTUALIZATION_BEGIN;
std::cout << " Default" << std::endl;
VL_VIRTUALIZATION_END;
break;
}
return;
}
#pragma optimize("", off)
void SwitchCaseTest() {
VL_VIRTUALIZATION_BEGIN;
for (int i = 0; i < 16; ++i) {
Warning_SwitchCaseTest(i);
}
VL_VIRTUALIZATION_END;
return;
}
Exception Handling
VxLang currently only supports SEH (Structured Exception Handling). Therefore, be cautious when using it in conjunction with try-catch blocks.
- As of version
2.1.6.1
, MSVC C++ exception handling has been added, but please be aware that the context is unstable.- This is explained in the next chapter.
#pragma optimize("", off)
void ObfuscationSEHTest() {
VL_OBFUSCATION_BEGIN;
__try {
printf("SEH Test \n");
__debugbreak();
}
__except (1) {
printf(" Except \n");
}
VL_OBFUSCATION_END;
return;
}
Avoiding C++ exception handlers
SEH works with Windows system specifications. C++ EH, on the other hand, depends on the compiler specification (e.g. MSVC/Clang/GCC/Etc.), which can be circumvented by using the SDK as described below.
- Unlike SEH, Catch syntax in C++ is represented as a separate function, so we apply the SDK separately as shown below.
- In addition, the C++ EH records where exceptions can be thrown. For this reason, code that can throw exceptions must be excluded from SDK sections.
#pragma optimize("", off)
void test() {
try {
VL_OBFUSCATION_BEGIN;
printf(" > ObfuscationCxxEHTest \n");
VL_OBFUSCATION_END;
// *** Raise Exception
throw std::runtime_error("Something went wrong - 1");
}
catch (...) {
VL_OBFUSCATION_BEGIN;
printf(" > ObfuscationCxxEHTest Catch .. \n");
VL_OBFUSCATION_END;
}
return;
}