Access C++ Private Member
Recently, I was seeking to bypass the access restrictions of private members and found two posts. Some of the solutions are straight forward, the others are mind blowing.
The first part are stratigies shown in post 1 with the following example header file:
// File x.h
class X
{
public:
X() : private_(1) { /*...*/ }
template<class T>
void f( const T& t ) { /*...*/ }
private:
int private_;
};
Copy class definition and add a friend to it
class X
{
// instead of including x.h, manually duplicates X's
// definition, and adds a line like:
friend ::Hijack( X& );
};
void Hijack( X& x )
{
x.private_ = 2; // evil laughter here
}
This is illegal because it violates the One Definition Rule, which says that if a type (here X) is defined more than once, the definitions must be identical.
Define private public
#define private public // illegal
#include "x.h"
void Hijack( X &x )
{
x.private_ = 2; // evil laughter here
}
Again:
- It is illegal to define a reserved word;
- It violates the One Definition Rule, as above.
Create a twin class with all member public
class BaitAndSwitch {
// hopefully has the same data layout as X
// so we can pass him off as one
public:
int notSoPrivate;
};
void f( X &x )
{
// evil laughter here
(reinterpret_cast<BaitAndSwitch &>(x)).notSoPrivate = 2;
}
However:
- The object layouts of X and BaitAndSwitch are not guaranteed to be the same, although in practice they probably always will be;
- The results of the reinterpret_cast are undefined, although most compilers will let you try to use the resulting reference in the way the hacker intended.
All above suffer from one problem as we access private members by defining a new class and the memory layout can be different between our new class and the original one.
But we do have legal methods granted by C++ standard.
Template specialization
As the class has a template method, we can define the following method to bypass access restriction.
namespace
{
struct Y {};
}
template<>
void X::f( const Y & )
{
private_ = 2; // evil laughter here
}
void Test()
{
X x;
cout << x.Value() << endl; // prints 1
x.f( Y() );
cout << x.Value() << endl; // prints 2
}
Class member pointer and template instantiation
It would be nice if we can have a class member pointer of the private member. That’s possible when we do template instantiation and pass the private member address to a template parameter as described here.
Here is the demo by post 2
template<typename Tag, typename Tag::type M>
struct Rob {
friend typename Tag::type get(Tag) {
return M; (1)
}
};
// use
struct A {
A(int a):a(a) { }
private:
int a;
};
// tag used to access A::a
struct A_f {
typedef int A::*type;
friend type get(A_f); (2)
};
template struct Rob<A_f, &A::a>; (3)
int main() {
A a(42);
std::cout << "proof: " << a.*get(A_f()) << std::endl; (4)
}
At line (3), the private member’s address is passed to the template and will be returned in the function at line (1). At line (2), the friend declaration matches the function defined at line (1), which will be found during argument dependent lookup when line (4) is executed.
At line (4), function get
is invoked. The compiler will search it in two ways:
- Normal lookup: from the scope it is called all the way to the global namespace;
- Argument Dependent Lookup: the compiler searches namespace where
struct A_f
is used.
There is one and only one get
function defined in struct Rob
. By defining a friend function like line (1), it’s invisible to the normal lookup as explained here, but will be found by argument dependent lookup according to this, so that function get
won’t pollute the global namespace. After get
is executed, it returned the member pointer of private member. By applying the pointer to class instance a
, we finally got the value of its private member.