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

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

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

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各有优劣)
人工干预 几乎不需要 重度依赖人工修正命名、逻辑结构
相关推荐
zchao945610 分钟前
关于ubuntu下交叉编译arrch64下的gtsam报错问题,boost中boost_regex.so中连接libicui18n.so.55报错的问题
学习
龙湾开发11 分钟前
计算机图形学编程(使用OpenGL和C++)(第2版)学习笔记 05.纹理贴图
c++·笔记·学习·3d·图形渲染·贴图
世事如云有卷舒38 分钟前
u-boot学习笔记(三)
笔记·学习
56498338 分钟前
爬虫学习————开始
爬虫·学习
每次的天空3 小时前
移动应用开发:自定义 View 处理大量数据的性能与交互优化方案
android·java·学习·交互
海尔辛3 小时前
学习黑客光猫-路由器-交换机
网络·学习·智能路由器
Kazefuku4 小时前
Excel学习笔记
笔记·学习·excel
小浪学编程4 小时前
C#学习——继承、封装、多态
学习
hnlucky4 小时前
《Zabbix Proxy分布式监控实战:从安装到配置全解析》
数据库·分布式·学习·adb·zabbix·集成学习·proxy模式