行业解决方案
查看所有行业解决方案
IDA 用于解决软件行业的关键问题。
发布时间:2026-11-14 17: 20: 00
打开一个函数,沿着反汇编代码读到call,还能理解为调用另一段程序。继续遇到jmp、jz或jg,代码的执行顺序就不那么好判断了。有时目标位置在前面,有时两个分支又绕回同一个代码块,单看地址排列很容易读错。IDA提供的图形视图和交叉引用能帮助梳理这些关系,不过指令本身的含义仍要分清。以下以x86、x64程序中的常见指令为例,说明调用、跳转及条件分支的阅读方法。
一、IDA反汇编代码中调用和跳转有什么区别
调用与跳转都会改变执行位置,区别在于是否为返回保留地址。阅读一段代码时,可以把目标位置和后续去向配对检查,避免只顾着进入函数,忘了返回后还有哪些处理。
1、从调用位置找到返回后的代码
常见的近调用call会把下一条指令的地址压入栈,再进入目标位置。目标函数正常通过ret返回时,程序会从保存的地址继续执行。
①在反汇编视图中找到【call】指令,记下紧随其后的【指令地址】。
②将光标放在【被调用函数名】上,按Enter进入函数,查看它的处理内容及返回路径。
③按Esc回到原位置,查看【call】之后是否读取返回值、保存结果或进行比较。
④对照调用前后的【寄存器】和【内存操作数】,记录传入内容与返回结果的使用位置。
2、沿跳转目标核对执行方向
①找到【jmp】指令,将光标移到【目标标签】上,按Enter进入目标位置。
②查看目标代码属于当前【函数】内部,还是位于另一个函数中。
③按Esc返回,检查【jmp】后面的代码是否有其他跳转入口。
jmp不会像call那样压入新的返回地址,执行到它时会直接转向目标位置。函数内部的流程连接、尾调用都可能使用jmp。call也不保证一定返回,例如目标函数结束了程序,调用后的代码便不会正常执行,判断时仍要结合目标函数的行为。
3、区分界面导航与程序执行
①将光标放在【函数名】或【地址标签】上,按Enter查看目标。
②按Esc回到原来的【调用位置】或【跳转位置】。
③需要核对目标来源时,将光标放在【目标名称】上,按X打开交叉引用列表,选择相关位置查看。
④回到原指令,重新核对【call】或【jmp】的类型及操作数。
按Enter和Esc只是移动IDA中的浏览位置,并没有执行程序。界面能返回上一个位置,与程序是否通过ret返回是两回事。阅读时将浏览历史和程序控制流分开,才不会把“能跳回去”误当作函数会返回的依据。
二、IDA反汇编代码里的条件分支应该怎么看
条件分支要同时看判断来源和两条去向。图中代码块的左右位置可以变化,不能直接把左边当成条件成立、右边当成条件不成立。
1、沿两条连线确认分支出口
图形视图把函数分成若干基本块,块之间用连线表示执行关系。普通条件跳转有跳转成立和未跳转两条路径,默认配色分别使用绿色和红色。
①在函数内部按空格切换到【图形视图】,找到块末尾的【条件跳转指令】。
②查看指令中的【目标标签】,沿对应连线定位跳转成立时进入的代码块。
③返回判断位置,查看另一条【连线】,核对未跳转时顺序执行的代码。
④将鼠标停在【连线】上预览另一端,或双击连线移动到相连代码块。
⑤分别记录两个【目标块】中的赋值、函数调用和返回操作。
2、把比较指令与跳转条件连起来读
①从【je】、【jne】等指令向前查看,寻找设置相关标志位的【cmp】、【test】或其他运算指令。
②遇到【cmp eax,5】时,按左侧减右侧的顺序记录比较对象;后接【je】表示相等时跳转,后接【jne】表示不相等时跳转。
③遇到【test eax,eax】后接【jz】时,记录【eax为零】对应的路径;后接【jnz】时,记录非零对应的路径。
④遇到【jg】、【jge】、【jl】、【jle】,按有符号数比较;遇到【ja】、【jae】、【jb】、【jbe】,按无符号数比较。
⑤检查判断前的【操作数宽度】,并核对比较与跳转之间是否有指令重新修改相关【标志位】。
cmp设置减法相关标志,但不保存减法结果。test进行按位与测试,同样不写回结果。条件依据不一定就在跳转的上一行,应追踪相关标志位来自哪里。例如cmp eax,5后接jl,表达的是有符号意义下eax小于5时跳转,不能只把jl记成笼统的“小于”。
三、IDA反汇编代码中的分支关系怎么核实
读懂单个判断后,还要把它放回函数中核对。分支可能提前返回、进入循环,也可能汇合后继续使用不同路径留下的结果。
1、核对两条路径是否汇合
①从【条件跳转】出发,分别沿两条路径向后查看,记录各自对【寄存器】或【变量】的修改。
②找到共同进入的【代码块】,比较进入前两条路径留下的值。
③如果某条路径以【ret】结束,记录它的返回结果,不再把它归入后续汇合路径。
④在已经核实的【判断指令】处按分号添加注释,简要写明条件及两边的处理内容。
两个分支调用了不同函数,并不代表它们从此互不相关。后面的共同代码可能继续读取两边分别设置的结果,遗漏这一段,容易误判前面判断的用途。
2、检查回跳与循环退出条件
回到较低地址的连线可以提示潜在循环,但循环次数还取决于计数、数据变化和退出判断。不能看到回跳就认定程序会一直重复。
①找到指向前方代码的【回跳目标】,定位重复经过的指令范围。
②检查范围内的【计数寄存器】、【指针】或状态变量如何变化。
③沿【退出分支】查看离开循环后进入的位置,记录退出前的比较条件。
3、遇到间接目标时追查地址来源
①看到【call rax】时,向前追踪【rax】的赋值位置,核对它是否来自函数指针或表项。
②遇到通过内存表项执行的【jmp】,检查【索引寄存器】、边界判断和目标地址表。
③对已识别的【目标函数】按X查看交叉引用,返回相关位置核对调用关系。
④对暂未确定的【目标地址】添加注释,将待确认内容与已核实结论分开记录。
间接调用和间接跳转的目标可能依赖运行时数据,静态视图未必列出全部去向。目标还没查清时,保留判断范围比直接写成固定函数更可靠,也便于后续继续核对。
总结
反汇编阅读不必一开始就追求还原完整源代码。能够说明一段代码为什么进入、在什么条件下离开,以及结果交给哪里使用,已经能建立有用的理解。IDA的图形视图适合整理路径,具体指令则用于核实判断细节,两者配合着读,遇到复杂分支也更有依据。希望这些方法能帮助大家把看似零散的跳转整理成清楚的执行关系。
展开阅读全文
︾