std::function逆向还原

std::function的内存结构

本文案例地址:https://wwmf.lanzout.com/b029diasb 密码:areg

std::function为lamda函数时

本文的代码都是32位为例

image

  • vftable

首先我们可以从Func_impl_no_alloc_V_lambda得知这是一个类型为lamda的std::function容器,把虚表赋值到对象首地址。我们将该对象的类型变更为 std::function

image

我们跳转到虚表,找到虚表的第三个虚函数

image

image

该函数正是我们的lamda函数

  • 捕获变量

看到上图,这个函数lamda函数返回的时 第一个参数 + std::function对象的第二个成员 + std::function对象的第三个成员的和,

std::function对象的第二个成员 + std::function对象的第三个成员其实就是捕获的第一个变量和第二个变量

image

上面显示第一个成员的值为1,第二个成员的值为2,它们存放在虚表指针后面

  • pStorage

    std::function对象会将对象的起始地址存放在对象的最后一个成员,这更加佐证了这是一个std::function

image

最后还原的结果为


#include <iostream>
#include <functional>

int main()
{
	int a = 1,b =2;
    std::function<int(int)> func = [a,b](int i) {return i + a +b; };
	std::cout << func(1) << std::endl;
	return 0;
}

std::function为普通函数时

image

进入sub_401400

image

看到一个虚表,虽然不是赋值到this处,但是后面肯定会复制过去的,std::_Func_impl表示这是一个std::function,后面还表明了容器类型为int (__cdecl *)(int).这种情况目标函数会存放在虚表的后面,sub_401000就是我们的目标函数了

image

回到main函数,我们将v8的类型更变为std::function

image

v3是_Ptrs的最后一个元素,这里存放的是std::function对象的首地址,通过这个地址去调用虚表的第三个函数,可调用目标函数,所以最后还原的效果为

#include <iostream>
#include <functional>


int fun1(int a) {
	std::cout << "fun1" << std::endl;
	return a;
}

int main(int argc, char* argv[]) {
    std::function<int(int)> callback;
    callback = fun1; 
    std::cout << callback(10) << std::endl;

    return 0;
}

std::function为成员函数时

std::function为成员函数与std::function为普通函数基本类似,只是成员函数的this指针会存存放到std::function对象的第四个成员处

posted @ 2023-10-20 12:23  乘舟凉  阅读(140)  评论(0编辑  收藏  举报