VirboxProtector的SDK标签使用流程
#
简介Virbox Protector工具的SDK标签静态载入到需要保护的函数当中,生成可执行程序,Virbox Protector 加壳工具解析该程序界面就能够分析出SDK标识的函数,这样就能帮助用户找到核心代码所在的位置。
目前支持的语言:c\c++\c#\oc\swift\java
tip
所有sdk标签功能,需要使用Virbox Protector
工具加固后功能才生效。
#
环境1.安装Virbox Protector
工具;
2.在工具的安装目录下包括SDK标签所用的头文件、静态库和动态库,以windows系统上安装工具为例;
头文件路径:C:\Program Files\senseshield\Virbox Protector 3\sdk\inc\virbox.h动态库路径:windows:C:\Program Files\senseshield\Virbox Protector 3\sdk\windows\x86Linux:C:\Program Files\senseshield\Virbox Protector 3\sdk\linux,包括arm和x86架构macOS:C:\Program Files\senseshield\Virbox Protector 3\sdk\darwin,包括arm和x86架构Android:C:\Program Files\senseshield\Virbox Protector 3\sdk\android,包括arm和x86架构静态库路径:C:\Program Files\senseshield\Virbox Protector 3\sdk\lib
3.demo示例
demo的路径:C:\Program Files\senseshield\Virbox Protector 3\example\sdk
#
Native程序Native程序包括Windows、Linux、ARM Linux、Android和macOS系统编译的可执行程序或动态库;
安装目录下包括SDK标签所用的头文件:
C:\Program Files\senseshield\Virbox Protector 3\sdk\inc\virbox.h
标签示例路径:C:\Program Files\senseshield\Virbox Protector 3\example\sdk
注意:
1.若一段代码两个标签同时先后顺序写,则在前面的标签不会生效,在后面的标签生效。
2.若只写Begin不写end,加壳工具解析时发现未闭合的标签则默认在保护日志
中进行提示。
#
函数标签函数标签可以标记整个函数,在保护时可以保护整个函数,包括编译生成的函数入口指令。
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;}
9.注意事项:
1)SDK标签库包括静态库(virbox_windows.lib)和动态库(virbox32.dll或virbox64.dll),均可进行调用。
注意:1. 动态库只能静态加载,不能动态加载(即LoadLibrary的方式); 原因是保护时要静态分析SDK的调用,所以不能使用LoadLibrary方式。2. 静态库可以直接链接到程序中。
2)若要静态调用virbox_windows.lib库。
2)VBProtectBegin
、VBVirtualizeBegin
等接口,传入的字符串参数,不能与其他函数共用;
3)传入的字符串参数保证为 ANSII 码的形式,这样显示在界面上的函数名称才正确,否则就会显示为乱码;
4)每个Begin
对应一个End
,并且一个函数里面不要出现多对 Begin+End,Begin/End不能嵌套使用。;
5)如果标签标记的保护方式和ssp配置文件中保存的保护方式冲突了,以ssp配置文件中的保护方式为准;
6)标签Begin和End
之间的代码最好大于3行(若标记的代码正汇编生成的指令小于15个字节,则加壳工具界面上不会显示该标记函数);
7)SDK动态库和静态库包括x86和x64架构,在使用的时候要开发者根据要编译的程序进行加载对应的库。
#
功能标签字符串加密接口比如(VBProtectDecrypt、VBDecryptData等)传入的缓冲区只能放在函数外,即全局变量或常量;
如果定义为局部变量或常量则解析后程序会报错"分析sdk参数失败或错误的sdk参数"。
#
VBProtectDecryptVBProtectDecrypt标签仅建议 Virbox Protector LM (Pro) 版本使用。
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;}
#
字符串和数据加密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;}
注意
- 由于编译器编译时优化可能将重复字符串给优化掉了,所以代码中使用字符串和数据加密的标签时,有可能会导致程序运行出现乱码问题;
- XXXXXFunction 函数不会受到编译器优化的影响;
- 函数中Begin 和 End 标签可能会受到编译器优化的影响,比如可能内联嵌套导致出现一些未知的问题;
#
安全退出VBSafeExit
如果程序发现一些恶意行为,调用 exit
、abort
等函数容易被破解者追踪到调用位置并绕过。VBSafeExit标签可动销毁调用位置的栈帧,返回地址等信息,让破解者难以追踪到调用位置。
#
内存校验void VB_API_CALL VBProtectVerifyImage();
VBProtectVerifyImage 可以校验当前模块的内存完整性,检查程序是否被篡改(包括静态补丁和动态内存补丁),如果发现篡改则自动安全退出。
int VB_API_CALL VBVerfiyImage();
VBVerifyImage 可以校验当前模块的内存完整性,检查程序是否被篡改(包括静态补丁和动态内存补丁),如果发现篡改则返回非0值。
界面上的内存校验默认检测到被篡改的行为时就生效;
使用内存校验的sdk标签可自行进行动态校验。
#
调试器检测int VB_API_CALL VBDetectDebugger(void);
检测程序是否正在被调试器进行调试,发现则返回非0值。
注意:
1.VBDetectDebugger和VBSafeExit一起使用,保护时界面不勾选"调试器检测",则程序调试运行到标记的代码位置处退出;
若保护时界面勾选"调试器检测",则程序只要被调试就会退出。
2.VBDetectDebugger单独使用,保护时界面不勾选"调试器检测",则程序调试运行不会退出,会返回非0值;
若保护时界面勾选"调试器检测",则程序只要被调试就会退出。
#
虚拟机检测int VB_API_CALL VBDetectVirtualMachine(void);
检测程序是否正在VMware, Virtual Box等虚拟机中运行,发现则返回非0值。(仅支持Windows)
#
功能示例int check(){ // 使用了检测的函数要加上混淆或虚拟化标签才更安全 VBMutateFunction("check#"); int code = 0; if (VBVerifyImage() != 0) { // memory patches found! code = 1; } if (VBDetectDebugger() != 0) { // debugger found! code |= 2; } if (VBDetectVirtualMachine() != 0) { // vm tools found! code |= 4; } if (code != 0) { // crash VBSafeEixt(0xdead0000 | code); } return 0;}
#
macOS和iOS程序1.macOS程序和iOS程序所用到的sdk标签是一样的;
2.在编译项目时Xcode可以调用动态库(.dylib)或静态库(.a或.framework),三种库类型的功能一样,根据自己需求任选一种即可。
#
函数标签参考上述Native程序中的函数标签
中的描述;
#
代码块标签参考上述Native程序中的代码块标签
中的描述;
#
功能模块macOS和iOS的SDK标签功能选项,如下表所示:
接口 | 描述 |
---|---|
VBProtectVerifyImage() | 内存校验可以校验当前模块的内存完整性,失败则自动退出进程 |
VBVerifyImage() | 内存校验可以校验当前模块的内存完整性,失败则返回非0值 |
VBDetectDebugger() | 检测调试器,发现则返回非0值 |
VBVerifySignature() | 签名校验,仅支持iOS app主模块 |
VBSafeExit | 检测到非0值就退出程序,销毁当前栈帧 |
注意:内存校验的实现不能是跨模块的,只校验自己的模块,所以主模块要检测,只能主模块来调SDk,否则内存校验sdk不会生效。
#
OC语言下面简述macOS应用使用OC语言时,通过调用动态库使用sdk标签的操作流程:
1)将virbox.h放到工程中,使用Xcode打开工程后,将virbox.h添加到工程中;
2)选中TARGETS->Build Settings->Architectures,查看项目的架构是arm64还是x64还是Fat格式的;
3)从Virbox Protector工具的安装目录sdk/darwin下找到对应架构的libvirbox64.dylib,选中TARGETS->Build Phases->Link Binary选项,添加libvirbox64.dylib;
4)在代码中引用virbox.h,并添加标签;
代码参考示例,:
#import "virbox.h"-(void)readLoad{ //可以根据自己需求选择其他标签 VBMutateBegin("load_test"); //代码混淆 for (int i=0; i<array.count; i++) { News * news=[[News alloc]init]; news.content=array[i]; [_newsArray addObject:news]; } VBProtectEnd(); return NO;}
- (BOOL)isImageSetFolder:(NSString *)folder{ //可以根据自己需求选择其他标签 VBVirtualizeFunction("reset_test"); //代码虚拟化 if ([folder hasSuffix:kSuffixImageSet] || [folder hasSuffix:kSuffixAppIcon] || [folder hasSuffix:kSuffixLaunchImage]) { return YES; } return NO;}
#
Swift语言下面简述macOS应用使用swift语言时,通过调用动态库使用sdk标签的操作流程:
1)将virbox.h放到工程中,使用Xcode打开工程后,将virbox.h添加到工程中,并将virbox.h设置为桥接文件;
TARGETS->Build Settings->Swift Compiler->Object-C Bridging Header->项目名/virbox.h
2)选中TARGETS->Build Settings->Architectures,查看项目的架构是arm64还是x64还是Fat格式的;
3)从Virbox Protector工具的安装目录sdk/darwin下找到对应架构的libvirbox64.dylib,选中TARGETS->Build Phases->Link Binary选项,添加libvirbox64.dylib;
4)在代码中直接添加标签,且需要给标签添加变量名;
代码参考示例:
struct ContentView: View { var body: some View { //可以根据自己需求选择其他标签 var body_begin = VBMutateBegin("body_test")//代码混淆 let columns = [ GridItem(.flexible()), GridItem(.flexible()), GridItem(.flexible()), GridItem(.flexible())] var body_end = VBProtectEnd()//代码段结束 }}
struct RdioApp: App { var body: some Scene { //可以根据自己需求选择其他标签 var myva = VBVirtualizeFunction("test") //代码虚拟化 HStack(spacing: 24) { Image(systemName: "backward.fill") .font(.title3) Image(systemName: "play.fill") .font(.title) Image(systemName: "forward.fill") .font(.title3) } }}
3.程序运行
1)编译后的app直接运行需要依赖libvirbox64.dylib
,即将对应app程序架构的libvirbox64.dylib
拷贝到/usr/local/lib/libvirbox64.dylib
,然后再运行编译后的app,即可正常运行;
如果不拷贝则会报以下错误:
注:若是arm架构和FAT格式的libvirbox64.dylib
,需要先对其进行签名后,再进行拷贝。
2)将编译后的app拖入到加壳工具中,函数选项即可显示标记的函数;
对文件进行保护,则保护后的程序即可运行,不会依赖libvirbox64.dylib
。
#
NET程序.NET程序支持代码加密、代码混淆和代码虚拟化三种函数保护方式,sdk标签参考微软标准的写法,程序编译成功后,将编译好的程序拖入到加壳工具界面,界面会显示代码中设置的函数保护方式:
标签示例参考:C:\Program Files\senseshield\Virbox Protector 3\example\sdk\dotnet_sdk_demo
代码书写方式:
//命名[Obfuscation(Feature = "Renaming", Exclude = true)]//名称混淆public class main{ [Obfuscation(Feature = "Mutate", Exclude = false)]//代码混淆 public static void test1(string[] args) { System.Console.WriteLine("hello Virbox.Mutate!"); } [Obfuscation(Feature = "Encrypt", Exclude = false)]//代码加密 public static void test2(string[] args) { System.Console.WriteLine("hello Virbox.Encrypt!"); } [Obfuscation(Feature = "Virtualization", Exclude = false)]//代码虚拟化 public static void test3(string[] args) { System.Console.WriteLine("hello Virbox.Virtualize!"); }}
注意事项:
1.可以添加到类名前,但如果方法也设置了sdk标签,那么将会优先显示方法里设置的。
2.函数标签和名称混淆标签不能添加到代码里,只能添加到类和方法名前面。
#
Java程序JAVA程序支持代码虚拟化保护方式,代码中设置VBVirtualize注解,并在函数上引用,程序编译成功后,将编译好的程序拖入到加壳工具界面,界面会显示代码中设置的函数保护方式:
注意:文件名必须是VBVirtualize,包名必须是virbox,否则标记的标签加壳工具无法识别到。
1.新建VBVirtualize.java,内容是:
package virbox;
public @interface VBVirtualize{}
2.调用方式:
import virbox.VBVirtualize;
@VBVirtualize //可添加到类上面,所有的方法都会默认保护public class Main { public static void main(String[] args) { System.out.println("hello"); test_vir(); }
@VBVirtualize //可添加到方法上面,只保护该方法 public static void test_vir() { System.out.println("test_vir"); }
}
#
Android程序#
函数标签适用场景
使用虚拟化标签标记过的类和方法后,编译出的Android APK/AAB应用拖入到Virbox Protector界面进行解析时,默认会显示标记的类和方法。
若使用proguard混淆后,无法判断函数名称,若使用虚拟化标签标记过的类和方法后,在对该应用保护时就不需要去查找对应的类和方法名。
标签接口位置:
C:\Program Files\senseshield\Virbox Protector 3\example\sdk\APK\com\virbox\VBVirtualize.java
注意:1)若开启proguard编译的Android APK/AAB应用,有些函数会被优化,导致标记的函数不会解析出来。2)文件名必须是VBVirtualize,包名必须是com.virbox,否则标记的标签加壳工具无法识别到。3)编译后的程序不需要要使用Virbox Protector工具进行保护,标签功能才生效。
操作流程
1.打开Android工程,新建一个目录,命名为virbox;
2.将VBVirtualize.java拷贝到com\virbox目录下,其中VBVirtualize.java中代码如下:
package com.virbox;import androidx.annotation.Keep;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;
@Keep@Retention(RetentionPolicy.RUNTIME)public @interface VBVirtualize {}
3.在其他类上调用VBVirtualize;
@VBVirtualize若放在类上面:
若使用proguard混淆,@VBVirtualize若放在类上面,将会对该类进行标记,并保留该类的名称,其他类的名称不会进行保留;
若不使用proguard混淆,@VBVirtualize若放在类上面,将会对该类的进行标记;
import virbox.VBVirtualize;
@VBVirtualizepublic class SecondFragment{ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { FragmentSecondBinding inflate = FragmentSecondBinding.inflate(inflater, container, false); this.binding = inflate; return inflate.getRoot(); } public void onDestroyView() { super.onDestroyView(); this.binding = null; }}
@VBVirtualize若放在方法上面:
若使用proguard混淆,@VBVirtualize若放在方法上面,将会对该方法进行标记,并保留该方法的名称,其他方法的名称不会进行保留;
若不使用proguard混淆,@VBVirtualize若放在方法上面,将会对该方法进行标记;
import virbox.VBVirtualize;
public class SecondFragment{ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { FragmentSecondBinding inflate = FragmentSecondBinding.inflate(inflater, container, false); this.binding = inflate; return inflate.getRoot(); } @VBVirtualize public void onDestroyView() { super.onDestroyView(); this.binding = null; }}
#
功能标签适用场景
Android APK/AAB应用通过调用指定接口后,程序在运行时触发了某些行为后返回非0值,进而可以通过返回值去判断该应用后续的运行行为。
比如调用了VBDetectRoot接口后,程序在root手机上运行,则其返回值为非0值,通过判断该返回值去判断程序在root手机上运行是闪退还是进行提示等操作。
标签接口位置:
C:\Program Files\senseshield\Virbox Protector 3\example\sdk\APK\com\virbox\Protector.java
注意:1)文件名必须是Protector,包名必须是com.virbox,否则标记的标签加壳工具无法识别到。2)编译后的程序不需要要使用Virbox Protector工具进行保护,标签功能才生效。
操作流程
1.打开Android工程,新建一个目录,命名为virbox;
2.将Protector.java拷贝到com\virbox目录下,其中Protector.java中代码如下:
package com.virbox;
public class Protector { // 调试器检测 public static int VBDetectDebugger() { return 0; } // 模拟器检测 public static int VBDetectEmulator() { return 0; } // root检测 public static int VBDetectRoot() { return 0; } // 反注入 public static int VBDetectInject() { return 0; } // 多开检测 public static int VBDetectMulti() { return 0; } // 代理检测 public static int VBDetectProxy() { return 0; } // VPN检测 public static int VBDetectVPN() { return 0; } // 文件校验和内存校验 public static int VBIntegrityCheck() { return 0; }}
3.调用Protector.java里面的接口,代码示例参考:
import com.virbox.Protector;
public class SecondActivity extends AppCompatActivity { @SuppressLint("SetTextI18n") @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second);
int vpn_result = Protector.VBDetectVPN(); TextView testView1 = findViewById(R.id.testView1); testView1.setText("vpn检测的返回值是:" + vpn_result);
int Emulator_result = Protector.VBDetectEmulator(); TextView testView2 = findViewById(R.id.testView2); testView2.setText("模拟器检测的返回值是:" + Emulator_result); // 调用其他标签等 int check_result = Protector.VBIntegrityCheck(); TextView testView8 = findViewById(R.id.testView8); testView8.setText("文件和签名校验的返回值是:" + check_result); }}
4.编译Android APK/AAB应用后,使用Virbox Protector工具进行保护,程序在运行时触发了某些行为后,该接口的返回值为非0值
注意:针对apk,文件校验功能触发后返回值为1,签名校验功能触发后返回值为2,文件校验和签名校验功能同时触发时返回值为1。针对aab,aab没有签名校验功能所以返回值会一直为0,文件校验功能触发后返回值为1。
#
问题1.标签、map、pdb文件谁的优先级高?
答:标签的优先级高且标签和map和pdb文件共存。
2.如果编译出来是arx,sdk标签也支持吗?
答:支持。
3、全局变量是否可以进行保护?
答:使用SDK标签VBDecryptStringA,PE、elf和macho格式的都可以。
4.begin end是只处理当前函数的函数体,如果函数A调用函数B,函数B使用了SDK标签,那么函数A也可以再使用SDK标签,这种情况属于嵌套么?
答:不属于嵌套。
5.c++程序,使用字符串加密sdk标签后,能使用OD调试器可以看到么?
答:使用OD在堆内存里能搜到,可以每次用完调用 VBFreeString(xxx)给释放了,就在堆内存里搜不到了。
6.C#程序,字符串加密,能防止从内存中dump出字符串么?OD调试器可以看到么?
答:不能防止从内存中dump出字符串,OD调试器直接扫是扫不到的,如果找到了真正使用字符串的地方断下来,那是可以看到的。
7.使用了sdk标签后编译的程序,标签功能就会生效么?
答:使用了sdk标签编译后的程序需要使用Virbox Protector
对程序进行保护,sdk标签功能才生效。