Действительно ли я могу получить доступ к членам парламента, не занимающим официального поста снаружи класса, не используя друзей?

Объявление функции extern означает, что ее определение будет разрешено во время связывания, а не во время компиляции.

В отличие от обычных функций, которые не объявлены extern, его можно определить в любом из источников (но не в нескольких исходных файлах, иначе вы получите сообщение об ошибке компоновщика, говорящее, что вы указали несколько определений функции), в том числе тот, в котором он объявлен extern.So, в ур случае компоновщик разрешает определение функции в тот же файл.

Я не думаю, что это было бы очень полезно, но такие эксперименты дают лучшее представление о том, как работает компилятор и компоновщик языка.

63
задан Jason Baker 8 January 2009 в 16:36
поделиться

13 ответов

Если класс содержит какие-либо шаблонные функции членства, можно специализировать ту функцию членства для удовлетворения потребностям. Даже если исходный разработчик не думал о нем.

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

Вывод:

900000
800000
68
ответ дан dalle 7 November 2019 в 12:23
поделиться

Всем людям, предлагающим" #define частная общественность ":

Такого рода вещь недопустима . Стандарт запрещает defining/undef-ing макросы, которые лексически эквивалентны зарезервированным ключевым словам языка. В то время как Ваш компилятор, вероятно, не будет жаловаться (я должен все же видеть компилятор, который делает), это не что-то, что это - "Хорошая Вещь", чтобы сделать.

0
ответ дан Tritium 7 November 2019 в 12:23
поделиться

Около #define частная общественность Вы можете также #define частный защищенный и затем определять некоторый класс нечто как потомка требуемого класса для имения доступа к, он (теперь защищен) методы через преобразование типа.

0
ответ дан dmajkic 7 November 2019 в 12:23
поделиться

просто создайте свою собственную функцию членства доступа для расширения класса.

0
ответ дан HörmannHH 7 November 2019 в 12:23
поделиться

Если Вы знаете, как Ваш компилятор C++ искажает имена, да.

, Если, я не предполагаю, это - виртуальная функция. Но тогда, если Вы знаете, как Ваш компилятор C++ создает VTABLE...

Редактирование: смотря на другие ответы, я понимаю, что неправильно читал вопрос и думал, что это было о функциях членства, не членских данных. Однако точка все еще стоит: если Вы знаете, как Ваш компилятор размечает данные, то можно получить доступ к тем данным.

3
ответ дан kdgregory 7 November 2019 в 12:23
поделиться

Это на самом деле довольно легко:

class jail {
    int inmate;
public:
    int& escape() { return inmate; }
};
1
ответ дан MSalters 7 November 2019 в 12:23
поделиться

Если можно получить указатель на члена класса, можно использовать указатель, неважно, что спецификаторы доступа (даже методы).

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

, Конечно, мой любимый небольшой взлом является другом шаблонный черный ход.

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

Принятие создателя вышеупомянутого определило бэкдор для его нормальной эксплуатации. Но Вы хотите получить доступ к объекту и посмотреть на переменные члена парламента, не занимающего официального поста. Даже если вышеупомянутый класс был скомпилирован в статическую библиотеку, можно добавить собственную шаблонную специализацию для бэкдора и таким образом получить доступ к участникам.

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());
}
10
ответ дан Martin York 7 November 2019 в 12:23
поделиться
class A 
{ 
   int a; 
}
class B
{
   public: 
   int b;
}

union 
{ 
    A a; 
    B b; 
};

, Который должен сделать это.

ЭТА: Это будет работать на этот вид тривиального класса, но как общая вещь это не будет.

TC ++ МН Раздел C.8.3: "Класс с конструктором, деструктором или операцией копии не может быть типом члена профсоюза..., потому что компилятор не знал бы который участник уничтожить".

, Таким образом, нас оставляют с лучшим выбором быть, чтобы объявить class B соответствовать A расположение и взлом для рассмотрения причинного места класса.

12
ответ дан iammilind 7 November 2019 в 12:23
поделиться

Hmmm, не знайте, работало ли это, но могло бы стоить попытки. Создайте другой класс с тем же расположением как объект с членами парламента, не занимающими официального поста, но с частным, измененным на общественность. Создайте переменную указателя на этот класс. Используйте простой бросок, чтобы указать на это на Ваш объект с членами парламента, не занимающими официального поста и попытаться вызвать закрытую функцию.

Ожидают искры и возможно катастрофический отказ;)

24
ответ дан SmacL 7 November 2019 в 12:23
поделиться

Определенно возможно получить доступ к членам парламента, не занимающим официального поста со смещением указателя в C++. Позволяет предполагают, что у меня было следующее определение типа, к которому я хотел получить доступ.

class Bar {
  SomeOtherType _m1;
  int _m2;
};

Принятие там не является никакими виртуальными методами в Панели, легкий случай является _m1. Участники в C++ хранятся как смещения ячейки памяти объекта. Первый объект при смещении 0, втором объекте при смещении sizeof (первый участник), и т.д.

, Таким образом, вот способ получить доступ к _m1.

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

Теперь _m2 является немного более трудным. Мы должны переместить исходный указатель sizeof (SomeOtherType) байты из оригинала. Бросок для обугливания должен гарантировать, что я увеличиваю в байтовом смещении

int& GetM2(Bar* pBar) {
  char* p = reinterpret_cast<char*>(pBar);
  p += sizeof(SomeOtherType);
  return *(reinterpret_cast<int*>(p));
}
8
ответ дан JaredPar 7 November 2019 в 12:23
поделиться

Следующее является подлым, недопустимым, зависимым от компилятора, и не может работать в зависимости от различных деталей реализации.

#define private public
#define class struct

, Но это - ответ на Ваш OP, в котором Вы явно приглашаете технику, которую, и я заключаю в кавычки, "полностью глупо и что любой, кто хотел бы попробовать такую вещь в производственном коде, должен быть уволен и/или застрелен".

<час>

Другая техника должна получить доступ к данным члена парламента, не занимающего официального поста путем построения указателей с помощью hard-coded/hand-coded смещения с начала объекта.

29
ответ дан James Adkison 7 November 2019 в 12:23
поделиться

поскольку у вас есть объект требуемого класса, я предполагаю, что у вас есть объявление класса. Теперь вы можете объявить другой класс с такими же членами, но оставить все спецификаторы доступа общедоступными.

Например, предыдущий класс:

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

public:
    somefunctions
}

вы можете объявить класс как

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

    somefunctions
};

Теперь все, что вам нужно сделать, это преобразовать указатель класса Iamcompprivate в указатель класса NowIampublic ] и используйте их по своему усмотрению.

Пример:

NowIampublic * changetopublic(Iamcompprivate *A)
{
    NowIampublic * B = (NowIampublic *)A;
    return B;
}
0
ответ дан 24 November 2019 в 16:05
поделиться

Я добавил запись в свой блог (см. ниже), которая показывает, как это можно сделать. Вот пример использования этого для следующего класса

struct A {
private:
  int member;
};

Просто объявите для него struct, где вы его описываете, и инстанцируйте класс реализации, используемый для ограбления

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

Шаблон класса Rob определен таким образом, и его нужно определить только один раз, независимо от того, к скольким приватным членам вы планируете получить доступ

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

Однако это не показывает, что правила доступа в c++ ненадежны. Правила языка предназначены для защиты от случайных ошибок - если вы попытаетесь похитить данные объекта, язык по замыслу не предпримет длинных путей, чтобы помешать вам.

54
ответ дан 24 November 2019 в 16:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: