浅入研究 tcache_perthread_struct

Index

  • 前情提要
  • 过程
  • 总结

前情提要

tcache_perthread_struct 是GLIBC从2.27开始引入的机制,本质就是链表。
最近我在复现CISCN往年题目,刚好想仔细研究研究劫持等的原理是什么,于是就研究了一会。

过程

找ChatGPT要了一段申请删除堆块的示例代码,然后直接开始实验。

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>#define MAX_CHUNKS 10 // 最大内存块数目int main() {void *chunks[MAX_CHUNKS] = {NULL}; // 存储多个内存块指针的数组size_t sizes[MAX_CHUNKS] = {0}; // 存储每个内存块大小的数组int num_chunks = 0; // 当前内存块数量while (1) {int choice;printf("选择操作:\n");printf("1. 申请内存块\n");printf("2. 删除内存块\n");printf("其他数字退出\n");printf("请输入您的选择:");scanf("%d", &choice);if (choice == 1) {if (num_chunks >= MAX_CHUNKS) {printf("已达到最大内存块数量\n");continue;}printf("请输入要申请的内存块大小(字节):");if (scanf("%zu", &sizes[num_chunks]) != 1) {printf("无效的输入\n");while(getchar() != '\n');continue;}if (sizes[num_chunks] > 0) {chunks[num_chunks] = malloc(sizes[num_chunks]);if (chunks[num_chunks] == NULL) {perror("内存申请失败");return 1;}printf("成功申请了 %zu 字节的内存块,地址为:%p\n", sizes[num_chunks], chunks[num_chunks]);num_chunks++;} else {printf("无效的大小,无法申请内存块\n");}} else if (choice == 2) {if (num_chunks > 0) {free(chunks[num_chunks - 1]);chunks[num_chunks - 1] = NULL;sizes[num_chunks - 1] = 0;printf("成功释放内存块\n");num_chunks--;} else {printf("没有内存块可删除\n");}} else {// 释放所有内存块for (int i = 0; i < num_chunks; i++) {free(chunks[i]);chunks[i] = NULL;sizes[i] = 0;}break; // 输入其他数字时退出循环}}return 0;
}

使用这段指令编译,便于测试保护全关。
gcc -o test test.c -fno-stack-protector -no-pie

首先我们需要先对tcache的源码有一定的初步了解:
GLIBC 2.27 malloc

#if USE_TCACHE/* We overlay this structure on the user-data portion of a chunk whenthe chunk is stored in the per-thread cache.  */
typedef struct tcache_entry
{struct tcache_entry *next;
} tcache_entry;/* There is one of these for each thread, which contains theper-thread cache (hence "tcache_perthread_struct").  Keepingoverall size low is mildly important.  Note that COUNTS and ENTRIESare redundant (we could have just counted the linked list eachtime), this is for performance reasons.  */
typedef struct tcache_perthread_struct
{char counts[TCACHE_MAX_BINS];tcache_entry *entries[TCACHE_MAX_BINS];
} tcache_perthread_struct;static __thread bool tcache_shutting_down = false;
static __thread tcache_perthread_struct *tcache = NULL;/* Caller must ensure that we know tc_idx is valid and there's roomfor more chunks.  */
static __always_inline void
tcache_put (mchunkptr chunk, size_t tc_idx)
{tcache_entry *e = (tcache_entry *) chunk2mem (chunk);assert (tc_idx < TCACHE_MAX_BINS);e->next = tcache->entries[tc_idx];tcache->entries[tc_idx] = e;++(tcache->counts[tc_idx]);
}/* Caller must ensure that we know tc_idx is valid and there'savailable chunks to remove.  */
static __always_inline void *
tcache_get (size_t tc_idx)
{tcache_entry *e = tcache->entries[tc_idx];assert (tc_idx < TCACHE_MAX_BINS);assert (tcache->entries[tc_idx] > 0);tcache->entries[tc_idx] = e->next;--(tcache->counts[tc_idx]);return (void *) e;
}

可以看到tcache的结构体定义是这样的:

typedef struct tcache_perthread_struct
{char counts[TCACHE_MAX_BINS];tcache_entry *entries[TCACHE_MAX_BINS];
} tcache_perthread_struct;

首先是一个存储堆块数量的地方,一个存储tcache_entry指针数组的地方。
在内存中往往是大小为0x200+,通常为0x250或0x290的堆,地址16字节对齐。
如:
在这里插入图片描述在这里插入图片描述
由于我目前一个堆块没有申请一个堆块没有释放,因此数据全是0。
现在我申请2个大小为0x20的,2个大小为0x40的,2个大小为0x70的堆块。
在这里插入图片描述
可以看到会在大小上加上10,这是因为这10字节大小是用来存储chunk header数据的。
然后我们全部释放。
在这里插入图片描述
可以看到这个堆块数据就变了。那么我们来分析一下具体是什么。
首先使用指令tcache可以查看tcache结构体的情况。
在这里插入图片描述
在这里插入图片描述
heapinfo用来查看链表。然后基于这些数据,我们来查看内存的情况。

pwndbg> x/20gx 0x405000
0x405000:	0x0000000000000000	0x0000000000000251
0x405010:	0x0002000002000200	0x0000000000000000
0x405020:	0x0000000000000000	0x0000000000000000
0x405030:	0x0000000000000000	0x0000000000000000
0x405040:	0x0000000000000000	0x0000000000000000
0x405050:	0x0000000000000000	0x0000000000405a80
0x405060:	0x0000000000000000	0x0000000000405ae0
0x405070:	0x0000000000000000	0x0000000000000000
0x405080:	0x0000000000405b80	0x0000000000000000
0x405090:	0x0000000000000000	0x0000000000000000

显而易见,0x405010地址就是用来存储堆块数量的。0x405050开始存储释放的堆块的指针。
那么0x4050100x405050具体是如何存储的呢,我们进一步研究。

根据tcache的结果可知:

tcache is pointing to: 0x405010 for thread 1
{counts = "\000\002\000\002\000\000\002", '\000' <repeats 56 times>,entries = {0x0, 0x405a80, 0x0, 0x405ae0, 0x0, 0x0, 0x405b80, 0x0 <repeats 57 times>}
}

可以发现在0x405010中,堆块数量是2个2个存储的:
0x00/02/00/00/02/00/02/00
分别对应大小:
0x80/0x70/0x60/0x50/0x40/0x30/0x20/0x10

同时可以得出entries指针也是类似的逻辑:
0x405050开始,第一段是0x20大小的chunk,第二段是0x30,第三段是0x40…以此类推。

通常tcache_perthread_struct结构体劫持是用来泄露libc地址和布置堆块构造ROP的。也就是说我们可以手动修改entries指针来让堆块申请在我们想要的任何位置,也就是任意地址写。

总结

tcache_perthread_struct 结构体存储了可以存放的最多tcache堆块数量、已释放的tcache堆块指针。
通过劫持并修改这些,可以做到任意地址写。

如有错误欢迎大佬们提出。

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

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

相关文章

六:Day05_Spring Security01

一、Spring Security引入 Spring Security 是一个功能强大且高度可定制的身份验证和访问控制&#xff08;认证和授权&#xff09;框架。它是保护基于 Spring 应用程序的事实标准。 2. 认证授权 认证授权实现平台所有用户的身份认证与用户授权功能。 2.1 什么是用户认证 认证…

关于pytorch中的dim的理解

今天碰到一个代码看起来很简单&#xff0c;但是细究原理又感觉好像不太通不太对劲&#xff0c;就是多维tensor数据的操作&#xff0c;比如&#xff1a;y.sum(dim2)&#xff0c;乍一看很简单数据相加操作&#xff0c;但是仔细一想&#xff0c;这里在第3维度的数据到底是横向相加…

DevOps的发展史了解

DevOps的历史发展史可以追溯到2000年代初期&#xff0c;当时软件开发行业开始意识到&#xff0c;软件开发和IT运维之间的问题已经成为阻碍软件开发速度和效率的重要因素。在此之前&#xff0c;软件开发和IT运维是两个相对独立的过程&#xff0c;开发人员开发软件并将其交付给运…

【计算机】硬件体系结构

计算机硬件体系结构 计算机硬件体系结构是指计算机系统的组织和设计&#xff0c;包括处理器、内存、输入/输出设备、总线等各个组件之间的连接和协作方式。硬件体系结构定义了计算机如何执行指令、存储和检索数据以及与外部设备通信。以下是计算机硬件体系结构的主要组成部分&…

[OpenWrt]RAX3000一根线实现上网和看IPTV

背景&#xff1a; 1.我家电信宽带IPTV 2.入户光猫&#xff0c;桥接模式 3.光猫划分vlan&#xff0c;将上网信号IPTV信号&#xff0c;通过lan口&#xff08;问客服要光猫超级管理员密码&#xff0c;具体教程需要自行查阅&#xff0c;关键是要设置iptv在客户侧的vlan id&#…

Socks5与代理IP技术探析:构建安全高效的网络通信

1. Socks5协议的技术内幕 1.1 握手与身份验证 Socks5协议的握手阶段通过版本协商和灵活的身份验证方式建立安全连接。这确保了通信的可靠性和用户身份的安全。 1.2 数据传输机制 Socks5通过代理实现数据传输&#xff0c;支持TCP和UDP协议&#xff0c;为用户提供了高度灵活的…

FPGA设计流程:从概念到实现的详细指南

目录 引言 1. 概念阶段 1.1 确定需求 1.2 制定规范 2. 设计阶段 2.1 系统设计 2.2 硬件描述语言&#xff08;HDL&#xff09;编写 2.3 仿真验证 3. 综合与优化 3.1 逻辑综合 3.2 布局与布线 4. 实现与调试 4.1 下载与配置 4.2 调试与验证 5. 部署与维护 5.1 系统…

vite与webpack的一些技巧

通常项目里会有很多的api与导入导出&#xff0c;为了避免过多而提高效率 vue3的使用过程中&#xff1a;可以读取文件然后异步的获取挂载在属性上面 虽然我知道按需的好处&#xff0c;但有时候很急效率至少就没办法考虑性能&#xff0c; 所以频繁的导出与import导入使用变量申明…

Zibll子比主题最新学习版

Zibll子比主题5.7.1是一款为WordPress平台设计的优秀主题。它具有独特而富有吸引力的设计风格&#xff0c;同时提供了丰富的功能和卓越的性能&#xff0c;使您的网站在众多网站中脱颖而出。以下是对Zibll子比主题5.7.1的详细介绍。 &#xff08;这是我在“布谷鸟网址导航”上看…

minio可用性磁盘/节点故障恢复的研究

做poc真的很累。年初的报告拿出来按topic拿出来分享一下。 目的 通过模拟各类条件下的minio集群状态&#xff0c;确认minio是否符合官方“N/2硬盘在线&#xff0c;数据可读取&#xff1b;N/21硬盘在线&#xff0c;数据可读写”的描述。 同时通过停止minio集群中节点的服务停止…

粗到细语义(Coarse-to-Fine Semantics)

粗到细语义&#xff08;Coarse-to-Fine Semantics&#xff09;是一种深度学习模型的设计方法&#xff0c;它通过逐步细化的方式来理解文本中的语义信息。这种方法通常用于文本分类、情感分析、问答等任务中。 在粗到细语义中&#xff0c;模型首先从整体上理解文本的大致意思&a…

【计算机设计大赛作品】诗意千年—唐朝诗人群像的数字展现_附源码—信息可视化赛道获奖项目深入剖析【可视化项目案例-20】

🎉🎊🎉 你的技术旅程将在这里启航! 记得看本专栏里顶置的可视化宝典导航贴哦! 🚀🚀 本专栏为可视化专栏,包含现有的所有可视化技术。订阅专栏用户在文章底部可下载对应案例完整源码以供大家深入的学习研究。 🎓 每一个案例都会提供完整代码和详细的讲解,不论你…

Arris VAP2500 list_mac_address未授权RCE漏洞复现

0x01 产品简介 Arris VAP2500是美国Arris集团公司的一款无线接入器产品。 0x02 漏洞概述 Arris VAP2500 list_mac_address接口处命令执行漏洞,未授权的攻击者可通过该漏洞在服务器端任意执行代码,写入后门,获取服务器权限,进而控制整个web服务器。 0x03 复现环境 FOFA…

AIGC与数据安全

数据安全是指保护数据不受非法或恶意的访问、使用、修改、泄露或破坏的能力。数据安全可能导致以下几个方面的问题&#xff1a; ✜ 数据泄露&#xff1a;AIGC可能泄露隐私信息&#xff0c;如姓名、地址、身份证号、银行账号等&#xff0c;危害用户安全和利益。AIGC可能生成包含…

值得收藏:一份完整的Mysql高性能优化规范建议

数据库命令规范 所有数据库对象名称必须使用小写字母并用下划线分割 所有数据库对象名称禁止使用mysql保留关键字&#xff08;如果表名中包含关键字查询时&#xff0c;需要将其用单引号括起来&#xff09; 数据库对象的命名要能做到见名识意&#xff0c;并且最后不要超过32个…

ES客户端RestHighLevelClient的使用

1 RestHighLevelClient介绍 默认情况下&#xff0c;ElasticSearch使用两个端口来监听外部TCP流量。 9200端口&#xff1a;用于所有通过HTTP协议进行的API调用。包括搜索、聚合、监控、以及其他任何使用HTTP协议的请求。所有的客户端库都会使用该端口与ElasticSearch进行交互。…

如何在不同的操作系统和架构中构建Go应用程序

在软件开发中,重要的是要考虑要编译二进制文件的操作系统和底层处理器架构。由于在不同的操作系统/体系结构平台上运行二进制文件通常很慢,甚至不可能,因此通常的做法是为许多不同的平台构建最终的二进制文件,以最大限度地吸引程序的受众。然而,当用于开发的平台与要部署程…

【PTA刷题】 顺序表(删除)(代码+详解)

文章目录 题目C代码详解 题目 已知一组数据&#xff0c;采用顺序存储结构存储&#xff0c;其中所有的元素为整数。设计一个算法&#xff0c;删除元素值在[x,y]之间的所有元素 输入格式: 输入包含三行数据&#xff0c;第一行是表中元素个数&#xff0c;第二行是顺序表的各个元素…

OpenCV极坐标变换函数warpPolar的使用

学更好的别人&#xff0c; 做更好的自己。 ——《微卡智享》 本文长度为1702字&#xff0c;预计阅读4分钟 前言 前阵子在做方案时&#xff0c;得了几张骨钉的图片&#xff0c;骨科耗材批号效期管理一直是比较麻烦的&#xff0c;贴RFID标签成本太高&#xff0c;所以一般考虑还是…

Crow:黑魔法 添加路由3 绑定lambda

Crow:黑魔法2 new_rule_tagged实现模板参数的绑定-CSDN博客 template<uint64_t N> typename black_magic::arguments<N>::type::template rebind<TaggedRule>& new_rule_tagged(const std::string& rule) {using RuleT = typename black_magic::arg…