谁说常量字符串不可修改

哈喽,我是子牙,一个很卷的硬核男人

深入研究计算机底层、Windows内核、Linux内核、Hotspot源码……聚焦做那些大家想学没地方学的课程。为了保证课程质量及教学效果,一年磨一剑,三年先后做了这些课程:手写JVM、手写OS、带你用纯汇编写OS、手写64位多核OS、实战Linux内核…

问你一个问题:你觉得下面这个程序能正确运行吗?

int main() {
    char* s = "ziya";
    s[0] = 'Z';
    return 0;
}

我大胆的预测,你的内心是这样子的

哈哈,别别,我没疯,我来证明给你看

看到没,我真的做到了!

细心的小伙伴可能发现了,在修改常量字符串之前,好像执行了一段代码!是的,就是执行了这段关键的代码,改变了Linux内核的规则束缚,才能做到此,代码长这样

其实规则只能束缚那些活在规则之下的人,当你有能力认清规则,并有实力去改变规则的时候,规则其实形同虚设!接下来听我娓娓道来,我是怎么用这段代码做到这逆天操作的……

看看ChatGPT怎么说

当下AI老火了,我们来看看chatgpt能不能给我们思路或答案

第一个问题:

第二个问题:

第三个问题:

第四个问题:

面对ChatGPT给的答案,是不是越来越没概念了?每个字都能看懂,但是好像看不懂它在说什么了……所以我一直觉得AI越来越强大,只会让认知高能力强的人变得更强,拉大弱者与强者的差距,进而拉大贫富差距……

看到很多人鼓吹AI是普通人的福音,它能帮你做PPT、画图、写文案、写代码……大家都不用学习了!那也得你懂那个东西,你问它,它给你答案,你做判断,你才能得到你想要的接近正确的答案!所以AI时代,你可以不用亲自动手去做,但是你得给AI想法,你得做判断,你还得能正确的做判断,所以其实更需要学习!提高认知,提高判断能力。狙击枪放在步兵手里跟放在狙击手手里,效果天壤之别!

如果你有深厚的底层功底:懂硬件、懂Linux内核,其实ChatGPT已经给了你答案:

  1. 常量字符串不可修改是编译器、操作系统、硬件三种共同作用的结果
  2. 常量字符串编译后是放在可执行文件的只读区域
  3. 程序执行后,常量字符串又被放在进程空间中的只读区域
  4. 进程空间中的只读区域受双重保护:操作系统内存保护、硬件支持
  5. Linux提供了mprotect函数可以改变Linux规则实现只读区域可写
  6. 如果你有实力,你甚至可以做到修改硬件支持实现只读区域可写

那咱们就选最难的,直接修改硬件支持,实现只读区域可写!

接下来我们一层一层来分析

常量字符串在ELF文件中的样子

如果你的程序中有常量字符串,编译后它会放在只读区域,如图

常量字符串编译后为什么要放在这个区域?这就是一种规则。Linux要跑程序,就需要把可执行文件加载到内存中,所以制定了ELF文件结构,告诉编译器,Linux平台的程序随便你怎么编译,但是你生成的文件得符合ELF文件结构我才能运行

常量字符串你编译器编译时要放到.rodata段中,我Linux加载程序的时候才会放到内存只读区域中,这样才能实现我们所学的:常量字符串不可以修改

如果你想详细了解.rodata,或者你想全面了解Linux平台的可执行文件ELF文件结构,这时候你就可以借助ChatGPT去学习研究了!

常量字符串在内存中的样子

再来看看常量字符串在内存中的样子,如图

有木有发现一个惊天大秘密?其实常量字符串跟代码,在内存中,即进程内存空间中,是在同一个区域!给你看一个更形象的图

文章中的很多演示效果,并不是Linux提供的,是我写代码实现的。如果这是你想学的,你也想有这样的实力与认知,欢迎加入我的《逆向思维带你玩转Linux内核》小班

关于Linux进程的内存空间,我之前写过文章 实战讲解Linux进程内存空间

Linux内核的规则束缚

还剩最后一层认知:Linux内核是如何提供内存保护的?那硬件支持呢?Linux内核就是使用了硬件提供的支持才能实现内存保护,所以它俩的本质是一个,只不过是两个层面

那硬件提供了什么支持呢?4-level paging,即4级分页,如图。关于4级分页,这里我就不展开讲了,但是我会给你讲明白硬件支持与只读区域的关系。

关于虚拟内存分页机制,你可以自己去研究学习,后面我也会写文章详谈,如果你想学习,关注公众号【硬核子牙】

当CPU尝试修改常量字符串的时候,CPU肯定有字符串的内存地址,这个地址叫逻辑地址,传给CPU内部的段部件,x64 CPU采用平坦模型,段基址一律为0,段部件产出线性地址,传给CPU内部的页部件

CPU页部件,就是大家所知的MMU,它的工作原理就是根据线性地址算出物理地址,因为数据是存放在内存条上的。硬件保护就是在这一步发挥作用的。MMU工作需要依赖Linux内核中的4级页表,就是上图。一般来说,前三级表不做权限控制,最后一级才做,如图

这个图中的数据叫页描述符,其中的RW位就是ChatGPT所说的硬件支持,为0表示只读,为1表示可读可写,我们来看看常量字符串这个位是多少

5的二进制是0b0101,RW位是0,即只读,秘密终于解开!

既然知道底层是如何实现的,那就知道怎么改了!

其他Linux内核提供的mprotect函数,本质就是干这个事的!

本文至此结束,你学会(废)了吗?

  • 11
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值