Фундаментальные основы хакерства



         

Идентификация констант и смещений - часть 4


Существует два типа указателей – указатели на данные и указатели на функцию. Указатели на данные используются для извлечения значения ячейки памяти и встречаются в арифметических командах и командах пересылки (например – MOV, ADD, SUB). Указатели на функцию используются в командах косвенного вызова и, реже, в командах косвенного перехода – CALL и JMP соответственно.

Рассмотрим следующий пример:

main()

{

static int a=0x777;

int *b = &a;

int c=b[0];

}

Листинг 123 Константы и указатели

Результат его компиляции должен выглядеть приблизительно так:

main         proc near

var_8        = dword      ptr -8

var_4        = dword      ptr -4

push   ebp

mov    ebp, esp

sub    esp, 8

; Открываем кадр стека

mov    [ebp+var_4], 410000h

; Загружаем в локальную переменную var_4 значение 0x410000

; Пока мы не можем определить его тип – константа это или указатель

mov    eax, [ebp+var_4]

; Загружаем содержимое локальной переменной var_4 в регистр EAX

mov    ecx, [eax]

; Загружаем в ECX содержимое ячейки памяти на которую указывает указатель EAX

; Ага! Значит, EAX все-таки указатель. Тогда локальная переменная var_4,

; откуда он был загружен, тоже указатель

; И непосредственный операнд 0x410000 – указатель, а не константа!

; Следовательно, чтобы сохранить работоспособность программы, создадим по

; смещению 0x410000 метку loc_410000, ячейку памяти, расположенную по этому

; адресу преобразует в двойное слово, и MOV

[ebp+var_4], 410000h заменим на:

; MOV [ebp+var_4], offset loc_410000

mov    [ebp+var_8], ecx

; Присваиваем локальной переменной var_8 значение *var_4 ([offset loc_41000])

mov    esp, ebp

pop    ebp

; Закрываем кадр стека

retn

main         endp

Листинг 124

Рассмотрим теперь пример с косвенным вызовом процедуры:

func(int a, int b)

{

return a+b;

};

main()

{

int (*zzz) (int a, int b) = func;

// Вызов функции происходит косвенно – по указателю zzz




Содержание  Назад  Вперед