Является ли Гидра неправильной интерпретацией вызова функции?

# #c #x86 #reverse-engineering #decompiling #ghidra

Вопрос:

Анализируя список сборок в Гидре, я наткнулся на эту инструкцию:

CALL dword ptr [EBX*0x4 0x402ac0]=gt;DAT_00402abc

Я предположил , что программа вызывала функцию, адрес которой находился внутри DAT_00402abc , и я сначала подумал, что это переменная dword. Действительно, при попытке создать функцию в том месте, где DAT_00402abc она находится, Гидра не позволила бы мне это сделать.

Декомпилятор показывает мне эту строку кода для перевода этой инструкции:

(*(code *)(amp;int2)[iVar2])();

Поэтому мне было интересно, что это значит и что программа должна делать с этим вызовом? Есть ли вероятность, что Гидра полностью облажался? И если да, то как я должен интерпретировать эту инструкцию?

Ответ №1:

Я совсем не знаком с Гидрой, но могу рассказать вам, как интерпретировать машинную инструкцию…

 CALL dword ptr [EBX*0x4   0x402ac0]  

Существует таблица адресов функций по адресу 0x402ac0 ; вызывается запись EBX в этой таблице. Я понятия не имею, что DAT_00402abc это значит, но если вы проверите память в блоках размером с dword по адресу 0x0402ac0 , вы должны найти правдоподобные адреса функций. [РЕДАКТИРОВАТЬ: 0x0040_2abc = 0x0040_2ac0 — 4. Я подозреваю, что это означает, что Гидра считает, что EBX имеет значение -1, когда контроль достигает этой точки. Это может быть неправильно, или, может быть, в программе есть ошибка. Можно было бы ожидать, что EBX будет иметь неотрицательное значение, когда контроль достигнет этой точки.]

Естественный исходный код C, соответствующий этой инструкции, будет выглядеть примерно так

 extern void do_thing_zero(void); extern void do_thing_one(void); extern void do_thing_two(void); extern void do_thing_three(void);  typedef void (*do_thing_ptr)(void); const do_thing_ptr do_thing_table[4] = {  do_thing_zero, do_thing_one, do_thing_two, do_thing_three };  // ...  void do_thing_n(unsigned int n) {  if (n gt;= 4) abort();  do_thing_table[n](); }  

Если функции в таблице принимают аргументы или возвращают значения, вы увидите код передачи аргументов до и после приведенной вами инструкции ВЫЗОВА, но сама инструкция ВЫЗОВА не изменится.

Вы бы увидели что-то другое и гораздо более сложное, если бы все функции не принимали один и тот же набор аргументов.