逆向工程学习记录:反汇编反编译

程序编译成二进制(指令集)

计算机是如何读懂二进制的

1.计算机外置存储

  • 硬盘: 非易失性存储器,解决了大量内容需要长久存储的问题(你可以自备多块硬盘,存储各种内容)
  • 内存: 主要解决CPU无法存储大量信息,但又要处理大量信息(硬盘里的)而出现,主要是为了提升速度,此后在内存基础上又发展出了cache。一般来说,内存存储的是近期需要的内容。

注意: 以二进制形式存储(苏联有过三进制的计算机,即计算机选用二进制性价比最高,而不是非要使用二进制)

2.计算机运算能力的承担者
CPU组成: 寄存器、运算器、控制器
CPU处理二进制的依据: 指令集架构(ISA),即最小的操作集合(比如取指令),指令是有限的,规定了CPU能执行的功能。
CPU上跑的是啥: 首先,是程序,进一步,是进程、线程,再进一步是根据代码生成的指令集,这样一条条指令的跑着。
CPU如何工作: 指令 + 操作数(程序编译成的代码最终被翻译成了一条条指令)

3. 其他设备------------即输入、输出设备
输入: 传感器、键盘...
输出: 显示屏、音响...

总结:

  • 整个过程信息都是以二进制存储的、CPU处理的也是二进制,CPU依据的指令集也是二进制的(不同二进制序列对应不同指令,指令有限)、而输入输出是把二进制信息与其他格式转换。(如音频转成声波播放)。而再电子计算机里,二进制的逻辑上用01表示,物理实现上为电容的有无等等。
  • 整个过程可以看作信息流的处理。本质还是数据的输入、处理与输出。 图片、音频、代码等等都是二进制存储,如何显示在显示屏幕上、能播放出来音乐。如何让音频存储为二进制等等。所以,关键在于如何处理,放在计算机中就是CPU。

程序的实现------------主要源代码与数据文件

代码与数据资源:

从项目构建的角度来说,一开始只需要主要源代码,如果有更多功能,考虑使用第三方库,由此项目里必需有这些文件。然后还可以实现其他功能操作其他类型资源,所以有存储这些资源的文件夹。后续,为了程序自动化的实现会增添更多的文件夹,这里不追溯。

代码实现了这段逻辑,最后变成了指令集在CPU上运行,但要知道图片、音频以及其他文件(如文本文件、视频文件等)是数据,它们不会被编译为指令集,而是通过在程序写入它们的地址来操作。

本质上,运行软件,就是运行这些主要源代码编译成的指令集。数据文件有不在CPU上运行,而是通过代码操作。 所以,代码也规定了可以操作的文件范围。(如代码里没有对某个文件的操作,翻译成的指令也就不会操作它,即使有这个文件,也不会处理。)

项目的结构原因

本质是主要源代码、第三方库以及数据文件,然后代码编译成指令集,操作数据文件。那为何有那么多文件夹?

本质是为了分类:文件不分类,看起来麻烦也不方便管理。所以,把源代码和库放一个文件夹、把数据文件放一个文件夹,同时,因为技术的发展,比如版本管理(git),所以又划分了一个文件夹便于操作,如此下来,项目依赖了其他软件,也就要它对应的文件夹,这就是项目管理。

程序的分发

不分发源代码的原因

  1. 一般用户不需要也不会,所以这种方法效率极低(毕竟你不可能希望用户用你的软件时候还要下载编译器编译吧)
  2. 安全角度考虑,防止自己的技术被剽窃(开源则不同,为了分享)

用户得到的软件是啥?

  1. 首先,不是源代码
  2. 主要源代码和第三方库,主要源代码会直接在开发完成后编译成针对不同OS与CPU的可执行二进制文件指令集。(即不用用户编译,点开就能用),第三方库有两种策略,也编译好和主要源代码打包在一起或者动态编译,需要时再转化为指令集。
  3. 数据文件直接打包放在项目文件夹里
  4. 以及其他的文件(如项目管理的文件、或者自动构建的配置文件)

所以,如果没有开源代码,我们得到的就是这样的一个已经处理好的项目文件。其中主要源代码已经被编译汇编完了。面对这样的东西,我们就要尝试把它(主要是由源代码生成的二进制文件,不要被无关内容干扰)从二进制文件恢复到高级语言源码。这就是软件逆向的过程。

总结

项目从开发者到用户:

项目文件(源代码、数据文件以及其他文件) ------------------> 编译 + 汇编 ------------------> 项目文件(其中源代码由高级语言变为汇编语言变为二进制指令集)


反编译与反汇编

正向开发与逆向工程

1. 正向开发过程

  • 先编译: 高级语言 ------> 汇编语言
  • 再汇编: 汇编语言 ------> 二进制文件

2. 逆向工程

  • 先反汇编: 二进制文件 ------> 汇编语言
  • 再反编译: 汇编语言 ------> 高级语言

逆向工程两步的难度

1. 反汇编难度

机器码(如0x89 0xD8)可直接翻译回汇编指令(如MOV EAX, EBX),而汇编指令能反映基础逻辑。所以二进制到汇编这一步当然没问题,关键是如何从汇编到源码

2. 反编译难度

编译的不可逆性导致 反编译的难度最大

原因:

  • 信息丢失:编译过程中,变量名、函数名、注释等高级语言信息通常会被丢弃,反编译工具需要通过分析来推测这些信息,但结果可能不准确。
  • 代码优化:编译器的优化操作(如循环展开、内联展开)会改变代码的结构和逻辑,使得反编译后的代码难以还原为原始的高级语言代码。
  • 复杂特性还原:对于C++等语言,反编译需要还原类、继承、多态等复杂特性,这增加了还原的复杂性。
  • 代码混淆与保护:开发者可以通过代码混淆、加密等手段增加反编译的难度。
  • 工具限制:高质量的反编译工具较少,且无法保证100%的正确性

总结

反汇编简单反编译难,反汇编(Assembly)是确定的、可逆的,而反编译(Decompilation)是近似的、依赖推理的,本质上是一种"有根据的猜测"

特性 反汇编(Disassembly) 反编译(Decompilation)
输入/输出 二进制机器码 → 汇编指令 汇编指令 → 高级语言伪代码(如C)
确定性 完全可逆(1:1映射) 部分可逆(多对一关系,信息已丢失)
工具依赖 工具结果基本一致(如objdump、IDA) 工具差异大(Ghidra/Hex-Rays各有优劣)
人工干预 几乎不需要 重度依赖人工修正命名、逻辑结构
相关推荐
西岸行者5 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意5 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码5 天前
嵌入式学习路线
学习
毛小茛6 天前
计算机系统概论——校验码
学习
babe小鑫6 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms6 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下6 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。6 天前
2026.2.25监控学习
学习
im_AMBER6 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J6 天前
从“Hello World“ 开始 C++
c语言·c++·学习