Skip to main content

Virbox Protector 保护指引(Native)

Native程序介绍#

Native程序,这里是指操作系统原生的二进制格式的程序,如Windows PE格式,Linux/Android下的ELF格式以及 macOS/iOS下的MachO格式。

Native程序常见扩展名

操作系统(格式)主程序动态库/共享库驱动程序
Windows (PE).exe.dll.sys
Linux/Android (ELF)/.so.ko
macOS/iOS (MachO)/.dylib/

Native 程序一般由 C/C++/Objective-C/Swift/Delphi/Go 等语言开发,具有资源消耗小,运行效率高等特点,运行在 PC、服务器、移动端、IoT等设备上。

Native程序的安全性问题#

虽然经过编译生成的Native程序一般不会存在原始的函数名、变量名,逆向分析难度较高,但由于相应的反编译工具也成熟强大,依然可以反编译为类C伪代码,再加上特征库定位、交叉引用分析等高级功能,仍然可以将代码高度还原,对于高安全性需要的场景,不经过保护很容易被逆向破解。

测试程序举例(Android ARM架构):

源代码

src

反编译效果

decompile

虽然函数中变量名等信息丢失,通过符号表(ELF)、导入/导出函数、字符串等信息的辅助分析,函数依然可以反编译为易读的代码。

功能介绍#

Virbox Protector 对Native程序支持基础保护和函数级的保护,可以起到防逆向、防调试、防篡改以及运行时环境检测等功能。

基础保护#

基础保护,是对程序整体的保护,对程序的性能影响小,操作简单,可以达到防反编译、防篡改、防调试等效果。

压缩#

压缩,是将程序中的代码、数据以及一些格式相关的程序数据(如导入表、重定位表、部分资源信息)进行打包、压缩和加密,再将程序入口替换为壳代码,运行时由壳代码将代码和数据解密并还原,并修复一些必须的程序数据,再跳转到原始的程序入口(OEP) 执行。

压缩加密了整个代码段和数据段(ELF程序不会加密可写数据段),可以防止程序被静态反汇编、反编译,一定程度上起到防止文件补丁的效果。

内存校验#

内存校验,可以在程序加载时校验自身完整性,如果发现程序被篡改,则会退出进程。

如果需要在运行时动态进行校验,可以使用SDK标签在代码中调用。

内存保护(ELF)#

程序启动后,防止被调试器附加调试,防止程序被Dump内存。

导入表保护(PE&ELF)#

导入表描述了程序的依赖库、依赖函数信息和导入地址,是模块间调用的边界,很容易暴露代码逻辑。

imp

imp

经过导入表保护后,原始的导入表被清除,模块间调用替换为壳的修复代码。

imp_protected

导入表保护可以去除程序中的导入函数和变量等敏感信息,防止反编译工具交叉引用分析模块边界。并将原始的 IAT(PE)或GOT表(ELF)中的地址替换为壳的修复函数,运行时不会还原,防止运行时被直接修复脱壳。

资源节加密(PE)#

Windows PE程序可以嵌入资源,一般存放界面布局、多语言字符串、图标等,开发者可能会将一些敏感数据以资源的形式嵌入到程序中,资源位于程序的资源节中(一般为 .rsrc节),很容易被提取和篡改。

res

资源节加密,可以将整个资源节加密,只保留图标和版本号等必要的信息,可以防止资源的提取和篡改。

附加数据加密(PE)#

附加数据是“拼接”到程序结尾的数据,某些音视频、PPT播放器等程序,会将资源、数据库等以附加数据的形式拼接到程序结尾。

附加数据加密,可以将附加数据加密,防止重要资源被提取。

移除调试信息(ELF)#

ELF程序中有时会包含Debug节,静态符号表,其中包含了函数名、函数地址等信息,对外发布时如果携带会降低程序的安全性。

移除调试信息,会将ELF程序中的 .debug 节,静态符号表移除。

检测调试器#

调试是逆向分析时的重要手段,可以在庞大的二进制指令中迅速定位到相关的逻辑。

调测调试器,可以检测当前模块的进程是否被 x64dbg/OllyDbg/IDA Pro/Windbg 等工具调试,被调试则退出阻止运行。

检测虚拟机(PE)#

检测程序是否在 VMWare, Virtual Box 等虚拟机中运行,检测到则退出阻止运行。

函数级保护#

函数保护以函数为粒度,提供了精细化,安全性高的针对性保护,适用于加密方案、客户端/服务端认证,通信加密等高安全性要求的场景。

代码加密#

代码加密是通过自修改代码(SMC)的方式,在函数被调用时解密自身,再跳转到正确的函数指令中执行。可以防止

代码加密后在运行时执行还是原始指令,因此几乎无性能影响,可以防脱壳,防止静态反编译。

保护前:

fn_enc_before

保护后:

fn_enc_after

代码混淆#

代码混淆是将函数中原始的指令,通过等价变换、立即数加密、间接跳转、虚假分支、花指令加扰、指令切片等手段,将原始指令转换为难以阅读的随机的指令片段。

功能特性

  • 防止函数被反编译为可阅读函数,提升逆向分析的难度。
  • 运行时也不会还原,干扰静态分析和动态调试分析。
  • 函数体被拆分为无数个随机分布的指令块,破坏函数边界。
  • 对内存访问和跳转指令进行转换,破坏反编译工具的交叉引用分析。
  • 使函数没有指令特征,防止被特征定位。
  • 混淆的指令中包含暗桩,可检测调试器Run Trace追踪。

保护前:

fn_obfus_before

保护后:

fn_obfus_after

代码虚拟化#

代码虚拟化,是保护过程中将函数中原始的汇编指令,转换为自定义的虚拟指令,运行时在自定义的虚拟机中执行,模拟了汇编指令中的内存访问、条件判断、寄存器状态等。

convert

功能特性

  • 虚拟指令每次保护时都是随机生成,需要逆向虚拟机代码才能理解虚拟指令对应的真实操作。
  • 针对算法类的代码保护效果更好(函数调用较少的代码)。
  • 虚拟机代码经过再度混淆,加强了自身安全性。

保护前:

fn_vm_before

保护后:

fn_vm_after

虚拟化后会在程序中插入解释器的汇编指令,还有虚拟机入口指令(用于加载虚拟指令,设置状态等)等,这些指令还会再度进行混淆,上图中只有部分入口跳转指令。

SDK标签#

Virbox Protector 还支持SDK标签的方式对程序保护,可以精细地控制保护哪些函数或代码片段,也可以用于加密数据或字符串以及校验内存完整性。SDK标签支持C/C++/Objective-C/Swift等语言的调用集成,可以在安装目录 <install_dir>/example/sdk目录下查看使用示例。

Virbox Protector 支持静态库标签和动态库标签。

静态库标签

静态库SDK位于 <install_dir>/example/sdk/lib 下,目录结构为:

├─a32├─a64├─fat├─framework│  ├─virbox_iOS.framework│  │  ├─Headers│  │  └─Modules│  └─virbox_macOS.framework│      ├─Headers│      ├─Modules│      └─Resources├─x64└─x86
x86: x86静态库x64: x64静态库a32: arm32静态库a64: arm64静态库fat: macOS/iOS fat格式静态库framework: macOS/iOS fat格式 framework

静态库以 virbox_\<sysabi> 命名。

virbox_windows.lib       # Windows静态库virbox_wdk.lib           # Windows驱动程序静态库libvirbox_android.a      # Android静态库...

动态库标签

SDK标签会使程序依赖virbox32或virbox64动态库,程序被保护后会清除清除该依赖。

动态库SDK位于 <install_dir>/example/sdk 下,以系统名命名,如 Windows 动态库位于 <install_dir>/example/sdk/windows 下。

SDK标签技术原理

SDK标签本身并不包含加解密或者保护的功能,而是以特征的方式标记代码位置。使用 Virbox Protector 对程序保护时才真正对标记的代码保护、对标记的字符串等数据加密。

SDK标签支持的功能

  • 常量数据加密(包括字符串、密钥等敏感数据)
  • 代码混淆
  • 代码虚拟化
  • 安全退出
  • 内存校验
  • 调试器检测
  • 虚拟机检测

函数标签#

函数标签可以标记整个函数,在保护时可以保护整个函数,包括编译生成的函数入口指令。

VBMutateFunction 混淆当前函数

VBVirtualizeFunction 虚拟化当前函数

代码示例:

int add(int x, int y){    int ret = 0;    VBMutateFunction("add#");    ret = x + y;    printf("x+y=%d\n", ret);    return ret;}
int sub(int x, int y){    int ret = 0;    VBVirtualizeFunction("sub#");    ret = x - y;    printf("x-y=%d\n", ret);    return ret;}

代码块标签#

代码块标签即 Begin&End 标签,可以标记函数中的代码片段,在保护时仅保护Begin和End之间的代码。

Begin标签

VBProtectBegin代码虚拟化开始

VBVirtualizeBegin代码虚拟化结束(同VBProtectBegin

VBMutateBegin代码混淆开始

VBSnippetBegin代码碎片化开始,仅支持 Virbox Protector LM (Pro)版。

End标签

VBProtectEnd代码保护结束,与Begin标签配对使用。

代码示例:

int foo(int x){    if (x == 0)    {        VBVirtualizeBegin("foo_1#");        // do something...        VBProtectEnd();    }    else    {        VBMutateBegin("foo_2");        // do something...        VBProtectEnd();    }    return 0;}

高级数据加密(LM)#

VBProtectDecrypt

VBProtectDecrypt标签仅供 Virbox Protector LM(许可)版本使用。

VBProtectDecrypt 使用高安全性算法(AES256)加密数据,数据长度必须为16的整数倍。

void *VB_API_CALL VBProtectDecrypt(void *dst, const void *src, int size);

示例:

static const char g_my_key[16] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,                                   0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 };
int test_decrypt(){    char buf[sizeof(g_mey_key)];    VBProtectDecrypt(buf, g_my_key, sizeof(g_my_key));    // do something...    return 0;}

字符串和数据加密#

如果程序中包含了涉及安全性的问题的敏感字符串或数据(如密钥,证书等),建议对数据也进行保护,可以使用SDK标签标记要加密的数据或字符串,标记后可以被Virbox Protector自动识别,在每次保护时会随机生成密钥加密,保证每次保护后的密文不同。

VBDecryptData

void* VB_API_CALL VBDecryptData(const void *data, int size);

VBDecryptData可以加密任意长度的常量数据

VBDecryptStringA

VBDecryptStringA 是对VBDecryptData的封装,用于加密字符串。

VBDecryptStringW

VBDecryptStringW 一般用于加密Windows下宽字符串。

VBFreeData

VBFreeData用于释放以上三个接口返回的数据或字符串。可以防止内存搜索工具搜索到该数据。


为了方便开发者调用,Virbox Protector 另外提供了无需释放的数据解密接口,仅在第一次使用字符串时解密到堆内存,在模块卸载时自动释放。

VBDecryptDataOnce

同 VBDecryptData,无需释放。

VBDecryptStringOnceA

同 VBDecryptStringA,无需释放。

VBDecryptStringOnceW

同 VBDecryptStringW,无需释放。

代码示例:

int test_encrypt_key(){    // 加密静态常量    static const unsigned char s_key[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,          0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 };    unsigned char* key = VBDecryptData(s_key, sizeof(s_key));    for (int i = 0; i != sizeof(s_key); ++i)    {        printf("%02x ", key[i]);    }    printf("\n");    // 释放内存    VBFreeData(key);        // 加密 hello字符串    printf(VBDecryptStringOnceA("hello"));    return 0;}

环境检测与安全退出#

安全退出#

VBSafeExit

如果程序发现一些恶意行为,调用ExitProcessexitkillabort 等函数容易被破解者追踪到调用位置并绕过。VBSafeExit标签可动销毁调用位置的栈帧,常用寄存器、返回地址等信息,让破解者难以追踪到调用位置。

内存校验#

Virbox Protector 加密选项中的内存校验,仅在程序启动时校验一次,如果破解者通过动态内存补丁的方式破解,可能会绕过检测,开发者可以通过 SDK 标签调用 VBProtectVerifyImage(自动安全退出)或 VBVerifyImage(不退出,返回校验结果)进行校验,将校验时机与业务代码混合,提升校验的安全性。

VBProtectVerifyImage

VBProtectVerifyImage 可以校验当前模块的内存完整性,检查程序是否被篡改(包括静态补丁和动态内存补丁),如果发现篡改则自动安全退出。

VBVerfiyImage

VBVerifyImage 可以校验当前模块的内存完整性,检查程序是否被篡改(包括静态补丁和动态内存补丁),如果发现篡改则返回非0值。

调试器检测#

VBDetectDebugger

int VB_API_CALL VBDetectDebugger(void);

检测程序是否正在被调试器进行调试,发现则返回非0值。

虚拟机检测#

VBDetectVirtualMachine

int VB_API_CALL VBDetectVirtualMachine(void);

检测程序是否正在VMware, Virtual Box等虚拟机中运行,发现则返回非0值。(仅支持Windows)

使用示例#
int check(){    // 使用了检测的函数要加上混淆或虚拟化标签才更安全    VBMutateFunction("check#");    int code = 0;    if (VBVerifyImage() != 0)    {        // 发现内存被篡改        code = 1;    }        if (VBDetectDebugger() != 0)    {        // 发现调试器        code |= 2;    }        if (VBDetectVirtualMachine() != 0)    {        // 发现在虚拟机中运行        code |= 4;    }        if (code != 0)    {        // 清场退出        VBSafeEixt(0xdead0000 | code);    }        return 0;}

插件#

DSProtector(Windows&Linux)#

DSProtector 插件可以用于加密程序使用到的只读文件,如脚本语言、音视频、图片、只读配置文件、数据库等,防止敏感文件被直接窃取。

支持范围#

操作系统与CPU架构支持#

操作系统x86x64arm32arm64
Windows✔️✔️✖️✖️
Linux✔️✔️✔️✔️
macOS✖️✔️✖️✔️
Android✔️✔️✔️✔️
iOS✖️✖️✖️✔️

功能与操作系统支持#

保护选项WindowsLinuxmacOSAndroidiOS
压缩✔️✔️✖️✔️✖️
内存校验✔️✔️✔️✔️✔️
内存保护✖️✔️✖️✔️✖️
导入表保护✔️✔️✖️✔️✖️
附加数据加密✔️✔️✔️✔️✔️
调试器检测✔️✔️✔️✔️✔️
虚拟机检测✔️✖️✖️✖️✖️
移除调试信息✖️✔️✖️✔️✖️
[E] 代码加密✔️✔️✔️✔️✔️
[M] 代码混淆✔️✔️✔️✔️✔️
[V] 代码虚拟化✔️✔️✔️✔️✔️

自动化集成#

命令行工具#

Virbox Protector 支持命令行选项,可以指定基础保护选项和函数选项,方便自动化集成。

命令行工具 virboxprotector_con 的默认路径位于:

Windows:C:\Program Files\senseshield\Virbox Protector 3\bin
Linux:/usr/share/virboxprotector/bin
macOS:/Applications/Virbox Protector 3.app/Contents/MacOS/bin

使用配置文件#

使用Virbox Protector工具界面进行保护,在被保护的程序所在目录会生成 .ssp 配置文件,然后调用virboxprotector_con

virboxprotector_con <input_file> -o <output_file>

virboxprotector_con 会自动查找 <input_file>.ssp 作为配置文件开始保护。

保护选项#

PE

选项命令行默认选项
压缩--pack=1
内存校验--mem-check=0
导入表保护--imp-protect=0
资源节加密--res-sect-enc=1
附加数据加密--overlay-enc=1
调试器检测--detect-dbg=0
虚拟机检测--detect-vm=0

ELF

选项命令行默认选项
压缩--pack=1
内存校验--mem-check=0
导入表保护--imp-protect=0
调试器检测--detect-dbg=0
剥离符号表--strip-dbginfo=1

MachO

选项命令行默认选项
内存校验--mem-check=1
调试器检测--detect-dbg=0
函数选项#
选项命令行
忽略不支持的函数--ignore-unsupported=<value>
代码加密-e
代码混淆-m
代码虚拟化-v

支持指定函数名称或规则保护,使用 ;号隔开,支持通配符 *,举例:

-m "function1;function2" -v "function3;function4" -e "test*" --ignore-unsupported=1

举例#

对Windows主程序保护:

virboxprotector_con test.exe --pack=1 --imp-protect=1 --mem-check=1 --res-sec-enc=1 --detect-dbg=1 -o protected/test.exe

对Linux程序保护:

virboxprotector_con libhello.so --pack=1 --mem-check=1 --detect-dbg=0 -o protected/libhello.so

对Linux程序保护(同时生成调试版和发布版):

#生成保留符号的版本用于故障分析virboxprotector_con libhello.so --pack=1 --mem-check=1 --strip-dbginfo=0 -o protected/libhello_with_sym.so
#去掉符号表对外发布virboxprotector_con -strip protected/libhello_with_sym.so -o protected/libhello.so

对macOS程序保护:

virboxprotector_con libtest.dylib --detect-dbg=1 --mem-check=1 -e "*" -o protected/libtest.dylib

保护指引#

普通的保护方式#

如果对安全性没有较高的要求,一般不需要函数级别的保护,只需要调整基础保护选项即可实现防反编译和防内存Dump脱壳,无需复杂的配置选项,直接用命令行工具即可完成保护。

保护选项保护建议保护效果
压缩勾选压缩可以加密整个代码段,隐藏一些原程序的结构信息(导入表、重定位等),防止直接反编译。
内存校验勾选防止程序被修改。
导入表保护勾选加密导入表,防止脱壳,防止查看API引用。
资源节加密勾选加密PE资源节(.rsrc),防止资源信息被提取。
附加数据加密有附加数据则勾选部分打包工具会生成附加数据,此功能会将程序结尾的附加数据加密,防止提取。
调试器检测每个进程只需要保护一个模块(如主程序exe); 如果模块做为SDK发布供第三方调用,则不勾选检测调试器,发现程序被调试则退出。
去除调试信息建议勾选; 如果要保留调试信息,请保护完毕调用命令行 -strip 后将调试信息移除再对外发布去除 .debug 节,去除静态符号表。
[E] 代码加密使用默认选项(仅加密入口函数)加密指定的函数
[M] 代码混淆无需选择混淆函数的指令
[V] 代码虚拟化无需选择虚拟化函数的指令

高安全性保护#

如果对安全性有较高要求,需要使用代码混淆代码虚拟化对关键函数进行保护,比如授权验证,加密算法及流程,协议封装流程等重要逻辑。

保护前准备#

  1. 准备静态分析(反汇编/反编译)工具,用于保护效果的查看和评估。
  2. 原程序对应的符号文件:Windows 平台的 .pdb/.map文件,Linux 平台需要保留符号表(编译选项加上 -g即可),如果使用SDK标签的方式则无需符号。

静态分析工具推荐:

去除导出函数#

gcc/clang 编译生成的动态库,函数/变量是默认导出的,这会极大地降低程序安全性,可以修改编译选项去除不需要导出的函数。C/C++程序配置导出函数的方法如下:

Linux&Android去除导出函数#

CMakeLists.txt配置:

set_target_properties(${MyTarget} PROPERTIES LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/symver.txt")

在CMakeLists.txt旁边创建symver.txt文件,内容示例如下:

{global:JNI_OnLoad;MyFunction1;MyFunction2;local:*;};

以上配置可以使用so库仅导出 JNI_OnLoad, MyFunction1, MyFunction2 三个函数,可以根据需要设置自己的导出函数。

macOS&iOS去除导出函数#

CMakeLists.txt配置:

set_target_properties(${MyTarget} PROPERTIES LINK_FLAGS "-Wl,-exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/export.txt")

export.txt示例:

_JNI_OnLoad_MyFunction1_MyFunction2
GO语言Linux&Android程序去除导出函数#

go build 编译选项:

go build -ldflags "-extldflags=-Wl,--version-script=symver.txt"

symver.txt文件,内容如下:

{global:empty;local:*;};

基础保护设置#

压缩

压缩可以防静态反编译,在保护方案调整完成前,建议不要勾选,方便评估保护效果。

注:勾选压缩会稍微降低内存校验的安全性。

内存校验

建议勾选,或者使用SDK标签进行内存校验。

导入表保护

建议勾选,防止脱壳,防止分析工具查看模块间函数调用。

调试器检测

如果程序是供三方调用的动态库,不要勾选。每个进程只需一个模块勾选。

保护选项效果
压缩压缩可以加密整个代码段,隐藏一些原程序的结构信息(导入表、重定位等),防止直接反编译。
内存校验防止程序被修改。
导入表保护加密导入表,防止脱壳,防止查看API引用。
资源节加密加密PE资源节(.rsrc),防止资源信息被提取。
附加数据加密部分打包工具会生成附加数据,此功能会将程序结尾的附加数据加密,防止提取。
调试器检测检测调试器,发现程序被调试则退出。
去除调试信息去除 .debug 节,去除静态符号表。
[E] 代码加密加密指定的函数
[M] 代码混淆混淆函数的指令
[V] 代码虚拟化虚拟化函数的指令

函数级保护#

对于高安全性需求的场景,需要用到代码混淆代码虚拟化,这里着重介绍代码混淆代码虚拟化 的使用场景。

对于破解者来说,最核心的步骤是定位代码,直接逆向关键代码逻辑修改代码完成破解。例如对于协议分析,一般来说只需要逆向其中的协议、加解密或签名算法,不需要对程序修改即可达到目的(用于直接制作机器人或写脚本模拟封包)。对于功能的破解,往往需要对原程序的验证逻辑打补丁进行篡改,或者对认证数据进行填充。

代码混淆

用于模糊函数边界,拆散函数的分布(对函数切片并随机分配),对一些指令做等价变换,加密指令中的立即数,增加随机花指令改变指令原有的特征,还可以使得静态分析工具的交叉引用功能失效。简而言之,就是可以起到“一眼望去不知道这个函数是干什么的”,还可以让分析工具“无法直接搜索特征和交叉引用”,以及”让分析工具的反编译功能失效“,往往需要破解者动态跟踪汇编指令去理解函数。

交叉引用:是指静态分析工具直接搜索函数和数据(包括全局变量、字符串等)之间的引用关系,快速定位相关的代码。

函数特征:通过常用库(包括运行时库、密码学库)里包含的特定指令序列或立即数,可以直接定位函数。

代码混淆对性能的有一定的影响,常用于保护:

  • 核心代码及其调用关系的上下游函数。
  • 密码学库函数的入口和特征位置(如AES SBox、ECC曲线特征)。
  • 协议的封装流程。
  • 重要的函数边界。

代码虚拟化

代码虚拟化,是将函数原本的汇编指令,转换自定义的虚拟机指令。函数被虚拟化保护后,可以将其看成一个黑盒,代码的核心逻辑是由对应的虚拟机解释执行的,安全性极高。如果一个加密方案可以逼迫破解者去分析虚拟化的代码,说明这个方案是非常成功的,需要分析的代码(破解点)越多,破解的难度就越大

代码虚拟化对程序的性能影响较大,不可大面积使用,常用于以下几类函数:

  • 对安全性要求较高的一些自定义算法。
  • 可能被篡改的函数(如关键的验证逻辑)。

使用SDK标签#

使用SDK标签可以标记函数进行混淆或虚拟化保护,也可以解决以下安全性问题:

防止敏感字符串被定位

可以使用 VBDecryptStringA 标签加密字符串,使用 VBDecryptData 加密数据。

防止被注入或跨进程打内存补丁

可以在代码中使用 VBProtectVerifyImageVBVerifyImage 校验内存完整性,防止代码被篡改。

注:对使用VBDecryptStringA 和 VBProtectVerifyImage 标签的函数再加上混淆或虚拟化更安全。

对外发布注意事项#

  • 对外发布的 Windows 系统的程序,不可携带符号文件(.pdb/.map)
  • 对于Linux/Android程序,需要去除符号表(请务必勾选移除调试信息
  • 确认打包后的程序不依赖virbox32/virbox64动态库(已被保护)

常见问题#

不支持的函数#

Native程序中的函数是通过反汇编以及引用分析解析出来的,由于编译器优化、代码复杂度、保护技术等原因,有些函数是无法被保护的,这类函数在保护过程中日志窗口会有提示,这里列出一些常见的不支持的函数和原因。

函数太小

原因:

  • 函数过于简单,指令字节数太少,无法容纳基本的跳转指令(具体大小要求不同CPU架构会有不同)。

解决办法:

  • 将函数声明为内联函数
  • 使用SDK标签

未分配的栈

原因:

  • 函数简单,没有调用任何函数,编译器优化后的指令直接使用未分配栈空间(常见于GCC和Clang),由于混淆和虚拟化都是基于栈的,保护后会导致数据访问错误。

解决办法:

  • 使用SDK标签,防止编译器优化
  • 加入编译选项-mno-red-zone

结构化异常处理函数

原因:

  • 由于Windows异常处理的技术细节,代码在混淆和虚拟化后会导致栈展开过程出现错误,仅PE程序有此问题。

解决办法:

  • 不使用异常处理
  • 不保护

分析失败

原因:

  • 在反汇编分析过程时逻辑出现错误,未正确分析函数的基本块,非常复杂的代码可能会出现

解决办法:

  • 提交工单和问题样本,由产品开发人员解决

运行崩溃#

原因:

  • 函数分析不正确,未正确识别外部调用。

解决办法:

  • 请勿选择没有函数名,或不知道函数作用的函数进行保护。
  • 提交工单和问题样本,由产品开发人员解决。

没有函数名#

原因:

  • 没有pdb文件(PE)
  • 程序经过strip,或使用 Release编译(ELF)

解决办法:

  • 将pdb文件放在被保护程序同一目录下 (PE)
  • 编译选项加入 -g (ELF)
  • 使用SDK标签

杀毒软件误报#

原因:

  • 程序被加密后,无法扫描特征,一般病毒和木马也借此逃避杀毒软件,因此杀毒软件常将加密后的程序直接定义为可疑文件。(一般Windows下的程序容易出现)

解决办法:

  • 使用数字签名,可以大幅减轻杀毒软件误报
  • 在杀软平台提交审核

其它问题#

产品BUG反馈可以在 Virbox Protector工单系统 提交,也可直接联系客服人员。