X86反汇编_深度学习:从 C 指针到汇编逻辑

1. 指针与数据的"暧昧"关系(基础篇)

  • 涵盖内容:

    • 字符指针 : char p = "hello" vs char arr[] = "hello" 的本质区别(常量区 vs 栈区)。

    • 指针数组 : int *arr[5] ------ 存放指针的数组。

    • 数组指针 : int (*p)[5] ------ 指向数组的指针。

  • 攻克目标:

    • 彻底分清"指针数组"和"数组指针"的写法和含义。

    • 理解字符串常量在内存中的位置。

    • 汇编映射点: mov 指令取地址的区别(取栈地址 lea vs 取常量区地址 mov)。

1.1 字符指针

反汇编映射:

  • 编译器优化(反汇编特征)

    • 现象: 没有看到 rep movsloop 循环复制。

    • 本质: 对于短字符串,编译器会将其拆解为多个 DWORD (4字节),使用 MOV 指令直接"暴力填充"到栈中。

    • 实战意义: 在逆向 Shellcode 或还原算法时,看到连续的 MOV [EBP-XX], Imm32,要立刻反应过来这是在初始化字符串或数组。

  • 字符数组 vs 字符指针(内存本质)

    • 字符数组 (char arr\[\]):

      • 动作: 搬运工。把常量区的数据,完整拷贝一份到栈(Stack)上。

      • 关键点: 栈上的数据是可读可写的。你可以修改 arr[0] = 'A',程序正常运行。

      • 汇编特征: mov reg, [地址] -> mov [栈], reg (先读内容,再写内容)。

    • 字符指针 (char *p):

      • 动作: 遥控器。只在栈上保存一个 4 字节的地址编号,直接指向常量区。

      • 关键点: 常量区通常是只读的(Read-Only)。如果你尝试 *p = 'A',程序会直接崩溃 (Access Violation)。

      • 汇编特征: mov [栈], 立即数地址 (直接写地址编号)。

1.2 指针数组

反汇编映射:

  • 从这里我们可以看到指针数组的元素是每个数组首元素的地址,也就是说是把首元素地址当作数据存储到指针数组中。

那么问题来了,在汇编角度中,我们该如何进行取出数组中每个数据(首元素地址 )里面的值(例如:arr_1里面的某个元素)呢?

  • 分析复盘:

    • 第一层:提取"钥匙" (Base Address)

      • 分析:[ebp - 0x4] 取出 arr_3 数组的首元素地址 汇编指令:mov eax, dword ptr [ebp-4]

      • 本质: arr 是一个指针数组,它在栈上存的不是数字,而是地址(即 arr_1, arr_2, arr_3 的首地址)。

      • 动作: [ebp-4] 是数组 arr 的第 3 个元素(arr2)。

      • 结果: 寄存器 EAX 现在拿着一把"钥匙",这把钥匙通向 arr_3 的老家。

    • 第二层:拿着钥匙找"宝藏" (Value Access)

      • 分析: 首元素地址 + 0x10 -> 偏移16个字节,找到 arr_34 的地址。然后取值。

      • 汇编指令: mov ecx, dword ptr [eax+10h]

      • 动作:CPU 以 EAX (arr_3 的基址) 为起点,向后跳 0x10 个字节,把在那里的数据读出来。

    • 核心特征总结:如何在逆向中一眼识别"指针数组"?

      • 指针数组 (int *arr3) 的汇编签名是: "两次 MOV,一次计算"
c 复制代码
mov reg1, [栈地址A]     ; 1. 先读出一个地址 (读到了 arr_3 的基址)
mov reg2, [reg1 + 偏移] ; 2. 再去读那个地址里的内容 (读到了 arr_3[4] 的值)

1.3 数组指针

C语言视角:

c 复制代码
int main()
{
	int arr[10] = { 0 };

	// 实验组 A:打印地址
	printf("%p\n", arr);
	printf("%p\n", &arr);

	// 实验组 B:加法运算(核心!)
	printf("%p\n", arr + 1);
	printf("%p\n", &arr + 1);

	return 0;
}

反汇编视角:

  • 我们可以看到编译器其实还是做了轻微优化,并没有告诉我们[ebp - 0x28]以及[ebp - 0x4]是什么,但是根据我们上下文分析可以推断,

  • [ebp - 0x28] -> arr + 1[ebp - 0x4] -> &arr + 1

  • arr+1是跨了一个字节距离,&arr + 1是跨了一个数组大小的距离。

战术总结:

  • 汇编里的"类型"就是"步长":

  • 当 CPU 看到 int *,它眼里的步长是 4。

  • 当 CPU 看到 int (*)[10],它眼里的步长是 40 (0x28)

  • 所谓的 "数组指针" ,在汇编层面不过是一次更大跨度的内存偏移计算而已。

1.4 遍历数组指针和指针数组的区别

指针数组遍历核心片段:

总结:先提取数组首元素地址,然后在进行数组内的偏移拿到值。

数组指针遍历核心片段:

总结:以数组首元素为基准,在此基础上进行偏移。

2. 调用函数指针与调用函数区别

C语言:

c 复制代码
void test()
{
	printf("hello world\n");
}

int main()
{
	test();
	void(*pa)() = &test;
	pa();
	return 0;
}

反汇编:

  • 调用函数: 直接call立即数

  • 调用函数指针: 将pa存储的值(函数地址)放入寄存器,call 寄存器

  • 因为立即数是死的,也就代表着调用的是死地址,这种直接的风格也是代表着调用的函数是确定性的;但是函数指针则不确定,我们要知道,指针严格意义上来讲是变量,变量存储什么函数地址是不确定的,所以我们把变量放入寄存器再去call符合间接调用。

2.1 遍历函数指针数组与分析反汇编特征

C语言:

反汇编:

  • 核心复盘:遍历函数指针数组 (The Essence of Function Pointer Arrays)

    • 内存布局:连续的"跳板"

      • 存储形态: 函数指针数组本质上是一个 "地址列表"。

      • 物理特征: 所有函数的入口地址(如 add, sub)在内存中是 紧密排列、互不间隔 的。

      • 数据宽度: 每个元素占用 4 字节(32位环境下),这决定了汇编运算的步长(Scale)。

    • 寻址逻辑:查表法 (Look-up Table)

      • 我们不是通过 if-else 去判断调用谁,而是通过 "计算" 来定位:

      • 输入: 数组下标 i (索引)。

      • 计算: i * 4 (偏移量)。

      • 定位: 基址 + 偏移量 = 目标函数指针在栈上的存储位置。

      • 动作: "下标背后的值,就是函数的地址。"

    • 汇编三部曲 (The Assembly Trilogy)

      • 在底层视角下,一次函数指针数组的调用 (pai) 永远分为这三步:

      • 算 (Calculate): 利用 CPU 的 SIB 寻址 硬件能力,直接计算出内存地址。

        • Raw Assembly: ebp - 基址偏移 + ecx \* 4
      • 取 (Fetch): 从计算出的内存地址中,把目标函数的 入口地址 搬运到寄存器。

        • Instruction: MOV EDX, 算出来的地址
      • 跳 (Indirect Call): CPU 对寄存器内的地址发起"盲跳"。

        • Instruction: CALL EDX (间接调用)
    • 一句话总结:

      • "函数指针数组,就是将'逻辑流'变成了'数据流'。我们通过计算偏移量(Stride),从连续的内存中抓取目标地址,实现精准的间接跳转。"

3. 模拟C语言以及正向汇编实现快速排序

3.1 模拟快排_C语言

3.2 正向汇编_模拟快排

3.2.1 cmp_stu_by_name

3.2.2 Swap

3.2.3 Bubble_Sort

3.2.4 main

  • 以上练习主要从汇编角度手写一个结构体排序算法,内心觉得只有把汇编当作母语般去学习,才能对汇编进行彻底祛魅。

本章完~

相关推荐
iCxhust18 小时前
c#多串口重量采集上位机程序
开发语言·汇编·c#·微机原理·8088单板机
AI科技星19 小时前
万有引力G与真空介电常数ε0全维度完整关系式汇编(基于v=c螺旋时空理论)
c语言·开发语言·前端·javascript·网络·汇编·electron
技术不好的崎鸣同学1 天前
x64汇编之GDB进阶与printf
汇编
是星辰吖~2 天前
X86反汇编:深度学习阶段_2
汇编
程序喵大人2 天前
从内存/汇编角度看C与C++:指针、引用、对象的底层差异
c语言·汇编·c++·指针·引用·对象
是星辰吖~2 天前
X86反汇编_深度学习阶段_1
汇编
say_fall2 天前
输入输出技术_接口到中断完全指南
汇编·微机原理·8086
Dovis(誓平步青云)2 天前
《QT学习第四篇:常见事件与UDP、TCP、文件系统、(锁、信号量、条件变量》
c语言·开发语言·汇编·qt
hef2883 天前
NASM工具怎么用 汇编转机器码实战教程
汇编