概述
众所周知,面向对象的语言都会有类似于private,protected,public之类的权限控制。其实如前一篇blog所讲(http://blog.csdn.net/cracker_zhou/article/details/70956249) :在C++中,权限只是为了在代码的运行期阻止获得变量或者某个函数的地址而达到不能调用的作用。言外之意就是只要能搞到内存地址,什么都好说。下面提供几种hack私有成员变量地址的方法。
1. 计算成员变量内存偏移
我相信对C++内存分配懂一点的小伙伴都知道这种方法。
class B
{
private:
int b;
std::string x;
char* ch;
public:
int getint(){ return b; }
std::string getstr(){ return x; }
char* getch(){ return ch; }
};
int main()
{
B b;
*(int*)&b = 20;
std::string* str = (std::string*)((long)&b + sizeof(int));
str->append("zhou");
char** ch = (char**)((long)str+sizeof(std::string));
*ch = new char('a');
std::cout << "int:" << b.getint() << std::endl // int:20
<< "str:" << b.getstr().c_str() << std::endl // str:"zhou"
<< "char*:" << *b.getch() << std::endl; // char*:'a'
delete *ch;
return 0;
}
2. 类的等效替换
上面通过计算成员变量的偏移确实可以hack内存地址,但是弊端也很明显成员变量越多,后面就越需要计算偏移,而且二重指针也很容易搞出事情。那么怎么办呢?我们只需要自定义一个拥有一样内存分布的数据结构即可。
class B
{
private:
int b;
std::string x;
char* ch;
public:
int getint(){ return b; }
std::string getstr(){ return x; }
char* getch(){ return ch; }
};
// 在此模拟一个与class B拥有相同内存分布的struct,但权限都是开放的
typedef struct
{
public:
int b;
std::string x;
char* ch;
}Proof;
int main()
{
B b;
Proof* proof = (Proof*)&b;
proof->b = 10;
proof->x.append("zhou");
proof->ch = new char('a');
std::cout << "int:" << b.getint() << std::endl // int:10
<< "str:" << b.getstr().c_str() << std::endl // str:"zhou"
<< "char*:" << *b.getch() << std::endl; // char*:'a'
delete proof->ch;
return 0;
}
3. 元编程(meta programming)
之前一直以为元编程只有python,js这种动态语言中有,但是没想到C++的元编程也很强大。概念是一样的,元编程(C++操作template,python操作type)的存在都是为了动态生成类。但是我发现一个问题:C++的模板类中传递参数时并不会校验权限问题。(比如上面中类B,当我们在运行时使用&B::b获得偏移时会直接报权限错误,但是在模板中传参并不会这样!)
// 这是一个简单的类模板传值的例子
template<typename T,typename T V>
typename T f(T)
{
return V;
}
int main()
{
std::cout << f<int,10>(int()); // 10
return 0;
}
那么如何把类成员地址传出去呢?原理是相同的。
struct A {
private:
int a;
};
// tag used to access A::a
struct A_f {
using type = int A::*;
};
template<typename Tag, typename Tag::type M>
struct Rob {
friend typename Tag::type get(Tag) {
return M;
}
};
template struct Rob<A_f, &A::a>;
int main()
{
A a;
a.*get(A_f()) = 20; // 传入A_f()纯属为了把类型传入,满足template的语法要求
std::cout << a.*get(A_f()); // 得到地址后可以进行get和set操作
return 0;
}
第三种方案实在强大,版权归外国某大神所有( http://stackoverflow.com/users/34509/johannes-schaub-litb ),它在stackoverflow原回答也贴出来(http://stackoverflow.com/questions/424104/can-i-access-private-members-from-outside-the-class-without-using-friends#3173080)
最后
以上就是高高蜜蜂为你收集整理的C++中hack private权限的全部内容,希望文章能够帮你解决C++中hack private权限所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复