Skip to content

Instantly share code, notes, and snippets.

@WorldSEnder
Created October 29, 2017 15:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save WorldSEnder/25ecf91236ec04a89ea3bdc9c1056142 to your computer and use it in GitHub Desktop.
Save WorldSEnder/25ecf91236ec04a89ea3bdc9c1056142 to your computer and use it in GitHub Desktop.
C++ private member access
#include <iostream>
class Foo {
int bar = 0;
int foobar = 999;
static inline int zip;
public:
void print() {
std::cout << "Bar: " << bar << std::endl;
std::cout << "Zip: " << zip << std::endl;
}
};
// "Attacker" code
// Descriminator struct - provides a unique linkage name, and the target type
struct FooBarValue { using type = int (Foo::*); };
// Explicit instantiation, where we are allowed to use the private member
template class public_cast<FooBarValue, &Foo::bar>;
// We are only allowed to use it in the explicit instantiation, thus
// we need a way to extract it without having to reuse the private member
using accessBar = public_access<FooBarValue>;
// Compact form (also showing static variables)
struct FooZipValue { using type = int &; };
template class public_cast<FooZipValue, Foo::zip>;
using accessZip = public_access<FooZipValue>;
// Can't reuse FooBarValue
// template class public_cast<FooBarValue, &Foo::foobar>;
int main(int argc, char** argv)
{
Foo foo;
foo.print();
// Look mom, we can access private members of Foo
foo.*(accessBar::unlock()) = 42;
accessZip::unlock() = 42;
foo.print();
}
#include <memory>
using std::reference_wrapper;
///
template<typename T>
struct _internalize;
template<typename T>
struct _internalize<T&> {
using type = reference_wrapper<T>;
};
template<typename T>
struct _internalize<T*> {
using type = T*;
};
template<typename T, typename M>
struct _internalize<M T::*> {
using type = M T::*;
};
template<typename T>
using internalize_t = typename _internalize<T>::type;
///
template<typename Tag, typename Tag::type P>
class public_cast;
template<typename Tag>
class public_access {
using public_type = typename Tag::type;
using internal_type = internalize_t<public_type>;
static inline internal_type value;
static public_type init(public_type p) {
static bool wasCalled = false;
if(wasCalled) {
throw "Double initialization forbidden";
}
public_access<Tag>::value = p;
wasCalled = true;
return p;
}
template<class T, typename T::type P>
friend class public_cast;
public:
static public_type unlock() {
return value;
}
};
///
template<typename Tag, typename Tag::type P>
class public_cast {
using internal_type = typename Tag::type;
static const inline internal_type value = public_access<Tag>::init(P);
friend constexpr internal_type enforce_once(Tag) {
return P;
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment