<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Estara的小窝</title>
        <link>http://estara.blog/</link>
        <description>一个NotionNext搭建的博客</description>
        <lastBuildDate>Fri, 26 Jun 2026 17:00:07 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en-US</language>
        <copyright>All rights reserved 2026, estara</copyright>
        <item>
            <title><![CDATA[机器学习入门]]></title>
            <link>http://estara.blog/article/3713139c-9ee7-802a-9496-ce94127c78b0</link>
            <guid>http://estara.blog/article/3713139c-9ee7-802a-9496-ce94127c78b0</guid>
            <pubDate>Wed, 03 Jun 2026 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[IO_FILE结构以及vtable相关知识]]></title>
            <link>http://estara.blog/article/25c3139c-9ee7-800e-b426-e9da6df39ab5</link>
            <guid>http://estara.blog/article/25c3139c-9ee7-800e-b426-e9da6df39ab5</guid>
            <pubDate>Fri, 15 Aug 2025 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<div id="notion-article" class="mx-auto overflow-hidden "><main class="notion light-mode notion-page notion-block-25c3139c9ee7800eb426e9da6df39ab5"><div class="notion-viewport"></div><div class="notion-collection-page-properties"></div><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-25c3139c9ee780a18f45cb29a64e3f1c" data-id="25c3139c9ee780a18f45cb29a64e3f1c"><span><div id="25c3139c9ee780a18f45cb29a64e3f1c" class="notion-header-anchor"></div><a class="notion-hash-link" href="#25c3139c9ee780a18f45cb29a64e3f1c" title="IO_FILE结构"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">IO_FILE结构</span></span></h2><div class="notion-text notion-block-25c3139c9ee780eeb0f1c9420effdccf">1.在 C 语言中，我们使用 <code class="notion-inline-code"><b>FILE*</b></code> 指针来操作文件（如 fopen, fread, fprintf 等）。这个 FILE 实际上就是 <code class="notion-inline-code"><b>IO_FILE</b></code> 结构体（在早期版本中直接定义为FILE，现代Glibc中FILE是 <code class="notion-inline-code"><b>struct _IO_FILE</b></code> 的别名）。</div><div class="notion-text notion-block-25c3139c9ee78089ad29ebea52ba63ca"><b>简单来说，</b><code class="notion-inline-code"><b>IO_FILE</b></code><b> 结构是 Glibc 用于管理文件流（file stream）的内部数据结构。</b>它包含了处理一个文件所需的所有信息：文件描述符、缓冲区指针、缓冲区大小、当前读写位置、错误和结束标志等。
每一个你用fopen()打开的文件，在用户空间的 Glibc 层都会有一个对应的 <code class="notion-inline-code"><b>IO_FILE</b></code> 结构体实例。我们常见的标准输入、输出、错误流（<code class="notion-inline-code"><b>stdin</b></code>, <code class="notion-inline-code"><b>stdout</b></code>, <code class="notion-inline-code"><b>stderr</b></code>）也是三个预定义好的 <code class="notion-inline-code"><b>IO_FILE</b></code> 结构体。不过需要注意的是这三个文件流位于 <a class="notion-link" href="http://libc.so/" target="_blank" rel="noopener noreferrer">libc.so</a> 的数据段。而fopen创建的文件流是分配在堆内存上的。

2.FILE结构定义在libio.h中，具体结构如下：</div><div class="notion-text notion-block-25c3139c9ee78061b46dd16d72460376">相关参数说明：</div><ol start="1" class="notion-list notion-list-numbered notion-block-25c3139c9ee780429634d099ea2061d5" style="list-style-type:decimal"><li><b>_flags</b>:</li><ol class="notion-list notion-list-numbered notion-block-25c3139c9ee780429634d099ea2061d5" style="list-style-type:lower-alpha"><ul class="notion-list notion-list-disc notion-block-25c3139c9ee780b6b298f1010619edcc"><li>这是一个非常重要的字段，它包含了各种状态标志。</li></ul><ul class="notion-list notion-list-disc notion-block-25c3139c9ee7803b9376d6488e1413e9"><li>标志位定义了流的属性，例如：</li><ul class="notion-list notion-list-disc notion-block-25c3139c9ee7803b9376d6488e1413e9"><li><b>_IO_NO_READS</b> (0x0004): 流不可读。</li><li><b>_IO_NO_WRITES</b> (0x0008): 流不可写。</li><li><b>_IO_EOF_SEEN</b> (0x0010): 已到达文件末尾（EOF）。</li><li><b>_IO_ERR_SEEN</b> (0x0020): 发生了错误。</li><li><b>_IO_USER_BUF</b> (0x0001): 缓冲区由用户提供，而非库分配。</li></ul></ul><ul class="notion-list notion-list-disc notion-block-25c3139c9ee7808c84e5e3bcb217b966"><li>最重要的是，它的高16位必须等于魔数 <code class="notion-inline-code"><b>_IO_MAGIC</b></code> (0xFBAD0000)，用于验证这是一个合法的IO_FILE结构。</li></ul></ol></ol><ol start="2" class="notion-list notion-list-numbered notion-block-25c3139c9ee780df86a1f232f3fe8888" style="list-style-type:decimal"><li><b>缓冲区指针</b>:</li><ol class="notion-list notion-list-numbered notion-block-25c3139c9ee780df86a1f232f3fe8888" style="list-style-type:lower-alpha"><ul class="notion-list notion-list-disc notion-block-25c3139c9ee780d1aebdc0cdd8e1f936"><li>这组指针管理着用户的 I/O 缓冲区。fread和fwrite等函数并不是每次都直接调用系统调用，而是先在这个缓冲区中进行操作，满了或空了再与内核交互，极大提高了效率。</li></ul><ul class="notion-list notion-list-disc notion-block-25c3139c9ee7801980fbed97425db9a3"><li><code class="notion-inline-code"><b>_IO_read_base</b></code> -&gt; 缓冲区的起始地址。</li></ul><ul class="notion-list notion-list-disc notion-block-25c3139c9ee780ab898fd89e141f45bb"><li><code class="notion-inline-code"><b>_IO_read_ptr</b></code> -&gt; 当前读取的位置。</li></ul><ul class="notion-list notion-list-disc notion-block-25c3139c9ee7802bb28ff46b6b60ba3b"><li><code class="notion-inline-code"><b>_IO_read_end</b></code> -&gt; 缓冲区中有效数据的结束位置。</li></ul><ul class="notion-list notion-list-disc notion-block-25c3139c9ee7807aa57bc9928a59a77c"><li><code class="notion-inline-code"><b>_IO_write_*</b></code> 系列指针同理，用于输出缓冲区。</li></ul></ol></ol><ol start="3" class="notion-list notion-list-numbered notion-block-25c3139c9ee7805a9400ec63d8974559" style="list-style-type:decimal"><li><b>_fileno</b>:</li><ol class="notion-list notion-list-numbered notion-block-25c3139c9ee7805a9400ec63d8974559" style="list-style-type:lower-alpha"><div class="notion-text notion-block-25c3139c9ee780c5a0acf0910a948d9e">这个整数存储着底层操作系统提供的<b>文件描述符</b>（file descriptor）。例如，stdin的_fileno是0,stdout是1，stderr是2。当你用fopen打开一个文件时，open()返回的fd就存放在这里。</div></ol></ol><div class="notion-text notion-block-25c3139c9ee7804dac5ec6d3d30bc90a">4._<b>offset</b></div><div class="notion-text notion-block-25c3139c9ee780d7ab07f900c91da6e2">  记录当前文件的偏移量。</div><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-25c3139c9ee78008b8c4e98b3cf28e7a" data-id="25c3139c9ee78008b8c4e98b3cf28e7a"><span><div id="25c3139c9ee78008b8c4e98b3cf28e7a" class="notion-header-anchor"></div><a class="notion-hash-link" href="#25c3139c9ee78008b8c4e98b3cf28e7a" title="Vtable"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">Vtable</span></span></h2><div class="notion-text notion-block-25c3139c9ee78043bc3ffa3fb45ac7fd">为了支持不同类型的文件，Glibc使用了一种类似C++虚函数的机制，每个IO_FILE结构体都包含了一个指向其虚函数表vtable的指针。</div><div class="notion-text notion-block-25c3139c9ee7804a91abf4685fbe0903">vtable是包含众多函数指针的结构体，当调用 fread,fwrite,fclose等函数时，最终会通过这个vtable找到对应的函数来执行具体的操作。

实际上，一个完整的文件流结构是struct_IO_FILE_plus，它包含一个标准的IO_FILE和一个vtable指针</div><div class="notion-text notion-block-25c3139c9ee780b087e5cc671ddd4558">vtable是IO_jump_t类型的指针，IO_jump_t本身是一个结构体，所以vtable本身就是一个巨大的函数指针数组结构。</div><div class="notion-text notion-block-25c3139c9ee780ce9ce0f82e814e3b99"><b>关键函数指针说明：</b></div><ul class="notion-list notion-list-disc notion-block-25c3139c9ee780149c0ad4dc8a31e3b8"><li><code class="notion-inline-code"><b>__overflow</b></code>: 对应于输出缓冲区满时的操作（类似 <code class="notion-inline-code"><b>fflush</b></code>）。</li></ul><ul class="notion-list notion-list-disc notion-block-25c3139c9ee78037acc9e884d5c3d763"><li><code class="notion-inline-code"><b>__underflow</b></code>: 对应于输入缓冲区空时的操作（类似 <code class="notion-inline-code"><b>fillbuf</b></code>）。</li></ul><ul class="notion-list notion-list-disc notion-block-25c3139c9ee7802aa053c1c2f7b223ff"><li><code class="notion-inline-code"><b>__finish</b></code>: 对应于流关闭时的操作。</li></ul><ul class="notion-list notion-list-disc notion-block-25c3139c9ee7807bbac6cd335cf3d191"><li><code class="notion-inline-code"><b>__close</b></code>: 底层的关闭操作。</li></ul><ul class="notion-list notion-list-disc notion-block-25c3139c9ee7804c9daaf2a841c7dd6e"><li><code class="notion-inline-code"><b>__read</b></code> 和 <code class="notion-inline-code"><b>__write</b></code>: 底层的读和写系统调用包装。</li></ul><div class="notion-text notion-block-25c3139c9ee780de8d79eedcde96f71d">对于普通文件，这个vtable指针指向一个名为 <code class="notion-inline-code"><b>_IO_file_jumps</b></code> 的全局结构体。对于内存流，它可能指向 <code class="notion-inline-code"><b>_IO_mem_jumps</b></code>。</div><div class="notion-text notion-block-25c3139c9ee780f584d8c9e79c8a5a78">示意图总结：</div><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-25c3139c9ee780e39e60d4d1ef3a042c" data-id="25c3139c9ee780e39e60d4d1ef3a042c"><span><div id="25c3139c9ee780e39e60d4d1ef3a042c" class="notion-header-anchor"></div><a class="notion-hash-link" href="#25c3139c9ee780e39e60d4d1ef3a042c" title="常见的IO函数"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">常见的IO函数</span></span></h2><h3 class="notion-h notion-h2 notion-h-indent-1 notion-block-25c3139c9ee780f0ac35e30e6efee515" data-id="25c3139c9ee780f0ac35e30e6efee515"><span><div id="25c3139c9ee780f0ac35e30e6efee515" class="notion-header-anchor"></div><a class="notion-hash-link" href="#25c3139c9ee780f0ac35e30e6efee515" title="fopen"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">fopen</span></span></h3><div class="notion-text notion-block-25c3139c9ee7808bab7cc4a94e7073c8">fopen在标准IO库中用于打开文件，函数原型：</div><div class="notion-text notion-block-25c3139c9ee7807ea2c8e5bd6acf4c4e">filename是打开文件路径，type指打开方式，返回一个文件指针。其具体实现逻辑如下：</div><div class="notion-text notion-block-25c3139c9ee7803d95a2d275c097d005">实现流程为：</div><div class="notion-text notion-block-25c3139c9ee78048a344c1cfeb812605">1.调用malloc分配FILE空间，分配了一个struct locked_FILE大小的结构体，并将返回的地址赋给了new_f变量。它包含三种变量：：_IO_FILE_plus、_IO_lock_t、IO_wide_data，其中_IO_FILE_plus为使用的IO_FILE结构体。</div><div class="notion-text notion-block-25c3139c9ee780069c30e7a9a8bb2673">2.调用IO_no_init对FILE初始化</div><div class="notion-text notion-block-25c3139c9ee780a79357c50bb31a8610">3.调用IO_file_init将结构体链接到IO_list_all链表</div><details class="notion-toggle notion-block-25c3139c9ee780708180f15349439536"><summary>IO_list_all:</summary><div><div class="notion-text notion-block-25c3139c9ee78068b663c76e5ea9a0af">IO_list_all是一个指向IO_FILE_plus结构体的指针。所有的FILE并非孤立的存在，而是通过 _IO_FILE 结构体内部的chain字段连接形成一个单链表<em>。IO_list_all</em>就是这个链表的<b>头指针</b>。</div><div class="notion-blank notion-block-25c3139c9ee78062abdee1c905877fa4"> </div></div></details><div class="notion-text notion-block-25c3139c9ee7806d85a7ebf79c550d09">4.调用IO_file_fopen根据用户传入的模式，进行系统调用打开文件</div><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-2983139c9ee7805cb135feb85e797ea0" data-id="2983139c9ee7805cb135feb85e797ea0"><span><div id="2983139c9ee7805cb135feb85e797ea0" class="notion-header-anchor"></div><a class="notion-hash-link" href="#2983139c9ee7805cb135feb85e797ea0" title="过程详解"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">过程详解</span></span></h4><div class="notion-blank notion-block-2983139c9ee780ee8c8bea29c2959d0a"> </div><h3 class="notion-h notion-h2 notion-h-indent-1 notion-block-25c3139c9ee780a58d63d7bc5944c77e" data-id="25c3139c9ee780a58d63d7bc5944c77e"><span><div id="25c3139c9ee780a58d63d7bc5944c77e" class="notion-header-anchor"></div><a class="notion-hash-link" href="#25c3139c9ee780a58d63d7bc5944c77e" title="fread"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">fread</span></span></h3><div class="notion-text notion-block-25c3139c9ee7809c80a1d381e86a457e">fread是标准IO库函数，作用是从文件流中读数据，函数原型：</div><div class="notion-text notion-block-25c3139c9ee7801bbb98cb8800bf326a">buffer是存放读取数据的缓冲区，size是指定读取的每个记录的长度，count是指定记录的个数，stream是文件流，返回读取到缓冲区的记录个数。具体实现逻辑：</div><div class="notion-text notion-block-25c3139c9ee78029b3a5da8701b25284">逻辑就是计算总字节数，加锁，然后调用 <code class="notion-inline-code"><b>_IO_sgetn</b></code>，最后解锁并返回结果。<code class="notion-inline-code"><b>_IO_sgetn</b></code> 是一个定义在vtable中的函数指针。</div><div class="notion-text notion-block-25c3139c9ee78074b21bd121ddfe9725">该函数又指向IO_FILE_xsgetn,这个函数是高效读取的核心：</div><div class="notion-text notion-block-25c3139c9ee780da8efcce8fdab735c0"><b>__underflow</b>是vtable中的另一个关键函数指针。对于普通文件，它指向<b>_IO_new_file_underflow</b>。</div><div class="notion-text notion-block-25c3139c9ee7805eafccddf43fc1ad81">通过 _IO_SYSREAD 宏调用底层__read函数。这个宏展开后就是fp-&gt;vtable-&gt;__read(...)</div><h3 class="notion-h notion-h2 notion-h-indent-1 notion-block-25c3139c9ee7809dbc84f496bcad9466" data-id="25c3139c9ee7809dbc84f496bcad9466"><span><div id="25c3139c9ee7809dbc84f496bcad9466" class="notion-header-anchor"></div><a class="notion-hash-link" href="#25c3139c9ee7809dbc84f496bcad9466" title="fwrite"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">fwrite</span></span></h3><div class="notion-text notion-block-25c3139c9ee780949f31f9f904b41724">fwrite是标准IO库函数，作用是向文件流写入数据，函数原型如下:</div><div class="notion-text notion-block-25c3139c9ee780ceb76ccca8e9479596">buffer是写入数据的地址，size是写入内容的单字节数，count是数据项个数，stream是目标文件指针，返回写入的数据项的个数。实现逻辑：</div><div class="notion-text notion-block-25c3139c9ee78046bc78e29efb389bf5">总体逻辑：计算总字节数，加锁，然后调用IO_sputn,最后解锁并返回结果。</div><div class="notion-text notion-block-25c3139c9ee78038a679d59b6f6540e7">这里IO_sputn是vtable中的一个函数指针，对于一个普通文件，它指向IO_FILE_xsputn:</div><div class="notion-text notion-block-25c3139c9ee78004b3d4f892006c50c0">重点是__overflow,它是vtable中与__underflow相对应的函数指针，也是FSOP攻击的核心目标。对于普通文件，它指向 _IO_new_file_overflow。（FSOP到时候写在另一篇文章里）</div><div class="notion-text notion-block-25c3139c9ee780b590d3e83a588155fc"><code class="notion-inline-code"><b>_IO_do_write</b></code>是一个封装函数，它最终会调用vtable中的 __write函数：</div><div class="notion-text notion-block-25c3139c9ee780da8a09ff5bed9a34ba">对于普通文件，__write 指向 _IO_file_write:</div><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-25c3139c9ee78000a8efcf8607f37169" data-id="25c3139c9ee78000a8efcf8607f37169"><span><div id="25c3139c9ee78000a8efcf8607f37169" class="notion-header-anchor"></div><a class="notion-hash-link" href="#25c3139c9ee78000a8efcf8607f37169" title="Vtable伪造"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">Vtable伪造</span></span></h2><div class="notion-text notion-block-25c3139c9ee780ed88b2f5877492ae03">由前面的内容我们知道，一些常见的IO函数都需要经过FILE结构的处理，会通过IO_FILE_plus中的vtable指针对一些函数进行调用，所以我们伪造的方向可以分为两种：</div><ul class="notion-list notion-list-disc notion-block-25c3139c9ee780bdb414f6ec07d88122"><li>一种是直接改写vtable指针，让它指向一个伪造的虚表，再对特定偏移处写入我们想让程序执行的指令</li></ul><ul class="notion-list notion-list-disc notion-block-25c3139c9ee780ed90f7c8f6c19e08d1"><li>另一种是改写vtable中特定偏移处的函数指针，但是stdin/stdout/stderr的vtable是存放在数据段的不可改写，这种方法不适用</li></ul><hr class="notion-hr notion-block-25c3139c9ee7801587fed0269cb11e40"/><div class="notion-text notion-block-25c3139c9ee780539a94c93c45e402da">这里还是主要讲一下面向对象的vtable：</div><div class="notion-text notion-block-25c3139c9ee780a88998db8e9a022591">C++为了实现运行时多态，引入了虚函数的概念。当一个基类指针指向一个派生类对象，并调用一个虚函数时，实际调用的是派生类中重写的那个函数版本。</div><div class="notion-text notion-block-25c3139c9ee78095bda9f4912ae28542">编译器是如何实现这一神奇功能的呢？答案就是<b>虚函数表（VTable）</b>。</div><ul class="notion-list notion-list-disc notion-block-25c3139c9ee7804b9461f660f9de9dae"><li><b>是什么</b>：VTable是一个函数指针数组。每个<b>包含虚函数的类</b>（或者从包含虚函数的类派生而来）都会有一个或多个对应的VTable。</li></ul><ul class="notion-list notion-list-disc notion-block-25c3139c9ee78051b011dee8b7f2eb5e"><li><b>内容</b>：VTable中的每一个条目（slot）都指向该类的一个虚函数的具体实现地址。</li></ul><ul class="notion-list notion-list-disc notion-block-25c3139c9ee7802b9f20d3207b840704"><li><b>vptr（虚表指针）</b>：当一个类包含虚函数时，编译器会隐式地在<b>每个对象实例的内存布局的最开始</b>添加一个隐藏的成员变量——<code class="notion-inline-code"><b>vptr</b></code>。这是一个指针，指向该对象所属类的VTable。</li></ul><div class="notion-text notion-block-25c3139c9ee7804785c3c6ec53e4fa8a">示例：</div><div class="notion-text notion-block-25c3139c9ee7808ea95ee461215d23b0">对于每一个Derived对象，它的大致布局如下：</div><div class="notion-callout notion-gray_background_co notion-block-25c3139c9ee78093b5c5d6f46aa3ee28"><div class="notion-page-icon-inline notion-page-icon-span"><span class="notion-page-icon" role="img" aria-label="💡">💡</span></div><div class="notion-callout-text"><div class="notion-text notion-block-25c3139c9ee78054a426e9490de11634">+---------------------------+  &lt;-- derived_obj 地址
| vptr (指向 Derived的vtable)|  (8字节，在64位系统上)
+---------------------------+
| Base::a                   |  (4字节，来自基类)
+---------------------------+
| Derived::b                |  (4字节，来自派生类)
+---------------------------+</div></div></div><div class="notion-text notion-block-25c3139c9ee780679e29d8c1353f6b42">其中vtable结构如下：</div><div class="notion-callout notion-gray_background_co notion-block-25c3139c9ee780bbb510eccd19e404f7"><div class="notion-page-icon-inline notion-page-icon-span"><span class="notion-page-icon" role="img" aria-label="💡">💡</span></div><div class="notion-callout-text"><div class="notion-text notion-block-25c3139c9ee7801f9e7ffa311b391689">Derived&#x27;s vtable:
+-------------------------------+
| &amp;Derived::func1 (覆盖了Base)   |  // 条目0
+-------------------------------+
| &amp;Base::func2 (从Base继承)      |  // 条目1
+-------------------------------+
| &amp;Derived::func3 (新增的虚函数)  |  // 条目2
+-------------------------------+</div></div></div><div class="notion-text notion-block-25d3139c9ee780378596c46b6b76af08">当调用 derived_obj-&gt;func1() 时，会发生：</div><ol start="1" class="notion-list notion-list-numbered notion-block-25d3139c9ee780d5a007e8234e36277f" style="list-style-type:decimal"><li>CPU 从 derived_obj 开头取出vptr。</li></ol><ol start="2" class="notion-list notion-list-numbered notion-block-25d3139c9ee780f0bd21f2e16af3c693" style="list-style-type:decimal"><li>通过vptr找到vtable。</li></ol><ol start="3" class="notion-list notion-list-numbered notion-block-25d3139c9ee780c1ad75ea4de1e259ba" style="list-style-type:decimal"><li>在vtable的第0个条目找到func1的地址(&amp;Derived::func1)。</li></ol><ol start="4" class="notion-list notion-list-numbered notion-block-25d3139c9ee7800d8c31e4fef7f1b262" style="list-style-type:decimal"><li>跳转到该地址执行。</li></ol><div class="notion-text notion-block-25d3139c9ee78051afa0d43931e77301">虚函数调用完全依赖于对象的vptr所指向的内存数据。</div><hr class="notion-hr notion-block-25d3139c9ee78007b417f917adc4c261"/><h3 class="notion-h notion-h2 notion-h-indent-1 notion-block-25d3139c9ee78077ad03f699bfbcbf6d" data-id="25d3139c9ee78077ad03f699bfbcbf6d"><span><div id="25d3139c9ee78077ad03f699bfbcbf6d" class="notion-header-anchor"></div><a class="notion-hash-link" href="#25d3139c9ee78077ad03f699bfbcbf6d" title="例题补充（未完待续）"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">例题补充（未完待续）</span></span></h3><div class="notion-text notion-block-25d3139c9ee780f1bc58dc0aa161717d">这是2025sekaictf的一道题，题目给处了源码，直接看源码：</div><div class="notion-text notion-block-25d3139c9ee780268b24dcb9d3634fc9">这个程序是一个宠物管理系统，用户可领养狗、猫、鹦鹉、马等宠物，通过菜单进行与宠物玩耍、喂食、让其休息等互动；每次选择之后，update函数会让宠物年龄+1，饱腹感-1,年龄达到最大值或者饱腹感为0时会死亡；用户在仍有宠物时无法退出。每个宠物对象初始年龄为0，饱腹感为10，喂食会让其饱腹感为20。</div><div class="notion-text notion-block-25d3139c9ee78049ab8bc9d5e8eba5bd">由于我们控制的是堆结构，具体是哪种宠物对我们来说不重要，这里可以选择年龄上限最大的马进行创建。Animal类结构：</div><div class="notion-callout notion-gray_background_co notion-block-25d3139c9ee780b18213d37fbeb815a8"><div class="notion-page-icon-inline notion-page-icon-span"><span class="notion-page-icon" role="img" aria-label="💡">💡</span></div><div class="notion-callout-text"><div class="notion-text notion-block-25d3139c9ee780c58d37f19bfa655c16">+-----------------------+
|       vptr (8字节)     |  --&gt; 指向 Animal 的虚函数表
+-----------------------+
|   name[0x100] (256字节)|
|                       |
|                       |
+-----------------------+
|       age (4字节)      |
+-----------------------+
|    fullness (4字节)    |
+-----------------------+
|     status (4字节)     |
+-----------------------+
|    填充 (4字节)         |  // 为了8字节对齐
+-----------------------+</div></div></div><div class="notion-text notion-block-25d3139c9ee780ec8ca1dd881dbbc653">Animal vtable:</div><div class="notion-callout notion-gray_background_co notion-block-25d3139c9ee780f1b431dabac017fdc9"><div class="notion-page-icon-inline notion-page-icon-span"><span class="notion-page-icon" role="img" aria-label="💡">💡</span></div><div class="notion-callout-text"><div class="notion-text notion-block-25d3139c9ee780008a93f2fe95f9dc13">+-----------------------+
|    &amp;Animal::eat       |
+-----------------------+
|    &amp;Animal::sleep     |
+-----------------------+
|    &amp;Animal::play      |
+-----------------------+
|    &amp;Animal::get_max_age| (纯虚函数，实际为0或占位符)
+-----------------------+</div></div></div><div class="notion-text notion-block-25d3139c9ee780269880cdf63929d9c9">HORSE vtable:</div><div class="notion-callout notion-gray_background_co notion-block-25d3139c9ee780529186ffffe7af5dd9"><div class="notion-page-icon-inline notion-page-icon-span"><span class="notion-page-icon" role="img" aria-label="💡">💡</span></div><div class="notion-callout-text"><div class="notion-text notion-block-25d3139c9ee780eb9af5fb3c7a2b5c53">+-----------------------+
|    &amp;Horse::eat        |  // 重写Animal::eat
+-----------------------+
|    &amp;Horse::sleep      |  // 重写Animal::sleep
+-----------------------+
|    &amp;Horse::play       |  // 重写Animal::play
+-----------------------+
|    &amp;Horse::get_max_age|  // 实现纯虚函数
+-----------------------+</div></div></div><div class="notion-text notion-block-25d3139c9ee780108940d5d2c1b81588">观察函数，Animal类中set_name()的std::cin &gt;&gt; this-&gt;name没有控制字节，存在堆溢出；die()函数会输出name的内容，并且name起始位置实在堆地址+8的位置，故无法通过tachebin或者fastbin泄露fd,于是想到unsortedbin泄露bk，从而获取libc。动调很容易看出一个HORSE对象占用0x120字节，堆溢出可以修改size,想要其分配到unsortedbin至少大小为0x480,分配4个堆块b、c、d、e,这四个堆块之前分配一个堆块a用于溢出改写下一个chunk的size,最后面还要分配一个堆块f防止和top_chunk合并，一共分配6个堆块。泄露libc大致过程：</div><ul class="notion-list notion-list-disc notion-block-25d3139c9ee780ea8ed2ce984a031a08"><li>分配a,b,c,d,e,f堆块，每个堆块可以溢出控制其age和fullness为合适的值让其在某一时刻被free</li></ul><ul class="notion-list notion-list-disc notion-block-25d3139c9ee780f281bec735190cf8a2"><li>6次操作后a刚好free掉，再次new()可复用a，溢出改写b的size为0x481</li></ul><ul class="notion-list notion-list-disc notion-block-25d3139c9ee780dcb4f2c66a560cbefd"><li>b被free，b、c、d、e一起进入unsortedbin</li></ul><ul class="notion-list notion-list-disc notion-block-25d3139c9ee780d48d0af06dd86d6db4"><li>new()操作unsortedbin分割，b被复用，c堆块被写入fd、bk,也就是name开始8字节变成bk的值</li></ul><ul class="notion-list notion-list-disc notion-block-25d3139c9ee780ae8bcdc273f0696022"><li>c的fullness变成0，输出其name再被free,成功泄露libc</li></ul><div class="notion-text notion-block-25d3139c9ee7808db3ccefe6dcc084ac">后面伪造vtable暂时还没写出来，后面补充。</div><hr class="notion-hr notion-block-2663139c9ee780d4b3eae72fbc56dbc3"/><div class="notion-text notion-block-2663139c9ee7805b8dd8f2189304aa51">补充来了👇：</div><div class="notion-text notion-block-2663139c9ee780f4bc8dc5654b76f963">这题既然题目给出libc和动态链接器，所以就用题目的吧，先patch一下，先把libc和动态连接器文件放到题目可执行文件所在目录下，接着输入：</div><div class="notion-blank notion-block-2663139c9ee780f09b26c852ae04021c"> </div><hr class="notion-hr notion-block-25d3139c9ee7808cb39ddb916c113ec0"/><blockquote class="notion-quote notion-block-25d3139c9ee780cda375da77a9e5ba31"><div>参考：<a class="notion-link" href="https://ctf-wiki.org/pwn/linux/user-mode/io-file/introduction/#file_1" target="_blank" rel="noopener noreferrer">FILE结构 - CTF Wiki</a></div></blockquote><div class="notion-blank notion-block-25d3139c9ee78032b029fc5e3de14051"> </div><div class="notion-blank notion-block-25d3139c9ee7801b93a8ddfd38d96bb2"> </div></main></div>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[SQL注入学习]]></title>
            <link>http://estara.blog/article/2633139c-9ee7-803e-8fb7-dd793b9b0cad</link>
            <guid>http://estara.blog/article/2633139c-9ee7-803e-8fb7-dd793b9b0cad</guid>
            <pubDate>Wed, 03 Sep 2025 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[堆练习wp（暑假）]]></title>
            <link>http://estara.blog/article/23d3139c-9ee7-80ac-9db7-ed81c404f574</link>
            <guid>http://estara.blog/article/23d3139c-9ee7-80ac-9db7-ed81c404f574</guid>
            <pubDate>Sun, 27 Jul 2025 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<div id="notion-article" class="mx-auto overflow-hidden "><main class="notion light-mode notion-page notion-block-23d3139c9ee780ac9db7ed81c404f574"><div class="notion-viewport"></div><div class="notion-collection-page-properties"></div><div class="notion-callout notion-gray_background_co notion-block-23d3139c9ee78099bf8ce6f5f5937e54"><div class="notion-page-icon-inline notion-page-icon-span"><span class="notion-page-icon" role="img" aria-label="💡">💡</span></div><div class="notion-callout-text"><div class="notion-text notion-default_background notion-block-23d3139c9ee780a59042e85093f2b108">续之前在<a class="notion-link" href="https://www.yuque.com/g/yuqueyonghug5dsz5/naxzu7/db0aqgqhlr9ky9ri/collaborator/join?token=pkzQ96rQZlaXifdu#" target="_blank" rel="noopener noreferrer">语雀的文章</a></div></div></div><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-23d3139c9ee780b7a4efe09dd1497a61" data-id="23d3139c9ee780b7a4efe09dd1497a61"><span><div id="23d3139c9ee780b7a4efe09dd1497a61" class="notion-header-anchor"></div><a class="notion-hash-link" href="#23d3139c9ee780b7a4efe09dd1497a61" title="2025NepCTF ASTRAY"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">2025NepCTF ASTRAY</span></span></h2><blockquote class="notion-quote notion-block-2453139c9ee780719e76db9125cde43f"><div>这道题逆向难度挺大的，本人复现的时候也是花了将近半天才把程序的整个逻辑和结构搞明白</div></blockquote><div class="notion-text notion-block-2453139c9ee7802c9710d2adab6c763b">checksec保护全开</div><h3 class="notion-h notion-h2 notion-h-indent-1 notion-block-2453139c9ee780199e93f3c674a2574f" data-id="2453139c9ee780199e93f3c674a2574f"><span><div id="2453139c9ee780199e93f3c674a2574f" class="notion-header-anchor"></div><a class="notion-hash-link" href="#2453139c9ee780199e93f3c674a2574f" title="分析"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">分析</span></span></h3><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-2453139c9ee780a3b372f10473b6db10" data-id="2453139c9ee780a3b372f10473b6db10"><span><div id="2453139c9ee780a3b372f10473b6db10" class="notion-header-anchor"></div><a class="notion-hash-link" href="#2453139c9ee780a3b372f10473b6db10" title="main函数"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">main函数</span></span></h4><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-2453139c9ee78086b1e6e24da8af69c0" data-id="2453139c9ee78086b1e6e24da8af69c0"><span><div id="2453139c9ee78086b1e6e24da8af69c0" class="notion-header-anchor"></div><a class="notion-hash-link" href="#2453139c9ee78086b1e6e24da8af69c0" title="init函数"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">init函数</span></span></h4><div class="notion-text notion-block-2453139c9ee7800599e0deb6b5da5341">首先malloc了一个超级大的堆块chunk1，以malloc过来的地址为起始，每隔256字节为一个地址，按顺序存放在位于bss段的manage_physic数组中（相当于把这个大堆块分割成等大的小堆块）；dword_4068数组下标1-9元素为2，10-19为3,0下标对应16；qword_41a8处存放了新malloc的chunk2地址并对chunk2作了初始化；chunk1往后16字节处存放onlyuser的地址，往后8字节处存放再次malloc的chunk3地址，并对chunk3作初始化，chunk1[0]变为1。</div><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-2453139c9ee780a5a99fdce20c3155a6" data-id="2453139c9ee780a5a99fdce20c3155a6"><span><div id="2453139c9ee780a5a99fdce20c3155a6" class="notion-header-anchor"></div><a class="notion-hash-link" href="#2453139c9ee780a5a99fdce20c3155a6" title="manager_operation函数"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">manager_operation函数</span></span></h4><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-2453139c9ee78046bed9e5f23bec7a93" data-id="2453139c9ee78046bed9e5f23bec7a93"><span><div id="2453139c9ee78046bed9e5f23bec7a93" class="notion-header-anchor"></div><a class="notion-hash-link" href="#2453139c9ee78046bed9e5f23bec7a93" title="check函数"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">check函数</span></span></h4><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-2453139c9ee780d48e41ebdfd6d47947" data-id="2453139c9ee780d48e41ebdfd6d47947"><span><div id="2453139c9ee780d48e41ebdfd6d47947" class="notion-header-anchor"></div><a class="notion-hash-link" href="#2453139c9ee780d48e41ebdfd6d47947" title="permission_confirm函数"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">permission_confirm函数</span></span></h4><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-2453139c9ee780bc861bc45385da9804" data-id="2453139c9ee780bc861bc45385da9804"><span><div id="2453139c9ee780bc861bc45385da9804" class="notion-header-anchor"></div><a class="notion-hash-link" href="#2453139c9ee780bc861bc45385da9804" title="checkvisit函数"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">checkvisit函数</span></span></h4><h4 class="notion-h notion-h3 notion-h-indent-2 notion-block-2453139c9ee78026a62bf1a23fe0571d" data-id="2453139c9ee78026a62bf1a23fe0571d"><span><div id="2453139c9ee78026a62bf1a23fe0571d" class="notion-header-anchor"></div><a class="notion-hash-link" href="#2453139c9ee78026a62bf1a23fe0571d" title="user_operation函数"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">user_operation函数</span></span></h4><div class="notion-text notion-block-2453139c9ee780558b45ceed60dc8f24">函数比较多，文字解释不如图形象生动👇：</div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-2463139c9ee78037a886ca1c26a5b628"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column;height:100%"><img style="object-fit:cover" src="https://www.notion.so/image/attachment%3A37ca69ea-c22e-4d20-a801-8f4cbe5afd7a%3Aimage.png?table=block&amp;id=2463139c-9ee7-8037-a886-ca1c26a5b628&amp;t=2463139c-9ee7-8037-a886-ca1c26a5b628" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-callout notion-gray_background_co notion-block-2453139c9ee78043b6b4fed1f162798e"><div class="notion-page-icon-inline notion-page-icon-span"><span class="notion-page-icon" role="img" aria-label="💡">💡</span></div><div class="notion-callout-text"><ul class="notion-list notion-list-disc notion-block-2453139c9ee7806896bfebc5d6532a16"><li><b>MANAGER 操作</b></li><ul class="notion-list notion-list-disc notion-block-2453139c9ee7806896bfebc5d6532a16"><li>MANAGER_visit（opcode1=8）</li><ul class="notion-list notion-list-disc notion-block-2453139c9ee78048aabfd5669031300c"><li>📖 读取：opcode1=6 → user_chunk →choose_chunk</li><li>📝 写入：opcode1=3 → user_chunk →choose_chunk</li></ul><li>MANAGER_read（opcode1=4）：📖 从 manager_chunk中choose_chunk指向位置读取</li><li>MANAGER_write（opcode1=2）:📝 从 manager_chunk中choose_chunk指向位置写入</li></ul></ul><ul class="notion-list notion-list-disc notion-block-2453139c9ee780748072d5cefbd742ea"><li><b>UER 操作</b></li><ul class="notion-list notion-list-disc notion-block-2453139c9ee780748072d5cefbd742ea"><li>UER_read（opcode2=4）：📖 从 user_chunk中choose_chunk指向位置 读取</li><li>UER_write（opcode2=1）：📝 从 user_chunk中choose_chunk指向位置写入</li></ul></ul></div></div><div class="notion-text notion-block-2453139c9ee7804cb243d72d7779007d">其中check函数中MANAGER_write和USER_write操作会进行权限检查，MANAGER_write操作要求chunk2+8的地方为2，USER_chunk要求chunk3+8的地方为3。</div><h3 class="notion-h notion-h2 notion-h-indent-1 notion-block-2463139c9ee780288387daeb72e36b8b" data-id="2463139c9ee780288387daeb72e36b8b"><span><div id="2463139c9ee780288387daeb72e36b8b" class="notion-header-anchor"></div><a class="notion-hash-link" href="#2463139c9ee780288387daeb72e36b8b" title="解题思路"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">解题思路</span></span></h3><ul class="notion-list notion-list-disc notion-block-2463139c9ee780239fd8dd24d1f18037"><li>无论是manager操作还是user操作，都没有对数组下标进行检查，也就是说若输入堆序列为0，程序并不会报错，而manager_read是不会进行权限检查的，利用manager_read可以直接泄露出chunk1中的&amp;manager_chunk和&amp;onlyuser，相当于泄露了堆地址和pie基地址。</li></ul><div class="notion-blank notion-block-2473139c9ee7807bbc78cc9f9df7b9d5"> </div><ul class="notion-list notion-list-disc notion-block-2473139c9ee780199e99e5643e6f5d4c"><li>从图中可以看出，下标为0的chunk（这里叫做key_chunk）是个关键，因为这里存放着可以控制写入的地址，一旦&amp;manager_chunk和&amp;onlyuser的值被篡改就会造成任意地址写，而二者定是要通过write功能修改，manager_write要求chunk1+8处为2，但是对于key_chunk，chunk1+8为最为特殊的值16，不可行；user_write同理；那么唯一的路径就是通过manager_visit中的write功能了。从manager功能入手，check函数manager_visit会有这么一个检查:<code class="notion-inline-code">!strcmp(a2, &quot;MANAGER_visit&quot;) &amp;&amp; !*(_QWORD *)qword_41A8</code> ,也就是说chunk3中的&amp;choose_chunk必须存在，要先进入user功能进行操作，checkvisit函数要求opcode2不能为4(不能读操作），user功能也允许manager操作，所以先进入user选择user_write返回opcode2为2，再用user功能选择manager_visit返回opcode2=8,然后利用manager功能选择manager_visit_write,就可绕过检查实现往key_chunk的写入。</li></ul><div class="notion-blank notion-block-2483139c9ee780dabd19e442e84a018a"> </div><ul class="notion-list notion-list-disc notion-block-2483139c9ee780b88b22f8213d6c3058"><li>修改了&amp;onlyuser使得manager_visit_write写入操作具有局限性，故可利用两次机会修改dword_4068[0]中的16，更改后的值&amp;2返回值非零，这样便可无限利用manager_write了。第一次往key_chunk写入，这里存在多级指针<code class="notion-inline-code">&amp;onlyuser+8→&amp;chunk3→&amp;choose_chunk→写入的地方</code> ，于是往key_chunk写入的时候，前16字节填充，从&amp;onlyuser开始，依次改为<code class="notion-inline-code">p64(&amp;chunk1+0x18)+p64(&amp;chunk1+0x28)+p64(dword_4068的地址)</code>,逻辑即为&amp;chunk1+0x18+0x8处指向&amp;chunk1+0x28处，&amp;chunk1+0x28处又指向dword_4068。第二次manager_visit_write会根据&amp;chunk1+0x18处的值，即往dword_4068写入，这里将16改为0xf。</li></ul><div class="notion-blank notion-block-2483139c9ee78040af91f1d01c86cc60"> </div><ul class="notion-list notion-list-disc notion-block-2483139c9ee780c7a6e3e6c8332e2545"><li>理解上一步之后后面就比较轻松了，利用manager_write修改&amp;chunk1+0x18指向puts_got,利用manager_visit_read泄露libc。因为这题不能覆写got表因此想到返回地址的修改，返回地址的修改依靠栈地址的泄露，于是想到用libc找到environ的真实地址，然后再次manager_write往key_chunk写入修改&amp;chunk1+0x18指向environ,manager_visit_read泄露出栈地址。</li></ul><details class="notion-toggle notion-block-2483139c9ee78055a72be492dfc5893c"><summary>关于environ：</summary><div><ul class="notion-list notion-list-disc notion-block-2483139c9ee78042932ddc5046884ca4"><li>environ 通常指代 C 标准库中的全局变量 _environ，它指向程序的环境变量数组。</li></ul><ul class="notion-list notion-list-disc notion-block-2483139c9ee78040a5a6d866446eecec"><li>通过读取 _environ 的值，可以获得环境变量的地址。由于环境变量存储在栈上，可以利用这个地址计算出栈的基址，从而进一步泄露其他敏感信息（如返回地址、函数地址等）。</li></ul><div class="notion-blank notion-block-2483139c9ee78096b356d75e4beebc0d"> </div><div class="notion-text notion-block-2483139c9ee7808ca12fe5d7637a4e96">   </div><div class="notion-blank notion-block-2483139c9ee780bba5d4e75e0056c401"> </div></div></details><div class="notion-blank notion-block-2473139c9ee78088aebfdd7475f3d520"> </div><ul class="notion-list notion-list-disc notion-block-2473139c9ee780d2b3ccfde66f25ea74"><li>根据偏移找到存放manager_operation函数返回地址的栈地址，利用manager_write修改&amp;chunk1+0x18指向返回地址，利用manager_visit_write改返回地址为rop链即可。</li></ul><div class="notion-text notion-block-2483139c9ee780e6814af43ac071d1b6">关于偏移的寻找，动调即可，如下图在main函数调用manager_operation时刻：</div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-2483139c9ee7806798cff1e5ef8cb53e"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column;height:100%"><img style="object-fit:cover" src="https://www.notion.so/image/attachment%3A46451d58-df5a-464b-a55a-b49111ac4de2%3Aimage.png?table=block&amp;id=2483139c-9ee7-8067-98cf-f1e5ef8cb53e&amp;t=2483139c-9ee7-8067-98cf-f1e5ef8cb53e" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-text notion-block-2483139c9ee78003a582c8500ba1a78a">下一条指令地址即为返回地址，s进入operation函数，如下图看到返回地址存放的栈地址和泄露出的栈地址偏移为0xbc0-0xa78=0x148：</div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-2483139c9ee7809cb8ffff693356eafc"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column;height:100%"><img style="object-fit:cover" src="https://www.notion.so/image/attachment%3Af5f7cee8-840b-4641-8ec6-fce0ce6676e3%3Aimage.png?table=block&amp;id=2483139c-9ee7-809c-b8ff-ff693356eafc&amp;t=2483139c-9ee7-809c-b8ff-ff693356eafc" alt="notion image" loading="lazy" decoding="async"/></div></figure><h3 class="notion-h notion-h2 notion-h-indent-1 notion-block-2483139c9ee780859738d3c6c27cd432" data-id="2483139c9ee780859738d3c6c27cd432"><span><div id="2483139c9ee780859738d3c6c27cd432" class="notion-header-anchor"></div><a class="notion-hash-link" href="#2483139c9ee780859738d3c6c27cd432" title="exp:"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">exp:</span></span></h3><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-2473139c9ee7800fa2fdf29f7a144569" data-id="2473139c9ee7800fa2fdf29f7a144569"><span><div id="2473139c9ee7800fa2fdf29f7a144569" class="notion-header-anchor"></div><a class="notion-hash-link" href="#2473139c9ee7800fa2fdf29f7a144569" title="buuctf hitcontraining_magicheap 1"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">buuctf hitcontraining_magicheap 1</span></span></h2><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-25d3139c9ee78027b14be458a4caa56a"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column;height:100%"><img style="object-fit:cover" src="https://www.notion.so/image/attachment%3Aba6ce0a9-42a2-4538-935c-426973c40d7a%3Aimage.png?table=block&amp;id=25d3139c-9ee7-8027-b14b-e458a4caa56a&amp;t=25d3139c-9ee7-8027-b14b-e458a4caa56a" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-text notion-block-25d3139c9ee780fe9568cad3213a4466">create_heap:</div><div class="notion-text notion-block-25d3139c9ee7808d92b9c2c65d9ec382">edit_heap:</div><div class="notion-text notion-block-25d3139c9ee78062842be3a159124ef6">delete_heap():</div><div class="notion-text notion-block-25d3139c9ee780ea9eadc92235f55063">133t()是后门函数。</div><div class="notion-text notion-block-25d3139c9ee780259e69d6779fe47481">还是那几个功能就不多说了，漏洞依然在edit函数size没有做检查，存在堆溢出。magic位于bss段0x6020a0处，初始值为0，大于0x1305就执行后门，利用fastbin attack就行，前面都说过了，这里简单说一下思路吧：</div><div class="notion-text notion-block-25d3139c9ee7803ca73bd4dac2c40fe8">1.分配3个0x60大小的堆块</div><div class="notion-text notion-block-25d3139c9ee78046982ee10028ccd817">2.释放第2个堆块使其进入fastbins</div><div class="notion-text notion-block-25d3139c9ee780c69751eee1378e32cd">3.编辑第1个堆块，溢出修改第2个堆块的fd指向magic附近，依旧是利用错位思想构造size</div><div class="notion-text notion-block-25d3139c9ee780adacd8f70cb16c27b6">4.连续两次malloc，第2次malloc的堆块是fake_chunk,写入修改magic的值大于0x1305即可</div><div class="notion-text notion-block-25d3139c9ee780b18b60eab36e1b5eb8">伪造的chunk位于0x60209d处，fd改为0x60208d：</div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-25d3139c9ee7809aa964da4ab2947199"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column;height:100%"><img style="object-fit:cover" src="https://www.notion.so/image/attachment%3A53d7a6cc-6c75-4f65-8268-28a39abdf6cc%3Aimage.png?table=block&amp;id=25d3139c-9ee7-809a-a964-da4ab2947199&amp;t=25d3139c-9ee7-809a-a964-da4ab2947199" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-text notion-block-25d3139c9ee780b4ab60d0b4834a442a">exp:</div></main></div>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[pwn知识点复习和拓展]]></title>
            <link>http://estara.blog/article/2693139c-9ee7-800d-8d16-c168caa96f55</link>
            <guid>http://estara.blog/article/2693139c-9ee7-800d-8d16-c168caa96f55</guid>
            <pubDate>Tue, 09 Sep 2025 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[tachebins相关知识]]></title>
            <link>http://estara.blog/article/2453139c-9ee7-8048-a236-c073ce12594c</link>
            <guid>http://estara.blog/article/2453139c-9ee7-8048-a236-c073ce12594c</guid>
            <pubDate>Sun, 24 Aug 2025 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<div id="notion-article" class="mx-auto overflow-hidden "><main class="notion light-mode notion-page notion-block-2453139c9ee78048a236c073ce12594c"><div class="notion-viewport"></div><div class="notion-collection-page-properties"></div><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-25d3139c9ee7804c8f19cce41dc68c84" data-id="25d3139c9ee7804c8f19cce41dc68c84"><span><div id="25d3139c9ee7804c8f19cce41dc68c84" class="notion-header-anchor"></div><a class="notion-hash-link" href="#25d3139c9ee7804c8f19cce41dc68c84" title="基础知识"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">基础知识</span></span></h2><div class="notion-text notion-block-25d3139c9ee780fb8d68d2c5ca0a8111">Tcache(Thread Local Caching)，即<b>线程本地缓存</b>，是 glibc（从版本2.26开始）引入的一种性能优化机制。</div><ul class="notion-list notion-list-disc notion-block-25d3139c9ee780aeb78ce95a34bee796"><li><b>目的</b>： 提升堆内存分配的性能。在多线程程序中，传统的堆分配需要频繁地对主堆区（main_arena）进行加锁和解锁操作，这在多核高并发场景下会成为性能瓶颈。</li></ul><ul class="notion-list notion-list-disc notion-block-25d3139c9ee78050ab35e1e79b89352b"><li><b>核心思想</b>： 为每个线程预先分配一个专属的、无锁的缓存池。当线程需要分配小块内存时，优先从这个缓存池中获取；释放时也优先放回这个缓存池。这样就避免了与其他线程竞争全局堆锁，大大加快了分配和释放的速度。</li></ul><div class="notion-text notion-block-25d3139c9ee7807fb529d777f9d6f2db">Tcache的管理是通过一系列单向链表来实现的，这些链表被称为<b>tcache bins</b>。</div><ul class="notion-list notion-list-disc notion-block-25d3139c9ee780a4a5c0ef289a6b8f19"><li><b>数量与大小</b>：</li><ul class="notion-list notion-list-disc notion-block-25d3139c9ee780a4a5c0ef289a6b8f19"><li>默认有64个tcache bins。</li><li>每个 bin 负责一个特定大小的内存块。</li><li>bin 0 -&gt; 负责24字节的 chunk（在 64 位系统上，考虑对齐后的实际大小）</li><li>bin 1 -&gt; 负责32字节的 chunk</li><li>bin 2 -&gt; 负责40字节的 chunk</li><li>...</li><li>bin 63 -&gt; 负责1032字节的 chunk</li></ul></ul><ul class="notion-list notion-list-disc notion-block-25d3139c9ee7802a9208d6428d478c9f"><li><b>数据结构</b>：</li></ul><div class="notion-text notion-block-25d3139c9ee7809e9a09eafef1b7c302">   在每个线程的堆管理结构中，有一个名为<b>tcache_perthread_struct</b>的关键结构：</div><ol start="1" class="notion-list notion-list-numbered notion-block-25d3139c9ee780b1acc2c4b1a6aafbc1" style="list-style-type:decimal"><li><b>counts[i]</b>： 记录第i个bin中当前有多少个chunk,每个bin的容量上限是7个chunk。</li></ol><ol start="2" class="notion-list notion-list-numbered notion-block-25d3139c9ee7801c9e83e91e9a53a047" style="list-style-type:decimal"><li><b>entries[i]</b>：指向一个单向链表，链表中的每个节点都是一个空闲的堆块。</li></ol><ul class="notion-list notion-list-disc notion-block-25d3139c9ee78036ba29e6118e593094"><li><b>链表结构 (tcache_entry)</b>：</li></ul><div class="notion-text notion-block-25d3139c9ee780f89be2ef84db395127">Tcache bins是单向链表。每个被释放并放入tcache的chunk，其用户数据区域的开头</div><div class="notion-text notion-block-25d3139c9ee780fa819cfc2e03b18be5">会被当作一个tcache_entry结构体：</div><div class="notion-text notion-block-25d3139c9ee7808aa741d140766a62d5">这与fastbin中的fd类似。</div><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-25d3139c9ee780f08f69cbdc7fd2ab6c" data-id="25d3139c9ee780f08f69cbdc7fd2ab6c"><span><div id="25d3139c9ee780f08f69cbdc7fd2ab6c" class="notion-header-anchor"></div><a class="notion-hash-link" href="#25d3139c9ee780f08f69cbdc7fd2ab6c" title="攻击手法"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">攻击手法</span></span></h2><ul class="notion-list notion-list-disc notion-block-25d3139c9ee7800ca432c50de0995d03"><li>tache poisoning</li></ul><div class="notion-text notion-block-25d3139c9ee780cb9187df008bd64493">   基本原理是通过覆盖next为控制的地址并利用malloc得到写入权限，并且目标地址无需伪造合适的size</div><ul class="notion-list notion-list-disc notion-block-25d3139c9ee7803fb48ff349279d47a6"><li>tache dup</li></ul><div class="notion-text notion-block-25d3139c9ee780ac9cbdccdbe60d42de">   利用tache_put()函数不严谨：</div><div class="notion-text notion-block-25d3139c9ee780648e48d9042ef308cd">该函数没有做任何检查，于是可以修改counts数组中的值，也可以对同一个chunk进行多次free，进而泄露堆地址。</div><ul class="notion-list notion-list-disc notion-block-25d3139c9ee780e38b31e2046d774bdf"><li>tache house of spirit</li></ul><div class="notion-text notion-block-25d3139c9ee780e0af85cd51997cd7e1">  （这个笔者暂时还没学到，以后补充）</div><hr class="notion-hr notion-block-2623139c9ee780189ea5c6826ae01362"/><div class="notion-text notion-block-2623139c9ee78098b5ead7cf07f21004">这里补充一点，在glibc2.29及其之后，链表结构就变了：</div><div class="notion-text notion-block-2623139c9ee7800daa24f1f5630bf1eb">新引入的key字段正是针对攻击者对同一块chunk多次释放的轻量级缓解措施：</div><ul class="notion-list notion-list-disc notion-block-2623139c9ee780ca8f86d9764590621c"><li>当一个chunk被放入tachebins时，除了设置next指针，还会添加key字段设置为指向这个 tcache所属的主管理结构（tcache_perthread_struct）的地址,作为已经释放的标记。</li></ul><ul class="notion-list notion-list-disc notion-block-2623139c9ee780dba498facb0bfa1139"><li><b>在再次释放时</b>：当free函数尝试再次释放同一个chunk时，它会检查该chunk的key字段,如果key字段的值等于当前线程的tcache_perthread_struct的地址，这就意味着这个chunk 已经在这个tcache的空闲链表里了,glibc 会立即检测到这是一个 Double Free 行为，并终止程序。</li></ul><div class="notion-text notion-block-2623139c9ee78076a1e1df5fd8c8b306">除此之外，还有另外一种保护措施Safe-Linking(指针加密）。</div><div class="notion-text notion-block-2623139c9ee78035947ac7cf4a5a8e3c">Safe-Linking 对每个放入Tcache链表的next指针进行了一个轻量级的加密处理，在从链表中取出时再进行解密。</div><ul class="notion-list notion-list-disc notion-block-2623139c9ee78019940adc27487de099"><li><b>加密（当chunk被free并放入链表时）：</b></li><ul class="notion-list notion-list-disc notion-block-2623139c9ee78019940adc27487de099"><div class="notion-text notion-block-2623139c9ee780d2a60cdd50e8c0c2ab">存储的next指针不再是真正的下一个chunk的地址，而是：</div><div class="notion-text notion-block-2623139c9ee780109cdad0733cf4bafe"><code class="notion-inline-code">加密后的_next = (真正的_next &gt;&gt; 12) ^ 当前 chunk 的地址</code></div></ul></ul><ul class="notion-list notion-list-disc notion-block-2623139c9ee780fbba84e4ade629dc38"><li><b>解密（当chunk被malloc并从链表中取出时）：</b></li><ul class="notion-list notion-list-disc notion-block-2623139c9ee780fbba84e4ade629dc38"><div class="notion-text notion-block-2623139c9ee780c197f8deb638024e9c">程序会从链表头取出chunk，然后根据存储的加密值，计算出真正的next指针：</div><div class="notion-text notion-block-2623139c9ee780b586c6db5fde9132ac"><code class="notion-inline-code">真正的_next = (加密后的_next ^ 当前 chunk 的地址) &lt;&lt; 12</code> </div></ul></ul><div class="notion-text notion-block-2623139c9ee780afa6c7e6669fc5c6bb">这就给tache poisoning攻击手法造成了极大困难。</div><hr class="notion-hr notion-block-2623139c9ee780b98bf1ebb416ae1c02"/><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-25d3139c9ee78068b7fdc83b9f4a0364" data-id="25d3139c9ee78068b7fdc83b9f4a0364"><span><div id="25d3139c9ee78068b7fdc83b9f4a0364" class="notion-header-anchor"></div><a class="notion-hash-link" href="#25d3139c9ee78068b7fdc83b9f4a0364" title="例题"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">例题</span></span></h2><div class="notion-text notion-block-25d3139c9ee7809c9996d1cb9f06bf9a">题目给出了源码，直接分析源码：</div><div class="notion-text notion-block-25d3139c9ee780f2b539cb96c0e1e62c">这段代码实现了一个简单的字符画布交互程序，主要功能如下：</div><ol start="1" class="notion-list notion-list-numbered notion-block-25d3139c9ee7802eaa40f93f500b470f" style="list-style-type:decimal"><li>初始化一个默认 20x20 的字符画布，画布上的元素默认用 &#x27;.&#x27; 表示。</li></ol><ol start="2" class="notion-list notion-list-numbered notion-block-25d3139c9ee7809abf4edd9540b5fe75" style="list-style-type:decimal"><li>提供交互式命令操作，支持以下功能：</li><ol class="notion-list notion-list-numbered notion-block-25d3139c9ee7809abf4edd9540b5fe75" style="list-style-type:lower-alpha"><ul class="notion-list notion-list-disc notion-block-25d3139c9ee780d0966feb8157e1760c"><li>绘制（p命令）：在指定坐标 (arg1, arg2) 处绘制十六进制字符arg3。</li></ul><ul class="notion-list notion-list-disc notion-block-25d3139c9ee78066878dc5659ce395e8"><li>调整大小（r命令）：将画布重新设置为 arg1 x arg2的尺寸，同时清空画布内容。</li></ul><ul class="notion-list notion-list-disc notion-block-25d3139c9ee7807b8cccf0c555478b03"><li>帮助（h命令）：显示操作说明。</li></ul><ul class="notion-list notion-list-disc notion-block-25d3139c9ee780ee95d2ec2febf6134a"><li>退出（e命令）：结束程序。</li></ul></ol></ol><div class="notion-text notion-block-25d3139c9ee780b58c7dc4cc5c2a07a3"> 3. 实时显示当前画布状态，并等待用户输入下一个操作命令。</div><div class="notion-text notion-block-25d3139c9ee780fb8365e831a29d0d19">这个程序存在一个很明显的漏洞就是没有对数组下标做检查，可以实现越界读写，于是我们可以想到利用越界读写修改tache结构体，使其分配到指定位置。</div><div class="notion-text notion-block-25d3139c9ee78027a05ee73c64783d35">主要利用思路：</div><ul class="notion-list notion-list-disc notion-block-25d3139c9ee780f4ae82daf03f15bb72"><li>绘制画布，利用数组越界改写tache结构体中0x20位置的count为1，对应的指针改成got表附近的地址，避免画布清空覆盖got表</li></ul><ul class="notion-list notion-list-disc notion-block-25d3139c9ee7802cb56bf42fc4f5c5ed"><li>调整画布大小为0x20,越界覆写free地址为printf</li></ul><ul class="notion-list notion-list-disc notion-block-25d3139c9ee78041ba81e7c3b4b723be"><li>绘制当前画布，从开头写入格式化字符串</li></ul><ul class="notion-list notion-list-disc notion-block-25d3139c9ee7809da024eaac34d0df3c"><li>调整画布为20x20，此时调用free，触发printf格式化字符串漏洞泄露栈上的libc_start_main地址，进而泄露libc;目前堆块的位置仍在最开始的20x20的堆处</li></ul><ul class="notion-list notion-list-disc notion-block-25d3139c9ee780b19987d1c52a5f4c59"><li>再次绘制画布，将tache结构体0x20的count仍改为1，对应指针改成got附近的地址</li></ul><ul class="notion-list notion-list-disc notion-block-25d3139c9ee78010bed6c7cfc8c29d62"><li>调整画布大小为0x20,越界覆写free地址为system</li></ul><ul class="notion-list notion-list-disc notion-block-25d3139c9ee7809d9358eb06f1e159f6"><li>绘制当前画布，从开头写入/bin/sh</li></ul><ul class="notion-list notion-list-disc notion-block-25d3139c9ee780039cdbe8fdf1922a55"><li>输入命令h，调用free,执行system(”/bin/sh”)</li></ul><div class="notion-text notion-block-25d3139c9ee7804a93a2d798a3a08fe2">exp:</div><div class="notion-blank notion-block-25d3139c9ee7808b93e1e79c0646c2c8"> </div></main></div>]]></content:encoded>
        </item>
    </channel>
</rss>