21

This is purely a theoretical question, I know that if someone declares a method private, you probably shouldn't call it. I managed to call private virtual methods and change private members for instances, but I can't figure out how to call a private non-virtual method (without using __asm). Is there a way to get the pointer to the method? Are there any other ways to do it?

EDIT: I don't want to change the class definition! I just want a hack/workaround. :)

Cactus
  • 27,075
  • 9
  • 69
  • 149
Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625

14 Answers14

18

See my blog post. I'm reposting the code here

template<typename Tag>
struct result {
  /* export it ... */
  typedef typename Tag::type type;
  static type ptr;
};

template<typename Tag>
typename result<Tag>::type result<Tag>::ptr;

template<typename Tag, typename Tag::type p>
struct rob : result<Tag> {
  /* fill it ... */
  struct filler {
    filler() { result<Tag>::ptr = p; }
  };
  static filler filler_obj;
};

template<typename Tag, typename Tag::type p>
typename rob<Tag, p>::filler rob<Tag, p>::filler_obj;

Some class with private members

struct A {
private:
  void f() {
    std::cout << "proof!" << std::endl;
  }
};

And how to access them

struct Af { typedef void(A::*type)(); };
template class rob<Af, &A::f>;

int main() {
  A a;
  (a.*result<Af>::ptr)();
}
Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
11

#include the header file, but:

#define private public
#define class struct

Clearly you'll need to get around various inclusion guards etc and do this in an isolated compilation unit.

EDIT: Still hackish, but less so:

#include <iostream>

#define private friend class Hack; private

class Foo
{
public:
    Foo(int v) : test_(v) {}
private:
    void bar();
    int test_;
};
#undef private
void Foo::bar() { std::cout << "hello: " << test_ << std::endl; }

class Hack
{
public:
    static void bar(Foo& f) {
        f.bar();
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    Foo f(42);
    Hack::bar(f);
    system("pause");
    return 0;
}
Pete
  • 4,784
  • 26
  • 33
  • 10
    What if I've `class A { void f() {} };`? – Nawaz Jul 29 '11 at 12:42
  • 2
    who -1'd me? - the OP said this is purely theoretical! – Pete Jul 29 '11 at 12:45
  • I didn't but probably because the formatting was off. I fixed it. –  Jul 29 '11 at 12:47
  • 11
    This is so dirty my eyes are bleeding XD – Antonio Pérez Jul 29 '11 at 12:55
  • @Nawaz: #define class struct ?! – Pete Jul 29 '11 at 13:03
  • @Pete : It would mean bluffing everybody :) – mukeshkumar Jul 29 '11 at 13:09
  • I'm not suggesting that anyone ever actually DOES this ;) – Pete Jul 29 '11 at 13:14
  • @Luchian: You were looking for something more hack-ish? Seriously? This is as hack-ish as it gets, and it does almost exactly what you want (there is a problem with private inheritance). No change to the header is needed if you do the `#define`s in your source file before you `#include` the header. – David Hammen Jul 29 '11 at 13:20
  • @Pete: One problem is that this changes private inheritance to public inheritance, thereby changing the semantics, and possibly the compilation, of the class. – David Hammen Jul 29 '11 at 13:21
  • @Pete, nonetheless worth +1 as a very evil hack. – David Hammen Jul 29 '11 at 13:29
  • I guess the other way is to #define private protected and then use a derived class for access. The private inheritance semantics are less changed. – Pete Jul 29 '11 at 13:30
  • 7
    These redefines render your entire program UB, and strictly speaking you've changed the type declaration. And writing `friend` is hardly a hack. – Lightness Races in Orbit Jul 29 '11 at 13:34
  • +1 The friend is also nice, but I'm looking for something eviler. – Luchian Grigore Jul 29 '11 at 14:49
  • 5
    **redefining keywords invokes undefined behaviour**. – Nawaz Jul 29 '11 at 15:01
  • This isn't very clever. All he did was use the keyword friend to allow the Hack class to access private members of the class Foo. What you should be thinking about is acquiring the memory address of the private function and calling on it through a pointer. – Kacy Raye Jun 25 '13 at 20:57
  • And how would you do that @KacyRaye, assuming that you cannot directly modify the header that contains Foo? You could write something to post-process a linker generated map file and modify the binary but it seems a little bit overkill? OP did actually ask for a hack.. – Pete Jul 01 '13 at 21:46
6

It can be called if a public function returns the address of the private function, then anyone can use that address to invoke the private function.

Example,

class A
{
   void f() { cout << "private function gets called" << endl; }
 public:
     typedef void (A::*pF)();
     pF get() { return &A::f; }
};

int main() 
{
        A a;
        void (A::*pF)() = a.get();
        (a.*pF)(); //it invokes the private function!
}

Output:

private function gets called

Demo at ideone : http://www.ideone.com/zkAw3

Nawaz
  • 353,942
  • 115
  • 666
  • 851
3

The simplest way:

#define private public
#define protected public
legendlee
  • 568
  • 4
  • 12
3

Followup on T.E.D.'s answer: Don't edit the header. Instead create your own private copy of the header and insert some friend declarations in that bogus copy of the header. In your source, #include this bogus header rather than the real one. Voila!

Changing private to public might change the weak symbols that result from inlined methods, which in turn might cause the linker to complain. The weak symbols that result from inline methods will have the same signatures with the phony and real headers if all that is done is to add some friend declarations. With those friend declarations you can now do all kinds of evil things with the class such as accessing private data and calling private members.

Addendum
This approach won't work if the header in question uses #pragma once instead of a #include guard to ensure the header is idempotent.

David Hammen
  • 32,454
  • 9
  • 60
  • 108
2

You have friend classes and functions.

I know that if someone declares a method private, you probably shouldn't call it.

The point is not 'you shouldn't call it', it's just 'you cannot call it'. What on earth are you trying to do?

Antonio Pérez
  • 6,702
  • 4
  • 36
  • 61
  • I'm just trying to call the private method... That's it. Without changing the class definition. – Luchian Grigore Jul 29 '11 at 12:49
  • Well, I think friendship is the tool you are looking for, though you do need to change the class declaration for that. You just can't do it using inheritance. – Antonio Pérez Jul 29 '11 at 12:52
  • What I'm looking for is a hack. I managed to call a private virtual by getting the address of the vftable and calling the function at that address. I could have done it using friendship, but this is the sort of thing I'm looking for. – Luchian Grigore Jul 29 '11 at 12:56
1

Call the private method from a public function of the same class.

ascanio
  • 1,506
  • 1
  • 9
  • 18
1

Easiest way to call private method (based on previous answers but a little simpler):

// Your class
class sample_class{
    void private_method(){
        std::cout << "Private method called" << std::endl;
    }
};

// declare method's type
template<typename TClass>
using method_t = void (TClass::*)();

// helper structure to inject call() code
template<typename TClass, method_t<TClass> func>
struct caller{
    friend void call(){
        TClass obj;
        (obj.*func)();
    }
};

// even instantiation of the helper
template struct caller<sample_class,&sample_class::private_method>;

// declare caller
void call();

int main(){
    call(); // and call!
    return 0;
}
0

If we are speaking of MSVC, I think the simplest way with no other harm than the fact of calling a private method itself is the great __asm:

class A
{
private:
    void TestA () {};
};

A a;
__asm
{
    // MSVC assumes (this) to be in the ecx.
    // We cannot use mov since (a) is located on the stack
    // (i.e. [ebp + ...] or [esp - ...])
    lea     ecx, [a]
    call    A::TestA
}
Kde
  • 77
  • 9
0

For GCC it can be done by using mangled name of a function.

#include <stdio.h>

class A {
public:
    A() {
        f(); //the function should be used somewhere to force gcc to generate it
    }
private:
    void f() { printf("\nf"); }
};

typedef void(A::*TF)();

union U {
    TF f;
    size_t i;
};

int main(/*int argc, char *argv[]*/) {
    A a;
    //a.f(); //error
    U u;
    //u.f = &A::f; //error

    //load effective address of the function
    asm("lea %0, _ZN1A1fEv"
    : "=r" (u.i));
    (a.*u.f)();
    return 0;
}

Mangled names can be found by nm *.o files.

Add -masm=intel compiler option

Sources: GCC error: Cannot apply offsetof to member function MyClass::MyFunction https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html

Community
  • 1
  • 1
bartolo-otrit
  • 2,396
  • 3
  • 32
  • 50
0

Well, the obvious way would be to edit the code so that it is no longer private.

If you insist on finding an evil way to do it...well...with some compilers it may work create your own version of the header file where that one method is public instead of private. Evil has a nasty way of rebounding on you though (that's why we call it "evil").

T.E.D.
  • 44,016
  • 10
  • 73
  • 134
0

I think the closest you'll get to a hack is this, but it's not just unwise but undefined behaviour so it has no semantics. If it happens to function the way you want for any single program invocation, then that's pure chance.

Community
  • 1
  • 1
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • That's one of the ways to change private members, but I don't see how you can call private methods. This sort of idea is what I'm looking for. – Luchian Grigore Jul 29 '11 at 13:43
  • Fair point. It's as close as you'll get, though (without re-writing the code with `#define`s, which is definitely cheating). – Lightness Races in Orbit Jul 29 '11 at 14:17
  • How? Private members reside in memory, at a specific offset relative to the object's address. Private non-virtual methods are somewhere else (at least that's what the assembler says). If you know how, please post an answer with some code and I will happily accept it. :) – Luchian Grigore Jul 29 '11 at 14:19
  • @Luchian: It doesn't matter where the member function is. When you call it, you pass it (implicitly) a pointer to the object it should work on. By hacking, you can send an object of type A into a member function expecting to work on a type B. This is of arguable benefit in this case, which is why I said "fair point". :) – Lightness Races in Orbit Jul 29 '11 at 14:25
  • I know, you actually put the address of this in a registry and the function then works on that... which is like passing the this to the function. That doesn't solve the issue though... – Luchian Grigore Jul 29 '11 at 14:30
  • @Luchian: Registry? No, it's an implicit first argument in the function call. Really, Luchian, there is no "issue" here other than you trying to sidestep every single feature that C++ gives you. – Lightness Races in Orbit Jul 29 '11 at 14:35
  • Okay, issue was miss-used. I don't get why you are so against this. Just because you think it's wrong or against C++ or whatever doesn't mean you shouldn't at least think of ways to do it. Think of it as a brain-teaser. If the question annoys you, you don't have to answer it... – Luchian Grigore Jul 29 '11 at 14:43
  • @Luchian: I didn't say that it annoys me, and I did answer it, and I did think of ways to do it. Don't be so defensive. It's not _me_ that's against this; it's the _facts of the language_. – Lightness Races in Orbit Jul 29 '11 at 15:01
  • Ok sorry about that... :) What I did do so far is try to find the address of the function considering the addresses of the functions from the same class, but that didn't work (they appear to be scattered). – Luchian Grigore Jul 29 '11 at 15:03
  • @Luchian: The addresses of functions are not relevant. I suggest ignoring them! – Lightness Races in Orbit Jul 29 '11 at 15:04
  • I did some advertisement for my blog. See below. – Johannes Schaub - litb Jul 30 '11 at 22:50
  • @Johannes: Stack Overflow is not an advertising space. – Lightness Races in Orbit Aug 01 '11 at 00:04
0

Define a similar class that is the same apart from the function being public.

Then typecast an object with the private function to one with the public function, you can then call the public function.

QuentinUK
  • 2,997
  • 21
  • 20
0

After reading Search for an elegant and nonintrusive way to access private methods of a class, I want to sum up an ideal way since no one else has pasted it here:

// magic
//

template <typename Tag, typename Tag::pfn_t pfn>
struct tag_bind_pfn
{
    // KEY: "friend" defines a "pfn_of" out of this template. And it's AMAZING constexpr!
    friend constexpr typename Tag::pfn_t pfn_of(Tag) { return pfn; }
};

// usage
//

class A
{
    int foo(int a) { return a; }
};

struct tag_A_foo
{
    using pfn_t = int (A::*)(int);
    // KEY: make compiler happy?
    friend constexpr typename pfn_t pfn_of(tag_A_foo);
};
// KEY: It's legal to access private method pointer on explicit template instantiation
template struct tag_bind_pfn<tag_A_foo, &A::foo>;

inline static constexpr const auto c_pfn_A_foo = pfn_of(tag_A_foo{});

#include <cstdio>

int main()
{
    A p;
    auto ret = (p.*(c_pfn_A_foo))(1);
    printf("%d\n", ret);
    return 0;
}
Hsu Pu
  • 81
  • 9