std::function逆向还原
本文案例地址:https://wwmf.lanzout.com/b029diasb 密码:areg
std::function为lamda函数时
本文的代码都是32位为例
- vftable
首先我们可以从Func_impl_no_alloc_V_lambda
得知这是一个类型为lamda的std::function容器,把虚表赋值到对象首地址。我们将该对象的类型变更为 std::function
我们跳转到虚表,找到虚表的第三个虚函数
该函数正是我们的lamda函数
- 捕获变量
看到上图,这个函数lamda函数返回的时 第一个参数 + std::function对象的第二个成员 + std::function对象的第三个成员的和,
std::function对象的第二个成员 + std::function对象的第三个成员其实就是捕获的第一个变量和第二个变量
上面显示第一个成员的值为1,第二个成员的值为2,它们存放在虚表指针后面
-
pStorage
std::function对象会将对象的起始地址存放在对象的最后一个成员,这更加佐证了这是一个std::function
最后还原的结果为
#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为普通函数时
进入sub_401400
看到一个虚表,虽然不是赋值到this处,但是后面肯定会复制过去的,std::_Func_impl
表示这是一个std::function,后面还表明了容器类型为int (__cdecl *)(int)
.这种情况目标函数会存放在虚表的后面,sub_401000就是我们的目标函数了
回到main函数,我们将v8的类型更变为std::function
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对象的第四个成员处