跳到主要内容

虚拟机加密 (vmcrypt)

基于自定义虚拟机的数据加解密模块。通过执行一段字节码程序对输入缓冲区进行变换,实现可定制的加解密逻辑。字节码与数据分离的设计使得加密算法可随时替换,而无需重新编译。

架构

字节码程序(prog) + 输入数据(buf)

vmcrypt 虚拟机执行

16个通用寄存器 + 256个RAM单元

输出变换后的数据(buf)

虚拟机在 vmcrypt_run 时对 buf 原地修改,加解密使用同一套程序,通过不同的字节码实现加密或解密。

数据结构

struct vmcrypt_t {
uint32_t regs[16]; /* 16个32位通用寄存器 (r0~r15) */
uint32_t rams[256]; /* 256个32位RAM单元 */
uint32_t pc; /* 程序计数器 */
uint8_t * prog; /* 字节码程序指针 */
uint32_t plen; /* 字节码长度 */
};

API

void vmcrypt_init(struct vmcrypt_t * vm, uint8_t * prog, uint32_t plen);

初始化虚拟机。progplen 为自定义字节码,传 NULL 则使用内置默认加密程序。内部调用 vmcrypt_reset 清零寄存器和 RAM。

void vmcrypt_reset(struct vmcrypt_t * vm);

重置虚拟机状态(寄存器、RAM、PC 归零),不改变程序指针。

void vmcrypt_run(struct vmcrypt_t * vm, uint8_t * buf, uint32_t len);

执行字节码程序,对 buf(长度 len)进行原地变换。每次运行前自动清零寄存器和 PC,但保留 RAM 内容。

指令集

控制指令

操作码操作数语义
END (0x00)停止执行
NOP (0x01)空操作

数据传送

操作码操作数语义
MOV (0x02)rd, rsrd = rs
MOVI (0x03)rd, imm32rd = imm32(4字节小端)
LDR (0x04)rd, raregs[rd] = rams[regs[ra]]
STR (0x05)rs, rarams[regs[ra]] = regs[rs]

算术运算

操作码操作数语义
ADD (0x06)r1, r2r1 = r1 + r2
SUB (0x07)r1, r2r1 = r1 - r2
MUL (0x08)r1, r2r1 = r1 * r2
DIV (0x09)r1, r2r1 = r1 / r2(除0停止)
MOD (0x0A)r1, r2r1 = r1 % r2(除0停止)
ADDI (0x0B)r, imm32r = r + imm32
SUBI (0x0C)r, imm32r = r - imm32
MULI (0x0D)r, imm32r = r * imm32
DIVI (0x0E)r, imm32r = r / imm32(除0停止)
MODI (0x0F)r, imm32r = r % imm32(除0停止)
INC (0x10)rr = r + 1
DEC (0x11)rr = r - 1
NEG (0x12)rr = -r

位运算

操作码操作数语义
AND (0x13)r1, r2r1 = r1 & r2
OR (0x14)r1, r2r1 = r1 | r2
XOR (0x15)r1, r2r1 = r1 ^ r2
ANDI (0x16)r, imm32r = r & imm32
ORI (0x17)r, imm32r = r | imm32
XORI (0x18)r, imm32r = r ^ imm32
NOT (0x19)rr = ~r
SHL (0x1A)r, nr = r << n(n & 0x1f)
SHR (0x1B)r, nr = r >> n(n & 0x1f)
SHLR (0x1C)r1, r2r1 = r1 << r2(r2 & 0x1f)
SHRR (0x1D)r1, r2r1 = r1 >> r2(r2 & 0x1f)
ROL (0x1E)r, nr = rotl32(r, n)(n & 0x1f)
ROR (0x1F)r, nr = rotr32(r, n)(n & 0x1f)
ROLR (0x20)r1, r2r1 = rotl32(r1, r2)(r2 & 0x1f)
RORR (0x21)r1, r2r1 = rotr32(r1, r2)(r2 & 0x1f)

比较与跳转

操作码操作数语义
CMP (0x22)rd, r1, r2rd = (r1 == r2) ? 1 : 0
JMP (0x23)off32pc += off32(4字节小端有符号)
JZ (0x24)r, off32if regs[r]==0: pc += off32
JNZ (0x25)r, off32if regs[r]!=0: pc += off32

I/O 操作

操作码操作数语义
IOR (0x26)rd, raregs[rd] = buf[regs[ra]]
IOW (0x27)rs, rabuf[regs[ra]] = regs[rs] & 0xff
IOL (0x28)rregs[r] = len(缓冲区长度)
TBL (0x29)rd, raregs[rd] = prog[regs[ra]](读取程序自身字节)

编码格式

  • 操作码:1 字节
  • 寄存器编号:1 字节(低4位有效,r0~r15)
  • 立即数:4 字节小端序
  • 跳转偏移:4 字节小端有符号,基于读取偏移后的 PC 计算

内置默认程序

不传入自定义字节码时,使用内置加密程序,逻辑等价于:

for(uint32_t i = 0; i < len; i++)
{
uint32_t key = (i * 0x9E3779B9) ^ 0x12345678;
key ^= (key << 13);
key ^= (key >> 17);
key ^= (key << 5);
buf[i] ^= (key & 0xFF);
}

该算法基于 TEA/XTEA 风格的黄金分割常数,对每个字节用位置相关的密钥做异或变换。由于是异或操作,加密和解密使用同一程序。

使用示例

使用内置程序加解密

struct vmcrypt_t vm;
vmcrypt_init(&vm, NULL, 0);

uint8_t data[] = "hello world";
vmcrypt_run(&vm, data, sizeof(data)); /* 加密 */
vmcrypt_run(&vm, data, sizeof(data)); /* 解密(恢复原文) */

使用自定义程序

static const uint8_t my_prog[] = {
VMCRYPT_OP_IOL, 0x05,
VMCRYPT_OP_IOR, 0x00, 0x05,
VMCRYPT_OP_XORI, 0x00, 0xAA, 0x00, 0x00, 0x00,
VMCRYPT_OP_IOW, 0x00, 0x05,
VMCRYPT_OP_INC, 0x05,
VMCRYPT_OP_IOL, 0x00,
VMCRYPT_OP_CMP, 0x06, 0x05, 0x00,
VMCRYPT_OP_JNZ, 0x06, 0xF0, 0xFF, 0xFF, 0xFF,
VMCRYPT_OP_END,
};

struct vmcrypt_t vm;
vmcrypt_init(&vm, (uint8_t *)my_prog, sizeof(my_prog));
vmcrypt_run(&vm, data, len);

保持 RAM 状态的多次运行

vmcrypt_run(&vm, buf1, len1); /* 第一次运行,RAM 可被程序写入 */
vmcrypt_run(&vm, buf2, len2); /* 第二次运行,RAM 保留上次结果 */
/* 如需清零 RAM,调用 vmcrypt_reset(&vm) */