ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

零基础IDA反汇编入门:从字符串定位到结构体识别

零基础IDA反汇编入门:从字符串定位到结构体识别

简介:《IDA简易教程共十四章(图)》是一份面向逆向工程初学者与安全分析入门者的图文教程,围绕 IDA 反汇编器的基础使用展开,帮助读者从简单 C 程序入手理解 IDB 分析、二进制代码查看与数据结构识别。教程按章节讲解基本类型识别与转换、操作数进制和正负号调整、字符与字符串风格设置、数组创建、枚举类型及位域定义,并延伸至函数分析、结构体、调试、图形视图与插件开发等方向,强调在真实二进制样本中逐步建立分析思路,并对 IDA 界面布局、名称标注与交叉引用等核心功能形成初步认识。压缩包内共 1 个 doc 文件,约 1.38MB,内容以图解配合操作说明组织,便于按主题查阅和对照练习。已有 261 人学习,适合软件安全、漏洞挖掘和逆向分析初学者作为入门参考与查漏补缺材料。

1. 零基础学 IDA,最容易卡的不是安装

零基础学 IDA,最容易卡住的地方不是软件装不上,而是打开之后满屏十六进制,手不知道往哪儿放。我手上这份《IDA 简易教程共十四章(图)》,前半部分几乎都在解决这一件事:反汇编、基本类型识别、进制转换、字符串、数组、枚举、位域,一步一张图,把逆向工程里最劝退的门槛拆成了一个个按键动作。

IDA 全称 Interactive Disassembler,中文一般叫反汇编器。它干的事说白了就一句话:把已经编译成机器码的程序,重新翻译回人能读的汇编,并且允许你在上面改名字、定类型、写注释。它适合三类人:想弄明白别人程序里到底写了什么的新手,学 C 和汇编想对照编译结果的学生,以及手头只有二进制、需要定位崩溃点的开发者。读完你会知道它是什么、先学哪几手、第一个例子怎么跑通。

2. 反汇编到底在做什么:从一行 C 代码到一堆字节

2.1 编译器把名字全扔了,这才是新手真正的痛点

你写下的 C 代码里,变量叫 a、函数叫 add,读起来清清楚楚。但这些名字只对你有意义,对机器没意义。编译过程走完预处理、编译、汇编、链接四步之后,函数名和变量名大多被抹掉,注释更是一个不留,剩下的是一串十六进制字节和一张“哪个地址对应哪条指令”的对照关系。所以拿到的二进制文件,本质上是一本被抽掉了目录、注释和章节标题的书。

看个最小例子。下面这个函数,人一眼就懂:

/* 两个整数相加,C 层面只有一行 */ int add(int a, int b) { return a + b; }

编译成 32 位 x86 之后,它在反汇编器里长这样:

push ebp ; 保存调用者的栈底指针 mov ebp, esp ; 建立当前函数的栈帧 mov eax, [ebp+8] ; 取出第一个参数 a add eax, [ebp+0xc] ; 加上第二个参数 b pop ebp ; 恢复栈底指针 ret ; 返回,结果留在 eax 里

一行a + b变成了六条指令,而且 a 和 b 这两个名字彻底消失,只剩下[ebp+8]、[ebp+0xc]这种“离栈底第几个字节”的说法。反汇编要干的第一件事,就是把这些冷冰冰的位置重新贴上人能读的标签。IDA 打开文件时会自动尝试做这层工作:切分代码和数据、找出函数起点、算出谁调用了谁、识别常见库函数。它猜得比较准,但一定会猜错一部分,尤其是数据区。

2.2 IDA 的定位:它做七成,剩下三成靠你手动纠正

理解这一点很关键,否则新手容易把 IDA 当黑匣子,指望它一键出源码。它不是。它更像一个带智能提示的编辑器:自动帮你把大框架搭好,然后留出一堆可以手动改的地方——这个字节到底是整数还是字符,这段地址到底是数组还是结构体,这个数字到底该显示成十进制还是十六进制。

教程前七节的内容,几乎全部落在“纠正”这两个字上。第二节教你在 IDA 认不出类型的时候按 D;第三节教你把数字的进制和正负改对;第四节教你把一串字节变成字符串;第五节教你把一片字节排成数组;第六节和第七节教你把魔法数字换成有名字的枚举和位域。这七节练完,你面对一个陌生的二进制不会再发怵,因为你知道每个看不懂的地方,都对应一个具体的按键。

2.3 值得学的三个理由,都不玄乎

第一个理由是教具。学 C 语言时,指针、结构体、数组越界这些概念总隔着一层纸,编译器把它们变成什么样,你其实没见过。用 IDA 对照着看一遍,纸就破了:结构体成员的偏移量是怎么排的、局部变量在栈上怎么分布、字符数组和指针到底差在哪,全都变成肉眼可见的地址和字节。

第二个理由是排查。手头一个第三方组件崩了,没源码,日志也不给力。这时候能看出它在读哪个配置文件、调了哪个系统接口、卡在哪条指令上,问题范围立刻缩小一大半。

第三个理由是它是安全方向的入门门槛。缓冲区溢出、整数溢出这些经典问题,只有先看懂汇编层面的数据流,才知道它们为什么发生。

提示:这三条理由里,新手最先尝到甜头的是第一条。拿自己写的十行小程序开刀,成就感来得最快。

2.4 学之前要不要先啃汇编:认得这十几条就够起步

很多新手卡在这儿不动了,觉得得先把一本汇编教材读完。不必。入门阶段你只需要认得下面这些指令的大概意思,看到时不至于完全陌生:

指令大概意思入门阶段认到什么程度
mov把数据从一个地方搬到另一个地方知道谁是源谁是目标
push / pop压栈、出栈知道常用来传参数和保存现场
call / ret调用函数、从函数返回看到 call 就要想到“这里进了一个新函数”
jmp / je / jne无条件跳、相等跳、不等跳能看出 if 和循环的形状
cmp / test比较两个值、做按位测试知道后面常跟着一条跳转
lea取地址看到它多半是在算地址或做乘法
xor异或常见于清零自身,如 xor eax, eax

把这张表记住,再配合 IDA 里按空格切换的图形视图,你已经能看出一个函数大致有几个分支、循环了几次。剩下的细节,边看边补比通读教材效率高得多。

2.5 心理准备:第一次看会晕,这很正常

我见过太多人在这一步放弃,不是能力问题,是预期错了。第一次打开反汇编窗口,几百行灰色文字铺满屏幕,确实劝退。但只要你手上有一个自己写的小程序,知道它本来该干什么,就能一行一行对回去。对上了第一处,后面就顺了。所以别一上来就拿别人的复杂程序练手,先用自己写的、结果自己完全清楚的代码开刀。

3. 第一个例子怎么跑:写一段小程序,让 IDA 把它拆开

3.1 第一步:写一个自己完全能读懂的小程序

教程第一节给了一个演示程序,输出几个客户和产品信息。我把它的结构简化一下,保留新手要用的几种数据形态:字符串、结构体、数组、循环、分支。代码如下,可以直接保存成 demo.c:

#include <stdio.h> /* 刻意写得朴素:有字符串、有结构体、有数组、有分支, 后面在 IDA 里要辨认的类型,这里全都能对应上 */ typedef struct { int id; char name[16]; char gender; } customer_t; typedef struct { int id; char kind[16]; char title[32]; } product_t; int main(void) { customer_t cs[3] = { {1, "Peter", 'm'}, {2, "John", 'm'}, {3, "Mary", 'f'} }; product_t ps[2] = { {1, "BOOK", "QUICKSTART GUIDE"}, {2, "SOFTWARE", "DEMO APP"} }; int i; printf("CUSTOMERS:\n"); for (i = 0; i < 3; i++) { printf("CUSTOMER %04d: %s (%c)\n", cs[i].id, cs[i].name, cs[i].gender); } printf("PRODUCTS:\n"); for (i = 0; i < 2; i++) { printf("PRODUCT %04d: %s: %s\n", ps[i].id, ps[i].kind, ps[i].title); } return 0; }

这段代码不需要解释太多,你只要确认三件事:它能编译、它能跑出预期结果、你清楚每一行在干什么。第三点最重要。因为等一下在 IDA 里,你就是靠“我知道这里本来该有什么”来判断它认错没认错。

数组cs[3]对应教程第五节要讲的数组识别,字符串"CUSTOMERS:\n"对应第四节,结构体成员的偏移量对应后续章节的结构体分析。也就是说,这一小段代码已经把前七节要用的素材全覆盖了。

3.2 第二步:编译它,两个参数先记住

Linux 或 macOS 下用 gcc 编译,命令和参数含义如下:

# -g 保留调试信息:练习阶段方便在 IDA 里和源码对照 # -O0 关闭优化:优化会合并函数、把变量塞进寄存器,新手容易看懵 gcc -g -O0 demo.c -o demo

两个参数都值得解释一遍,因为它们的取舍正好是“练习”和“实战”的分界线。

-g会在二进制里留下调试符号,IDA 打开时能直接看到函数名main、add这些原始名字,你对照源码会轻松很多。但真实要分析的样本,绝大多数不带调试符号,甚至还会被处理过。所以在练习阶段用-g,是为了先把“数据长什么样”这件事看清楚;等你看熟了,就主动去掉-g再练一遍,逼自己去靠字符串和函数调用关系找入口。

-O0是关闭优化。编译器开优化之后,会把只有一行的函数直接内联进调用者、把反复用到的变量扔进寄存器、把循环展开成好几段。这些变换对程序行为没影响,但会把反汇编的结构打乱,新手看着就像被人拆过的积木。所以练习时一律-O0。

Windows 下用任意一个 C 编译器都行,产物是 exe,不影响后面的操作。编译器给出的提示里如果有警告,先别急着忽略,有时候一个类型警告就对应着后面反汇编里看不懂的地方。

注意:编译完先运行一遍,把输出结果截图或复制下来。后面在 IDA 里要反复拿它当对照答案。

3.3 第三步:拖进去,先认清三块地方

把编译出来的文件拖进 IDA,弹窗一路默认确认就行。打开后界面元素很多,新手只需要先认三块:

第一块是反汇编窗口,也叫 IDA View。左边是地址,中间是汇编指令,右边是 IDA 自动加的注释。你后面所有的分析动作,主体都在这个窗口里完成。

第二块是函数窗口,也叫 Functions window。它列出 IDA 识别出来的所有函数名和地址。带调试信息时你能看到 main,不带时可能是一串 sub_开头的自动名字。这个窗口是你在大程序里导航的地图。

第三块是十六进制窗口,也叫 Hex View。它显示原始的字节流。当你怀疑 IDA 把某块数据认错了,回到这里看原始字节,往往一眼就能确认。

这三块地方能互相联动:在函数窗口双击一个函数,反汇编窗口就跳过去;在反汇编窗口点一个地址,十六进制窗口跟着定位。先把这种联动感建立起来,操作就不会手忙脚乱。

3.4 第四步:从字符串摸回主干,这是最快的入口

新手最常问的一个问题是:“程序这么大,我从哪看起?”答案是字符串。字符串是二进制里最难被抹掉的东西,界面上的提示语、配置项的名称、报错信息,几乎都以明文躺在数据区里。

操作步骤大致是这样:

  1. 打开字符串窗口,快捷键 Shift+F12,或者走菜单 View → Open subviews → Strings。
  2. 在列表里找到CUSTOMERS:这一条,它就是你程序里那行 printf 的格式串。
  3. 双击这一条,反汇编窗口会跳到它所在的地址,此时它被当成一段数据。
  4. 在这个地址上按 X,打开交叉引用列表,看看谁引用了它。
  5. 列表里通常只有一条记录,双击过去,你就站在了引用它的代码附近,多半就是 main 函数内部的某条指令。

这一套动作的价值在于:它把一个“从几千个函数里找入口”的问题,变成了“顺着一条字符串往回走三步”的问题。学会这一招,你已经能对付大部分小体量的程序了。

定位到 main 之后,建议先做一件小事:按 N 给这个函数改个你认得的名字。IDA 自动起的sub_401000这类名字,看十遍也记不住。改成main或者demo_main,之后再从函数窗口看,一眼就能认出来。

3.5 第五步:存盘,IDB 是你唯一的后悔药

所有你在 IDA 里做的手工标注——改的名字、定的类型、写的注释——都不会写回原始的可执行文件,它们全都存在一个独立的数据库文件里,扩展名通常是 .idb 或 .i64。这意味着两件事:一是原始文件始终不会被你改坏,可以放心大胆地试;二是如果你不存盘,关掉窗口的瞬间,几个小时的标注就全没了。

养成习惯:一打开文件就先另存一份带日期的副本,之后每做完一个阶段就按一次保存。这个动作花不了两秒,但能救命。我第一次做练习的时候,把几十处类型全改好了,顺手关了窗口,第二天打开发现干干净净,那种感觉至今记得。

4. 让数据变得看得懂:D 键、A 键和数组的三个参数

4.1 按 D 定义类型:byte、word、dword 到底怎么选

IDA 打开文件时会把大部分区域自动分类,但总有一些地方它拿不准,显示成灰色的db后面跟一串数字。这时候轮到 D 键上场。

把光标放在那个地址上,按一次 D,它会变成db(一个字节);再按一次变成dw(两个字节);再按变成dd(四个字节)。这三个名字对应的是数据宽度:db 是 byte,dw 是 word,dd 是 dword。选哪个不看心情,看数据结构本身。

判断依据很朴素:这个位置在原程序里是什么类型,就选什么宽度。一个 char 类型的字符,用 db;一个 short 类型的计数,用 dw;一个 int 类型的编号,用 dd。如果你不确定,去看它周围的代码怎么用这块数据——如果指令里是mov al, [地址]这种按字节取的写法,那它就是 db;如果是mov eax, [地址],那就是 dd。

教程里提到,转换类型不是只有这三种可选。走 Options → Setup data types,可以把更多类型加进 D 键的循环列表里,比如 qword、tbyte 这些更宽的类型。勾选之后,再按 D 就能一路循环到你要的那个宽度。

还有一个细节值得提前知道:IDA 在转换时会参考数据自身的结构。你按 D 的时候,如果紧接着的下一个字节已经被你转换过,IDA 会弹一个确认框,问你确定要覆盖吗。这不是 bug,是它在保护你之前的劳动成果。如果你确实想改,确认即可;如果嫌这个提示烦,可以在 Options → Convert already defined bytes 里调整默认行为。

4.2 按 U 撤销:手滑之后的补救

改错了怎么办?按 U。U 的意思是 Undefine,把当前地址的数据定义撤掉,让它回到未识别的原始状态。这个键在练习阶段会被你按很多次,因为新手对宽度的判断一定会出错几次。

血泪经验是:当你对一片区域的类型没把握时,先按 U 全部撤销,再从第一个字节开始,一小段一小段地重新定义。这比在一片已经被改乱的数据上东补西补要快得多。撤销之后,IDA 会重新把那片区域显示成原始字节,你就能心平气和地重新判断。

4.3 进制和符号:同一个数字的几种皮肤

一个数字在不同场景下的可读性差别巨大。0x3F看着莫名其妙,63就亲切得多;反过来,一个地址写成十进制4198400毫无意义,写成0x401000立刻能看出它在代码段。

改法在 Operands 工具栏上,找到 Number 命令,点开之后可以切换成二进制、八进制、十进制、十六进制。选完之后那片数据的显示方式立刻改变,但底层字节一个都没动,改变的只是“皮肤”。

同一个菜单里还有个 Toggle leading point,作用是给没占满整个数据宽度的高位补 0。举个具体场景:你定义了一个 dd(四字节),但实际有效的数值只占低两位,显示出来高位是空的,看着别扭。开启这个选项之后,高位会用 0 填满,整个数字看起来完整规整,读起来顺眼很多。

再往下是符号位的转换。同一个字节,当成无符号数读是 255,当成有符号数读是 -1。程序里到底按哪种解释,取决于它后面参与的运算。如果看到一条cmp后面跟着jg(大于则跳),那多半是按有符号数比较的;如果跟的是ja(高于则跳),那多半是无符号。这种对应关系不用背,看多了自然有感觉。

4.4 字符串:A 键和 ASCII string style

数据区里最常见的东西就是字符串。把光标放在一段字节上,按 A,IDA 会把它识别成字符串,并且自动在地址旁边加一个名字,比如aCustomers这种由内容生成的标识。这个名字之后会出现在所有引用它的地方,代码的可读性立刻上一大截。

这里有个容易被忽略的点:字符串的存储格式跟编程语言有关。C 语言的字符串以 0x00 结尾,而有些语言习惯在字符串前面放一个长度字节,还有的用特定字符做终止符。IDA 默认按 C 的风格处理,所以你分析一个 C 程序时通常一切顺利;但如果你面对的不是 C 写的程序,按 A 出来可能是乱码或者被截断的半截字符串。

解决办法在 Options → ASCII string style 里。这个设置允许你更改默认的字符串风格,也能自定义一个不常见的终止字符。设置好之后再按 A,IDA 就会按新的规则去切分字符串。教程里特别提到,默认风格的快捷键就是 A,也就是说改完设置之后,平时操作习惯完全不用变。

4.5 数组:三个参数决定它长什么样

在 C 里,字符串本身就是字符数组。IDA 处理数组的逻辑是:你先手工定义第一个元素的类型,然后告诉它“从这里开始,往后是一片数组”。

具体操作分两步。第一步,把数组第一个元素定义成 byte 类型、格式为 char,也就是按一次或几次 D 调到 db。第二步,把光标放在这个元素上,按*键,或者走 Edition 工具栏里的 Array 命令,弹出数组对话框。

对话框里有几个参数,直接决定数组显示成什么样子:

参数作用新手怎么设
元素总数这个数组一共有多少个元素数一下,或者根据后面的代码推算
一行显示个数每行排几个元素,纯粹影响排版8 或 16,看着舒服就行
Element width每个元素占几个字节字符数组填 1,整数数组填 4
Use dup construct把连续的相同字节合并显示数据重复度高时勾上,否则不勾
Display index像注释一样标出每个元素的下标想数第几个时勾上

教程举的例子很直观:64 个元素、一行 8 个、元素宽度 4、不勾 dup、勾上 Display index。这么设完之后,你会看到一个整整齐齐的表格,每行八个,每个元素前面标着下标,像极了一个二维数组。这种排版对读代码的帮助非常大,尤其是当程序里有一个大的查找表时。

还有两个细节。一是当 IDA 遇到它没识别出来的字节时,会用红色高亮标出来,这是提醒你“这里可能需要你手动处理”,不是报错。二是你可以先框选一段范围再创建数组,IDA 会根据你选的字节数自动推算元素个数,省得自己数。

4.6 枚举和位域:给魔法数字贴上人类的名字

程序里经常出现一些数字,比如 0、1、2 表示三种产品类别。在反汇编里它们就是赤裸裸的 0、1、2,读代码时你得不停回头查“2 到底代表什么”。枚举就是来解决这个问题的。

打开 Enumerations 窗口,新建一个枚举类型,把每个数值和对应的名字填进去。然后在反汇编窗口里,右键点在那条指令的数值上,选 Symbolic constant,IDA 会把当前函数里所有能匹配上的数值自动替换成枚举名。替换完之后,原来那个让人抓瞎的cmp eax, 2就变成了cmp eax, CATEGORY_SOFTWARE,一眼就懂。

位域稍微绕一点,但理解之后很有用。它的本质是“一个字节里的某几位表示一个含义”。教程里的处理思路是:IDA 把位域当成一种特殊的枚举类型,你在新建枚举时可以勾上 Bitfield 选项。

这里有个关键区别要讲清楚。有些位域是“互斥”的,比如产品类别,一个产品同时只能属于一类,那么一个数值就对应一个类别;有些位域是“可组合”的,比如一个产品可以同时运行在多个平台上,那就需要用按位或把几个值合起来。IDA 里一个指定的位域模式只能包含一个值,所以遇到可组合的位域时,正确做法是为每一个 bit 单独建一个小小的位域,让它们各管一位,这样才能把组合关系表达出来。

这一步刚开始会有点绕,我第一次做的时候把组合位域直接当普通枚举填了,结果反汇编里显示出来的名字跟实际对不上,排查了半天才发现是模式建错了。记住一句话就行:互斥的用普通枚举,可组合的拆成一位一个。

5. 新手最容易踩的五个坑:现象、原因和补救办法

5.1 坑一:一上来就狂按 D,把代码段当成了数据

现象:改着改着,反汇编窗口里出现一大片看不懂的东西,原本好好的指令变成了一堆 db 定义,按 F5 也恢复不了原来的样子。

原因:D 键是全局生效的,它不区分你当前在代码区还是数据区。新手看到灰色字节就想按一下试试,很容易把本该是指令的字节定义成数据,IDA 随之把整段代码重新解释,后面的结构就全乱了。

解决:在代码区动手之前先看清楚这片区域的颜色和形态——正常的指令区通常是浅色背景加规整的指令格式,数据区多是灰底或带 db/dd 标记。已经改错了,就在出错的位置按 U 撤销定义,IDA 会重新分析。如果乱得比较厉害,最稳的办法是不保存直接关掉重开,反正原始文件没被动过。

5.2 坑二:以为改完就自动保存了,关窗口才发现全没了

现象:花了两小时把函数名、变量类型、注释全整理好,第二天打开文件,一切回到初始状态。

原因:IDA 的所有手工标注都存在独立的数据库文件里,不写回原始二进制。关窗口时如果没有保存,改动就丢了。这个机制本身是保护性的,但新手往往不知道它的存在。

解决:打开文件的第一件事就是另存一份数据库副本,之后每完成一个阶段按一次保存。判断有没有保存过,看标题栏有没有星号之类的未保存标记。这个习惯花两秒,省的是几小时。

5.3 坑三:在优化过的程序里死活找不到 main

现象:字符串窗口里有内容,交叉引用也跟到了,但跟过去发现那个函数只有十几条指令,跳来跳去,完全看不出哪里是程序主干。

原因:程序是用优化选项编译的。编译器会把小函数内联、把 main 的一部分逻辑拆到别的函数里、把循环改写,导致入口函数的形态和你写的源码对不上。

解决:练习阶段一律用关闭优化的方式重新编译。如果手头的样本是别人给的、没法重新编译,就换个入口思路:从程序启动相关的库函数调用往回找,或者从字符串引用的位置往上层函数逐级回溯,主干通常在两三层之上。

5.4 坑四:字符串一片乱码,或者只显示半截

现象:按了 A,出来的字符串后面跟着一堆问号,或者本该连着的字符串在中间断开了。

原因:字符串的终止规则和你当前设置的风格不匹配。默认按 C 风格(0x00 结尾)处理,如果目标程序用的是长度前缀或其他终止符,切分位置就会错。

解决:走 Options → ASCII string style 检查当前风格,改成与目标程序匹配的那种。另外有些字符串是被拆开存储的,编译器会为了节省空间做合并,遇到这种情况需要手动把相邻的几段拼起来读。

5.5 坑五:数组的宽度设错,后面整片数据全歪了

现象:创建数组之后,每个元素显示的内容都是错位的,本该是一个整数的地方被拆成了四个字符。

原因:Element width 参数填错了。宽度决定 IDA 按几个字节切一个元素,填 1 就是按字节切,填 4 才是按 32 位整数切。宽度错了,整片数据的对齐方式就全错。

解决:先按 U 撤销这次数组定义,回到原始字节状态,重新判断元素宽度。判断方法还是看代码:如果访问这片数据的指令用的是mov eax, [地址 + 4*i]这种按四字节步进的写法,宽度就是 4。确定之后再重新创建数组。

提示:这五个坑里有四个都能用一个动作救回来——按 U 撤销。把这个键当成日常操作,不用怕改错。

6. 接下来学什么:从看懂一个函数到看懂一段逻辑

前面几节练完,你已经能把数据区整理得井井有条。接下来的路,按下面的顺序走最省力。

第一步是把结构体定义出来。你的程序里有customer_t和product_t,在 IDA 里它们目前还是一堆散落的字节。找到定义类型的地方,把结构体的每个成员按顺序填进去,成员宽度和偏移量照着你源码里的声明来。定义完成之后,回到反汇编窗口,把那些[ebp-0x28]之类的偏移量应用成结构体成员,代码会瞬间变得像源码一样好读。这一步是新手成就感最强的一步。

第二步是给函数补原型。看到call sub_401100的时候,你不知道它传了什么参数、返回了什么。走改类型的命令,按 C 的语法写一行函数声明,比如int check_product(int id),IDA 就会按这个原型去解释调用处的寄存器。原型写对了,参数和返回值对不上的问题会立刻暴露出来。

第三步是跟数据流。不要一行一行从头读,而是挑一个你关心的值,比如某个产品编号,从它被读入的位置开始,顺着指令往下跟,看它经过哪些判断、最后存到了哪里。这种跟法比通读代码效率高得多,也是实际分析工作中最常用的方式。

阶段主要动作建议练习时长
第一阶段类型、进制、字符串、数组每天半小时,连续一周
第二阶段结构体定义、函数原型每天半小时,连续一周
第三阶段跟一个变量的完整数据流每次挑一个小函数,慢慢磨

练习素材就用自己写的程序,一步步加复杂度:先加一个结构体数组,再加一个带分支的校验函数,最后加一个简单的加密循环,看 IDA 里的形态怎么变。自己写的代码你完全知道答案,对不上就是自己看错了,这种反馈最直接。

从那以后我每次打开一个新样本,第一件事一定是先存一份带日期的数据库副本,然后把字符串窗口过一遍,再动手改任何类型。这个顺序看起来笨,但它让我少丢过无数次已经做完的标注。希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进