加密壳

4、封装简易验证与解密流程

1、课程目标

  1. 设计壳的验证机制
  2. 实现多种加密算法
  3. 完成壳的解密流程
  4. 添加反调试检测

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、课后作业

  1. 实现多种加密算法

    • 实现XOR加密
    • 实现RC4加密
    • 实现自定义变形算法
  2. 添加反调试措施

    • 实现多种检测方法
    • 添加反分析技术
    • 测试绕过能力
  3. 实现完整性验证

    • 对壳代码进行CRC校验
    • 对解密数据进行校验
    • 处理校验失败情况