#c #visual-studio #assembly
#c #visual-studio #сборка
Вопрос:
Выгружено из visual Studio:
CheckPointer(pReceivePin,E_POINTER);
017D616D cmp dword ptr [ebp 0Ch],0
017D6171 jne CBasePin::Connect 4Dh (17D617Dh)
017D6173 mov eax,80004003h
017D6178 jmp CBasePin::Connect 1A7h (17D62D7h)
Но фактическое определение:
#define CheckPointer(p,ret) {if((p)==NULL) return (ret);}
Хотя моя сборка не так хороша, я не вижу никакой связи между исходным кодом и asm.
Ответ №1:
Вы упустили достаточно, чтобы трудно было быть уверенным, но та часть, с которой можно разобраться, выглядит разумной. NULL == 0, поэтому:
017D616D cmp dword ptr [ebp 0Ch],0 ; if [ebp 0ch] == 0
017D6171 jne CBasePin::Connect 4Dh (17D617Dh) ; goto 172617dh
017D6173 mov eax,80004003h ; else load 'ret'
017D6178 jmp CBasePin::Connect 1A7h (17D62D7h) ; and return it.
Очевидная проблема в том, что вы не показали нам, что находится в 17D617Dh или 17D62D7h, поэтому мы не можем догадаться, что на самом деле делается со значениями.
Комментарии:
1. Настоящий Ollydbg, безусловно, знает!
jmp
Начинается выполнение кода по указанному адресу. Acall
делает то же самое, но сначала помещает текущий адрес в стек, чтобы aret
мог продолжить возврат туда.2. Не текущий адрес, а адрес следующей инструкции, если быть точным.
3. @ollydbg: Я действительно имел в виду что-то вроде «адрес, находящийся в данный момент в EIP», но да, это будет адрес, следующий за текущей инструкцией (хотя в действительно ранних процессорах x86 этого не было — что вызвало проблему с обработкой исключений в нескольких странных угловых случаях).
Ответ №2:
Вероятно
CheckPointer(pReceivePin,E_POINTER);
017D616D cmp dword ptr [ebp 0Ch],0
017D6171 jne CBasePin::Connect 4Dh (17D617Dh)
017D6173 mov eax,80004003h
017D6178 jmp CBasePin::Connect 1A7h (17D62D7h)
pReceivePin
оказывается, что она находится по адресу, хранящемуся в стеке — обычно доступ к ней осуществляется косвенным путем с использованием хранилища значений в ebp
.
Это значение сравнивается с null, и если оно равно null ( jne
не запускается), фактическое значение E_POINTER
перемещается в eax
( eax
используется для хранения возвращаемого значения функции), а управление передается функции epilogue, где выполняется очистка, а затем управление возвращается вызывающему ( ret
инструкция). Если значение pReceivePin
не равно null ( jne
срабатывает), управление передается в какое-то другое место, где хранится код, который оказался после CheckPointer
, и этот код затем выполняется.
Комментарии:
1. Почему вы упомянули
ret
, что в моем дампе vs нет такой инструкции, верно?2. @ollydbg: Это где-то в другом месте. Попробуйте вызвать этот код с
pReceivePin
значением null — код выполнитсяjne
и попадет в файл, гдеret
находится.
Ответ №3:
Вам нужно предоставить больше контекста, но, вполне возможно, последняя строка переходит к завершающим частям функции CBasePin::Connect, за которой вскоре следует RET. Это довольно согласуется с логикой вашего макроса. Вторая строка переходит сразу после последней строки, если указатель не равен нулю (т.Е. null).
Ответ №4:
Сборка выглядит совершенно нормально.
cmp dword ptr [ebp 0Ch],0
выполняется ли сравнение pReceivePin
с NULL
. pReceivePin
это локальная переменная внутри вашей функции, поэтому ее адрес является смещением от начала фрейма стека функции. ebp
содержит адрес начала фрейма стека. 0Ch
это смещение pReceivePin
внутри фрейма стека. Все локальные переменные в вашей функции будут адресоваться как [ebp something]
, за исключением параметров. Параметры обычно обозначаются как [ebp - something]
.
mov eax,80004003h
это не что иное, как E_POINTER
значение, помещенное в область «возвращаемое значение» функции (для этой цели используется регистр eax
).
В финале jmp
управление передается коду эпилога текущей функции ( CBasePin::Connect
), который заканчивается на ret
command (и «возвращает» текущее eax
значение, т.е. E_POINTER
)
Средний jne
элемент управления sens в коде сразу после вашего макроса, if pReceivePin
не равен E_POINTER
.
Комментарии:
1. Почему
pReceivePin
расширяется до[ebp 0Ch]
?2. @ollydbg: Она хранится в stack и к ней можно получить доступ через косвенное обращение.
3. В чем разница между
jmp xxx
иcall xxx
then?