[C++逆向] 7 变量在内存中的位置和访问方式

变量类型 作用域 可访问
全局变量 进程作用域 整个进程可访问
静态变量 文件作用域 当前代码文件可访问
局部变量 函数作用域 函数内可访问
{}内变量 块作用域 只能在{}内访问

块作用域举例

image-20200425112110704

全局变量和局部变量的区别

  • 全局变量
    • 在PE文件中,一般是.data节表
    • 在程序执行之前就已经存在了(有内存地址)
    • 程序退出时销毁
    • 全局变量直接通过立即数寻址
    • 先定义的在低地址,后定义变量在高地址(实践得知,Release版本中不是这样的)

用户在运行文件的时候,操作系统线分析这个PE中的数据,将各个节中的数据填入对应的虚拟地址中,此时全局变量已经存在了,等PE的分析和加载完成之后,才开始执行入口点的代码,因此全局变量不受作用域影响,程序的任何位置都可以被访问到。

通过变量2访问变量1 (但是该代码在Release版本中不成立 书上的bug 哈哈)

image-20200425123027424

  • 局部变量
    • 生命周期和函数相同
    • 超出作用域之后。由栈平衡操作来释放局部变量的空间
    • 通过esp或者ebp寻址
  • {} 块变量
    • 在{}内的局部变量生命周期和函数一样,但是编译器会编译前检查语法,限制块外代码对其访问

局部静态变量

局部静态变量实际上和全局变量是一样的,都保存再执行文件的数据区,局部静态变量会预先被当作全局变量处理,初始化实际上只是赋值

和全局变量内存结构和访问原理上是一样的,相当于全局静态变量,等价u有限制外部源码文件访问的全局变量

  • 编译器通过名称粉碎法使得其他作用域对局部静态变量不可见。
    • 也即是在编译器及对静态变量重新命名

有意思的#

image-20200425173706629

以上代码执行之后结果是什么呢?

image-20200425173743534

结果居然是五个0,为什么呢?我各种仔细检查代码,发现啥问题都没有。通过调试发现,第7行执行过后,j变量还是0。

最后,书上给了答案,原因是因为为了保证局部静态变量只能被初始化一次,编译器在局部静态变量内存周围做了一个标记,每次通过检查标记判断是否已经被初始化了。如果初始化了就直接跳过。

但是!!!!!!!!!

经过我实际操作发现,上面的方法是vc6的方法,在我用的vs2019中似乎使用了新的方法。。。

image-20200425174220257

这样让我很头大,但是发现了线索,就是_tls_index翻译过来就是tls索引?tls似乎听过!似乎有一个特殊的节表就是tls!通过百度,知道了tls是线程局部储存的意思。而fs里面包含了很多指针,通过查询 2Ch偏移指向的正是 线程局部储存,所以,是否可以认为,新的编译器使用了线程局部储存的方式来标记静态变量呢?

通过修改代码,把代码改成下图,可以得到正确结果。

image-20200425140140486

image-20200425140108783

堆变量

  • 通过malloc或者new申请的空间变量,就是在堆中。
  • 内存中,对结构的每个节点都是使用双向链表的形式储存的

作者:cjdty

出处:https://www.cnblogs.com/cjdty/p/12774310.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   Startu  阅读(517)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
历史上的今天:
2018-04-25 JFrame图形界面 ----鼠标消息
more_horiz
keyboard_arrow_up light_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示