
VM आधारित अस्पष्टीकरण के लिए एक x86-64 कोड वर्चुअलाइज़र
VM-आधारित अस्पष्टता के लिए एक x86-64 कोड वर्चुअलाइज़र।
*PE समर्थन केवल MinGW-w64 के माध्यम से संकलित बाइनरी पर परीक्षण किया गया
CMake ये सभी निर्भरताएँ स्वचालित रूप से लाएगा, इसलिए इन्हें स्वयं स्थापित करना आवश्यक नहीं है।
| नाम | संस्करण |
|---|
| CMake | 3.25+ |
| Zydis | 4.1.0+ |
| zasm | Latest |
| LIEF | 0.15.1+ |
C++23 संगत कंपाइलर आवश्यक है।
git clone https://github.com/dmaivel/covirt.git
cd covirt
mkdir build
cd build
cmake ..
cmake --build . --config Release
यदि आप Windows पर Visual Studio के माध्यम से संकलन कर रहे हैं, तो आपको clang-cl का उपयोग करना होगा: cmake .. -T ClangCL -A x64।
Usage: covirt [--help] [--version] [--output OUTPUT_PATH] [--vm_code_size MAX] [--vm_stack_size SIZE] [--no_self_modifying_code] [--no_mixed_boolean_arith] [--show_dump_table] INPUT_PATH
Code virtualizer for x86-64 ELF & PE binaries
Positional arguments:
INPUT_PATH path to input binary to virtualize
Optional arguments:
-h, --help shows help message and exits
-v, --version prints version information and exits
-o, --output OUTPUT_PATH specify the output file [default: INPUT_PATH.covirt]
-vcode, --vm_code_size MAX specify the maximum allowed total lifted bytes [default: 2048]
-vstack, --vm_stack_size SIZE specify the size of the virtual stack [default: 2048]
-no_smc, --no_self_modifying_code disable smc pass
-no_mba, --no_mixed_boolean_arith disable mba pass
-d, --show_dump_table show disassembly of the vm instructions
covirt को यह पता चले कि किन फ़ंक्शनों को वर्चुअलाइज़ करने की आवश्यकता है, आपको अपने स्रोत कोड में प्रारंभ और समाप्ति मार्कर जोड़ने होंगे, जैसे:
#include "covirt_stub.h"
int my_function(...)
{
int result = 0;
__covirt_vm_start();
// ...
__covirt_vm_end();
return result;
}
[!IMPORTANT]
__covirt_vm_endको अगम्य स्थानों पर न रखें (जैसे कि return के बाद), क्योंकि इससे अंतिम स्टब उत्सर्जित नहीं होगा।__covirt_vm_...();स्टबMSVCका उपयोग करते हुए काम नहीं करेंगे क्योंकि वे इनलाइन असेंबली का उपयोग करते हैं।SSE4समर्थन आवश्यक है।

#include <covirt_stub.h>
#include <stdio.h>
int calculate(int a, int b)
{
int result = 0;
__covirt_vm_start();
for (int i = 0; i < 10; i++)
if (i > 5)
result += result + a;
else
result += (result >> 1) + b;
printf("result = %d\n", result);
__covirt_vm_end();
return result;
}
int main()
{
calculate(5, 12);
}
उपरोक्त उदाहरण एप्लिकेशन को covirt a.out -d का उपयोग करके वर्चुअलाइज़ किया गया था, जो अस्पष्टता और वर्चुअलाइज़ेशन के बाद VM निर्देशों का एक डंप आउटपुट करता है। वर्तमान VM कार्यान्वयन अधिकांश ऑपरेंड को संसाधित करने के लिए स्टैक पर धकेलता है, जिससे VM निर्देशों को एन्कोड करने की जटिलता कम हो जाती है। उन निर्देशों के लिए जिनके लिए परिभाषित VM हैंडलर नहीं है, वे मूल रूप से निष्पादित होंगे (vm_exit -> native instruction -> vm_enter)। फ़ंक्शन कॉल करना उसी पाइपलाइन का अनुसरण करता है, जिसमें हम बाहर निकलते हैं, फ़ंक्शन को कॉल करते हैं, और VM में पुनः प्रवेश करते हैं। सब मिलाकर, ये परिवर्तन बाइनरी के आकार को काफी बढ़ा देते हैं:
a.out एक ELF के रूप में: 15.5 kB -> 1.0 MBa.out एक PE के रूप में: 259.3 kB -> 1.3 MB| विवरण | IDA |
|---|---|
vm_entry का IDA डीकंपाइलेशन, जिसे केवल MBA पास के माध्यम से अस्पष्ट किया गया है। डीकंपाइलर द्वारा 27k से अधिक LOC उत्पन्न किए गए। | ![]() |
vm_entry का IDA डिसअसेंबली, जिसे MBA और SMC पास के माध्यम से अस्पष्ट किया गया है। डीकंपाइलेशन काम नहीं करता। | ![]() |