加密壳
4、封装简易验证与解密流程
1、课程目标
- 设计壳的验证机制
- 实现多种加密算法
- 完成壳的解密流程
- 添加反调试检测
2、名词解释
| 名词 | 全称 | 解释 |
|---|---|---|
| XOR | Exclusive OR | 异或加密 |
| RC4 | Rivest Cipher 4 | 流密码算法 |
| AES | Advanced Encryption Standard | 高级加密标准 |
| Anti-Debug | 反调试 | 检测调试器的技术 |
| Integrity Check | 完整性检查 | 验证代码未被修改 |
| License Check | 许可证检查 | 软件授权验证 |
3、使用工具
- Visual Studio 2022
- x64dbg
- CryptoAPI
- 自定义加密库
4、技术原理
4.1、壳验证流程
壳入口
|
v
+------------------+
| 反调试检测 |
+------------------+
| 通过
v
+------------------+
| 完整性验证 |
+------------------+
| 通过
v
+------------------+
| 解密密钥派生 |
+------------------+
|
v
+------------------+
| 解密代码段 |
+------------------+
|
v
+------------------+
| 恢复导入表 |
+------------------+
|
v
+------------------+
| 跳转到OEP |
+------------------+
5、代码实现
5.1、反调试检测
// 检测方法1:IsDebuggerPresent
BOOL CheckDebugger_IsDebuggerPresent(API_TABLE* api) {
typedef BOOL (WINAPI* PFN_IsDebuggerPresent)(void);
PFN_IsDebuggerPresent pIsDebuggerPresent =
(PFN_IsDebuggerPresent)api->GetProcAddress(
GetModuleByHash(HASH_KERNEL32), "IsDebuggerPresent");
if (pIsDebuggerPresent && pIsDebuggerPresent()) {
return TRUE;
}
return FALSE;
}
// 检测方法2:PEB.BeingDebugged
BOOL CheckDebugger_PEB() {
BOOL beingDebugged;
#ifdef _WIN64
beingDebugged = *(PBYTE)(__readgsqword(0x60) + 2);
#else
__asm {
mov eax, fs:[0x30] // PEB
movzx eax, byte ptr [eax + 2] // BeingDebugged
mov beingDebugged, eax
}
#endif
return beingDebugged;
}
// 检测方法3:NtGlobalFlag
BOOL CheckDebugger_NtGlobalFlag() {
DWORD ntGlobalFlag;
#ifdef _WIN64
ntGlobalFlag = *(PDWORD)(__readgsqword(0x60) + 0xBC);
#else
__asm {
mov eax, fs:[0x30]
mov eax, [eax + 0x68] // NtGlobalFlag
mov ntGlobalFlag, eax
}
#endif
// 调试器设置的标志
#define FLG_HEAP_ENABLE_TAIL_CHECK 0x10
#define FLG_HEAP_ENABLE_FREE_CHECK 0x20
#define FLG_HEAP_VALIDATE_PARAMETERS 0x40
return (ntGlobalFlag & 0x70) != 0;
}
// 检测方法4:堆标志
BOOL CheckDebugger_HeapFlags() {
DWORD heapFlags;
#ifdef _WIN64
PVOID heap = *(PVOID*)(__readgsqword(0x60) + 0x30);
heapFlags = *(PDWORD)((PBYTE)heap + 0x70);
#else
__asm {
mov eax, fs:[0x30]
mov eax, [eax + 0x18] // ProcessHeap
mov eax, [eax + 0x40] // Flags
mov heapFlags, eax
}
#endif
return (heapFlags & 0x50000062) != 0x40000060;
}
// 检测方法5:时间检测
BOOL CheckDebugger_Timing(API_TABLE* api) {
typedef DWORD (WINAPI* PFN_GetTickCount)(void);
PFN_GetTickCount pGetTickCount =
(PFN_GetTickCount)api->GetProcAddress(
GetModuleByHash(HASH_KERNEL32), "GetTickCount");
DWORD start = pGetTickCount();
// 执行一些操作
volatile int dummy = 0;
for (int i = 0; i < 10000; i++) {
dummy += i;
}
DWORD elapsed = pGetTickCount() - start;
// 正常执行应该很快,调试时会很慢
return elapsed > 100;
}
// 综合反调试
BOOL IsBeingDebugged(API_TABLE* api) {
if (CheckDebugger_PEB()) return TRUE;
if (CheckDebugger_NtGlobalFlag()) return TRUE;
if (CheckDebugger_IsDebuggerPresent(api)) return TRUE;
if (CheckDebugger_HeapFlags()) return TRUE;
// if (CheckDebugger_Timing(api)) return TRUE; // 可选
return FALSE;
}
5.2、完整性验证
// CRC32校验
DWORD Crc32(const BYTE* data, DWORD size) {
static DWORD table[256] = {0};
static BOOL tableInit = FALSE;
// 初始化CRC表
if (!tableInit) {
for (DWORD i = 0; i < 256; i++) {
DWORD crc = i;
for (int j = 0; j < 8; j++) {
crc = (crc >> 1) ^ ((crc & 1) ? 0xEDB88320 : 0);
}
table[i] = crc;
}
tableInit = TRUE;
}
DWORD crc = 0xFFFFFFFF;
for (DWORD i = 0; i < size; i++) {
crc = table[(crc ^ data[i]) & 0xFF] ^ (crc >> 8);
}
return crc ^ 0xFFFFFFFF;
}
// 验证壳代码完整性
BOOL VerifyShellIntegrity(LPBYTE shellStart, DWORD shellSize, DWORD expectedCrc) {
DWORD actualCrc = Crc32(shellStart, shellSize);
return actualCrc == expectedCrc;
}
5.3、加密算法实现
// XOR加密(简单但有效)
void XorCrypt(LPBYTE data, DWORD size, const BYTE* key, DWORD keyLen) {
for (DWORD i = 0; i < size; i++) {
data[i] ^= key[i % keyLen];
}
}
// RC4算法
typedef struct _RC4_STATE {
BYTE S[256];
int i, j;
} RC4_STATE;
void Rc4Init(RC4_STATE* state, const BYTE* key, DWORD keyLen) {
for (int i = 0; i < 256; i++) {
state->S[i] = (BYTE)i;
}
int j = 0;
for (int i = 0; i < 256; i++) {
j = (j + state->S[i] + key[i % keyLen]) % 256;
BYTE temp = state->S[i];
state->S[i] = state->S[j];
state->S[j] = temp;
}
state->i = 0;
state->j = 0;
}
void Rc4Crypt(RC4_STATE* state, LPBYTE data, DWORD size) {
for (DWORD n = 0; n < size; n++) {
state->i = (state->i + 1) % 256;
state->j = (state->j + state->S[state->i]) % 256;
BYTE temp = state->S[state->i];
state->S[state->i] = state->S[state->j];
state->S[state->j] = temp;
BYTE k = state->S[(state->S[state->i] + state->S[state->j]) % 256];
data[n] ^= k;
}
}
// 更复杂的变形XOR
void TransformXor(LPBYTE data, DWORD size, DWORD key) {
DWORD state = key;
for (DWORD i = 0; i < size; i++) {
// 简单的伪随机数生成器
state = state * 1103515245 + 12345;
// 应用变换
data[i] ^= (BYTE)(state >> 16);
data[i] = (data[i] << 3) | (data[i] >> 5); // 循环左移
data[i] ^= (BYTE)(i & 0xFF);
}
}
// 逆变换
void InverseTransformXor(LPBYTE data, DWORD size, DWORD key) {
DWORD state = key;
for (DWORD i = 0; i < size; i++) {
state = state * 1103515245 + 12345;
// 逆向应用变换
data[i] ^= (BYTE)(i & 0xFF);
data[i] = (data[i] >> 3) | (data[i] << 5); // 循环右移
data[i] ^= (BYTE)(state >> 16);
}
}
5.4、完整的壳解密流程
// 壳配置结构(与加壳器共享)
#pragma pack(push, 1)
typedef struct _SHELL_CONFIG {
DWORD magic; // 魔数标识
DWORD originalOEP; // 原始入口点
DWORD packedDataRVA; // 加密数据RVA
DWORD packedDataSize; // 加密数据大小
DWORD originalDataSize; // 原始数据大小
DWORD encryptionType; // 加密类型
DWORD key; // 加密密钥
DWORD shellCrc; // 壳代码CRC
DWORD dataCrc; // 解密后数据CRC
DWORD flags; // 标志位
} SHELL_CONFIG;
#pragma pack(pop)
#define SHELL_MAGIC 0xDEADC0DE
#define ENCRYPT_XOR 1
#define ENCRYPT_RC4 2
#define ENCRYPT_TRANSFORM 3
#define FLAG_ANTI_DEBUG 0x0001
#define FLAG_INTEGRITY 0x0002
#define FLAG_COMPRESS 0x0004
// 壳入口函数
void __stdcall ShellMain() {
// 初始化API表
API_TABLE api;
if (!InitApiTable(&api)) {
return; // 无法获取API,终止
}
// 获取当前基址
LPBYTE imageBase = (LPBYTE)GetModuleByHash(0); // 自身
if (!imageBase) {
// 通过其他方式获取
#ifdef _WIN64
imageBase = (LPBYTE)__readgsqword(0x60);
imageBase = *(LPBYTE*)(imageBase + 0x10);
#else
__asm {
mov eax, fs:[0x30]
mov eax, [eax + 0x08]
mov imageBase, eax
}
#endif
}
// 定位配置(假设在壳代码段末尾)
SHELL_CONFIG* config = FindShellConfig(imageBase);
if (!config || config->magic != SHELL_MAGIC) {
return; // 配置无效
}
// 反调试检测
if (config->flags & FLAG_ANTI_DEBUG) {
if (IsBeingDebugged(&api)) {
// 检测到调试器,可以选择退出或迷惑
return;
}
}
// 完整性验证
if (config->flags & FLAG_INTEGRITY) {
// 验证壳代码完整性
// ...
}
// 修改内存保护
DWORD oldProtect;
LPBYTE packedData = imageBase + config->packedDataRVA;
api.VirtualProtect(packedData, config->packedDataSize,
PAGE_EXECUTE_READWRITE, &oldProtect);
// 解密
switch (config->encryptionType) {
case ENCRYPT_XOR:
XorCrypt(packedData, config->packedDataSize,
(BYTE*)&config->key, 4);
break;
case ENCRYPT_RC4: {
RC4_STATE rc4;
Rc4Init(&rc4, (BYTE*)&config->key, 4);
Rc4Crypt(&rc4, packedData, config->packedDataSize);
break;
}
case ENCRYPT_TRANSFORM:
InverseTransformXor(packedData, config->packedDataSize, config->key);
break;
}
// 验证解密结果
if (config->flags & FLAG_INTEGRITY) {
DWORD actualCrc = Crc32(packedData, config->originalDataSize);
if (actualCrc != config->dataCrc) {
return; // 解密失败
}
}
// 恢复内存保护(可选)
api.VirtualProtect(packedData, config->packedDataSize,
PAGE_EXECUTE_READ, &oldProtect);
// 跳转到OEP
LPBYTE oep = imageBase + config->originalOEP;
((void(*)())oep)();
}
6、课后作业
-
实现多种加密算法
- 实现XOR加密
- 实现RC4加密
- 实现自定义变形算法
-
添加反调试措施
- 实现多种检测方法
- 添加反分析技术
- 测试绕过能力
-
实现完整性验证
- 对壳代码进行CRC校验
- 对解密数据进行校验
- 处理校验失败情况