How to obfuscate code with the SDK


How to build and use the SDK

The path to the SDK source code and msvc-project is as follows:

Configuring the SDK is very simple. You can export the VxLang API as follows.

extern "C"
void VxVirtualizationBegin() {
    return;
}

extern "C"
void VxVirtualizationEnd() {
    return;
}

//

extern "C"
void VxDualModeBegin() {
    return;
}

extern "C"
void VxDualModeEnd() {
    return;
}

//

extern "C"
void VxObfuscationBegin() {
    return;
}

extern "C"
void VxObfuscationEnd() {
    return;
}

//

extern "C"
void VxCodeFlatteningBegin() {
    return;
}

extern "C"
void VxCodeFlatteningEnd() {
    return;
}

These functions are defined by the following macros:

#define VL_OBFUSCATION_BEGIN               VxObfuscationBegin()
#define VL_OBFUSCATION_END                 VxObfuscationEnd()

#define VL_CODE_FLATTENING_BEGIN           VxCodeFlatteningBegin()
#define VL_CODE_FLATTENING_END             VxCodeFlatteningEnd()

#define VL_VIRTUALIZATION_BEGIN            VxVirtualizationBegin()
#define VL_VIRTUALIZATION_END              VxVirtualizationEnd()

#define VL_DUAL_MODE_BEGIN                 VxDualModeBegin()
#define VL_DUAL_MODE_END                   VxDualModeEnd()

By applying this macro, you can protect your code like this:

void test() {
   VL_OBFUSCATION_BEGIN;
   
   printf("Hello Wolrd ! \n");
   
   VL_OBFUSCATION_END;
   
   return;
}

How to check for obfuscation

To check if your code is obfuscated, you can use --disable-core.

TIP

vxlang.exe ${Your-Binary} –disable-core

When you issue this command, VxLang only performs obfuscation behavior, and does not perform VxLang core estimation and packing behavior.

The changed example is shown below:


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;
}

results matching ""

    No results matching ""