Код мусора
Когда в результате аварийного останова вы оказываетесь в окне Disassembly, необходимо определить, действительно ли там отображается реальный код (это иногда довольно трудно). Вот некоторые советы:
- оказалось, что для просмотра кодов инструкций ассемблера полезно включение режима Code Bytes (в контекстном меню окна Disassembly);
- если в окне Disassembly отображается ряд идентичных инструкций ADD BYTE PTR [EAX], AL, это не есть правильный код ассемблера. Вы видите ряд нулей;
- если отображаются символы, но добавленные к ним смещения — очень большие числа, в общем случае превосходящие 0x1000, то вы, вероятно, вне секции кода. Однако очень большие числа могут также означать, что отлаживается модуль, который не содержит доступных частных (private) символов;
- если вы видите группу инструкций, которые не описаны в этой главе, значит вы, вероятно, видите данные;
- если дизассемблер Visual C++ не может дизассемблировать инструкцию, то в качестве кода операции он показывает "???".
Команда Set Next Statement окна Disassembly доступна в контекстном меню (открываемом правым щелчком мыши) и позволяет изменить EIP (регистр указателя инструкций), при помощи перевода указателя на следующую позицию исполнения. В окнах с исходными кодами команда Set Next Statement допускает некоторую "небрежность", но следует быть очень осторожным с этой командой в окне Disassembly.
Чтобы избежать аварийных остановов при переустановках EIP, необходимо обратить внимание на стек. Произвольные размещения в стеке и извлечения из него могут привести к аварийному завершению программы.
Например, для того чтобы повторно выполнить функцию без немедленного аварийного останова, необходимо обеспечить такое изменение выполнения, чтобы стек оставался сбалансированным. Ниже приводится двукратное обращение к функции, расположенной по адресу 0x00401005.
00401032 PUSH EBP
00401033 MOV EBP , ESP
00401035 PUSH 404410h
0040103А CALL 00401005h
0040103F ADD ESP , 4
00401042 POP EBP
00401043 RET
Дважды проходя через дизассемблирование, необходимо удостовериться, что при выполнении инструкции ADD по адресу 0x0040103F не нарушает баланс стека. Как было показано ранее при обсуждении различных соглашений о вызовах, данный фрагмент ассемблерного кода показывает обращение к _cded-функции (потому что инструкция ADD расположена прямо после ее вызова). Чтобы повторно выполнять функцию, следует установить указатель инструкций на 0x00401035, гарантируя, что операция PUSH выполнится должным образом.