Frage

Disclaimer

Ja, ich bin voll und ganz bewusst, dass, was ich fragen, um total bescheuert ist und dass jeder, wünschen würde, um versuchen so etwas in der Produktion Code sollte gefeuert und / oder Schuss werden. Ich bin in erster Linie schauen, um zu sehen, ob kann erfolgen.

Nun, da das aus dem Weg ist, ist es eine Möglichkeit, private Klassen Mitglieder in C ++ für den Zugriff von außerhalb der Klasse? Zum Beispiel ist es eine Möglichkeit, dies mit Zeiger-Offsets zu tun?

(Naive und sonst nicht-produktionsfertige Techniken willkommen)

Update

Wie in den Kommentaren erwähnt, fragte ich diese Frage, weil ich eine Blog-Post auf over-Kapselung (und wie es wirkt TDD) schreiben wollte. Ich wollte sehen, ob es ein Weg, zu sagen, „mit privaten Variablen ist nicht 100% zuverlässig Weise Verkapselung zu erzwingen, auch in C ++.“ Am Ende entschied ich mich mehr darauf zu konzentrieren, wie das Problem zu lösen, anstatt, warum es ein Problem gibt, so dass ich nicht etwas von dem Material verfügen hier als prominent gebracht, wie ich geplant hatte, aber ich habe noch einen Link.

Auf jeden Fall, wenn jemand interessiert ist, wie es herauskam, hier ist sie: Enemies von Test Driven Development Teil I:. Kapselung (ich schlage vor, zu lesen, bevor Sie sich entscheiden, dass ich verrückt bin)

War es hilfreich?

Lösung

Wenn die Klasse aller Vorlagenelementfunktionen enthält können Sie die Member-Funktion spezialisiert Ihre Bedürfnisse anzupassen. Selbst wenn der ursprüngliche Entwickler nicht daran gedacht.

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

Ausgabe:

900000
800000

Andere Tipps

Ich habe einen Eintrag in meinem Blog hinzugefügt (siehe unten), das zeigt, wie es gemacht werden kann. Hier ist ein Beispiel dafür, wie man es für die folgende Klasse verwenden

struct A {
private:
  int member;
};

deklarieren nur eine Struktur für sie, wo Sie es beschreiben und die Implementierungsklasse für Raub

verwendet instanziiert
// 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;
}

Die Rob Klassenvorlage ist wie folgt definiert, und muss nur einmal definiert werden, unabhängig davon, wie viele private Mitglieder, die Sie planen, den Zugriff

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

Dies ist jedoch nicht zeigen, dass c ++ 's Zugriffsregeln nicht zuverlässig ist. Die Sprachregeln ausgelegt sind gegen unbeabsichtigte Fehler zu schützen - wenn Sie rauben Daten eines Objekts versuchen, die Sprache by-Design dauert nicht lange, Möglichkeiten, wie Sie zu verhindern.

Hier finden Sie hinterhältig, illegal, Compiler abhängig und möglicherweise nicht auf verschiedene Details der Implementierung abhängig.

#define private public
#define class struct

Aber es ist eine Antwort auf Ihre OP, in denen Sie explizit eine Technik, die einladen, und ich zitiere, ist „total bescheuert und dass jeder, der so etwas in der Produktion Code versuchen wünschen würde gefeuert werden soll und / oder Schuss “.


Eine andere Technik ist privat Mitglied auf Daten zuzugreifen, die durch Zeiger contructing hartcodiert / Hand codierte Offsets vom Anfang des Objekts.

Hmmm, weiß nicht, ob das funktionieren würde, aber vielleicht einen Versuch wert sein. Erstellen Sie eine andere Klasse mit dem gleichen Layout wie das Objekt mit einem eigenen Mitgliedern, sondern mit privaten zu öffentlichen geändert. Erstellen Sie eine Variable von Zeiger auf diese Klasse. Verwenden Sie einen einfachen Guss diese mit einem eigenen Mitglieder zu Ihrem Objekt zu zeigen und versuchen, eine private Funktion aufrufen.

Erwarten Funken und vielleicht einen Absturz;)

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

union 
{ 
    A a; 
    B b; 
};

Das sollte es tun.

ETA: Es wird für diese Art von trivialer Klasse arbeiten, aber als eine allgemeine Sache wird es nicht.

  

TC ++ PL Abschnitt C.8.3: „Eine Klasse mit einem Konstruktor, Destruktor oder Kopiervorgang nicht der Typ eines Gewerkschaftsmitgliedes sein kann ... weil der Compiler nicht wissen würde, welches Element zu zerstören“

So wir links mit der besten Wette class B zu erklären seinem A Layout und hacken paßt in einer Klasse Gemeine suchen.

Wenn Sie einen Zeiger auf ein Mitglied einer Klasse erhalten können Sie den Zeiger ganz gleich verwenden können, was die Zugriffsbezeichner sind (auch Methoden).

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

Natürlich mein Favorit wenig Hack ist der Freund Vorlage Hintertür.

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

Angenommen, den Schöpfer der oben definierte Hintertür für seinen normalen Gebrauch. Aber Sie wollen das Objekt zuzugreifen und Blick auf den privaten Membervariablen. Auch wenn die obige Klasse hat sich in eine statische Bibliothek erstellt wurden, können Sie Ihre eigene Vorlage Spezialisierung für BackDoor hinzufügen und damit die Mitglieder zugreifen können.

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

Es ist auf jeden Fall möglich, private Mitglieder mit einem Zeiger in C versetzt zuzugreifen ++. Nehmen wir an, ich die folgende Typdefinition hatte, dass ich Zugang zu wollen.

class Bar {
  SomeOtherType _m1;
  int _m2;
};

Unter der Annahme, es gibt keine virtuellen Methoden in Bar, Der einfache Fall ist _M1. Mitglieder in C ++ werden als Offsets des Speicherplatz des Objekts gespeichert. Die erste Aufgabe wird bei 0 versetzt, um das zweite Objekt von sizeof Offset (erstes Element), etc ...

So, hier ist ein Weg, _M1 zugreifen zu können.

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

Jetzt _M2 ist ein bisschen schwieriger. Wir brauchen die ursprüngliche Zeiger sizeof (SomeOtherType) Bytes vom Original zu bewegen. Die Besetzung zu char ist, um sicherzustellen, dass ich in einem Byte am Inkrementieren Offset

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

kühle Frage btw ... hier ist mein Stück:

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, das hilft.

Diese Antwort beruht auf der genauen Konzept demonstriert von @ Johannes Antwort / blog , so dass der einzige zu sein scheint „legitime“ Art und Weise. Ich habe dieses Beispiel-Code in ein handliches Dienstprogramm umgewandelt. Es ist leicht kompatibel mit C ++ 03 (von std::remove_reference & Ersetzen nullptr Implementierung).

Bibliothek

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

#define ALLOW_ACCESS(CLASS, TYPE, MEMBER) \
  template<typename Only, TYPE CLASS::*Member> \
  struct CONCATE(MEMBER, __LINE__) { friend TYPE (CLASS::*Access(Only*)) { return Member; } }; \
  template<typename> struct Only_##MEMBER; \
  template<> struct Only_##MEMBER<CLASS> { friend TYPE (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>, <type>, <member>);

Verwendung

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

Beispiel

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

ALLOW_ACCESS(X, int, member);

int main() {
  X x;
  ACCESS(x, member) = 42;
  std::cout << "proof: " << x.get_member() << std::endl;
}

Wenn Sie wissen, wie Sie Ihre C ++ Compiler Namen verstümmelt, ja.

Es sei denn, ich nehme an, es ist eine virtuelle Funktion. Aber dann, wenn Sie wissen, wie Sie Ihre C ++ Compiler die VTABLE baut ...

Edit: bei den anderen Antworten sucht, merke ich, dass ich die Frage falsch verstanden und dachte, dass es über das Mitglied Funktionen war, nicht Mitglied Daten. Jedoch immer noch der Punkt steht:., Wenn Sie wissen, wie Sie Ihre Compiler Daten legt, dann können Sie diese Daten zugreifen

Es ist eigentlich ganz einfach:

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

Als Alternative Backdoor-Methode Vorlage Sie Vorlage Backdoor-Klasse verwenden können. Der Unterschied ist, dass Sie nicht über diese Backdoor-Klasse in den öffentlichen Bereich der Klasse setzen müssen, um Ihre testen gehen. Ich benutze die Tatsache, dass viele Compiler verschachtelte Klassen ermöglichen den Zugriff auf privaten Bereich Klasse umschließenden (die nicht genau 1998 Standard ist aber als „richtiges“ Verhalten sein). Und natürlich in C ++ 11 dieses Recht Verhalten wurde.

Sehen Sie folgendes Beispiel:

#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();
}

Neben #define private public Sie können auch #define privat geschützt und dann einige foo Klasse definieren als Nachkomme der gesuchten Klasse Zugang zu haben, um es Methoden (jetzt geschützt) via Typ Gießen.

Sie einfach Ihre eigene Zugang Memberfunktion erstellen die Klasse zu erweitern.

An alle Leute, was darauf hindeutet, " #define private public ":

Diese Art der Sache ist illegal . Der Standard verbietet die Definition / undef-ing-Makros, die lexikalisch gleichwertig reservierten Sprache Schlüsselwörter sind. Während Ihr Compiler wird wahrscheinlich nicht beschweren (ich habe noch einen Compiler, um zu sehen, der Fall ist), ist es nicht etwas, das eine „gute Sache“ zu tun ist.

"mit privaten Variablen ist nicht 100% zuverlässig Weise Verkapselung zu erzwingen, auch in C ++." "Ja wirklich?" Sie können die Bibliothek zerlegen Sie benötigen, finden alle Offsets sie benötigt und verwendet werden. Das gibt Ihnen die Fähigkeit, jedes privates Mitglied zu ändern, die Sie mögen ... ABER! Sie können nicht private Mitglieder zugreifen, ohne einige schmutzig Hacking. Lassen Sie uns sagen, dass das Schreiben const wird nicht Ihre Konstante wirklich konstant machen ‚, Ursache können Sie werfen const weg oder einfach nur benutzen es Adresse ist es ungültig zu machen. Wenn Sie MSVC verwenden ++ und von Ihnen angegebenen „-merge: .rdata = .data“ an einen Linker, funktioniert der Trick ohne Speicherzugriff Fehler. Wir können sogar sagen, dass das Schreiben Anwendung in C ++ ist nicht zuverlässig Weg, um Programme zu schreiben, weil geringen Code ergibt, kann von irgendwo außerhalb gepatcht werden, wenn Ihre Anwendung ausgeführt wird. Was ist dann zuverlässig dokumentiert Weise Verkapselung durchzusetzen? Können wir die irgendwo Daten im RAM verstecken und nichts verhindern, dass sie außer unseren Code zugreifen? Die einzige Idee, die ich habe, ist private Mitglieder und Backup sie zu verschlüsseln ‚etwas beschädigt möglicherweise die Mitglieder führen. Sorry, wenn meine Antwort zu grob ist, meine ich habe niemanden zu beleidigen, aber ich diese Aussage ist glaube wirklich nicht klug.

da Sie ein Objekt der erforderlichen Klasse Ich vermute, dass Sie Deklaration der Klasse haben. Nun, was Sie tun können, ist eine andere Klasse mit denselben Mitgliedern erklären, aber alle dort Zugriffsbezeichner als öffentlich halten.

Zum Beispiel vorherige Klasse ist:

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

public:
    somefunctions
}

können Sie eine Klasse als

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

    somefunctions
};

Alles was Sie jetzt tun müssen, ist werfen Zeiger der Klasse Iamcompprivate in einen Zeiger der Klasse NowIampublic und sie als U möchten.

Beispiel:

NowIampublic * changetopublic(Iamcompprivate *A)
{
    NowIampublic * B = (NowIampublic *)A;
    return B;
}

Durch Bezugnahme auf * das Sie eine Backdoor auf alle privaten Daten innerhalb eines Objekts ermöglichen.

class DumbClass
{
private:
    int my_private_int;
public:
    DumbClass& backdoor()
    {
        return *this;
    }
}

Oft eine Klasse bietet Mutatormethoden auf private Daten (Getter und Setter).

Wenn eine Klasse einen Getter tut schaffen, die eine konstante Referenz zurückgibt (aber keine Setter), dann können Sie nur den Rückgabewert des Getter const_cast, und verwenden, die als L-Wert:

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;

Ich habe einen anderen nützlichen Ansatz (und Lösung) verwendet, um eine c zuzugreifen ++ private / geschützt Mitglied.
Die einzige Bedingung ist, dass Sie aus der Klasse, die Sie zugreifen möchten, erben können.
Dann werden alle Kredit geht an reinterpret_cast <> () .

Ein mögliches Problem ist, dass es nicht, wenn Sie eine virtuelle Funktion einfügen arbeiten, die virtuelle Tabelle ändern wird, und so, Objektgröße / Ausrichtung.

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

Dann brauchen Sie nur die Klasse wie folgt zu verwenden:

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

Mein ursprüngliches Problem war, wie folgt: Ich habe eine Lösung benötigt, die neu zu kompilieren QT-Bibliotheken nicht bedeuten werden
. Es gibt zwei Methoden in QObject dumpObjectInfo () und dumpObjectTree (), dass nur funktionieren, wenn QT-Bibliotheken im Debug-Modus kompiliert werden, und sie natürlich Zugang benötigen proteted Mitglied d_ptr (unter anderen internen Strukturen).
Was ich tat, war die vorgeschlagene Lösung zu verwenden, neu zu implementieren (mit Kopieren und Einfügen) diese Methoden in dumpObjectInfo2 () und dumpObjectTree2 () in meiner eigenen Klasse ( QObjectWrapper ), um diese Debug preprocesor Wachen zu entfernen.

Der folgende Code zugreift und ändert ein eigenes Mitglied der Klasse einen Zeiger auf diese Klasse.

#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).*/

Studie Zweck nur .... versuchen Sie dies .... kann hilfreich Ich denke ..... Dieses Programm kann auf die privaten Daten zugreifen nur durch die Werte zu wissen ...

//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.....";
}

Inspiriert von @Johannes Schaub -. Litb, der folgende Code kann ein bisschen leichter zu verdauen

    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;

  }
class Test{
    int a;
    alignas(16) int b;
    int c;
};

Test t;

Methode A: intrusive Stimmung . da wir Quellcode zugreifen und recomplie, können wir verwenden viele andere Art und Weise wie Freund-Klasse für den Zugriff auf private Member, sie sind alle rechtlichen Hintertür.

Methode B: Brute-Stimmung

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

verwenden wir eine magische Zahl (20), und es ist nicht immer richtig. Wenn das Layout der Klasse-Test verändert, die magische Zahl ist ein großer Fehler Quelle.

Methode C: super Hacker Stimmung . Gibt es eine non-intrusive und nicht-Brute-Stimmung? da das Layout Infomationen Klasse-Test ist ausblenden vom complier, wir können keine Informationen aus dem complie Mund versetzt bekommen. Ex.

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

Wir können auch nicht Mitglied Zeiger von Klasse-Test erhalten. Ex.

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

@Johannes Schaub - litb hat einen Blog, fand er einen Weg zu rauben Privat Mitglied Zeiger. aber ich dachte, das sollte complier Bug oder Sprache pitfall sein. Ich kann es auf gcc4.8 complie, aber nicht auf vc8 complier.

so kann die Schlussfolgerung: der Vermieter alle Backdoor-bauen. Der Dieb hat immer brutaler und schlechte Art und Weise, in die Pause. der Hacker versehentliche hat elegante und automatisierte Möglichkeit, in die Pause.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top