软件安全实验-静态分析技术

软件安全实验-静态分析技术

【实验目的】

本实验结合x32dbg和IDA,分析简单注册程序(TraceMe.exe)的序列号生成逻辑,以此学习 Windows 32 位应用程序的静态分析技术。

【实验原理】

  • 静态分析的基本思路: 静态分析是在不直接运行程序的情况下,对可执行文件的结构、代码和数据进行观察与推理,从而理解程序的功能和关键逻辑。与动态调试相比,静态分析更适合先把程序整体“看清楚“,尤其适用于定位函数、梳理调用关系以及分析程序中较稳定的计算流程。

  • PE 文件与地址定位: Windows 下的可执行程序通常采用 PE 格式。程序在内存中的实际地址由默认加载基址(Image Base)和相对虚拟地址(RVA)共同决定,因此分析时需要先弄清楚程序被加载到哪里的内存,再把调试器中看到的地址换算成 IDA 中对应的函数位置。这个过程是把动态调试信息和静态反汇编结果对应起来的关键。

  • 逆向序列号生成逻辑: 拿到目标函数后,可以通过反汇编代码观察寄存器运算、循环结构、常量表和字符串处理方式,逐步还原序列号的生成公式。通常这类注册程序的核心逻辑并不复杂,主要是对输入用户名做若干轮累加、乘法或取模运算,最后得到一个与用户名相关的结果。只要把汇编中的数据流关系理清,就能把程序还原成等价的高级语言代码,并进一步验证算法是否正确。

【实验任务】

1 寻找RVA

使用x32dbg打开TraceMe.exe,依照实验2中的步骤定位生成序列号的函数地址,如图1所示,函数地址为0x009b1086。之后打开内存布局窗口,寻找待分析程序加载的内存基址,如图2所示,内存基址为0x009b0000。以此确认该函数的相对虚拟内存地址为:0x00001086(相对虚拟内存地址=函数地址-内存基址)。

动态调试找到验证函数的地址

确定内存基址

2 确定程序默认基址

用StudyPE+打开TraceMe.exe,获取程序的默认加载基址(Image Base),如图3所示,为0x00400000。

在StudyPE+中获取程序默认基址

3 定位到验证函数

用IDA打开TraceMe.exe,根据第1步得到的相对虚拟内存地址、第2步得到的默认基址,确定生成序列号函数的入口地址为0x00401086。然后通过快捷键G,打开“Jump to Address“窗口,定位到该函数,如图4所示。也可以直接在函数列表中找到入口地址对应的函数。

在IDA中找到序列号生成逻辑

4 编写计算程序

根据图4所示的汇编代码,分析运行逻辑,并写出对应的高级语言代码,逆向得到完整的序列号生成函数,该函数以输入的用户名字符串作为参数,输出计算得到的序列号。代码如下所示:

#include<bits/stdc++.h>
unsigned char byte4000[8]={0x20,0x22,0x11,0x13,
    0x1f,0x3f,0x35,0x47};
unsigned char byte4008[12]={3,7,1,0x67,
    0x85,0x11,0x23,0x25,
    0xff,0xff,0xff,0xff};
void calc(char user[], char result[], int n)
{
    //user ebx
    unsigned int ecx=1;
    unsigned int esi=0;
    unsigned int edi=esi;
    unsigned int eax;
    unsigned int v1=ecx;
    unsigned int edx;
    for(;edi<n;edi++)
    {
        eax=user[edi];
        ecx=edi&7;
        edx=byte4000[ecx];
        ecx=byte4008[ecx];
        edx=edx*eax;
        esi+=ecx;
        ecx=v1*10;
        esi+=edx;
        v1=ecx;
    }
    edx=0;
    eax=esi;
    sprintf(result,"%u",eax%v1);
    return;
}
int main()
{
    
    char user[100];
    char result[100];
    scanf("%s",user);
    calc(user,result,strlen(user));
    printf("%s\n",result);
    return 0;
}

5 验证

结合TraceMe.exe,验证第4步实现的序列号生成功能是否正确。如图5所示,使用自己编写的keygen程序生成序列后,以自己的学号作为用户名输入TraceMe.exe,注册成功。

验证序列号生成成功

【思考与总结】

(1)为什么不直接在IDA中使用x64dbg 获取到的函数地址,作为TraceMe.exe序列号生成函数的地址?

因为x32dbg里看到的是程序运行时的实际地址,而IDA中分析的是文件本身的静态地址,两者并不是同一个概念。程序在加载到内存后,地址会随着加载基址发生变化,如果直接把调试器里的地址拿到IDA里用,往往会找不到对应位置。正确的做法是先根据运行时地址减去内存基址得到RVA,再结合程序的默认加载基址换算出IDA里应该跳转到的地址,这样才能准确定位到同一段代码。实际上,考虑程序的具体复杂度,有时也可以直接使用IDA进行分析。

(2)思考动态调试和逆向分析的优缺点,以及应如何分析程序。

动态调试的优点是直观,可以直接看到程序运行时的真实行为,适合定位关键函数、观察输入输出变化,也便于验证自己的判断是否正确。不过它也有局限,很多逻辑只有在特定条件下才会执行,而且程序运行过程中可能会受到环境影响,单靠动态调试不容易看全。

逆向分析则更适合从整体上理解程序结构,可以在不运行程序的情况下看到函数关系、常量和控制流程,但分析过程通常更费时间,也更依赖经验。实际分析时,综合上述两种方法,比较王道的方法是先用动态调试找到关键位置,再回到静态反汇编中梳理逻辑,最后再通过动态方式验证结果。


软件安全实验-静态分析技术
https://eleco.top/2026/05/07/软件安全实验-静态分析技术/
作者
Eleco
发布于
2026年5月7日
许可协议