Анимация
JavaScript
|
Главная Библионтека 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] Endp PUSH 10 CALL C func ADD SP,2 Но с появлением оптимизирующих компиляторов все изменилось. Они могли выталкивать аргументы командой POP в неиспользуемые регистры или вовсе оставлять стек несбалансированным на то время пока к нему нет обращений. Поэтому в определении размера аргументов стали возможны ошибки. C opimize func: Push bp Mov bp,sp Mov ax,[BP+4] 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 сравнительно редко ошибается.
long GetFrameSize(long ea); Возвращает полный размер стекового фрейма в байтах. Он вычисляется по следующей формуле: FrameSize == FrameLvarSize + FrameArgsSize + FrameRegsSize + ReturnAddresSize То есть сумме размеров локальных переменных, аргументов, сохраненных в стеке регистров и адреса возврата всех вместе взятых. Подробнее о каждой из них можно прочитать в описании функций GetFrameLvaerSize, GetFrameArgsSize, GetFrameRegsSize. Специальной функции, возвращающий значение размера адреса возврата не существует, однако, он может быть вычислен по следующей формуле: ReturnAddresSize == FrameSize - FrameLvarSize + FrameArgsSize + FrameRegsSize 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 [ 60 ] 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |