# VMProtect 压缩引擎实现详解

## 1. 压缩引擎概述
VMProtect 使用 LZMA 算法进行数据压缩,压缩引擎位于 `code/core/packer.cc`。
### LZMA 特点
– **高压缩比** – 比 ZIP/GZIP 更好的压缩率
– **可变字典大小** – 支持 4KB 到 4GB 的字典
– **多种模式** – 支持最快到最大压缩级别
## 2. 压缩流实现
### 输入流
“`cpp
struct PackerInputStream {
ISeqInStream p; // LZMA 输入流接口
IArchitecture *file; // 文件对象(用于从文件读取)
Data *data; // 数据对象(用于从内存读取)
size_t size; // 总大小
size_t pos; // 当前位置
// 从文件构造
PackerInputStream(IArchitecture *file_, size_t size_);
// 从数据构造
PackerInputStream(Data *data_);
};
“`
### 文件读取回调
“`cpp
static SRes ReadFromStream(void *object, void *data, size_t *size) {
PackerInputStream *p = reinterpret_cast<PackerInputStream *>(object);
// 计算可读取的大小
size_t read_size = (*size < p->size – p->pos) ?
*size : p->size – p->pos;
if (read_size) {
// 从文件读取
read_size = p->file->Read(data, read_size);
p->pos += read_size;
}
*size = read_size;
return SZ_OK;
}
PackerInputStream::PackerInputStream(IArchitecture *file_, size_t size_)
: file(file_), data(NULL), size(size_), pos(0) {
p.Read = ReadFromStream;
}
“`
### 内存读取回调
“`cpp
static SRes ReadFromData(void *object, void *data, size_t *size) {
PackerInputStream *p = reinterpret_cast<PackerInputStream *>(object);
// 计算可读取的大小
size_t read_size = (*size < p->size – p->pos) ?
*size : p->size – p->pos;
if (read_size) {
// 从内存复制
memcpy(data, p->data->data() + p->pos, read_size);
p->pos += read_size;
}
*size = read_size;
return SZ_OK;
}
PackerInputStream::PackerInputStream(Data *data_)
: file(NULL), data(data_), size(data_->size()), pos(0) {
p.Read = ReadFromData;
}
“`
### 输出流
“`cpp
struct PackerOutputStream {
ISeqOutStream p; // LZMA 输出流接口
Data *data; // 输出数据缓冲区
PackerOutputStream(Data *data_);
};
static size_t WriteToStream(void *object, const void *data, size_t size) {
PackerOutputStream *p = reinterpret_cast<PackerOutputStream *>(object);
p->data->PushBuff(data, size); // 追加到数据缓冲区
return size;
}
PackerOutputStream::PackerOutputStream(Data *data_)
: data(data_) {
p.Write = WriteToStream;
}
“`
## 3. 进度回调
“`cpp
struct PackerProgress {
ICompressProgress p; // LZMA 进度接口
IArchitecture *file; // 文件对象(用于报告进度)
uint64_t last_pos; // 上次报告的位置
PackerProgress(IArchitecture *file_);
};
SRes PackProgress(void *object, UInt64 inSize, UInt64 /*outSize*/) {
PackerProgress *p = reinterpret_cast<PackerProgress *>(object);
if (p->file) {
// 报告进度增量
p->file->StepProgress(inSize – p->last_pos);
}
p->last_pos = inSize;
return SZ_OK;
}
PackerProgress::PackerProgress(IArchitecture *file_)
: file(file_), last_pos(0) {
p.Progress = PackProgress;
}
“`
## 4. Packer 类实现
### 类定义
“`cpp
class Packer {
public:
Packer();
~Packer();
// 压缩文件数据
bool Code(IArchitecture *file, size_t size, Data *data);
// 压缩内存数据
bool Code(IArchitecture *file, Data *in_data, Data *out_data);
// 写入压缩属性
bool WriteProps(Data *data);
private:
bool Code(IArchitecture *file, PackerInputStream &in,
PackerOutputStream &out);
CLzmaEncHandle encoder_; // LZMA 编码器句柄
CLzmaEncProps props_; // 压缩属性
};
“`
### 构造函数
“`cpp
Packer::Packer() {
// 创建 LZMA 编码器
encoder_ = LzmaEnc_Create(&g_Alloc);
if (encoder_ == 0)
throw 1; // 创建失败
// 初始化默认属性
LzmaEncProps_Init(&props_);
// 设置压缩级别(0-9,9为最大压缩)
props_.level = 9;
// 写入结束标记
props_.writeEndMark = true;
// 设置字典大小(16MB)
props_.dictSize = 1 << 24;
// 应用属性
if (LzmaEnc_SetProps(encoder_, &props_) != SZ_OK)
throw 1;
}
“`
### 析构函数
“`cpp
Packer::~Packer() {
if (encoder_ != 0) {
// 销毁编码器,释放内存
LzmaEnc_Destroy(encoder_, &g_Alloc, &g_BigAlloc);
}
}
“`
### 写入压缩属性
“`cpp
bool Packer::WriteProps(Data *data) {
data->clear();
// 属性缓冲区
Byte props_buff[LZMA_PROPS_SIZE];
size_t props_size = sizeof(props_buff);
// 获取编码属性
if (LzmaEnc_WriteProperties(encoder_, props_buff, &props_size) != SZ_OK)
return false;
// 写入属性
data->PushBuff(props_buff, props_size);
return true;
}
“`
### 核心压缩函数
“`cpp
bool Packer::Code(IArchitecture *file, PackerInputStream &in,
PackerOutputStream &out) {
// 清空输出缓冲区
out.data->clear();
// 创建进度报告器
PackerProgress progress(file);
// 执行压缩
SRes res = LzmaEnc_Encode(encoder_, &out.p, &in.p,
&progress.p, &g_Alloc, &g_BigAlloc);
if (res != SZ_OK)
return false;
// 报告最终进度
file->StepProgress(in.size – progress.last_pos);
return true;
}
“`
### 文件压缩接口
“`cpp
bool Packer::Code(IArchitecture *file, size_t size, Data *data) {
PackerInputStream in(file, size); // 创建文件输入流
PackerOutputStream out(data); // 创建输出流
return Code(file, in, out);
}
“`
### 内存压缩接口
“`cpp
bool Packer::Code(IArchitecture *file, Data *in_data, Data *out_data) {
PackerInputStream in(in_data); // 创建内存输入流
PackerOutputStream out(out_data); // 创建输出流
return Code(file, in, out);
}
“`
## 5. 压缩属性详解
### CLzmaEncProps 结构
“`cpp
typedef struct _CLzmaEncProps {
int level; // 压缩级别 0-9,默认 5
UInt32 dictSize; // 字典大小,默认 (1 << 24)
int lc; // 字面量上下文位数,默认 3
int lp; // 字面数位置位数,默认 0
int pb; // 位置位数,默认 2
int algo; // 算法 0-1,默认 1
int fb; // 快速字节数,默认 32
int btMode; // 二叉树模式,默认 1
int numHashBytes; // 哈希字节数,默认 4
UInt32 numThreads; // 线程数,默认 2
int writeEndMark; // 是否写入结束标记
UInt64 reduceSize; // 估计的输入大小
} CLzmaEncProps;
“`
### 压缩级别设置
| 级别 | 字典大小 | 算法 | 说明 |
|——|———-|——|——|
| 0 | 64KB | 0 | 最快,压缩比最低 |
| 1 | 1MB | 0 | 快速 |
| 3 | 4MB | 0 | 中等 |
| 5 | 16MB | 1 | 默认 |
| 7 | 32MB | 1 | 高压缩 |
| 9 | 64MB | 1 | 最大压缩 |
### 属性计算
“`cpp
void SetCompressionLevel(int level) {
// 根据级别设置字典大小
static const UInt32 dict_sizes[] = {
65536, // level 0
1048576, // level 1
2097152, // level 2
4194304, // level 3
8388608, // level 4
16777216, // level 5
33554432, // level 6
33554432, // level 7
67108864, // level 8
67108864 // level 9
};
props_.level = level;
props_.dictSize = dict_sizes[level];
// 高级别使用更慢的算法
props_.algo = (level >= 5) ? 1 : 0;
// 设置快速字节数
props_.fb = (level < 7) ? 32 : 64;
LzmaEnc_SetProps(encoder_, &props_);
}
“`
## 6. 解压实现
### 解压属性头
“`cpp
struct LZMAHeader {
uint8_t props[5]; // 压缩属性(5字节)
uint64_t unpackedSize; // 解压后大小(8字节,小端序)
};
“`
### 解压函数
“`cpp
bool Unpack(const uint8_t *src, size_t srcLen,
uint8_t *dst, size_t *dstLen) {
// 解析属性
CLzmaDec dec;
LzmaDec_Construct(&dec);
SRes res = LzmaDec_Allocate(&dec, src, LZMA_PROPS_SIZE, &g_Alloc);
if (res != SZ_OK) return false;
// 初始化解码器
LzmaDec_Init(&dec);
// 解压
ELzmaStatus status;
size_t srcPos = LZMA_PROPS_SIZE;
size_t dstPos = 0;
res = LzmaDec_DecodeToBuf(&dec,
dst + dstPos, dstLen,
src + srcPos, &srcLen,
LZMA_FINISH_END, &status);
LzmaDec_Free(&dec, &g_Alloc);
return (res == SZ_OK && status == LZMA_STATUS_FINISHED_WITH_MARK);
}
“`
## 7. 运行时解压
### 解压存根
“`cpp
// 运行时解压代码(汇编)
void DecompressStub() {
// 1. 定位压缩数据
uint8_t *compressed_data = GetCompressedDataAddress();
// 2. 分配内存
size_t unpacked_size = GetUnpackedSize();
uint8_t *unpacked_buffer = VirtualAlloc(NULL, unpacked_size,
MEM_COMMIT, PAGE_READWRITE);
// 3. 解压
LZMA_Decode(compressed_data, unpacked_buffer, unpacked_size);
// 4. 设置内存保护
DWORD old_protect;
VirtualProtect(unpacked_buffer, unpacked_size,
PAGE_EXECUTE_READ, &old_protect);
// 5. 跳转到解压后的代码
JumpTo(unpacked_buffer);
}
“`
### LZMA 解码器集成
“`cpp
// 精简版 LZMA 解码器(用于运行时)
class RuntimeLZMADecoder {
public:
bool Initialize(const uint8_t *props);
bool Decode(uint8_t *dst, size_t dstLen,
const uint8_t *src, size_t srcLen);
private:
CLzmaDec dec_;
uint32_t state_;
uint32_t rep0_, rep1_, rep2_, rep3_;
uint64_t processedSize_;
uint64_t limit_;
};
“`
## 8. 压缩优化
### 预处理
“`cpp
bool PreprocessData(Data &data) {
// 1. 去除重定位信息(如果不需要)
if (IsOptionEnabled(cpStripFixups)) {
StripRelocations(data);
}
// 2. 去除调试信息
if (IsOptionEnabled(cpStripDebugInfo)) {
StripDebugInfo(data);
}
// 3. 对齐数据
AlignData(data);
return true;
}
“`
### 分块压缩
“`cpp
bool PackInChunks(IArchitecture *file, size_t totalSize) {
const size_t CHUNK_SIZE = 1024 * 1024; // 1MB 每块
size_t offset = 0;
while (offset < totalSize) {
size_t chunkSize = std::min(CHUNK_SIZE, totalSize – offset);
Data compressedChunk;
Packer packer;
// 压缩当前块
if (!packer.Code(file, chunkSize, &compressedChunk))
return false;
// 写入压缩块头(原始大小 + 压缩大小)
WriteChunkHeader(chunkSize, compressedChunk.size());
// 写入压缩数据
WriteData(compressedChunk);
offset += chunkSize;
}
return true;
}
“`
## 9. 错误处理
### 错误码定义
“`cpp
enum LZMAError {
LZMA_OK = 0,
LZMA_ERROR_DATA = 1, // 数据错误
LZMA_ERROR_MEM = 2, // 内存分配错误
LZMA_ERROR_UNSUPPORTED = 3, // 不支持的属性
LZMA_ERROR_PARAM = 4, // 参数错误
LZMA_ERROR_INPUT_EOF = 5, // 输入数据不足
LZMA_ERROR_OUTPUT_EOF = 6, // 输出缓冲区不足
LZMA_ERROR_READ = 7, // 读取错误
LZMA_ERROR_WRITE = 8, // 写入错误
LZMA_ERROR_PROGRESS = 9, // 进度回调错误
LZMA_ERROR_THREAD = 10, // 线程错误
LZMA_ERROR_ARCHIVE = 16 // 归档错误
};
“`
### 异常处理
“`cpp
bool SafeCompress(IArchitecture *file, Data *in_data, Data *out_data) {
try {
Packer packer;
return packer.Code(file, in_data, out_data);
}
catch (int error_code) {
LogError(“Compression failed with code: %d”, error_code);
return false;
}
catch (std::bad_alloc &) {
LogError(“Out of memory during compression”);
return false;
}
catch (…) {
LogError(“Unknown compression error”);
return false;
}
}
“`














暂无评论内容