Использование недокументированных классов в C ++ - PullRequest
3 голосов
/ 06 августа 2010

Я в процессе реинжиниринга исполняемого файла Windows. Я нашел класс, который хочу использовать из некоторого кода, который я вставляю в исполняемый файл (другой поток, собственный стек). Как мне объявить такой класс, учитывая адреса методов и структуру переменных-членов?

Например, допустим, я нашел класс с именем foo, с его конструктором @ 0x4012D30 и функцией doTheMario @ 40125D4. Я также знаю, что он содержит три DWORD личных данных. Поскольку оба метода являются _thiscalls, я объявляю класс в своем коде следующим образом:

class GuessedFoo {
    private:
        int bar;
        char *cafebabe;
        float deadbeef;
    public:
        GuessedFoo(int a, int b);
        void doTheMario();
};

Так вот, это совершенно отличный класс, но теперь есть ли способ заставить компилятор / компоновщик связать методы класса с двумя предыдущими адресами, которые я указал? Конечно, я могу написать оболочку asm для преобразования stdcall в thiscall для каждого метода, который мне нужно использовать, и затем использовать структуры вместо классов, но должен быть лучший способ.

В данный момент я использую gcc / g ++, но я могу переключиться на VC ++ (поскольку встроенный ассемблер gcc в любом случае вызывает у меня головную боль).

Ответы [ 4 ]

4 голосов
/ 06 августа 2010

Если у класса нет vtable, вы можете, в принципе, создать такой класс в своем собственном коде, где все вызовы функций вызывают соответствующие реальные реализации.Вы можете сделать это, запрограммировав функции-члены как голые функции , содержащие инструкцию перехода к сборке, к реальной реализации.

Если у класса есть vtable, вещи, вероятно, станут намного сложнее;вам, вероятно, нужно явно создать виртуальную таблицу как структуру указателей на функции и сделать так, чтобы ваши заглушки вызывали их.Это означает более сложные функции прокладки;простой голой функции с прыжком может быть недостаточно, и может быть лучше пойти с реальной функцией.Помните, однако, что функции-члены на win32 используют другое соглашение о вызовах ;это означает, что обычный вызов функции-члена не будет работать.Вы можете иметь возможность обходиться без построения указателей на функции-члены, но имейте в виду, что у них довольно странная структура , и вам нужно будет соответствовать ейс чем-то, что имеет то же представление, что и указатели vtable.Удачи!

1 голос
/ 06 августа 2010

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

Я бы вызвал эту функцию, используя чистый код сборки.Если базовый адрес EXE-файла фиксирован, это еще проще.
Пример кода:

void main()
{
    int bar = 5;
    int * cafebabe = &bar;
    __asm
    {
        push [bar];
        push [cafebabe];
        mov eax, 123456; // address of the function
        call eax;
    }
}

Просто проверьте, как эта функция вызывается исходным кодом, чтобы увидеть, в каком порядке нужно выдвигать аргументы.Не забывайте, что некоторые аргументы могут нуждаться в передаче через регистры!

0 голосов
/ 06 августа 2010

C ++ не определяет какой-либо двоичный интерфейс, что делает практически невозможным реализацию какого-либо динамического связывания для классов c ++.

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

Конечно - поскольку __thiscall в методе класса передает 'this' через регистр ecs, я не верю, что вы действительно можете сделать явное объявление функции cэто будет иметь тот же эффект, поэтому вам может потребоваться выполнить все вызовы с помощью пользовательского «CallThisCallMethodWithParameters», который вы написали в сборке.

0 голосов
/ 06 августа 2010

Я не совсем уверен, что правильно вас понимаю, но в любом случае: я думаю, что самый простой путь к «ручному поиску» методов - это использование указателей на функции.

...