
مُحوِّل كود x86-64 إلى كود افتراضي للتعتيم القائم على الآلة الافتراضية (VM)
مُظلِّل كود x86-64 للترميز التشويشي المبني على الآلة الافتراضية (VM).
*دعم PE تم اختباره فقط على الثنائيات المبنية عبر MinGW-w64
سيتولى CMake جلب كل هذه التبعيات، لذلك ليس من الضروري تثبيتها بنفسك.
يلزم مترجم متوافق مع 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لأنها تستخدم التجميع المضمّن (inline assembly)- دعم
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_exit -> native instruction -> vm_enter). استدعاء الدوال يتبع المسار نفسه، حيث نخرج، نستدعي الدالة، ثم نعيد الدخول إلى الـVM. جميع هذه التحويلات تجعل حجم الثنائيات ينمو بشكل كبير:
a.out كملف ELF: 15.5 kB -> 1.0 MBa.out كملف PE: 259.3 kB -> 1.3 MB| الوصف | IDA |
|---|---|
فك ترجمة IDA لـ vm_entry، الذي تم تشويشه عبر مسار MBA فقط. تم توليد أكثر من 27k سطرًا من الكود (LOC) بواسطة أداة فك الترجمة. | ![]() |
تفكيك IDA لـ vm_entry، الذي تم تشويشه عبر مساري MBA وSMC. لا يعمل فك الترجمة. | ![]() |