变量

局部变量
- 保存在栈上,先声明的变量在高地址,后声明在低地址。
- 局部变量在栈上会内存对齐。

静态局部变量
- 等价全局变量(生命周期一致)。

区分
int fun1(int n1){ static int i = n1; // return i;}
在tls
环境中,保存着i
是否被初始化的标志,每次进函数的时候,都要进行判断。
通过汇编我们可以看到,静态局部变量的初始标志的检查是无锁的。
但是标志的改写,仍然是需要线程同步的。
unsigned __int64 `__local_stdio_printf_options'::`2'::_OptionsStorage DQ 01H DUP (?) ; `__local_stdio_printf_options'::`2'::_OptionsStorageint `int fun1(int)'::`2'::i DD 01H DUP (?) ; `fun1'::`2'::iint `int fun1(int)'::`2'::$TSS0 DD 01H DUP (?) ; `fun1'::`2'::$TSS0`string' DB '%d', 00H ; `string'
_n1$ = 8 ; size = 4int fun1(int) PROC ; fun1, COMDAT mov eax, DWORD PTR fs:__tls_array mov ecx, DWORD PTR __tls_index mov ecx, DWORD PTR [eax+ecx*4] mov eax, DWORD PTR int `int fun1(int)'::`2'::$TSS0 cmp eax, DWORD PTR __Init_thread_epoch[ecx] jg SHORT $LN5@fun1$LN2@fun1: push DWORD PTR int `int fun1(int)'::`2'::i push OFFSET `string' call _printf mov eax, DWORD PTR int `int fun1(int)'::`2'::i add esp, 8 ret 0$LN5@fun1: push OFFSET int `int fun1(int)'::`2'::$TSS0 call __Init_thread_header add esp, 4 cmp DWORD PTR int `int fun1(int)'::`2'::$TSS0, -1 jne SHORT $LN2@fun1 mov eax, DWORD PTR _n1$[esp-4] push OFFSET int `int fun1(int)'::`2'::$TSS0 mov DWORD PTR int `int fun1(int)'::`2'::i, eax call __Init_thread_footer add esp, 4 jmp SHORT $LN2@fun1int fun1(int) ENDP ; fun1
堆变量
- 调用
malloc
,但是有可能被静态链接,如果sig
文件未识别的话,往下找可以找到调用系统的API
。
全局变量
- 保存在
.rdata
或者.data
、.bss
,常量区或全局数据区、未初始化区。
有初始值

没有初始值
全局变量的动态初始化

#include <stdio.h>#include <cstdint>int fun1(int n1);int g_int = fun1(10); // 动态初始化int fun1(int n1){ static int i = n1; printf("%d", i); return i;}
生成汇编:
# License: MSVC Proprietary# The use of this compiler is only permitted for internal evaluation purposes and is otherwise governed by the MSVC License Agreement.# See https://visualstudio.microsoft.com/license-terms/vs2022-ga-community/unsigned __int64 `__local_stdio_printf_options'::`2'::_OptionsStorage DQ 01H DUP (?) ; `__local_stdio_printf_options'::`2'::_OptionsStorageint g_int DD 01H DUP (?) ; g_intint `int fun1(int)'::`2'::i DD 01H DUP (?) ; `fun1'::`2'::iint `int fun1(int)'::`2'::$TSS0 DD 01H DUP (?) ; `fun1'::`2'::$TSS0`string' DB '%d', 00H ; `string'
void `dynamic initializer for 'g_int''(void) PROC ; `dynamic initializer for 'g_int'', COMDAT mov eax, DWORD PTR fs:__tls_array mov ecx, DWORD PTR __tls_index mov ecx, DWORD PTR [eax+ecx*4] mov eax, DWORD PTR int `int fun1(int)'::`2'::$TSS0 cmp eax, DWORD PTR __Init_thread_epoch[ecx] jg SHORT $LN7@dynamic$LN4@dynamic: push DWORD PTR int `int fun1(int)'::`2'::i push OFFSET `string' call _printf mov eax, DWORD PTR int `int fun1(int)'::`2'::i add esp, 8 mov DWORD PTR int g_int, eax ; g_int ret 0$LN7@dynamic: push OFFSET int `int fun1(int)'::`2'::$TSS0 call __Init_thread_header add esp, 4 cmp DWORD PTR int `int fun1(int)'::`2'::$TSS0, -1 jne SHORT $LN4@dynamic push OFFSET int `int fun1(int)'::`2'::$TSS0 mov DWORD PTR int `int fun1(int)'::`2'::i, 10 ; 0000000aH call __Init_thread_footer add esp, 4 jmp SHORT $LN4@dynamicvoid `dynamic initializer for 'g_int''(void) ENDP ; `dynamic initializer for 'g_int''
- 首先生成一个
dynamic initializer for 'g_int'
函数。 - 在入口之前执行动态初始化。
逆向时向上查找全局变量被引用地址,看看是否被动态初始化调用。(通过IDA的绘图向上溯源)

数组
连续的变量如何证明为数组?
- 类型是否一致?
- 是否跟着循环、判断下标等语句?
- 是否有初始化代码?
- 数组寻址公式:
ary + index * sizeof(type)
,或者指针累加。lea eax, ary``mov ary, ary+4
- 数组的初始化通常有
rep
或者memset
,特别是memset
。(debug
会使用rep
),默认值会使用xmm0
寄存器。
数组初始化
不完全初始化
第一种,未初始化的元素个数较少,会使用xmm0
与movups、movaps
等指令处理。
int array_1[4] = {1, 2, 3}; // 第一种,不完全初始化


第二种,较多的元素未初始化,会使用memset
将未初始化的元素全部初始化为0

未初始化
并不会使用memset
将元素初始化为0
,而是会使用栈上的残留值。

初始化为0
会使用memset
将数组全部初始化为0
。

全初始化
要么使用xmm0
或者直接优化为多个mov
语句。

数组的遍历
一维数组的遍历,可以找到循环和一次乘法。

二维数组,可以找到两层循环和两个步长

二维数组/多维数组
在内存中,并不存在多维数组,只是步长更精细。
二维数组乘两次、三位乘三次…
务必记得乘法会被优化为移位。