Я пишу какую-то многопоточную программу на Си. Я попытался изменить несколько инструкций в начале тела функции, чтобы перенаправить выполнение куда-то еще.
Но я заметил, что при отладке в Visual Studio 2015 некоторая область памяти кажется неизменной, как показано вMemory
окно.
Например:
На рисунке ниже функция ApSignalMceToOs()
начинается с 0x7FFBBEE51360
. Я удалил диапазон памяти от 0x7FFBBEE51360
до 0x7FFBBEE5136E
, чтобы изменить его.
Строки с 305 до 312 изменили диапазон адресов 0x7FFBBEE51360
~ 0x7FFBBEE5136E
.
Все хорошо, пока 0x7FFBBEE51369
. В строке 311 (uint32_t(((uintptr_t)dst) >> 32
составляет 0x00007ffb
. После выполнения строки 311 я ожидал, что диапазон памяти в 0x7FFBBEE51369
~ 0x7FFBBEE5136C
будет заполнен как fb 7f 00 00
. Но, как показано ниже, Visual Studio говорит, что это 48 7f 00 00
, где 48
- старое значение.
Затем я пошел проверитькод разборки функции ApSignalMceToOs()
. И неудивительно, что инструкция на 00007FFBBF171365
равна mov dword ptr [rsp+4], 7F48h
, которая должна быть 7FFB
. Как показано ниже в красном поле ниже.
Так что до этого момента Visual Studio 2015 сообщала мне, что моя модификация произойдет сбой .
Но, как показывает желтая стрелка на над изображением, после выполнения mov dword ptr [rsp+4], 7F48h
я проверил содержимое в области стека. Удивительно это действительно 7f fb
перенесено в стек (показано в поле зеленый на над изображением).
И послеret
инструкция выполнена, регистр RIP
изменится на 00007FFBBEEAD940
, что неудивительно. См. Ниже:
И в другой функции читается то же место. Ниже показано:
code[len]
или byte ptr [rax]
- это ячейка памяти, содержащая 48
или fb
. Но он читает 0xcc
, что не является ни 0x48
, ни 0xfb
.
Код дизассемблирования Visual Studio декодируется из содержимого памяти. Таким образом, содержимое памяти или , как VS2015 считывает / обновляет ее , является ключевым моментом.
Исходя из вышесказанного, я пришел к двум выводам в режиме отладки VS 2015:
- Некоторое содержимое памяти отображается неправильно (или обновляется в графическом интерфейсе).
- Некоторые операции чтения из памяти не работают правильно.
Но программа работает без сбоев.
Кто-нибудь знает, почему это происходит?
ADD 1 - 17:08 PM 10/14/2019
Благодаря @MichaelBurr. Думаю, теперь я могу это объяснить.
Основная причина в том, что я добавил точку останова на 0x00007FFB...369
на уровне кода разборки, а не на уровне исходного кода C.
Когда я сделал это, отладчик VS сделал и добавил 0xCC
инструкцию в расположении 0x00007FFB...369
. Но, похоже, Visual Studio 2015 делает все возможное, чтобы скрыть этот факт . Ниже показано отображение содержимого памяти с точкой останова на 0x00007FFB...369
, мы видим, что 0x00007FFB...369
все еще содержит старое значение 0x48
.
Но после того, как я вручную скопировал память из 0x00007FFB...360
в 0x00007FFB...36e
куда-то еще. Инструкция 0xCC
со смещением 0x9
является раскрытой . См. Ниже:
Когда я изменял содержимое в 0x00007FFB...369
, Visual Studio, казалось, был предупрежден, и он просто восстановил содержимое в сохраненном старомодин, то есть 0x48
. Не мой недавно написанный.
Но я думаю, что само это восстановление не имеет никакого смысла. Восстановление сохраненного байтового содержимого ни в коем случае не должно запускаться в данный момент. Более разумное действие - немного обновить местоположение точки останова и вставить инструкцию 0xCC в новое место. Потому что недавно измененный код может изменить «границы команд». Таким образом, опыт отладки самоизменяющегося кода может быть лучше сохранен. Но для этого потребуется Visual Studio, чтобы разобрать новый код в соседнем. И новый контент инструкции может быть недействительным, если программист допустил ошибку.