79

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).

Community
  • 1
  • 1
Jason Baker
  • 192,085
  • 135
  • 376
  • 510
  • Out of interest, why ask the question. The only use I can think for this is to hack into someone elses API to wreak havoc. – SmacL Jan 08 '09 at 14:48
  • I'm writing a blog post on over-encapsulation. I was just looking to see if it was possible to say "protection by private methods isn't perfect, even in C++!" I'll post the link once I've gotten it written. – Jason Baker Jan 08 '09 at 15:34

27 Answers27

83

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
dalle
  • 18,057
  • 5
  • 57
  • 81
69

I've added an entry to my blog (see below) that shows how it can be done. Here is an example on how you use it for the following class

struct A {
private:
  int member;
};

Just declare a struct for it where you describe it and instantiate the implementation class used for robbery

// tag used to access A::member
struct A_member { 
  typedef int A::*type;
  friend type get(A_member);
};

template struct Rob<A_member, &A::member>;

int main() {
  A a;
  a.*get(A_member()) = 42; // write 42 to it
  std::cout << "proof: " << a.*get(A_member()) << std::endl;
}

The Rob class template is defined like this, and needs only be defined once, regardless how many private members you plan to access

template<typename Tag, typename Tag::type M>
struct Rob { 
  friend typename Tag::type get(Tag) {
    return M;
  }
};

However, this doesn't show that c++'s access rules aren't reliable. The language rules are designed to protect against accidental mistakes - if you try to rob data of an object, the language by-design does not take long ways to prevent you.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • shouldn't it be "the language rules are NOT.."? –  Feb 26 '13 at 22:32
  • This does not seem to work. It works with the private function example on your blog, but with int I get: error: non-type template argument of type 'int A::*' must have an integral or enumeration type (for template class rob;) – chris Jun 30 '14 at 08:36
  • @chris i recommend making a question on SO about this. i can't help with comments – Johannes Schaub - litb Jul 09 '14 at 17:34
  • I use this: struct Am { typedef int A::* type; }; It worked on GCC4.8. I think the method uses compiler's bug. It has portability issues. – thomas Sep 11 '14 at 01:30
  • @thomas if you read my blog post, you will be enlightened and see that this is not a compiler's bug. I recommend to use my follow-up blog post, though. Since is has a technically better implementation of the exploit. http://bloglitb.blogspot.de/2011/12/access-to-private-members-safer.html – Johannes Schaub - litb Sep 11 '14 at 17:49
  • The Committee should be very sorry. What Herb Sutter said ? "don't do these things in real code". the Committee should take these thing seriously. Your method really shock us. good work@ Johannes Schaub - litb – thomas Sep 14 '14 at 07:38
  • Thanks for this answer. It was helpful to me while using auto generated google protobuf library. :-) In [my answer](http://stackoverflow.com/a/41416529/514235), I have converted your code into a general purpose utility for frequent usage (though it may not be 'so good'). To @Puppy, nothing to be embarrassed, sometimes it's necessary. Before reading this answer (back in July-2016), I never knew such thing even can be possible. Even never knew that I will end up using 6 months later. – iammilind Jan 01 '17 at 15:27
  • 2
    Take notice of two main points if the answer looks tricky for you:1) `template struct Rob;` This is an explicit template class instantiation. `&A::member` works here [because](http://en.cppreference.com/w/cpp/language/class_template): "Explicit instantiation definitions ignore member access specifiers: parameter types and return types may be private" – bartolo-otrit May 02 '17 at 12:48
  • 2
    2) `a.*get(A_member())` calls non-member friend function `get(A_member)` which returns `&A::member`. This works because of "[friend injection](https://bytes.com/topic/c/answers/820592-template-friend-function-injection)". Try to remove "useless" argument of the get() function and you should get "get was not declared in this scope" (I would like to see a concise explanation of this behaviour). – bartolo-otrit May 02 '17 at 12:50
  • 1
    Is there any possible modification for the case when `A::member` is not an `int`, but an `enum Foo` where the name `Foo` is private within `A`? – M.M Feb 22 '18 at 05:21
  • @M.M I made the above answer more generic using templates, without having to know the member's type. Check out my answer https://stackoverflow.com/a/67242467/8176989 – 김선달 Apr 24 '21 at 11:51
32

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.

James Adkison
  • 9,412
  • 2
  • 29
  • 43
ChrisW
  • 54,973
  • 13
  • 116
  • 224
  • 7
    You also need #define class struct, otherwise the private-by-default may thwart you. – Tom Jan 08 '09 at 13:36
  • 1
    Preprocessor hacks are no more access to private members than pointer dereferencing is. – cletus Jan 08 '09 at 13:42
  • rq is wrong on the mechanism (relaxing access checks never invalidate a valid program, due to the moment when they happen). The hack violates the ODR and might break the program due to name mangling. – MSalters Jan 08 '09 at 16:21
  • @MSalters it will break (on vc2005) when attempting to link a (now) public constructor to a private constructor in the .lib file. – Aaron Jan 09 '09 at 15:38
  • I've tried this trick in order to add unit tests to some legacy code with mixed results. It seemed to work for private data but not private methods. Apparently the compiler I was using (VC++ 9.0) included a method's visibility as part of its name mangling scheme. – Ferruccio Jul 03 '10 at 22:47
  • 1
    Also worked well for TDD using Xcode 6 (LLVM), this answer is the best solution to solve my problem, without having to modify original code at all. – Kaa Nov 02 '14 at 01:19
  • FYI if you are in the Visual Studio world you must also add _XKEYCHECK_H to preprocessor definitions. – sevensevens Jan 27 '16 at 19:52
  • 1
    This doesn't work in some cases, because `class` can be used in template parameter(same as `typename`, but `struct` cannot. – user202729 Feb 22 '20 at 04:44
24

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 ;)

SmacL
  • 22,555
  • 12
  • 95
  • 149
  • 2
    "with the same layout". This is the hard part. The compiler has a good bit of freedom on how it lays out members in a non-POD. In practice though, it will probably work. – Richard Corden Jan 08 '09 at 13:35
  • @Richard Corden - That would be my feeling as well. Illustrating once againa that 'Would probably work' and 'should be done in a piece of release' are worlds apart. – SmacL Jan 08 '09 at 14:41
  • 1
    Bear in mind that the compiler is perfectly free to reorder members based on access control (actually, it's perfectly free to reorder if there is any access control). I don't know how many actually do this.... – David Thornley Jan 08 '09 at 20:39
  • Most compilers will not reorder members - they're not permitted to do so for POD structures, or else they would break compatibility with C structures (struct sockaddr, for one). Really, there's very little incentive to provide automatic member reordering. – Tom Jan 09 '09 at 05:50
12
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.

iammilind
  • 68,093
  • 33
  • 169
  • 336
Rob K
  • 8,757
  • 2
  • 32
  • 36
10

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());
}
Martin York
  • 257,169
  • 86
  • 333
  • 562
  • @formerlyknownas_463035818 Only from a method that has accesses. If a method has access to a method it can get a pointer to the function and return it. Once you have the pointer it can be passed around and used as there are no permissions on that pointer. – Martin York Sep 03 '19 at 13:49
  • @formerlyknownas_463035818 1: `test()` is `private` and the value returned by `getMethod()` (which is `public`) could be anything. 2: No you can not get a pointer externally. – Martin York Sep 03 '19 at 15:51
  • Thanks for your comments. It took me a while to realize that almost all classes I use daily do have a backdoor. I knew before that it is better not to open the door, now I also know where to find it. If you dont mind, I'll delete my comments and I guess you want to delete yours – 463035818_is_not_an_ai Sep 04 '19 at 19:16
9

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));
}
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
6

This answer is based on the exact concept demonstrated by @Johannes's answer/blog, as that seems to be the only "legitimate" way. I have converted that example code into a handy utility. It's easily compatible with C++03 (by implementing std::remove_reference & replacing nullptr).

Library

#define CONCATE_(X, Y) X##Y
#define CONCATE(X, Y) CONCATE_(X, Y)

#define ALLOW_ACCESS(CLASS, MEMBER, ...) \
  template<typename Only, __VA_ARGS__ CLASS::*Member> \
  struct CONCATE(MEMBER, __LINE__) { friend __VA_ARGS__ CLASS::*Access(Only*) { return Member; } }; \
  template<typename> struct Only_##MEMBER; \
  template<> struct Only_##MEMBER<CLASS> { friend __VA_ARGS__ CLASS::*Access(Only_##MEMBER<CLASS>*); }; \
  template struct CONCATE(MEMBER, __LINE__)<Only_##MEMBER<CLASS>, &CLASS::MEMBER>

#define ACCESS(OBJECT, MEMBER) \     
 (OBJECT).*Access((Only_##MEMBER<std::remove_reference<decltype(OBJECT)>::type>*)nullptr)

API

ALLOW_ACCESS(<class>, <member>, <type>);

Usage

ACCESS(<object>, <member>) = <value>;   // 1
auto& ref = ACCESS(<object>, <member>); // 2

Demo

struct X {
  int get_member () const { return member; };
private:
  int member = 0;
};

ALLOW_ACCESS(X, member, int);

int main() {
  X x;
  ACCESS(x, member) = 42;
  std::cout << "proof: " << x.get_member() << std::endl;
}
iammilind
  • 68,093
  • 33
  • 169
  • 336
  • I am unable to use this with a private member of type `enum Foo` where `Foo` was also in the private section, because `Class::Foo` cannot be used in the `ALLOW_ACCESS` macro due to being private! Any suggestions? – M.M Feb 22 '18 at 05:11
  • @M.M don't have idea how to make that work. Tried few alternatives to no avail. Will update if I find a solution. – iammilind Feb 22 '18 at 06:19
3

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.

kdgregory
  • 38,754
  • 10
  • 77
  • 102
  • 1
    I find this answer interesting because the biggest argument against using Python's private members is that it's really just name mangling (albeit a more standardized name mangling). It's interesting to know that things are about the same in C++. – Jason Baker Jan 08 '09 at 16:39
  • 2
    Jason - the difference is, in Python, you may get your wrist slapped for accessing privates. In C++, your fellow developers will shoot you for going to these lengths to subvert encapsulation. – Tom Jan 09 '09 at 05:47
3

cool question btw... here's my piece:

using namespace std;

class Test
{

private:

  int accessInt;
  string accessString;

public:

  Test(int accessInt,string accessString)
  {
    Test::accessInt=accessInt;
    Test::accessString=accessString;
  }
};

int main(int argnum,char **args)
{
  int x;
  string xyz;
  Test obj(1,"Shit... This works!");

  x=((int *)(&obj))[0];
  xyz=((string *)(&obj))[1];

  cout<<x<<endl<<xyz<<endl;
  return 0;
}

Hope this helps.

Cosmin
  • 21,216
  • 5
  • 45
  • 60
1

As an alternative to template backdoor method you can use template backdoor class. The difference is that you don't need to put this backdoor class into public area of the class your are going to test. I use the fact that many compilers allow nested classes to access private area of enclosing class (which is not exactly 1998 standard but considered to be "right" behaviour). And of course in C++11 this became legal behaviour.

See this example:

#include <vector>
#include <cassert>
#include <iostream>
using std::cout;
using std::endl;


///////// SystemUnderTest.hpp
class SystemUnderTest
{
   //...put this 'Tested' declaration into private area of a class that you are going to test
   template<typename T> class Tested;
public:
   SystemUnderTest(int a): a_(a) {}
private:
   friend std::ostream& operator<<(std::ostream& os, const SystemUnderTest& sut)
   {
      return os << sut.a_;
   }
   int a_;
};

/////////TestFramework.hpp
class BaseTest
{
public:
   virtual void run() = 0;
   const char* name() const { return name_; }
protected:
   BaseTest(const char* name): name_(name) {}
   virtual ~BaseTest() {}
private:
   BaseTest(const BaseTest&);
   BaseTest& operator=(const BaseTest&);
   const char* name_;
};

class TestSuite
{
   typedef std::vector<BaseTest*> Tests;
   typedef Tests::iterator TIter;
public:
   static TestSuite& instance()
   {
      static TestSuite TestSuite;
      return TestSuite;
   }
   void run()
   {
      for(TIter iter = tests_.begin(); tests_.end() != iter; ++iter)
      {
         BaseTest* test = *iter;
         cout << "Run test: " << test->name() << endl;
         test->run();
      }
   }
   void addTest(BaseTest* test)
   {
      assert(test);
      cout << "Add test: " << test->name() << endl;
      tests_.push_back(test);
   }
private:
   std::vector<BaseTest*> tests_;
};

#define TEST_CASE(SYSTEM_UNDER_TEST, TEST_NAME) \
class TEST_NAME {}; \
template<> \
class SYSTEM_UNDER_TEST::Tested<TEST_NAME>: public BaseTest \
{ \
   Tested(): BaseTest(#SYSTEM_UNDER_TEST "::" #TEST_NAME) \
   { \
      TestSuite::instance().addTest(this); \
   } \
   void run(); \
   static Tested instance_; \
}; \
SYSTEM_UNDER_TEST::Tested<TEST_NAME> SYSTEM_UNDER_TEST::Tested<TEST_NAME>::instance_; \
void SYSTEM_UNDER_TEST::Tested<TEST_NAME>::run()


//...TestSuiteForSystemUnderTest.hpp
TEST_CASE(SystemUnderTest, AccessPrivateValueTest)
{
   SystemUnderTest sut(23);
   cout << "Changed private data member from " << sut << " to ";
   sut.a_ = 12;
   cout << sut << endl;
}

//...TestRunner.cpp
int main()
{
   TestSuite::instance().run();
}
AlexT
  • 1,413
  • 11
  • 11
0

By referencing to *this you enable a backdoor to all private data within an object.

class DumbClass
{
private:
    int my_private_int;
public:
    DumbClass& backdoor()
    {
        return *this;
    }
}
mage_hat
  • 151
  • 1
  • 10
0

Quite often a class provides mutator methods to private data (getters and setters).

If a class does provide a getter that returns a const reference (but no setter), then you can just const_cast the return value of the getter, and use that as an l-value:

class A {
  private:
    double _money;
  public:
    A(money) :
      _money(money)
    {}

    const double &getMoney() const
    {
      return _money;
    }
};

A a(1000.0);
const_cast<double &>(a.getMoney()) = 2000.0;
Lanting
  • 3,060
  • 12
  • 28
0

I've used another useful approach (and solution) to access a c++ private/protected member.
The only condition is that you are able to inherit from the class you want to access.
Then all credit goes to reinterpret_cast<>().

A possible problem is that it won't work if you insert a virtual function, which will modify virtual table, and so, object size/alignment.

class QObject
{
    Q_OBJECT
    Q_DECLARE_PRIVATE(QObject)
    void dumpObjectInfo();
    void dumpObjectTree();
...
protected:
    QScopedPointer<QObjectData> d_ptr;
...
}

class QObjectWrapper : public QObject
{
public:
    void dumpObjectInfo2();
    void dumpObjectTree2();
};

Then you just need to use the class as follows:

QObject* origin;
QObjectWrapper * testAccesor = reinterpret_cast<QObjectWrapper *>(origin);
testAccesor->dumpObjectInfo2();
testAccesor->dumpObjectTree2();

My original problem was as follows: I needed a solution that won't imply recompiling QT libraries.
There are 2 methods in QObject, dumpObjectInfo() and dumpObjectTree(), that just work if QT libs are compiled in debug mode, and they of course need access to d_ptr proteted member (among other internal structures).
What I did was to use the proposed solution to reimplement (with copy and paste) those methods in dumpObjectInfo2() and dumpObjectTree2() in my own class (QObjectWrapper) removing those debug preprocesor guards.

kikeenrique
  • 2,589
  • 2
  • 25
  • 46
0

The following code accesses and modifies a private member of the class using a pointer to that class.

#include <iostream>
using namespace std;
class A
{
    int private_var;
    public:
    A(){private_var = 0;}//initialized to zero.
    void print(){cout<<private_var<<endl;}
};

int main()
{
    A ob;
    int *ptr = (int*)&ob; // the pointer to the class is typecast to a integer pointer.  
    (*ptr)++; //private variable now changed to 1.
    ob.print();
    return 0;
}
/*prints 1. subsequent members can also be accessed by incrementing the pointer (and
  type casting if necessary).*/
  • This is "ideal" situation where you do know the class instance variables layout. However, it's incorrect in case where class has ancestors with ivars or has virtual members. Nevertheless you solution based on knowledge of particular implementation. So, basically, you don't answer the original question "Can I access private members from outside the class without using friends?", you show how to access memory of class private members in particular implementation. – Petro Korienev Aug 10 '14 at 13:07
0

since you have an object of required class I am guessing that you have declaration of class. Now what you can do is declare another class with same members but keep all of there access specifiers as public.

For example previous class is:

class Iamcompprivate
{
private:
    Type1 privateelement1;
    Typ2 privateelement2;
    ...

public:
    somefunctions
}

you can declare a class as

class NowIampublic
{
**public:**
    Type1 privateelement1;
    Type2 privateelement2;
    ...

    somefunctions
};

Now all you need to do is cast pointer of class Iamcompprivate into an pointer of class NowIampublic and use them as U wish.

Example:

NowIampublic * changetopublic(Iamcompprivate *A)
{
    NowIampublic * B = (NowIampublic *)A;
    return B;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Alok
  • 11
0

study purpose only.... try this ....may be helpfull i guess..... this program can access the private data just by knowing the values...

//GEEK MODE....;)
#include<iostream.h>
#include<conio.h>

    class A
    {
    private :int iData,x;
    public: void get()             //enter the values
        {cout<<"Enter iData : ";
            cin>>iData;cout<<"Enter x : ";cin>>x;}

        void put()                               //displaying values
    {cout<<endl<<"sum = "<<iData+x;}
};

void hack();        //hacking function

void main()
{A obj;clrscr();
obj.get();obj.put();hack();obj.put();getch();
}

void hack()         //hack begins
{int hck,*ptr=&hck;
cout<<endl<<"Enter value of private data (iData or x) : ";
cin>>hck;     //enter the value assigned for iData or x
for(int i=0;i<5;i++)
{ptr++;
if(*ptr==hck)
{cout<<"Private data hacked...!!!\nChange the value : ";
cin>>*ptr;cout<<hck<<" Is chaged to : "<<*ptr;
return;}
}cout<<"Sorry value not found.....";
}
0

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.

dmajkic
  • 3,448
  • 1
  • 18
  • 24
0

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

RichieHH
  • 2,116
  • 4
  • 28
  • 30
0

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.

Tritium
  • 79
  • 3
  • But you'll note that the question doesn't require that this be a "good thing" to do. In fact, a good way to do this may not exist. – Jason Baker Jan 08 '09 at 16:27
  • 2
    Well, the question *does* require that the method work, right? Since the standard forbids this sort of thing the method outlined by other is simply broken by definition. It works because most compilers don't enforce this **rule**. – Tritium Jan 08 '09 at 16:35
  • Jason, the question requires that this can be done. at least when you include a standard header, then you run into undefined behavior, and that can't be an answer to this question. turning stuff into undefined behavior allows the compiler to do just about anything it wants. (formatting your HD) – Johannes Schaub - litb Jan 08 '09 at 19:23
  • (and including forbidding you to access the privates - which ironically is just what the questioner does *not* want). It's as far as i know allowed to #define keywords when there is no standard header included into the same translation unit though. but as i said, that can't be the solution! – Johannes Schaub - litb Jan 08 '09 at 19:28
  • litb, your logic isn't quite right. It's is explicitly FORBIDDEN to define a macro name that is lexically identical to ANY reserved keyword, regardless of what you include in a translation unit. It's as simple as: "don't do it, it's illegal". – Tritium Jan 08 '09 at 20:26
  • Tritium - In the context of this question, the standard doesn't matter. Anyone subverting the language's built-in access control mechanisms only cares if it works or not in their given environment. Anyone who -ansi-pedantic-ally adheres about the standard wouldn't be doing this in the first place. – Tom Jan 09 '09 at 05:52
  • 1. Given the fact that people actually responded with this suggestion in the first place says that they didn't know that this was illegal. 2. By your logic, people will also be dereferencing null pointers, writing past array bounds, etc. because it happens to "work" on their machine. – Tritium Jan 09 '09 at 15:28
0

It's actually quite easy:

class jail {
    int inmate;
public:
    int& escape() { return inmate; }
};
MSalters
  • 173,980
  • 10
  • 155
  • 350
  • 1
    I assume that the OP wants access **without modifying the class definition itself**. – j_random_hacker Jan 09 '09 at 09:51
  • For Test-Driven Development, such backdoors could make sense. They're easy to remove with a #define. #define's that mess with public/private can affect program semantics, e.g. POD-ness. – MSalters Jan 09 '09 at 12:56
0

"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.

  • The question is about the language itself, not about platform-specifics you can or cannot do. – Ruslan Aug 19 '16 at 14:49
0

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;

  }
Yunzhou Wu
  • 71
  • 4
0

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.

Sapphire_Brick
  • 1,560
  • 12
  • 26
0

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();
}
mada
  • 1,646
  • 1
  • 15
-1
class Test{
    int a;
    alignas(16) int b;
    int c;
};

Test t;

method A : intrusive mood. since we can access source code and recomplie it, we can use many other way like friend class to access private member, they are all legal backdoor.

method B : brute mood.

int* ptr_of_member_c = reinterpret_cast<int*>(reinterpret_cast<char*>(&t) + 20);

we use a magic number (20) , and It's not always right. When the layout of class Test changed, the magic number is a big bug source.

method C : super hacker mood. is there any non-intrusive and non-brute mood ? since the class Test's layout infomation is hide by the complier, we can not get offset information from the complie's mouth. ex.

offsetof(Test,c); //complie error. they said can not access private member.

we also can not get member pointer from class Test. ex.

&Test::c ;  //complie error. they said can not access private member.

@Johannes Schaub - litb has a blog, he found a way to rob private member pointer. but i thought this should be complier's bug or language pitfall. i can complie it on gcc4.8, but not on vc8 complier.

so the conclusion may be : the landlord build all backdoor. the thief always has brute and bad way to break into. the hacker accidental has elegant and automated way to break into.

thomas
  • 505
  • 3
  • 12
  • This sounds like a rant about other answers, rather than an answer. You have enough reputation to leave clarifying comments on the other answers. – Ben Voigt Sep 11 '14 at 02:34
  • sorry , i have not learned the right discussion rules. but the conclusion is real my thought results. – thomas Sep 11 '14 at 03:15
-1

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.

김선달
  • 1,485
  • 9
  • 23