逆向工程 - 第2部分(高级编程概念)
字数 862 2025-08-06 08:35:14
逆向工程高级编程概念解析
前言
本文深入解析逆向工程中常见的高级编程概念及其对应的汇编表示,包括数组、指针、动态内存分配、套接字编程和线程。通过对比C代码与反编译的汇编代码,帮助读者理解高级编程概念在底层的实现方式。
数组的汇编表示
数组声明与初始化
在汇编层面,数组的声明和初始化涉及以下步骤:
- 数组长度保存:首先将数组长度保存到局部变量(如ArraySize)
- 索引计算:计算最大和最小索引值以及数组的总长度
- 内存位置计算:使用计算结果确定数组在内存中的基本位置
; 数组长度设置
mov [rbp+ArraySize], 0Ah
; 计算数组总大小
mov eax, [rbp+ArraySize]
shl eax, 2
; 分配内存空间
sub rsp, rax
预定义索引数组
对于有预定义索引的数组,编译器会为每个索引创建独立变量:
mov [rbp+objArray4], 1337h ; objArray[4] = 0x1337
矩阵操作
矩阵操作更为复杂:
- 首先设置行和列大小(row和col变量)
- 计算行和列的最大最小索引
- 计算内存中矩阵的基本位置或总大小
; 设置矩阵大小
mov [rbp+row], 3
mov [rbp+col], 3
; 计算总大小
mov eax, [rbp+row]
imul eax, [rbp+col]
shl eax, 2
; 分配内存
sub rsp, rax
指针的汇编表示
指针操作在汇编中主要通过以下指令实现:
-
变量赋值:
mov [rbp+num], 0Ah ; num = 10 -
指针赋值:
lea rax, [rbp+num] mov [rbp+ptr], rax ; ptr = &num -
输出变量地址:
lea rsi, [rbp+num] ; 使用lea获取有效地址而非mov -
指针解引用:
mov rax, [rbp+ptr] mov eax, [rax] ; 获取指针指向的值
动态内存分配
malloc分配
char *mem_alloc = malloc(11);
strcpy(mem_alloc, "Hello World");
对应汇编:
mov edi, 0Bh ; 分配11字节
call _malloc
mov [rbp+ptr], rax ; 保存返回指针
mov rcx, "Hello Wo" ; 分段复制字符串
mov [rax], rcx
mov rcx, "rld"
mov [rax+8], rcx
calloc分配
与malloc类似,但会初始化内存为0:
mov edi, 0Bh ; 分配11字节
mov esi, 1 ; 元素大小为1
call _calloc
realloc重新分配
char *mem_alloc = realloc(mem_alloc, 21);
strcpy(mem_alloc, "1337 h4x0r @nonymoose");
对应汇编:
mov rdi, [rbp+ptr] ; 原指针
mov esi, 15h ; 新大小21字节
call _realloc
mov [rbp+ptr], rax ; 更新指针
mov rcx, "1337 h4" ; 分段复制长字符串
mov [rax], rcx
mov rcx, "0r @nony"
mov [rax+8], rcx
套接字编程
服务器端实现
关键步骤及对应汇编:
-
创建套接字:
mov edi, 2 ; AF_INET mov esi, 1 ; SOCK_STREAM mov edx, 0 ; 协议 call _socket mov [rbp+server], eax -
设置套接字选项:
mov edi, [rbp+server] mov esi, 1 ; SOL_SOCKET mov edx, 2 ; SO_REUSEADDR lea rcx, [rbp+optval] mov [rbp+optval], 1 call _setsockopt -
绑定地址:
mov word ptr [rbp+address.sin_family], 2 mov [rbp+address.sin_addr], 0 mov edi, 3905 ; 1337端口(网络字节序) call _htons mov [rbp+address.sin_port], ax call _bind -
监听连接:
mov edi, [rbp+server] mov esi, 3 ; 最大队列长度 call _listen -
接受连接:
lea rsi, [rbp+address] lea rdx, [rbp+addrlen] call _accept mov [rbp+sock], eax
客户端实现
关键步骤及对应汇编:
-
创建套接字:
mov edi, 2 ; AF_INET mov esi, 1 ; SOCK_STREAM mov edx, 0 ; 协议 call _socket mov [rbp+sock], eax -
设置服务器地址:
mov edi, [rbp+s] ; server_address结构 mov esi, 10h ; 结构大小 call _memset mov word ptr [rbp+server_addr.sin_family], 2 mov edi, 3905 ; 1337端口 call _htons mov [rbp+server_addr.sin_port], ax -
连接服务器:
mov edi, [rbp+sock] lea rsi, [rbp+server_addr] mov edx, 10h ; 地址结构大小 call _connect
线程编程
线程创建与连接
pthread_create(&thread, NULL, mythread, NULL);
pthread_join(thread, NULL);
对应汇编:
-
创建线程:
lea rdi, [rbp+thread] xor esi, esi ; NULL lea rdx, mythread ; 线程函数 xor ecx, ecx ; NULL call _pthread_create -
线程函数:
mythread proc near mov edi, 1 ; 1秒 call _sleep lea rdi, aHelloFromMythr ; "Hello from mythread" call _puts xor eax, eax retn mythread endp -
线程连接:
mov rdi, [rbp+thread] xor esi, esi ; NULL call _pthread_join
总结
通过分析这些高级编程概念在汇编层面的表示,我们可以得出以下关键点:
- 数组和矩阵:涉及复杂的内存布局计算和索引处理
- 指针操作:大量使用LEA(加载有效地址)指令和间接寻址
- 内存分配:不同分配函数(malloc/calloc/realloc)有相似但不同的底层实现
- 网络编程:遵循标准的socket-bind-listen-accept/connect模式
- 线程管理:依赖系统调用实现线程创建和同步
理解这些高级概念在底层的实现方式,对于逆向工程和分析编译后的二进制文件至关重要。