Используя 'bytes at CS:EIP', чтобы узнать, где произошел сбой
Я получаю отчеты о сбоях от конечных пользователей с информацией доктора Ватсона, и я хочу использовать их, чтобы узнать, где произошел сбой (то есть, по какой строке кода).
Я не могу просто использовать EIP из отчета о сбое, потому что файл, который мы отправляем, имеет цифровую подпись, и это меняет все смещения. Однако информация о сбое также имеет "байты в CS:EIP", которые являются первыми 16 байтами, начиная с EIP, где произошел сбой. Это выглядит так:
Bytes at CS:EIP:
85 c4 14 c3 8b ff 55 8b ec 6a 0a 6a 00 ff 75 08
Эти 16 байтов встречаются ровно один раз в exe. Я могу найти их смещение в EXE, используя только средство просмотра HEX, но чтобы перейти туда во время отладки и посмотреть, какая строка находится в источнике, мне нужно знать их смещение в памяти после загрузки EXE.
Как лучше всего сканировать сегмент кода программы после ее загрузки? Могу ли я добавить код, который находит, где находится базовое смещение EXE-файла, а затем перебрать его и использовать memcmp, чтобы найти, где находится шаблон байта.
Кроме того, как я могу найти, где базовое смещение EXE?
5 ответов
Я использую очень простой подход к той же проблеме.
Сначала я сбрасываю свой исполняемый файл, чтобы найти физическое (в файле) смещение сегмента кода.
Затем я вычитаю его из адреса памяти, где эти "волшебные" байты расположены в двоичном файле.
Затем я запускаю программу в отладчике и просто добавляю это смещение к виртуальному адресу сегмента кода.
.text name
10EE8E virtual size
1000 virtual address (00401000 to 0050FE8D)
10F000 size of raw data
--> 400 file pointer to raw data (00000400 to 0010F3FF) <--
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
60000020 flags
Code
Execute Read
Если вы используете что-то вроде ollydbg, вы можете сканировать их память процесса во время ее работы и сообщать вам файл: строку и исходный код при просмотре найденных точек (при условии, что pdb связаны правильно). Это также позволяет вам просматривать виртуализированный адрес, если вы открываете файл статически.
Или, если вы просто работаете с основными инструментами, вы можете использовать dumpbin
(ака link /dump /all
) из Visual Studio или платформы SDK. Он может дать вам шестнадцатеричный дамп и / или разборку со всеми примененными перемещениями, а также подберет PDB для добавления имен символов в ваши списки. Все это говорит о том, что DLL могла быть перемещена на другой адрес во время загрузки из-за конфликта, но вы используете dumpbin /headers
чтобы узнать базовое смещение DLL по умолчанию.
Разве доктор Ватсон не дает вам значение EIP, а не только байты? Прошло много времени с тех пор, как я использовал это. Лучшее решение - подписаться на WinQual - тогда конечные пользователи смогут загружать свои аварийные дампы в Microsoft, и вы сможете собирать их оттуда, и вы сможете просматривать фактические мини-дампы и дампы кучи.
Все, что вам нужно сделать, это поместить ваши файлы PE (.dll и.exe) и файлы PDB на сервер символов, а затем указать отладчик (windbg или VS) на ваш сервер символов плюс сервер символов Microsoft. PE-файлы и PDB-файлы будут автоматически загружены, разборка будет показана для всех уровней стека вызовов и найдены исходные файлы.
Если ваши PE-файлы подписаны, то вы должны поместить подписанные PE-файлы на ваш сервер символов, хотя если вы поместите неподписанные файлы на свой сервер символов, то они, вероятно, будут нормально загружаться (байты кода не будут затронуты), возможно, с некоторыми предупреждениями контрольной суммы.
Для получения бонусных отметок вы должны выполнить индексацию источника перед добавлением PDB на сервер символов. Таким образом, отладчики могут получить правильную версию исходного файла из системы контроля версий - магическую. Это действительно не так сложно. Я делаю все эти шаги в своих хобби условно-бесплатных проектах.
Ссылки из моего блога: https://randomascii.wordpress.com/2013/03/09/symbols-the-microsoft-way/ https://randomascii.wordpress.com/2011/11/11/source-indexing-is-underused-awesomeness/
Повторим: это должно сработать. Я просматривал сотни аварийных дампов с компьютеров клиентов, работая во многих различных компаниях, и благодаря серверу символов и исходному серверу я получаю машинный код, имена функций, исходный код, локальные переменные и т. Д. С минимальными усилиями.
Я публикую здесь возможное решение, которое я нашел, хотя оно не очень элегантно. Я не уверен, правильно ли использовать GetModuleHandle в качестве базового смещения, но, похоже, он работает с 2-3 сообщениями об ошибках, которые я пробовал до сих пор.
unsigned char buf[] = { 0x85, 0xc4, 0x14, 0xc3, 0x8b, 0xff, 0x55, 0x8b, 0xec, 0x6a, 0x0a, 0x6a, 0x00, 0xff, 0x75, 0x08 };
HMODULE hModule = GetModuleHandle(NULL);
char* ii;
for (ii = (char*) hModule; memcmp(ii, buf, sizeof(buf)); ii++);
char buf2[1000];
sprintf(buf2, "%p", ii);
MessageBox(0,buf2,0,0);