САБЖ Стало интересно, как трейсить ехе из своего ехе, чтобы был доступ к памяти и регистрам. Подскажите пожалуйста, как реализовывается подобное в простейшем случае.
spa За пост #3 спасибо, не обратил внимание на статью! Сонный уже, наверное =\ [upd] Очень жаль, что я невнимательно сайт изучил. Огромное спасибо Аквиле за перевод и spa, что ткнул носом на статьи
Почитал статьи, попробовал что-то свое реализовать. Скажите, как реализуется трассировка без захода в вызываемую функцию. Было бы супер, если бы можно было трассировать программу, но не заходить внутрь функции, если функция находится во внешнем модуле.
dyn давай думать логически, хорошо? Что такое заход в функцию call (ну в подавляющем бОльшенство случаев), дальше как только мы "встали" на call и проверили ( по адресу) что она во внешнем модуле мы ставим бряк ( int 3 например) сразу за call и выполняем программу(выключая режим трассировки), когда срабатывает бряк снова включаем режим трассировки. Это самый очевидный вариант, думаю еще много чего можно придумать.
Не понятно как включить и выключить режим трассировки. Я использую те функции, которые в статье описаны: CreateProcess, WaitForDebugEvent, ContinueDebugEvent. Т.е. впоймали мы EXCEPTION_SINGLE_STEP. Сняли trap-бит. Продолжили выполнение. Как Сделать так, чтобы на наш обработчик управлние сразу за кэлом передалось?
Почитай инфу елки палки. Что такое TF? Когда он установлен происходит бряк на каждом шаге, тебе и надо шагнуть еще на 1 инструкцию внутрь кола, так зачем ты его снимаешь?
Просьба не пинать сильно Я только только первые шаги в этом направлении делаю. Вот смотрите что я хочу. Есть например такой код (смотрю обычное делфи-приложение): *************************** push [arg_1] push [arg_2] push [arg_3] push [arg_4] push [arg_5] call _ReadFile //... iat _ReadFile: jmp [ReadFile] *************************** либо просто: call [ReadFile] *************************** Вот хотелось бы сделать так, чтобы обрабатывалось оба случая, при чем трассировка не входила внутрь ReadFile. Информацию я читаю, но я нуб и для вас мои вопросы могут казаться примитивные. Вот что я делаю: CreateProcess с дебаг-флагом на myapplication.exe Дальше делаю: WaitForDebugEvent. Жду первого пряка. Ставлю TF. Дальше трассирую пошагово, получая контекст потока и каждый раз выставляя TF. Управление возвращаю через ContinueDebugEvent. Проблемы у меня 2 на данный момент: 1. Судя по EIP, трассируемый поток начинается где-то в недрах ntdll.dll. И там же и заканчивается. Делаю так на каждом шаге: printf("\n 0x%p", ThreadContext.EIP); И все адреса на начале и в конце внутри нтдлл. Внутрь приложения я так и не попадаю. 2. Не совсем понимаю, как отладить ситуацию с обходом кола. Я не хочу заходить в посторонние модули, т.к. медленно очень это все. А как обработать - хз.
Ну вы его еще запутайте аппаратными бряками))) Так и есть, читай Руссиновича. Про бряки тебе spa написал уже. Смотришь если инструкция call/jump и ты не хочешь в нее заходить то пишешь(в память процесса) за этой инструкцией int 3, 0xCC. При этом не забудь сохранить тот байт который там был. Сбрасываешь флаг и отпускаешь тред. Т.о. ты получишь управление уже после кола. Далее, восстанавливаешь тот байт, и ставишь контекст на байт назад, на начало инструкции которую ты затер int 3.
Понял. Огромное спасибо! Скажите, а аппаратный брекпоинт как поставить? Где-то читал, что с dr-регистрами связано. Еще интересно, чем отличается 2х-байтный int3 от однобайтного (0xCC) ?
Ладно хватит шуток, давай код, может поможет кто. Может даже это буду я. И еще за бей на бред ,пиши 0xCC. И еще забей на хардварнные бряки. пока тупо обычным бряком сделай, не забудь только сохранить что было в памяти до затирания.
> что было в памяти до затирания при использовании двухбайтного int3 сохранить следует от и до (включительно). связка инструкций push 0x302; popfd не должна быть нарушена.