Pull to refresh

Comments 69

UFO just landed and posted this here
Да, у каждой задачи — свои методы решения.
Я сейчас тоже не так часто использую отладчик, т.к. разрабатываемый продукт работает на уровне ядра и с сотнями потоков, которые нельзя прерывать.

Но ведь есть еще всякие небольшие домашние проектики или на работе тулзы — их приходится и поотлаживать по старинке :)
Под веб отладчики таки тоже есть.
а я вот раньше писал много всякого винапишного и 3-дешного, на delphi и с++, под час, при помощи отладчика было удобнее сам алгоритм писать.

А теперь пишу на PHP и никак не заставил себя настроить отладчик в eclipse… недавно прикрутил firebug к своему фреймворку… жить стало лучше (особенно AJAX), но это всё не то… сейчас вот сделаю над собой усилие и попробую таки прикрутить нормальный…
Рекомендую Zend Debugger. XDebug у меня часто ронял Apache.
> С того времени как начал писать под веб о них забыл :)

А зря… удаленный дебаг какого-нибудь приложения под томкатом или JBoss экономит кучу времени… Даже если ты пишешь plain html страницы, то можно дебажить javascript (той же MS Visual Studio, например)
UFO just landed and posted this here
«И вообще, лучше писать без ошибок, чем потом отлаживать ^_^»
я б вам душу продал если б вы научили меня так (:
UFO just landed and posted this here
недавно пытался объяснить знакомому про bp. не вышло.
у вас отлично получается, продолжайте в том же духе. спасибо.
Еще можно упомянуть, что опкод int3 занимает в памяти ровно один байт (CCh), а опкоды прерываний с другими номерами — два байта (CD xx). Это удобно, т.к. отладчику нужно запоминать/заменять только один первый байт оригинальной команды.
Можно было бы, но я старался написать максимально просто и не перегрузить лишней информацией.
А 1 или 2 байта — это не так уж и важно для понимания сути процесса.
int3 занимает один байт для того, чтобы можно было им заменять однобайтные команды. Если бы int3 занимал два байта и им заменили однобайтную команду, он бы затёр первый байт следующей команды, что сломало бы все переходы на эту вторую команду (так как переход осуществлялся бы в середину команды int3).
Точно. Век живи — век учись)
Какая разница, каким числом байт затирать код? Одного бита достаточно.
Ну то есть какой смысл переходить к следующей команде, если текущая затерта?
Поразмыслил.
Я предположил(неверно прочел), что после выполнения отладочного прерывания управление возвращается восстановленной команде. Тогда нет разницы, какой длины была затерающая команда. Но тогда совершенно не ясно, как снова вернуть точку останова и как избежать ветвлений на сломанную команду, да.
А в статье по-русски написано, что обработчик сам выполняет затертую инструкцию и переходит к следующей за int 3.
Вероятно, если затерта была многобайтная команда, int 3 дополняется nop; ами, да? И на них возвращается управление.
Пусть есть такой код по адресу скажем 100:
X1 Y1 Y2 Y3

X1 — первая команда, Y? — вторая.

Пусть int3 занимает два байта. Тогда если поставить брейкпоинт по адресу 100, получим:
Z1 Z2 Y2 Y3

Если в коде были переходы на адрес 101, то они сейчас сломаны, потому что переход будет осуществляться в середину команды int3 (это не вызовет выполнения команды int3, отладчик не сможет ничего подменить, будет выполнен какой-то мусор или вообще это будет считаться некорректным кодом).
Дополнение к P.S.:

Может стоит еще добавить, что это не касается и компилируемых языков, но с другой средой выполнения (Java)? Там вроде бы используется Virtual Machine Debug (кажется так называлось).
UFO just landed and posted this here
да. вот меня заинтересовала ситуация с Java.
Статья хорошая, спасибо.

Еще один момент, если не ошибаюсь, то отладчик VC++ при срабатывании брейкпоинта останавливает только один поток, в котором он сработал, все остальные потоки продолжают выполнятся. Также при пошаговом исполнении вы можете быть переброшены на другой брекпоинт, который сработал в другом потоке. В gdb останавливаются все потоки.

Вообще дебагер — расслабляет. Им очень легко не просто отлаживать, но и помогать себе при написании. К примеру написал кусок алгоритма, запустил и посмотрел как, что и где. Поскольку я сейчас часто пишу ядерный код, то приходится часто напрягатся и выверять каждую строку кода, иначе будет «приплыли» :)
Если бы он останавливал только 1 поток, то было бы очень много проблем — как уследить за целостностью данных? Надо все время пересчитывать значения переменных и обновлять их и т.п. Так что даже судя по этим возможным проблемам можно утверждать, что он все потоки останавливает :)
Практика показывает, что VS2005 останавливает всё же один поток. Не знаю, как в 2008 версии.
Мне не очень хочется писать тестовое приложение, т.к. я уверен, что он останавливает все потоки.
Но если вы настаиваете, то могу написать и проверить. Или сами проверьте :)
Спасибо, было интересно. Может быть напишете еще про аппаратную отладку?
Я никогда не отлаживал аппаратуру, так что знаю про это мало.
>> Когда процессор встречает эту инструкцию, то он инициирует хардварное прерывание и передает его в обработчик хардварных прерываний операционной системы.

Это прерывание как раз программное, ты ведь его в своей программе сгенерировал. Кроме int 3 (оно обозначается #BP) существует ещё отладочное прерывание int 1 (#DB), но его обработчик можно переназначить, чем пользуются некоторые защиты(StarForce) или отладчики (Syser, SoftIce).
int 3 — это обычное аппаратное прерывание, а не программное. Программное — это throw в C++. Просто это прерывание конвертится ОС в программное.
AFAIK синхронно вызываемые из кода прерывания всегда было принято называть программными. До тех пор, пока переключаться на вектор 3 код будет путем выполнения инструкции int 3 оно будет программным. Если вы подключите внешний аппаратный отладчик, который по своим соображениям сгенерирует это прерывание, его назовут аппаратным.
А throw это механизм совершенно другого уровня.
Его называют аппаратным, т.к. это прерывание приходит в операционную систему из процессора — поэтому оно аппаратное.
А как оно «пришло в процессор» в вашем восприятии предмета не учитывается?
Это не мое восприятие предмета — это то, как пишут в книгах. Я своих терминов не вводил :)
Интересно узнать, что это за книги. Там за вас ввели неверное определение. Гляньте википедию, там указано более расхожее :)
Что за книги такие интересные? И как конкретно они определяют прерывания
1. программные
2. внутренние
3. аппаратные
?
Это очень спорный вопрос. Я читал и сам считаю, что аппаратное прерывание — это IRQ, которое пришло от какого-нибудь девайса, APIC контроллера. int3 — программное, во-первых потому что isr хендл на него не повесить. Также посмотрите в исходники той же Mac OS X. Там int3 обслуживает тот же trap хендлер, который обслуживает остальные инструкции, как-то вызов rdmsr или in/out из юзермодного кода, все идет в один и тот же kernel_trap.
Любое прерывание «приходит в систему» из процессора. Это не критерий.
Тьфу, я в своём комменте выше ошибся. int 3 это программное ИСКЛЮЧЕНИЕ, а не прерывание.

Под исключения в архитектурах x86 отведены первые 20 записей в IDT(interrupt descriptor table).

Intel® 64 and IA-32 Architectures Software Developer's Manual, Volume 1:

The Processor provides two mechanisms for interrrupting programm execution, interrupts and exceptions:

— An interrupt is a asynchronous event that is typically triggered by an I/O device.
— An exception is as synchronous event that is generated when the processor detects one or more predefined conditions while execution instruction. The IA-32 architecture specifies three classes of exceptions: faults, traps and aborts.

int3/int1 — отладочные исключения, throw в С++ — программное исключение. Нажатие кнопки мышки — аппаратное прерывание.
>>int3/int1 — отладочные исключения, throw в С++ — программное исключение. Нажатие кнопки мышки — аппаратное прерывание.

Да, все правильно. Но отладочные исключения работают посредством аппаратных прерываний :)
Я ведь привёл определение. Это два разных термина. Механизм один, а терминология разная. Поэтому если говорить, а уж тем более писать статью, про int3, то его надо называть так, как принято, а не как захочется.
Напишите свою статью, причем так, чтобы было просто и понятно — тогда имеет смысл давать советы что и как писать :)
Я не претендую на научность статьи, вполне мог что-то напутать или не проверить термины, т.к. писал без проверки. Но моя основная идея — показать на верхнем уровне, как оно работает без лишних деталей.
Да ладно вам, не обижайтесь :)

Я привёл отрывок из мануалов от интела. На них стоит ровняться. Вопрос терминологии достаточно важен, особенно, если вы пишите для новичков. Всем хочется, чтобы новая информация была достоверной, в том числе соответствовала общепринятой терминологии.
Я не обижаюсь :)
Исправил это место в статье — теперь лучше?
>> Но отладочные исключения работают посредством аппаратных прерываний :)

Ничего подобного. Я извиняюсь, но если вы это говорите, то у вас отсутствует понимание того, что вы пишите.
Отладочные исключения в Windows работают не по средствам аппаратных прерываний, а благодаря механизму структурной обработки исключений(SEH) на уровне системы и аппаратному механизму контроля исполнения программы архитектуры x86-64.

Генерируется исключение, определяется вектор и процедура обработки по IDT. Управление передаётся системному коду уровня ядра(диспетчеру исключений), он определяет тип в каком потоке было сгенерировано исключение, извлекает TEB из регистра FS[0] и начинает обработку исключения в поисках подходящего обработчика(более подробно у Руссиновича и Питрека).
Где тут аппаратные прерывания?
Цитата из Advanced Windows Debugging (Mario Hewardt). Глава 3. Debuggers uncovered. How breakpoints work (стр. 168):
In response to the STATUS_BREAKPOINT exception, the processor executes the interrupt handler registered for the interrupt vector 3.
и т.д. там еще много текста про векторы прерываний.

Я не хочу развивать эту техническую тему дальше — статья написана специально предельно просто и не вдается в подробности, т.к. они большинству не нужны. Аппаратные прерывания или аппаратные исключения — это по большому счету неважно для понимания сути процесса.
Так что спасибо за детали из Руссиновича, но я опирался на книгу Хьюварта, которую, кстати, тоже Руссинович рецензировал.
Не увидел в отрывке выше «hardware interrupt», поэтому не понял к чему вы его привели. Там как раз говорится про исключение. А «interrupt vector» потому что таблица из которой он берётся называется interrupt descriptor table.
Да, с «аппаратным прерыванием» возможно я был неправ и действительно запутался в терминах — не хочу перечитывать заново литературу и уточнять. Хотя «the processor executes the interrupt handler „ для меня звучит, как указание на то, что происходит прерывание, по крайней мере вызывается обработчик прерывания. Но не в этом суть.
Через пару недель иду на семинар Соломона — бывшего партнера Руссиновича по windows internals. Надеюсь там это будет детально раскрыто.
увлекался исследованием защиты программ. Да и сейчас ещё многое помню. Увлекательный процесс, скажу я вам…
Эмс. Неужели Microsoft такая отсталая система, что ничего не знает о debug-регистрах? Чего-то плохо в это верится. Если я не ошибаюсь, то точки останова там можно было ставить и на доступ к данным, что, по идее, как раз и говорит о том, что MS умеет пользоваться этими регистрами… Вобщем, что-то тут не сходится.

int 3, они, конечно, должны были бы оставить для совместимости, но вряд ли это — основной механизм отладки.
Про регистры на доступ к памяти я немного написал в статье. Конечно, они их используют, но это не основной механизм работы.
Вы имеете ввиду отладочные регистры DRx? Конечно знает, но причём здесь система? Речь об отладчиках и отлапдочных средствах. Debug API windows позволяют с ними работать. Ну а собственно это ведь не системный механизм, а процессорный.
Для отладки приложения, написанного в MS VS имеющегося int 3 вполне достаточно. Другое дело, если вы хотите проникнуть в недра чужой программы, вдобавок еще защищенной чем-либо, тут без отладочных регистров будет труднее, чем с ними. Хотя бы потому, что int 3 модифицирует код. Про такие вещи очень хорошо написано у Криса Касперски в книге «Техника отладки программ без исходных текстов» — живой язык, масса примеров и аналогий, для понимания не требуется заранее обладать навыками, которым там учат.
полезная статья.

вот у меня вопрос возник. почему условные брейкпоинты работают так как выговорите? не легче просто вызывать int 3 по нужному условию, т.е. воспользоваться самим языком, а не передавать в отладчик?
все, сам понял. ступил.
Это бы сделало невозможным установку условия во время выполнения без перекомпановки (linking'а) кода. А для этого его пришлось бы перезапускать. Поэтому условные ТО такие медленные.
; Когда вы удаляете брейкпойнт, то:
Отладчик просто заменяет вставленный int 3 обратно на нужную команду и забывает про этот брейкпойнт
;

Как-то сложно получается. Гораздо проще понавставлять перед каждым оператором nop, который при необходимости легко заменяется на int 3.
И иметь проблемы с производительностью и размером ехе файла?
Напиминаю, что брейкпойнты можно и в релизных сборках ставить.
Вспоминаю я многомесячную отладку железки, когда добавление одного NOPа приводило к полному исчезновению багов. Причем NOP ставился в участок кода, который управления никогда не получал! Размещение блоково кода менялось и начиналось… Под винду с многопоточными приложениями, если они криво написаны, то же самое будет — поставил NOP и работать начинает иначе. Или не работает дебажная сборка, а релизная пашет. Лишние нопы лучше не ставить :-)
UFO just landed and posted this here
Есть особенность использования бряков в самомодифицирующемся коде: если поставить бряку (не хардварную) на код, который будет изменен, бряка с большой долей вероятности не сработатет. Думаю, это из-за того, что выполняющийся код заменит INT3 на то, что ему надо. Хардварные лучше, но их мало :-(
Кстати, написал бы про это статью — было бы очень интересно почитать про методы борьбы с таким кодом. Как вы узнаете, как такой процесс работает и что делает?
Кстати, у вас в drWeb система HIPS есть? Или эвристический анализ файла с поиском внутри всяких ссылок на левые сайты и т.п.?
Да, тема интересная. Я вот все хочу стащить с работы десяток разных вирусных пакеров да написать, как авторы изголяются. И про антиоладку на SEH основанную, и чтоже все-таки делать, чтобы их вскрыть :-) Самомодифицирующийся код я встречал только в упаковщиках, распакованные данные так не делают. Либо же я не понял, что код сам себя модифицировал. А пакеры видно либо в Hiew либо же в IDA с первых строк. Методики распаковки я для себя уже вывел :-)

HIPS — это en.wikipedia.org/wiki/Intrusion-prevention_system? Кажется нет. Чтобы посмотреть, куда троянчег ломится, достаточно и ethereal, в общем. Надо бы, конечно, сделать сборку поудобнее, да что-то руки не доходят.
HIPS — это мощная фича. Она позволяет находить новые вирусы по их вредоносному поведению. Например, если программа пишет себя в автозагрузку, да шлет что-то вовне, да пытается устанавливать хуки — hips ее заблочит и спросит пользователя — а уверен ли он, что это не вирус?
Так можно ловить даже новые вирусы… теоретически, сам понимаешь :)
А, кажется понял, про что ты :-) Обычно термин «поведенческий блокиратор» слышу :-) Я не очень вкурсе нововведений в 5-й версии (которая до НГ должна выйти), которые не касаются непосредственно баз.
Главный минус такой штуки, как мне кажется, — довольно большое количество ложных срабатываний. Соответственно, окончательные решения будет принимать пользователь, который далеко не всегда понимает что и как.
Да, выбор за пользователем в спорных случаях.
Там так: есть у каждого процесса показатель его «опасности» — число от 0 до 100, например.
Также есть 2 числа — minDanger (например 30) и maxDanger (например 60). Соответственно если опасность процесса меньше minDanger, то HIPS его игнорирует. Если от minDanger до maxDanger, то спрашивает пользователя. А если больше maxDanger, то сразу блочит без вопросов.
Так что самые вредоносные сразу блочатся без вопросов, но в некоторых случаях спрашивается совет у пользователя.
Конечно, в UI можно всегда изменить решение и разрешить или заблокировать что-то.
Не понятен только один пункт: тормозят ли брейкпоинты.

Как они могут тормозить, если они останавливают выполнение программы. Но если отбросить этот момент, то думаю, что даже брейкпоинты без условий замедляли бы выполнение программы(это мое имхо исходя из скудных знаний асма на x86 и микроконтроллерах).
Имелось в виду конечно, тормозят ли брейкпойнты, которые не срабатывают. Если сработал — то тут уже не до тормозов, все стоит.
А насчет второго — как брекпойнт может замедлить программу, если это просто инструкция в нужном месте, которое не вызывается?
Если сильно придираться, можно сказать что процессор некогда не передает отладочное исключение в обработчик прерываний операционной системы, он передает его по адресу указанному в векторе прерываний, который в свою очередь любая уважающая себя ОСь переписывает… но о самой ОС процессору не как не извесно)
Sign up to leave a comment.

Articles