Can I access private members from outside the class without using friends?

Viewed 76904

Disclaimer

Yes, I am fully aware that what I am asking about is totally stupid and that anyone who would wish to try such a thing in production code should be fired and/or shot. I'm mainly looking to see if can be done.

Now that that's out of the way, is there any way to access private class members in C++ from outside the class? For example, is there any way to do this with pointer offsets?

(Naive and otherwise non-production-ready techniques welcome)

Update

As noted in the comments, I asked this question because I wanted to write a blog post on over-encapsulation (and how it affects TDD). I wanted to see if there was a way to say "using private variables isn't a 100% reliable way to enforce encapsulation, even in C++." At the end, I decided to focus more on how to solve the problem rather than why it's a problem, so I didn't feature some of the stuff brought up here as prominently as I had planned, but I still left a link.

At any rate, if anyone's interested in how it came out, here it is: Enemies of Test Driven Development part I: encapsulation (I suggest reading it before you decide that I'm crazy).

27 Answers

If the class contains any template member functions you can specialize that member function to suit your needs. Even if the original developer didn't think of it.

safe.h

class safe
{
    int money;

public:
    safe()
     : money(1000000)
    {
    }

    template <typename T>
    void backdoor()
    {
        // Do some stuff.
    }
};

main.cpp:

#include <safe.h>
#include <iostream>

class key;

template <>
void safe::backdoor<key>()
{
    // My specialization.
    money -= 100000;
    std::cout << money << "\n";
}

int main()
{
    safe s;
    s.backdoor<key>();
    s.backdoor<key>();
}

Output:

900000
800000

The following is sneaky, illegal, compiler-dependent, and may not work depending on various implementation details.

#define private public
#define class struct

But it is an answer to your OP, in which you explicitly invite a technique which, and I quote, is "totally stupid and that anyone who would wish to try such a thing in production code should be fired and/or shot".


Another technique is to access private member data, by contructing pointers using hard-coded/hand-coded offsets from the beginning of the object.

Hmmm, don't know if this would work, but might be worth a try. Create another class with the same layout as the object with private members but with private changed to public. Create a variable of pointer to this class. Use a simple cast to point this to your object with private members and try calling a private function.

Expect sparks and maybe a crash ;)

class A 
{ 
   int a; 
}
class B
{
   public: 
   int b;
}

union 
{ 
    A a; 
    B b; 
};

That should do it.

ETA: It will work for this sort of trivial class, but as a general thing it won't.

TC++PL Section C.8.3: "A class with a constructor, destructor, or copy operation cannot be the type of a union member ... because the compiler would not know which member to destroy."

So we're left with the best bet being to declare class B to match A's layout and hack to look at a class's privates.

If you can get a pointer to a member of a class you can use the pointer no matter what the access specifiers are (even methods).

class X;
typedef void (X::*METHOD)(int);

class X
{
    private:
       void test(int) {}
    public:
       METHOD getMethod() { return &X::test;}
};

int main()
{
     X      x;
     METHOD m = x.getMethod();

     X     y;
     (y.*m)(5);
}

Of course my favorite little hack is the friend template back door.

class Z
{
    public:
        template<typename X>
        void backDoor(X const& p);
    private:
        int x;
        int y;
};

Assuming the creator of the above has defined backDoor for his normal uses. But you want to access the object and look at the private member variables. Even if the above class has been compiled into a static library you can add your own template specialization for backDoor and thus access the members.

namespace
{
    // Make this inside an anonymous namespace so
    // that it does not clash with any real types.
    class Y{};
}
// Now do a template specialization for the method.
template<>
void Z::backDoor<Y>(Y const& p)
{
     // I now have access to the private members of Z
}

int main()
{
    Z  z;   // Your object Z

    // Use the Y object to carry the payload into the method.
    z.backDoor(Y());
}

It's definately possible to access private members with a pointer offset in C++. Lets assume i had the following type definition that I wanted access to.

class Bar {
  SomeOtherType _m1;
  int _m2;
};

Assuming there are no virtual methods in Bar, The easy case is _m1. Members in C++ are stored as offsets of the memory location of the object. The first object is at offset 0, the second object at offset of sizeof(first member), etc ...

So here is a way to access _m1.

SomeOtherType& GetM1(Bar* pBar) {
  return*(reinterpret_cast<SomeOtherType*>(pBar)); 
}

Now _m2 is a bit more difficult. We need to move the original pointer sizeof(SomeOtherType) bytes from the original. The cast to char is to ensure that I am incrementing in a byte offset

int& GetM2(Bar* pBar) {
  char* p = reinterpret_cast<char*>(pBar);
  p += sizeof(SomeOtherType);
  return *(reinterpret_cast<int*>(p));
}

If you know how your C++ compiler mangles names, yes.

Unless, I suppose, it's a virtual function. But then, if you know how your C++ compiler builds the VTABLE ...

Edit: looking at the other responses, I realize that I misread the question and thought it was about member functions, not member data. However, the point still stands: if you know how your compiler lays out data, then you can access that data.

It's actually quite easy:

class jail {
    int inmate;
public:
    int& escape() { return inmate; }
};

Beside #define private public you can also #define private protected and then define some foo class as descendant of wanted class to have access to it's (now protected) methods via type casting.

just create your own access member function to extend the class.

To all the people suggesting "#define private public":

This kind of thing is illegal. The standard forbids defining/undef-ing macros that are lexically equivalent to reserved language keywords. While your compiler probably won't complain (I've yet to see a compiler that does), it isn't something that's a "Good Thing" to do.

"using private variables isn't a 100% reliable way to enforce encapsulation, even in C++." Really? You can disassemble the library you need, find all the offsets needed and use them. That will give you an ability to change any private member you like... BUT! You can't access private members without some dirty hacking. Let us say that writing const won't make your constant be really constant, 'cause you can cast const away or just use it's address to invalidate it. If you're using MSVC++ and you specified "-merge:.rdata=.data" to a linker, the trick will work without any memory access faults. We can even say that writing apps in C++ is not reliable way to write programs, 'cause resulting low level code may be patched from somewhere outside when your app is running. Then what is reliable documented way to enforce encapsulation? Can we hide the data somewhere in RAM and prevent anything from accessing them except our code? The only idea I have is to encrypt private members and backup them, 'cause something may corrupt those members. Sorry if my answer is too rude, I didn't mean to offend anybody, but I really don't think that statement is wise.

Inspired by @Johannes Schaub - litb, the following code may be a bit easier to digest.

    struct A {
    A(): member(10){}
    private:
    int get_member() { return member;}
    int member;
   };

   typedef int (A::*A_fm_ptr)();
   A_fm_ptr  get_fm();

  template<   A_fm_ptr p> 
  struct Rob{ 
     friend A_fm_ptr  get_fm() {
   return p;
  }
};

 template struct Rob<  &A::get_member>;

 int main() {
   A a;
  A_fm_ptr p = get_fm();

    std::cout << (a.*p)() << std::endl;

  }

Well, with pointer offsets, it's quite easy. The difficult part is finding the offset:

other.hpp

class Foo
{
  public:
    int pub = 35;

  private:
    int foo = 5;
    const char * secret = "private :)";
};

main.cpp

#include <iostream>
#include <fstream>
#include <string>
#include <regex>

#include "other.hpp"

unsigned long long getPrivOffset(
  const char * klass,
  const char * priv,
  const char * srcfile
){

  std::ifstream read(srcfile);
  std::ofstream write("fork.hpp");
  std::regex r ("private:");
  std::string line;
  while(getline(read, line))
    // make all of the members public
    write << std::regex_replace(line, r, "public:") << '\n';
  write.close();
  read.close();
  // find the offset, using the clone object
  std::ofstream phony("phony.cpp");
  phony << 
  "#include <iostream>\n"
  "#include <fstream>\n"
  "#include \"fork.hpp\"\n"
  "int main() {\n";
  phony << klass << " obj;\n";
  // subtract to find the offset, the write it to a file
  phony << 
  "std::ofstream out(\"out.txt\");\n out <<   (((unsigned char *) &(obj." 
<< priv << ")) -((unsigned char *)   &obj)) << '\\n';\nout.close();";
  phony << "return 0;\n}";
  phony.close();
  system(
    "clang++-7 -o phony phony.cpp\n"
    "./phony\n"
    "rm phony phony.cpp fork.hpp");
  std::ifstream out("out.txt");
  // read the file containing the offset
  getline(out, line);
  out.close();
  system("rm out.txt");
  unsigned long long offset = strtoull(line.c_str(), NULL, 10);
  return offset;
}


template <typename OutputType, typename Object>
OutputType hack(
  Object obj, 
  const char * objectname,
  const char * priv_method_name,
  const char * srcfile
  ) {
  unsigned long long o = getPrivOffset(
    objectname, 
    priv_method_name, 
    srcfile
  );
  return *(OutputType *)(((unsigned char *) (&obj)+o));
}
#define HACK($output, $object, $inst, $priv, $src)\
hack <$output, $object> (\
  $inst,\
  #$object,\
  $priv,\
  $src)

int main() {
  Foo bar;
  std::cout << HACK(
    // output type
    const char *, 
    // type of the object to be "hacked"
    Foo,
    // the object being hacked
    bar,
    // the desired private member name
    "secret",
    // the source file of the object's type's definition
    "other.hpp"
    ) << '\n';
  return 0;
}
clang++ -o main main.cpp
./main

output:

private :)

You could also use reinterpret_cast.

Maybe some pointer arithmetics can do it

#pragma pack(1)
class A
{
    int x{0};
    char c{0};
    char s[8]{0};
    
    public:
    void display()
    {
        print(x);
        print(c);
        print(s);
    }; 
};


int main(void)
{
    A a;

    int *ptr2x = (int *)&a;
    *ptr2x = 10;
    
    char *ptr2c = (char *)ptr2x+4;
    *ptr2c = 'A';
    
    char *ptr2s = (char *)ptr2c+1;
    strcpy(ptr2s ,"Foo");
    
    a.display();
}

I made Johannes answer more generic. You can get the source here: https://github.com/lackhole/Lupin
All you have to know is just the name of the class and the member.

You can use like,

#include <iostream>

#include "access/access.hpp"

struct foo {
 private:
  std::string name = "hello";
  int age = 27;
  void print() {}
};

using tag_foo_name = access::Tag<class foo_name>;
template struct access::Accessor<tag_foo_name, foo, decltype(&foo::name), &foo::name>;

int main() {
  foo f;
  
  // peek hidden data
  std::cout << access::get<tag_foo_name>(f) << '\n'; // "hello"
  
  // steal hidden data
  access::get<tag_foo_name>(f) = "lupin";
  std::cout << access::get<tag_foo_name>(f) << '\n'; // "lupin"
}

Call private functions, get the type of private members is also possible with only using the tag.

Related