C&C++软件逆向技术

1、分析定位目标功能

1、课程目标

  1. 掌握逆向分析的基本流程和方法
  2. 学会使用调试器定位关键代码
  3. 理解静态分析与动态调试的结合
  4. 掌握常用的断点技术

2、名词解释

术语 英文 说明
逆向工程 Reverse Engineering 分析程序内部工作原理的过程
静态分析 Static Analysis 不运行程序直接分析代码
动态调试 Dynamic Debugging 运行程序并观察其行为
断点 Breakpoint 使程序在特定位置暂停执行
交叉引用 Cross Reference (XRef) 代码之间的调用关系

3、使用工具

工具 用途
IDA Pro 专业反汇编和分析工具
x64dbg/x32dbg Windows动态调试器
Ghidra 免费的逆向分析工具
OllyDbg 经典的x86调试器
Process Monitor 监控文件/注册表操作

4、技术原理

4.1、逆向分析流程

  1. 信息收集 - 了解程序功能和行为
  2. 入口点定位 - 找到程序入口
  3. 功能定位 - 定位感兴趣的代码
  4. 代码分析 - 理解实现逻辑
  5. 验证结论 - 确认分析结果

4.2、定位方法

方法 适用场景
字符串搜索 有明显提示信息
API断点 知道会调用的API
消息断点 GUI程序事件处理
内存断点 跟踪数据访问
条件断点 特定条件下触发

5、代码实现

5.1、示例1:目标程序(用于练习)

#include <stdio.h>
#include <string.h>
#include <windows.h>

// 模拟的密码验证程序
BOOL CheckPassword(const char* input) {
    // 硬编码的密码(逆向目标)
    const char* secret = "SecretPass123";
    
    if (strlen(input) != strlen(secret)) {
        return FALSE;
    }
    
    // 简单的字符比较
    for (int i = 0; i < strlen(secret); i++) {
        if (input[i] != secret[i]) {
            return FALSE;
        }
    }
    
    return TRUE;
}

int main() {
    char password[64] = {0};
    
    printf("=== Password Checker ===\n");
    printf("Enter password: ");
    scanf("%63s", password);
    
    if (CheckPassword(password)) {
        printf("Access Granted!\n");
        MessageBoxA(NULL, "Welcome!", "Success", MB_OK);
    } else {
        printf("Access Denied!\n");
        MessageBoxA(NULL, "Wrong password!", "Error", MB_ICONERROR);
    }
    
    return 0;
}

5.2、示例2:字符串搜索定位

在IDA中进行字符串搜索:

1. 打开目标程序
2. View -> Open subviews -> Strings (Shift+F12)
3. 搜索关键字:"Access Granted" 或 "password"
4. 双击跳转到字符串位置
5. 查看交叉引用 (X键) 找到使用该字符串的代码
6. 分析周围代码逻辑

5.3、示例3:API断点定位

// 常用断点API及其用途
/*
文件操作:
- CreateFileA/W      - 打开文件
- ReadFile/WriteFile - 读写文件
- DeleteFileA/W      - 删除文件

注册表:
- RegOpenKeyExA/W    - 打开注册表键
- RegSetValueExA/W   - 设置键值
- RegQueryValueExA/W - 查询键值

网络:
- socket/connect     - 网络连接
- send/recv          - 数据传输

内存:
- VirtualAlloc       - 分配内存
- VirtualProtect     - 修改保护

弹窗:
- MessageBoxA/W      - 消息框
*/

// 在x64dbg中设置API断点
// bp MessageBoxA
// bp CreateFileA

5.4、示例4:用程序分析流程

#include <windows.h>
#include <stdio.h>

// 程序化方式查找模块地址
void FindModuleAddress() {
    HMODULE hMod = GetModuleHandleA(NULL);
    printf("Module Base: 0x%p\n", hMod);
    
    // 获取模块信息
    MODULEINFO mi;
    GetModuleInformation(GetCurrentProcess(), hMod, &mi, sizeof(mi));
    printf("Entry Point: 0x%p\n", mi.EntryPoint);
    printf("Image Size: 0x%X\n", mi.SizeOfImage);
}

// 搜索内存中的字符串
void* SearchString(void* start, size_t size, const char* target) {
    size_t targetLen = strlen(target);
    unsigned char* p = (unsigned char*)start;
    
    for (size_t i = 0; i < size - targetLen; i++) {
        if (memcmp(p + i, target, targetLen) == 0) {
            return p + i;
        }
    }
    return NULL;
}

int main() {
    FindModuleAddress();
    
    // 在自身模块中搜索字符串
    HMODULE hMod = GetModuleHandleA(NULL);
    MODULEINFO mi;
    GetModuleInformation(GetCurrentProcess(), hMod, &mi, sizeof(mi));
    
    void* found = SearchString(hMod, mi.SizeOfImage, "password");
    if (found) {
        printf("Found 'password' at: 0x%p\n", found);
    }
    
    return 0;
}

5.5、示例5:x64dbg调试命令

常用x64dbg命令:

断点:
bp <address>       - 设置断点
bp MessageBoxA     - 在API上设置断点
bph <addr> r 4     - 硬件读断点
bph <addr> w 4     - 硬件写断点
bc <addr>          - 清除断点

搜索:
find <addr>,"text" - 搜索字符串
findall <module>,"pattern" - 搜索特征码

执行:
run                - 运行
stepover/sto       - 单步越过
stepinto/sti       - 单步进入
rtr                - 执行到返回

分析:
follow             - 跳转到地址
graph              - 显示流程图
xref               - 查看交叉引用

6、课后作业

  1. 基础练习:编译示例程序,用IDA找到密码存储位置
  2. API断点:用x64dbg在MessageBoxA上设置断点,跟踪调用栈
  3. 字符串定位:在一个实际程序中用字符串搜索定位关键功能
  4. 综合练习:分析一个简单的CrackMe程序