从汇编层看64位程序运行——栈保护

news2024/11/24 2:25:50

大纲

  • 栈保护
  • 延伸阅读
  • 参考资料

在《从汇编层看64位程序运行——ROP攻击以控制程序执行流程》中,我们看到可以通过“微操”栈空间控制程序执行流程。现实中,黑客一般会利用栈溢出改写Next RIP地址,这就会修改连续的栈空间。而编译器针对这种场景,设计了“栈保护”机制。

栈保护

比如下面的代码,buffer[8] = 'b’这句会导致栈溢出。

int main() {
    char buffer[8] = {0};
    buffer[0] = 'a';
    buffer[1] = buffer[0] + 1;
    buffer[8] = 'b';
    return 0;
}

如果我们采用“栈保护”机制编译,即增加-fstack-protector-strong(或者-fstack-protector、-fstack-protector-all等)编译选项。

# makefile
# 定义编译器
CC := gcc

# 定义编译选项
CFLAGS := -Wall -Werror -O0 -fstack-protector-strong

# 定义目标目录
OBJDIR := build
BINDIR := bin

# 定义源文件和目标文件
SRCS := $(wildcard src/*.c)
OBJS := $(patsubst src/%.c,$(OBJDIR)/%.o,$(SRCS))

# 获取当前工作目录名,即工程目录名
PROJECT_DIR_NAME := $(notdir $(shell pwd))

# 最终目标:编译所有文件并生成可执行文件
$(BINDIR)/$(PROJECT_DIR_NAME): $(BINDIR) $(OBJS)
	$(CC) $(CFLAGS) $(OBJS) -o $@

# 通用规则:如何从每个.c文件生成.o文件
$(OBJDIR)/%.o: src/%.c $(OBJDIR)
	$(CC) $(CFLAGS) -c $< -o $@

# 规则:创建build目录
$(OBJDIR):
	mkdir -p $(OBJDIR)

# 规则:创建bin目录
$(BINDIR):
	mkdir -p $(BINDIR)

# 伪目标:清理项目
.PHONY: clean
clean:
	rm -rf $(OBJDIR) $(BINDIR)

# 伪目标:打印变量(用于调试)
.PHONY: print
print:
	@echo "SRCS = $(SRCS)"
	@echo "OBJS = $(OBJS)"
	@echo "PROJECT_DIR_NAME = $(PROJECT_DIR_NAME)"

则程序在运行时,会报出栈移除提示。
在这里插入图片描述
那编译器如何做到“栈保护”的呢?

也许听着挺高大上,但是代码面前了无秘密,其原理也非常的简单。

我们看下这段代码的汇编
在这里插入图片描述
+12和+21这两行,汇编将段寄存器fs偏移+0x28的值保存到main函数栈帧的第一个局部变量位置(-0x8(%rbp))。这个局部变量是一个隐藏变量,后续没有代码对其进行改动。

+58和+62这两行,将检测第一个局部变量的值和寄存器fs偏移+0x28的值是否一致。如果一致就说明没问题,如果不一致就说明栈被污染了。
在这里插入图片描述

延伸阅读

那么段寄存器fs偏移+0x28是什么值?它为什么会在函数调用期间值不变?

这是因为fs断寄存器保存的是当前线程的TLS(Thread Local Storage),这样这个函数在线程上调度时,并不会被其他线程影响这段空间值。

但是GDB却无法打印出FS段地址,这个需要我们对代码进行改造,引入自定义的fs_base方法

#include <asm/prctl.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <stdint.h>

uint64_t fs_base() {
    uint64_t fs_base;
    long result = syscall(SYS_arch_prctl,ARCH_GET_FS,&fs_base);
    if (result == -1) {
        return 0;
    }
    return fs_base;
}

uint64_t gs_base() {
    uint64_t gs_base;
    long result = syscall(SYS_arch_prctl,ARCH_GET_GS,&gs_base);
    if (result == -1) {
        return 0;
    }
    return gs_base;
}

int main() {
    char buffer[8] = {0};
    buffer[0] = 'a';
    buffer[1] = buffer[0] + 1;
    buffer[8] = 'b';
    return 0;
}

然后我们调试这段代码,可以看到被赋值到rax寄存器中的,%fs:0x28指向的值是0x6ac935d29472ff00。
在这里插入图片描述
而fs段地址通过gdb看不到
在这里插入图片描述
我们在gdb中使用下面指令来查看fs段地址

 p/x (uint64_t) fs_base()

然后查看偏移0x28的空间中的值,可以发现这个值和上面被赋值到rax寄存器中的值一致。
在这里插入图片描述
那我们如何确定它是TLS中的地址呢?

我们可以通过下面指令查看TLS的起始地址

p (void*) pthread_self()

我们会发现这个地址和我们通过fs_base获得的地址是一样的。

在这里插入图片描述

参考资料

  • https://stackoverflow.com/questions/23095665/using-gdb-to-read-msrs

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1930889.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

集合媒体管理、分类、搜索于一体的开源利器:Stash

Stash&#xff1a;强大的媒体管理工具&#xff0c;让您的影音生活井井有条- 精选真开源&#xff0c;释放新价值。 概览 Stash是一个专为个人媒体管理而设计的开源工具&#xff0c;基于 Go 编写&#xff0c;支持自部署。它以用户友好的界面和强大的功能&#xff0c;满足了现代用…

16_网络IPC2-寻址

进程标识 字节序 采用大小模式对数据进行存放的主要区别在于在存放的字节顺序&#xff0c;大端方式将高位存放在低地址&#xff0c;小端方式将高位存放在高地址。 采用大端方式进行数据存放符合人类的正常思维&#xff0c;而采用小端方式进行数据存放利于计算机处理。到目前…

IDEA快速生成项目树形结构图

下图用的IDEA工具&#xff0c;但我觉得WebStorm 应该也可以 文章目录 进入项目根目录下&#xff0c;进入cmd输入如下指令&#xff1a; 只有文件夹 tree . > list.txt 包括文件夹和文件 tree /f . > list.txt 还可以为相关包路径加上注释

系统架构师考点--软件工程(下)

大家好。今天继续总结软件工程的知识点。 一、处理流程设计 业务流程重组BPR BPR是对企业的业务流程进行根本性的再思考和彻底性的再设计&#xff0c;从而获得可以用诸如成本、质量、服务和速度等方面的业绩来衡量的显著性的成就。BPR设计原则、系统规划和步骤如下图所示&am…

从 Pandas 到 Polars 十八:数据科学 2025,对未来几年内数据科学领域发展的预测或展望

我在2021年底开始使用Polars和DuckDB。我立刻意识到这些库很快就会成为数据科学生态系统的核心。自那时起&#xff0c;这些库的受欢迎程度呈指数级增长。 在这篇文章中&#xff0c;我做出了一些关于未来几年数据科学领域的发展方向和原因的预测。 这篇文章旨在检验我的预测能力…

日志的编写与线程池的结合

目录 一、认识日志 二、时间的等级划分 三、日志的输出端 3.1 保存至文件 四、日志的部分信息 4.1 日志等级 4.2 日志时间 五、加载日志 六、日志的宏编写 七、ThreadPool Log 一、认识日志 记录事件&#xff1a; 日志用于记录系统运行过程中发生的各种事件&…

word 设置多级混合标题自动更新

目录预览 一、问题描述二、原因分析三、解决方案四、参考链接 一、问题描述 有没有体会过多级标题&#xff0c;怎么设置都不听使唤的情况&#xff1f; 我想要的格式是&#xff1a; 二、原因分析 多级标题中发现&#xff0c;输入编号格式这里有个数字没有底纹,是了&#xff0…

解析 Mira :基于 Web3,让先进的 AI 技术易于访问和使用

“Mira 平台正在以 Web3 的方式解决当前 AI 开发面临的复杂性问题&#xff0c;同时保护 AI 贡献者的权益&#xff0c;让他们可以自主拥有并货币化自己的模型、数据和应用&#xff0c;以使先进的 AI 技术更加易于访问和使用。” AI 代表着一种先进的生产力&#xff0c;它通过深…

nginx代理缓存

在服务器架构中&#xff0c;反向代理服务器除了能够起到反向代理的作用之外&#xff0c;还可以缓存一些资源&#xff0c;加速客户端访问&#xff0c;nginx的ngx_http_proxy_module模块不仅包含了反向代理的功能还包含了缓存功能。 1、定义代理缓存规则 参数详解&#xff1a; p…

万字长文之分库分表里如何优化分页查询?【后端面试题 | 中间件 | 数据库 | MySQL | 分库分表 | 分页查询】

分库分表的一般做法 一般会使用三种算法&#xff1a; 哈希分库分表&#xff1a;根据分库分表键算出一个哈希值&#xff0c;根据这个哈希值选择一个数据库。最常见的就是数字类型的字段作为分库分表键&#xff0c;然后取余。比如在订单表里&#xff0c;可以按照买家的ID除以8的…

开发实战经验分享:互联网医院系统源码与在线问诊APP搭建

作为一名软件开发者&#xff0c;笔者有幸参与了多个互联网医院系统的开发项目&#xff0c;并在此过程中积累了丰富的实战经验。本文将结合我的开发经验&#xff0c;分享互联网医院系统源码的设计与在线问诊APP的搭建过程。 一、需求分析 在开发任何系统之前&#xff0c;首先要…

UPFC统一潮流控制器的simulink建模与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 5.完整工程文件 1.课题概述 UPFC统一潮流控制器的simulink建模与仿真。能够在不增加输电线路物理容量的情况下&#xff0c;显著提高电力系统的传输能力和稳定性。UPFC能够同时控制输电线路的有功功率、无…

技术速递|Let’s Learn .NET Aspire – 开始您的云原生之旅!

作者&#xff1a;James Montemagno 排版&#xff1a;Alan Wang Let’s Learn .NET 是我们全球性的直播学习活动。在过去 3 年里&#xff0c;来自世界各地的开发人员与团队成员一起学习最新的 .NET 技术&#xff0c;并参加现场研讨会学习如何使用它&#xff01;最重要的是&#…

微软研究人员为电子表格应用开发了专用人工智能LLM

微软的 Copilot 生成式人工智能助手现已成为该公司许多软件应用程序的一部分。其中包括 Excel 电子表格应用程序&#xff0c;用户可以在其中输入文本提示来帮助处理某些选项。微软的一组研究人员一直在研究一种新的人工智能大型语言模型&#xff0c;这种模型是专门为 Excel、Go…

在设计电气系统时,电气工程师需要考虑哪些关键因素?

在设计电气系统时&#xff0c;电气工程师需要考虑多个关键因素&#xff0c;以确保系统的安全性、可靠性、效率和经济性。我收集归类了一份plc学习包&#xff0c;对于新手而言简直不要太棒&#xff0c;里面包括了新手各个时期的学习方向编程教学、问题视频讲解、毕设800套和语言…

【Neural signal processing and analysis zero to hero】- 1

The basics of neural signal processing course from youtube: 传送地址 Possible preprocessing steps Signal artifacts (not) to worry about doing visual based artifact rejection so that means that before you start analyzing, you can identify those data epic…

《学会 SpringBoot · 定制 SpringMVC》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; 近期刚转战 CSDN&#xff0c;会严格把控文章质量&#xff0c;绝不滥竽充数&#xff0c;如需交流&#xff…

Pytorch学习笔记day1—— 安装教程

这里写自定义目录标题 Pytorch安装方式 工作需要&#xff0c;最近开始搞一点AI的事情。但是这个国产的AI框架&#xff0c;实话说对初学者不太友好 https://www.mindspore.cn/ 比如说它不支持win下的CUDA&#xff0c;可是我手里只有3070Ti和4060也不太可能自己去买昇腾就有点绷不…

C语言 | Leetcode C语言题解之第239题滑动窗口最大值

题目&#xff1a; 题解&#xff1a; int* maxSlidingWindow(int* nums, int numsSize, int k, int* returnSize) {int prefixMax[numsSize], suffixMax[numsSize];for (int i 0; i < numsSize; i) {if (i % k 0) {prefixMax[i] nums[i];} else {prefixMax[i] fmax(pref…

C++深度解析教程笔记9-静态成员变量,静态成员函数,二阶构造,友元,函数重载,操作符重载

C深度解析教程笔记9 第25课 - 类的静态成员变量实验-数对象个数&#xff08;失败&#xff09;实验-静态变量小结 第26课 - 类的静态成员函数实验-修改对象的静态变量数值实验-利用静态成员函数实验-静态变量静态函数实现统计对象个数小结 第27课 - 二阶构造模式实验-初始化是否…