C&C++软件逆向技术

9、阶段合集

1、课程目标

  1. 回顾整个逆向分析章节的核心知识
  2. 通过综合实战巩固学习内容
  3. 掌握完整的逆向分析流程
  4. 为后续安全研究打下基础

2、知识回顾

课时 核心内容
课时01 定位目标功能、断点技术、字符串搜索
课时02 调用约定(cdecl/stdcall/fastcall/thiscall)
课时03 if-else识别、条件跳转、短路求值
课时04 switch识别、跳转表分析
课时05 循环结构识别(for/while/do-while)
课时06 数组与指针识别、内存寻址模式
课时07 类与对象识别、vtable分析
课时08 构造/析构函数识别

3、综合实战项目

3.1、项目1:密码验证程序分析

// 目标程序 - 分析并绕过密码验证
#include <stdio.h>
#include <string.h>

int CheckLicense(const char* serial) {
    // 算法: 第1位 + 第3位 = 第5位
    // 且长度为10
    if (strlen(serial) != 10) return 0;
    
    if ((serial[0] + serial[2]) % 10 != (serial[4] - '0'))
        return 0;
    
    return 1;
}

int main() {
    char serial[64];
    printf("Enter serial: ");
    scanf("%63s", serial);
    
    if (CheckLicense(serial)) {
        printf("Valid license!\n");
    } else {
        printf("Invalid license!\n");
    }
    return 0;
}

/*
分析步骤:
1. 搜索字符串 "Valid" 定位成功分支
2. 向上找到比较/跳转逻辑
3. 分析CheckLicense函数
4. 理解序列号算法
5. 生成有效序列号或Patch程序
*/

3.2、项目2:类结构还原

// 根据以下反汇编还原类结构
/*
sub_401000:  ; 构造函数
    mov eax, ecx
    mov dword ptr [eax], offset vtable_401200
    mov dword ptr [eax+4], 0
    mov dword ptr [eax+8], 0
    mov dword ptr [eax+0Ch], 0
    ret

sub_401020:  ; 成员函数
    mov eax, [ecx+4]
    add eax, [ecx+8]
    mov [ecx+0Ch], eax
    ret

vtable_401200:
    dd offset sub_401040
    dd offset sub_401060
*/

// 还原结果:
class Unknown {
private:
    int field1;    // +0x04
    int field2;    // +0x08  
    int field3;    // +0x0C
    
public:
    Unknown() : field1(0), field2(0), field3(0) {}
    
    void Calculate() {
        field3 = field1 + field2;
    }
    
    virtual void VFunc1();
    virtual void VFunc2();
};

3.3、项目3:循环算法还原

// 从反汇编还原算法
/*
sub_401000:
    push ebp
    mov ebp, esp
    mov esi, [ebp+8]      ; arr
    mov ecx, [ebp+0Ch]    ; count
    xor eax, eax          ; result = 0
    test ecx, ecx
    jle done
loop_start:
    mov edx, [esi]
    cmp edx, eax
    jle skip
    mov eax, edx
skip:
    add esi, 4
    dec ecx
    jnz loop_start
done:
    pop ebp
    ret
*/

// 还原结果:
int FindMax(int* arr, int count) {
    int result = 0;
    
    if (count <= 0) return result;
    
    for (int i = 0; i < count; i++) {
        if (arr[i] > result) {
            result = arr[i];
        }
    }
    
    return result;
}

3.4、项目4:完整程序分析

// 综合分析流程
/*
1. 初步分析:
   - 查看PE信息(导入表、导出表)
   - 确定程序类型(GUI/Console)
   - 查看字符串表

2. 定位关键代码:
   - 通过字符串搜索
   - 通过API断点
   - 通过交叉引用

3. 分析函数:
   - 识别调用约定
   - 识别控制结构
   - 识别数据结构

4. 还原算法:
   - 理解数据流
   - 还原逻辑关系
   - 编写等价代码

5. 验证结果:
   - 动态调试确认
   - 对比行为是否一致
*/

3.5、项目5:Patch技术

// 常见的Patch方法
/*
1. 跳转改NOP:
   原: jnz fail_label
   改: nop nop (90 90)

2. 跳转条件反转:
   原: jz success (74 xx)
   改: jnz success (75 xx)

3. 改返回值:
   原: xor eax, eax (33 C0)
   改: mov eax, 1; ret (B8 01 00 00 00)

4. 改比较值:
   原: cmp eax, 1234
   改: cmp eax, eax (39 C0, 永远相等)

5. 直接跳过:
   jmp over_check (EB xx)
*/

// x64dbg中的Patch操作:
// 1. 在目标位置按空格键
// 2. 输入新的指令
// 3. File -> Patch file -> 保存

4、逆向分析速查表

4.1、常见代码模式

模式 含义
xor eax, eax eax = 0
test eax, eax 检查eax是否为0
cmp eax, ebx; jz if (eax == ebx)
lea eax, [ebx+ecx*4] 数组寻址
mov ecx, obj; call thiscall调用
mov eax, [ecx]; call [eax] 虚函数调用
add esp, N cdecl清栈
ret N stdcall清栈

4.2、IDA快捷键

快捷键 功能
G 跳转到地址
X 查看交叉引用
N 重命名
Y 修改类型
H 十六进制/十进制切换
Space 图形/文本视图切换
F5 反编译(Hex-Rays)

4.3、调试技巧

技巧 用途
硬件断点 跟踪内存访问
条件断点 特定条件触发
日志断点 记录但不暂停
跟踪执行 观察执行流程

5、课后作业

  1. CrackMe练习:找一个简单的CrackMe程序进行分析
  2. 类还原:从真实程序中还原一个类结构
  3. 算法分析:分析并还原一个加密算法
  4. 完整分析:对一个小程序进行完整的逆向分析