windows样本高级静态分析之识别汇编中C代码结构四
字数 1577 2025-08-24 23:51:13

Windows样本高级静态分析:识别汇编中的C代码结构

引言

在二进制安全分析中,理解如何将汇编指令映射回高级语言结构是一项核心技能。本文详细讲解如何通过静态分析识别汇编代码中的数组、结构体和链表等常见C语言数据结构。

分析方法论

  1. 编写源代码并生成对应程序
  2. 反汇编目标程序
  3. 分析汇编代码,总结数据类型特征
  4. 建立汇编模式与高级语言结构的对应关系

数组类型的识别

源代码示例

#include <stdio.h>
void main() {
    int arr[5];
    arr[0] = 1;
    arr[1] = 2;
    for(int i = 2; i < 5; i++) {
        arr[i] = i;
    }
}

汇编特征分析

  1. 内存分配方式

    • 通常在栈上分配连续内存块
    • 基址通常为ebp+arr(栈帧指针加偏移)
  2. 元素访问模式

    • 使用索引访问:[ebp+eax*4+arr]
    • 元素长度一致(本例中为4字节int)
    • 连续填充数据到内存块中
  3. 典型指令模式

    • mov [ebp+eax*4+arr], ecx
    • 看到这种基址+索引*元素大小的指令模式,通常对应数组访问

识别要点

  • 一块连续内存区域
  • 每个元素长度一致
  • 通过基址+索引*元素大小的方式访问

结构体类型的识别

源代码示例

#include <stdio.h>
#include <stdlib.h>

struct mystruct {
    int x[5];
    char y;
};

struct mystruct *test;

void main() {
    test = (struct mystruct*)malloc(sizeof(struct mystruct));
    for(int i = 0; i < 5; i++) {
        test->x[i] = i;
    }
    test->y = 'a';
}

汇编特征分析

  1. 内存分配方式

    • 通常通过malloc动态分配
    • 分配大小通过sizeof计算结构体总大小
  2. 元素访问模式

    • 混合类型访问:mov [ecx+eax*4], edx(访问int数组)
    • 单字节访问:mov byte ptr [eax+14h], 'a'(访问char成员)
    • 同一内存块内不同偏移处有不同类型的数据
  3. 典型指令模式

    • 对同一基址的不同偏移进行不同类型的数据操作
    • 偏移量计算可能包含编译时确定的常量(如14h

识别要点

  • 通过malloc分配的内存块
  • 同一内存区域包含不同类型的数据
  • 不同成员通过固定偏移量访问
  • 访问指令的数据宽度不一致(如dword和byte混用)

链表类型的识别

源代码示例

#include <stdio.h>
#include <stdlib.h>

struct node {
    int x;
    struct node *next;
};

typedef node pnode;

void main() {
    pnode *curr, *head;
    int i;
    head = NULL;
    for(i = 1; i <= 3; i++) {
        curr = (pnode*)malloc(sizeof(pnode));
        curr->x = i;
        curr->next = head;
        head = curr;
    }
}

汇编特征分析

  1. 内存分配方式

    • 多次调用malloc分配节点
    • 每个节点大小相同
  2. 元素访问模式

    • 节点包含数据成员(如mov [eax], ecx设置x值)
    • 节点包含指针成员(如mov [eax+4], edx设置next指针)
    • 指针成员指向相同类型的其他内存块
  3. 链接特征

    • 通过指针成员将多个内存块连接起来
    • 常见操作如将新节点的next指向当前head,然后更新head
  4. 典型指令模式

    • 内存块中包含指向同类内存块的指针
    • 通过指针遍历多个相同结构的节点

识别要点

  • 动态分配的多个内存块
  • 每个块中包含指向同类块的指针
  • 通过指针字段将多个块链接起来
  • 通常伴随插入、遍历等操作模式

总结对比表

数据类型 内存特征 访问模式 典型指令模式 关键识别点
数组 连续内存块,元素大小相同 基址+索引*元素大小 mov [ebp+eax*4+arr], ecx 连续内存,统一大小的元素,索引访问
结构体 单块内存包含不同类型数据 固定偏移访问不同成员 mov [ecx+eax*4], edxmov byte ptr [eax+14h], 'a'混用 同一内存块内混合类型访问,固定偏移
链表 多个动态分配节点 节点包含数据和指针成员 mov [eax], ecxmov [eax+4], edx 内存块中包含指向同类块的指针

实践建议

  1. 在分析时注意内存访问指令的操作数宽度
  2. 观察同一基址不同偏移处的访问模式
  3. 注意指针解引用操作,特别是循环遍历模式
  4. 结合上下文理解数据结构的用途
  5. 对动态分配的内存,跟踪其生命周期和访问方式

掌握这些模式识别技巧,可以大大提高逆向工程中重构高级语言数据结构的效率和准确性。

Windows样本高级静态分析:识别汇编中的C代码结构 引言 在二进制安全分析中,理解如何将汇编指令映射回高级语言结构是一项核心技能。本文详细讲解如何通过静态分析识别汇编代码中的数组、结构体和链表等常见C语言数据结构。 分析方法论 编写源代码并生成对应程序 反汇编目标程序 分析汇编代码,总结数据类型特征 建立汇编模式与高级语言结构的对应关系 数组类型的识别 源代码示例 汇编特征分析 内存分配方式 : 通常在栈上分配连续内存块 基址通常为 ebp+arr (栈帧指针加偏移) 元素访问模式 : 使用索引访问: [ebp+eax*4+arr] 元素长度一致(本例中为4字节int) 连续填充数据到内存块中 典型指令模式 : mov [ebp+eax*4+arr], ecx 看到这种基址+索引* 元素大小的指令模式,通常对应数组访问 识别要点 一块连续内存区域 每个元素长度一致 通过基址+索引* 元素大小的方式访问 结构体类型的识别 源代码示例 汇编特征分析 内存分配方式 : 通常通过 malloc 动态分配 分配大小通过 sizeof 计算结构体总大小 元素访问模式 : 混合类型访问: mov [ecx+eax*4], edx (访问int数组) 单字节访问: mov byte ptr [eax+14h], 'a' (访问char成员) 同一内存块内不同偏移处有不同类型的数据 典型指令模式 : 对同一基址的不同偏移进行不同类型的数据操作 偏移量计算可能包含编译时确定的常量(如 14h ) 识别要点 通过 malloc 分配的内存块 同一内存区域包含不同类型的数据 不同成员通过固定偏移量访问 访问指令的数据宽度不一致(如dword和byte混用) 链表类型的识别 源代码示例 汇编特征分析 内存分配方式 : 多次调用 malloc 分配节点 每个节点大小相同 元素访问模式 : 节点包含数据成员(如 mov [eax], ecx 设置x值) 节点包含指针成员(如 mov [eax+4], edx 设置next指针) 指针成员指向相同类型的其他内存块 链接特征 : 通过指针成员将多个内存块连接起来 常见操作如将新节点的next指向当前head,然后更新head 典型指令模式 : 内存块中包含指向同类内存块的指针 通过指针遍历多个相同结构的节点 识别要点 动态分配的多个内存块 每个块中包含指向同类块的指针 通过指针字段将多个块链接起来 通常伴随插入、遍历等操作模式 总结对比表 | 数据类型 | 内存特征 | 访问模式 | 典型指令模式 | 关键识别点 | |---------|---------|---------|-------------|-----------| | 数组 | 连续内存块,元素大小相同 | 基址+索引* 元素大小 | mov [ebp+eax*4+arr], ecx | 连续内存,统一大小的元素,索引访问 | | 结构体 | 单块内存包含不同类型数据 | 固定偏移访问不同成员 | mov [ecx+eax*4], edx 和 mov byte ptr [eax+14h], 'a' 混用 | 同一内存块内混合类型访问,固定偏移 | | 链表 | 多个动态分配节点 | 节点包含数据和指针成员 | mov [eax], ecx 和 mov [eax+4], edx | 内存块中包含指向同类块的指针 | 实践建议 在分析时注意内存访问指令的操作数宽度 观察同一基址不同偏移处的访问模式 注意指针解引用操作,特别是循环遍历模式 结合上下文理解数据结构的用途 对动态分配的内存,跟踪其生命周期和访问方式 掌握这些模式识别技巧,可以大大提高逆向工程中重构高级语言数据结构的效率和准确性。