Останов на точке входа программы в WinDbg

Не так давно столкнулся с проблемой при открытии исполняемого файла в WinDbg. Проблема, скорее всего, достаточно тривиальна и с ней из раза в раз сталкиваются те, кто впервые пытается отладить типовой исполняемый модуль (.exe) при помощи отладчика WinDbg. Заключается она в том, что совершенно непонятно как поставить точку останова на первую инструкцию исполняемого файла (программы). Обычно мы открываем приложение через меню File - Open Executable... (или просто нажатие комбинации клавиш Ctrl+E). При загрузке исполняемого файла отладчик останавливается задолго до начала непосредственно кода самой программы, глубоко в коде загрузчика образов Windows:

Узнать больше о том, как поставить точку останова на точку входа программы

Тормозят программы - висят на ntoskrnl.exe!_misaligned_access+0x1843

Встретился тут с одной проблемой, вполне возможно для профессионалов она и покажется покажется достаточно легкоразрешимой, однако для меня это пока что дремучий лес. Собственно, сама проблема заключалась в том, что на станции пользователя, вдруг ни с того, ни с сего, начали тормозить программы. Причем тормозить как-то достаточно интересно: при запуске приложения оно очень долго стартует, период старта может продолжаться несколько десятков минут. Подобное поведение было отмечено для почтового клиента Outlook 2010, инсталляционного (не помню уже какого) пакета .msi и ряда других приложений.

Подробнее о тормозящих программах

Последовательность вызова функций

Эта статья планировалась по мотивам освещения различных сторон работы с дампами в отладчике Windbg. Если кому вдруг выпала удача поработать в Windbg с различного рода дампами, да и просто со стеками "живого" кода, неоднократно видели в списке стека вызова запись, подобную вот этой:

portcls!PcHandlePropertyWithTable+0x1b

Я не утверждаю, что она именно в точности такая, я просто хочу обратить Ваше внимание на саму структуру записи. В подобном формате отладчик выводит данные о вызываемых в ходе выполнения кода функциях. Конечно же эта запись имеет свой собственный формат, и выглядит он таким вот образом:

callsite-names

Как можно увидеть по скриншоту, формат записи следующий: имя_модуля!имя_функции+смещение, где:

  • имя_модуля - имя исполняемого файла, код которого содержит функцию;
  • имя_функции - наименование функции, в которой содержится инструкция, вызывающая вышестоящую функцию;
  • смещение - количество байт (в шестнадцатеричной системе счисления) от точки входа функции до начала инструкции, следующей за инструкцией, вызвавшей вышестоящую функцию. В ряде ситуаций, например при отсутствии символов, имя функции может быть недоступно, тогда адрес отображается в формате имя_модуля+смещение. Смещение высчитывается от стартового адреса функции (от первого её байта).

Читать далее о последовательности вызова функций

RasEnumConnections

Функция RasEnumConnections возвращает список всех активных соединений Службы удаленного доступа (RAS, Remote Access Service). Функция возвращает хендл каждого соединения и имя записи телефонной книги.

Синтаксис:

C++:

DWORD RasEnumConnections(
  _Inout_ LPRASCONN lprasconn,
  _Inout_ LPDWORD   lpcb,
  _Out_   LPDWORD   lpcConnections
);

Подробнее о функции RasEnumConnections

_security_init_cookie

Я, на данный момент, в различных отладчиках и дизассемблерах я лично встречал две интересных функции:
__security_init_cookie@?
__security_check_cookie@4
Почему-то мне кажется, что данные функции каким-то образом связаны с различными проверками на переполнение стека, неинициализированные переменные и пр. Компилятор вставляет данные функции в код программ, написанных на языке MS Visual C/C++.
Однако, опции могут отключаться заданием соответствующих ключей компиляции. Например, опция Buffer security check отключается убиранием ключа /GS.
Встречал мнение, что отключение данных опций настоятельно не рекомендуется разработчиками уже в рабочем коде, по причине возникновения различных проблем безопасности (недаром ведь называется это все соответствующим образом). Механизм призван затруднить потенциальным хакерам создание различных эксплоитов, основанных на переполнении буферов.

Что еще можно узнать про _security_init_cookie

Пролог и эпилог функции

Прежде чем начать разговор о прологе и эпилоге функции, давайте сделаем некоторое лирическое отступление и поговорим о терминах, которые помогут нам разобраться в обсуждаемом вопросе. Как мы уже говорили в статье по соглашении о вызовах (ссылка), зачастую в подпрограммах (функциях/процедурах) используют так называемый указатель кадра стека, зачастую называемый так же указателем фрейма стека, просто указателем фрейма (frame pointer) или стековым кадром.

Стековый фрейм (stack frame) — механизм использования системного стека, предназначенный для передачи аргументов и выделения временной памяти для функции (процедуры), написанной на языке программирования высокого уровня.

Ну да, это механизм передачи параметров функции из кода вышестоящей функции программы и выделения памяти для использования кодом вызываемой функции (например, для хранения локальных переменных). Дело в том, что когда под архитектуру x86 компилируется (переводится в машинный код) программа, написанная на высокоуровневых языках, в получившемся коде для передачи параметров в подпрограмму (функцию) используется стек. Почему именно стек? Вероятно, данность эта обуславливается историческими факторами, в силу которых архитектура x86 содержит ограниченное количеством регистров, и их использование в качестве указателей на параметры функции было бы неоправдано, поскольку в Windows зачастую требуется передача в функцию большого количества значений. Код, который вызывает функцию, перед её вызовом должен положить аргументы функции в стек в определенном порядке (определяемым соглашением о вызовах), и только после этого вызвать саму функцию. Таким образом, когда процедура получает управление, она получает и программный стек от вызвавшей функции, на вершине которого располагается адрес возврата из функции, затем уже идут параметры (аргументы), с которыми данная функция была вызвана. Затем, для того, чтобы не портить стек вызвавшей функции, вызываемая функция настраивает собственный стековый кадр, для оперирования локальными параметрами, сохранения значений в стек и прч.

Продолжить изучать пролог и эпилог