2013-05-15 3 views
1

Я делаю статический анализ на Win32 .dll с использованием IDA Pro 6.3 и использую декомпилятор Hex-Rays в тандеме с дизассемблером IDA. Я хотел бы понять, что делает эта линия.Разделено __thiscall выражение указатель на функцию?

v4 = (*(int (__thiscall **)(int, int))(*(_DWORD *)dword_10087418 + 4))(dword_10087418, v11); 

Он отформатирован как вызов функции. Является ли этот код декомпилированным кодом похожим на то, когда указатель на функцию используется в вызове подпрограммы?

Спасибо.

+0

Ух ты .. Я думаю, что это одна из причин, почему я так сильно избегаю C-Style. – Brandon

ответ

0

Это отличает адрес от * dword_10087418 + 4 до функции и вызывает ее.

Итак, это отличает dword_10087418 указателю на dword, а затем разыменовывает его, а затем добавляет 4 к этому результату. Полученный адрес приводится к функции, чье объявление выглядит следующим образом:

int __thiscall foo(int, int) 

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

dword_10087418 и v11 - целые числа, переданные этой функции. Результат вызова функции сохраняется в v4. Код C будет выглядеть следующим образом:

int v4 = foo(dword_10087418, v11); 
1

Это, скорее всего, C++, а не обычный C. То есть именно то, что Visual C++ - генерироваться вызовы виртуального метода выглядеть. Я бы сказал, что:

  • dword_10087418 является указателем на объект. Это либо глобальная, либо статическая переменная, а не локальная.
  • Этот объект имеет таблицу виртуальных методов, а код вызывает вторую функцию в этой таблице.
  • Предполагая, что Hex-Rays правильно определили аргументы функции, вызываемая функция принимает один 32-битный аргумент. Тип возврата не ясен.
  • Вызов C++ был, скорее всего, очень простым, похожим на SomeClass::Instance->func(arg).

Если вы не знакомы с планировкой объекта в C++, вы должны прочитать C++ Under the Hood, Reversing: Secrets of Reverse Engineering или Inside the C++ Object Model. Книга IDA Pro также содержит краткий раздел по этой теме.


Если вы хотите получить краткое резюме, читайте дальше. Имейте в виду, что все это деталь реализации MSVC, другие компиляторы делают это по-другому, и они могут свободно изменять ее по своему усмотрению. (Кроме того, я упрощаю вещи, не говоря уже о виртуальном/множественном наследовании). Когда класс использует виртуальные функции, компилятор строит таблицу всех таких функций в этом классе и помещает указатель на эту таблицу в качестве первого скрытого члена каждого объекта этого класса.Затем, вызывая виртуальную функцию из таблицы так же просто, как:

mov ecx, esi ; pretend that esi contains a pointer 
       ; to the object whose method is being called 
       ; also known as "this" 
       ; __thiscall functions expect to find this pointer in ecx 
       ; and all later arguments on the stack 
mov edx, [ecx] ; get the vtable address 
push edi  ; set up some integer-sized argument 
call [edx + 4] ; call the second function in the vtable 

И это в основном то, что строка кода делает:

(*(int (__thiscall **)(int, int))(*(_DWORD *)dword_10087418 + 4))(dword_10087418, v11) 
            ^-----------------------^ 
            dereference pointer to get the address of the vtable 
            (it's the first piece of data in the object) 
           ^-----------------------------^ 
           add 4 bytes to get address of the second function 
^------------------------------------------------------------------------------------^ 
cast that pointer to a particular function pointer and call it 
(cast is invisible in assembler code, so it's just a call) 

Обратите внимание, что поскольку функция член нуждается в доступе к this , компилятор должен передать его также. Это деталь, которая не видна в C++, но this рассматривается как дополнительный аргумент для функции - следовательно, вы видите два аргумента, но функция принимает только один (в соглашении MSVC thiscall указывается, что указатель передан в ecx). IDA не беспокоится о том, чтобы скрывать этот указатель, потому что это запуталось бы.


Дополнительные советы: Получить ms_rtti скрипт для IDA и запустить его, чтобы найти таблицы виртуальных методов в DLL, а затем искать другие ссылки на dword_10087418, чтобы увидеть, какие значения записываются в ней - вы должны быть в состоянии определить, какая vtable связана с этим объектом, а затем выяснить, какая функция вызывается.

Вы можете сделать шестнадцатеричные лучи более удобным для отображения кода, если вы определяете типы структуры stub для класса и рассматриваемого vtable, а затем сообщите IDA, что указатель использует этот тип структуры.