Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ida.final.doc
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
6 Mб
Скачать

Long GetFrameArgsSize(long ea);

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

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

Например:

Pascal_func:

Push bp

Mov bp,sp

Mov ax,[BP+4]

RET 2

Endp

PUSH 10

CALL Pascal_func

Си – соглашение предписывает очищать локальные переменные вызываемому коду. При выходе из функции стек остается несбалансированным. Поэтому необходимо скорректировать его верхушку.

Долгое время не оптимизирующие компиляторы использовали для этого команду ADD SP, N. Где N размер аргументов в байтах. Очевидно, что IDA так же без проблем могла распознать такую ситуацию.

Например:

C_func:

Push bp

Mov bp,sp

Mov ax,[BP+4]

RET

Endp

PUSH 10

CALL C_func

ADD SP,2

Но с появлением оптимизирующих компиляторов все изменилось. Они могли выталкивать аргументы командой POP в неиспользуемые регистры или вовсе оставлять стек несбалансированным на то время пока к нему нет обращений. Поэтому в определении размера аргументов стали возможны ошибки.

C_opimize_func:

Push bp

Mov bp,sp

Mov ax,[BP+4]

RET

Endp

PUSH 10

CALL C_optimize_func

OR AX,AX

JZ xxx

MOV AX,[BX]

Xxx:

POP AX

RET

Даже для человека с первого взгляда не очевидно назначение команды POP AX. Кроме того, современные компиляторы поддерживают «совмещенные аргументы», что делает задачу определения их размера практически невозможной.

Допустим, что по ходу программы необходимо передать один и то же аргумент нескольким функциям.

H=open(“MyFile”,”rb”);

read(buff,10,H);

seek(20,1,H);

По идее Си-компилятор должен был бы сгенерировать следующий код.

PUSH offset arb

PUSH offset aMyFile

CALL open

ADD SP,4

MOV [offset H],AX

PUSH [offset H]

PUSH [10]

PUSH buff

CALL read

ADD SP,6

PUSH [offset H]

PUSH 1

PUSH 20

CALL seek

ADD SP,6

Как нетрудно видеть один и тот же аргумент – дескриптор файла многократно заносится в стек, а потом выталкивается из него. Поэтому оптимизирующие компиляторы поступят, скорее всего, приблизительно так:

PUSH offset arb

PUSH offset aMyFile

CALL open

PUSH AX

PUSH [10]

PUSH buff

CALL read

ADD SP,4

PUSH 1

PUSH 20

CALL seek

ADD SP,10

Разобраться сколько аргументов принимает каждая функция одним лишь анализом балансировки стека абсолютно невозможно!

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

И «отдуваться» за все это приходится третей функции, которая выталкивает из стека аж 5 слов! Но на самом деле размер его аргументов гораздо скромнее.

Можно, конечно, попытаться отслеживать аргументы, к которым функция обращается и, выбрав из них тот, что лежит «внизу» всех, вычислить на основе этого размер аргументов.

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

Поэтому можно только удивляться, что даже на оптимизированном коде IDA сравнительно редко ошибается.

Операнд

Пояснения

Ea

Линейный адрес, принадлежащий функции

Return

Завершение

Пояснения

!=0

!=BADADDR

Размер аргументов в байтах

0

Функция не имеет кадра стека

BADADDR

Ошибка

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]