Skip to content

修改 fin_array

复制本地路径 | 在线编辑

有时我们有一次任意写的机会, 但总会感觉似乎威力不够, 此时可以通过修改 fin_array 来实现任意写.

fin_array_libc_csu_fini 中, 这个函数会在 main 函数结束后执行.

下面以 pwnable.tw 的 3x17 题目为例.

__int64 _libc_csu_fini()
{
    signed __int64 index; // rbx

    // 右移 3 位的目的: 除以 8
    // (4B4100 - 4B40F0) / 8 = 2,所以该函数一共执行 2 次子函数: fin_arr[1], fin_arr[0]
    if ( (&unk_4B4100 - (_UNKNOWN *)off_4B40F0) >> 3 )
    {
        // 0x4B40F0 为 fin_array 存放位置
        // 通过代码可发现, 逆序执行, 先执行 fin_arr[1]
        index = ((&unk_4B4100 - (_UNKNOWN *)off_4B40F0) >> 3) - 1;
        do
            off_4B40F0[index--]();
        while ( index != -1 );
    }
    return sub_48E32C();
}

注意 fin_array 是逆序执行, 由于 main 函数中我们有一次任意写的机会, 所以采用如下方法:

  • 程序执行 main, 需要把 fin_array[1] 更改为 main 函数, fin_array[0] 改为 libc_csu_fin 函数.
  • 程序执行 libc_csu_fin, 执行 fin_array[1]main, 我们有一次任意写的机会, 此时可以修改任意地址内容.
  • 之后执行 fin_array[0]libc_csu_fin, 通过上面代码可知, 会再一次执行 fin_array[1]main.
  • 执行完 fin_array[1] 后又执行 fin_array[0]libc_csu_fin, 程序不断循环, 每一次都可以修改一次内存.
  • 当内存全部修改完毕, 在 main 函数中将 fin_array[0] 修改为退出函数.

需要注意的是, 我们的任意写机会要能够一次性将 fin_array[1]fin_array[0] 都修改掉, 否则无法进入上面的循环.

Comments