C&C++软件逆向技术

1、分析定位目标功能

1、课程目标

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

2、名词解释

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

3、使用工具

工具用途
IDA Pro专业反汇编和分析工具
x64dbg/x32dbgWindows动态调试器
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程序