数据逆向(二)——区分常量、变量、指针

本文介绍了数据逆向分析中如何区分常量、变量和指针。局部非静态变量通常存储在栈区,利用ebp或esp寻址;全局变量和局部静态变量存储在数据节,采用直接寻址。常量同样直接寻址但只读。指针作为存储地址的变量,初始化时用offset或lea,使用时需二次寻址。

做数据逆向分析最先应该区分数据是常量、变量,还是指针。可是作为二进制数据本身不会标记自己是什么,然而编译器将不同的的类别储存在不同的区域。

 

 

变量数据应分为这两类:

      1. 局部非静态变量:对于1KB以下的该种变量,一般都要放在栈区,那么它的寻址用到ebp寄存器来间接变址进行寻址。另外,有些编译器(比如gcc)出于优化考虑,也会用到esp寄存器。

举例:

void fun()
{
 int i=0;
 char a[5]="AAAA";
}

//vc2005Debug版反汇编

void fun()
{

-------------------------------------------------保护寄存器数据
00411390  push        ebp 
00411391  mov         ebp,esp
00411393  sub         esp,0E0h
00411399  push        ebx 
0041139A  push        esi 
0041139B  push        edi 

---------------------为局部变量在栈区预留内存,以及vc编译器的添加防溢出措施

0041139C  lea         edi,[ebp-0E0h]
004113A2  mov         ecx,38h
004113A7  mov         eax,0CCCCCCCCh
004113AC  rep stos    dword ptr es:[edi]
004113AE  mov  eax,dword ptr [___security_cookie (417000h)] //研究溢出漏洞
的人,

                                                                                       //可以看一下蓝色代码,

                                                                                       //通过在回调地址前,

                                                                                       //添加安全码

                                                                                       //使shellcode不可以覆盖

                                                                                       //这里,否则异常
004113B3  xor           eax,ebp
004113B5  mov         dword ptr [ebp-4],eax 

                                                                                        //这是vs2005的新特性,

                                                                                        //你想能出破解方案吗?

-------------------------------------------------

int i=0

004113B8  mov         dword ptr [ebp-0Ch],0
 char a[5]="AAAA";
004113BF  mov         eax,dword ptr [string "AAAA" (41563Ch)]
004113C4  mov         dword ptr [ebp-1Ch],eax

004113C7  mov         cl,byte ptr ds:[415640h]
004113CD  mov         byte ptr [ebp-18h],cl
}

004113D0 push edx
004113D1 mov ecx,ebp
004113D3 push eax
004113D4 lea edx,[ (4113F4h)]
004113DA call @ILT+140(@_RTC_CheckStackVars@8) (411091h)
004113DF pop eax
004113E0 pop edx
004113E1 pop edi
004113E2 pop esi
004113E3 pop ebx
004113E4 mov ecx,dword ptr [ebp-4]
004113E7 xor ecx,ebp
004113E9 call @ILT+25(@__security_check_cookie@4) (41101Eh)
004113EE mov esp,ebp
004113F0 pop ebp
004113F1 ret  

     2. 全局变量、局部静态变量:它们统一储存在数据节,因为它们的实现方式是一样的,都是直接寻址方式来寻址,只是全局变量,在所有区域均可访问,而局部静态变量只能在函数内部访问。

 

char a[5]="AAAA";
void fun()
{
 static int i;
 i=0;
 a[0]='b';
 
}

 

 

 void fun()
{
00411390  push        ebp 
00411391  mov         ebp,esp
00411393  sub         esp,0C0h
00411399  push        ebx 
0041139A  push        esi 
0041139B  push        edi 
0041139C  lea         edi,[ebp-0C0h]
004113A2  mov         ecx,30h
004113A7  mov         eax,0CCCCCCCCh
004113AC  rep stos    dword ptr es:[edi] //由于没有使用堆栈,编译器没有添加防溢出措施
 static int i;
 i=0;
004113AE  mov         dword ptr [41719Ch],0
 a[0]='b';
004113B8  mov         byte ptr [417034h],62h 
 }

004113BF pop edi
004113C0 pop esi
004113C1 pop ebx
004113C2 mov esp,ebp
004113C4 pop ebp
004113C5 ret

 

 

常量  

      常量和全局变量、静态变量实现方法使一样的,使用直接寻址,但区别是:只能读、不可写。

 

      比如:1. mov eax, [417034h]

              2. cmp eax, [417034h]

 

指针

       指针可以当做是存储地址的变量,它即可以是全局变量,也可以是局部非静态变量,但与普通变量的区别是:"初始化时使用offset或lea,使用指向内容时二次寻址"。

      举例:初始化:

              1.mov [417034h],offset “AAAA”//全局指针

              2.lea   eax,ARRAY

                 mov [esp-4ch],eax//局部指针

              使用:

              1.mov eax, [417034h]

                 mov edx, [eax]

              2.mov eax, [esp-4ch]

                 mov edx, [eax+i]//指针可能指向的是数组

//vc2005Debug版反汇编

<think>我们讨论的是在C语言中,如何使用volatile来强制保留一个const常量变量(即被const修饰的全局变量)不被编译器优化掉。 根据前面的引用,我们知道: 1. 在C语言中,const常量实际上是可以被修改的(通过指针强行修改),但这样做是未定义行为(UB)[^2][^3]。 2. volatile关键字告诉编译器不要优化对该变量的访问,因为它可能在程序外部被改变(例如硬件寄存器、中断等)[^1][^3]。 所以,对于const常量,如果我们希望它被保留(即使它没有被使用),并且防止编译器进行优化(比如将它当作编译期常量进行替换),我们可以使用volatile修饰。 具体回答如下: </think> ### 使用 `volatile` 强制保留 `const` 常量变量的可行性分析 #### 一、核心结论 **可以**使用 `volatile` 强制保留 `const` 常量变量。该组合实现以下效果: 1. **保留物理存储**:禁止编译器优化移除变量 2. **保留运行时访问**:阻止编译期常量替换(宏替换式优化) 3. **语义约束**: - `const` 声明"程序自身不应修改此变量" - `volatile` 声明"变量可能被外部因素修改" ```c volatile const int sensor_value = 0; // 正确用法✅ ``` --- #### 、C/C++ 行为差异 | **行为** | C语言实现 | C++实现 | 验证代码片段 | |-------------------------|-----------------------------|-------------------------------|---------------------------------| | **修改变量值** | 允许(但属未定义行为) | 允许(但属未定义行为)[^3] | `int* p = (int*)&v; *p = 2;` | | **阻止编译期常量替换** | 无效(仍可能优化) | 有效(强制运行时访问) | `cout << sensor_value;` | | **保留未使用变量** | 有效 | 有效 | 检查符号表/反汇编 | > 示例验证(C++): > ```cpp > #include <iostream> > int main() { > volatile const int a = 1; // 关键组合 > int* pa = (int*)&a; > *pa = 2; // 强制修改(未定义行为) > std::cout << a; // 输出2(volatile阻止常量替换) > } > ``` > 输出结果:`2`(未启用优化时) --- #### 三、实现原理 1. **编译器优化阻断** `volatile` 强制每次访问都从内存读取,阻止以下优化: - ❌ 移除"未使用"的常量 - ❌ 编译期值替换(如将 `a` 替换为字面量1) ```mermaid graph LR A[源代码] --> B[编译器优化阶段] B -->|无volatile| C[常量替换/移除] B -->|有volatile| D[保留内存访问指令] ``` 2. **内存映射约束** 在嵌入式系统中常用于映射硬件寄存器: ```c volatile const uint32_t* HW_REG = (volatile const uint32_t*)0x4000; // 寄存器值可能被硬件改变,且程序不应写入 ``` --- #### 四、应用场景 1. **只读硬件寄存器** (如嵌入式设备的传感器只读寄存器) 2. **跨线程共享常量** (需与 `const` 配合保证线程安全) 3. **防逆向工程保护** (阻止常量被编译期内联暴露) > ⚠️ **注意事项**: > 通过指针修改 `volatile const` 变量属于**未定义行为(UB)**,实际开发中应避免此操作[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值