Всем привет. Есть приложение, написанное на плюсах, которое просто посылает APC заданному потоку (оно его успешно находит по пиду процесса). Компилировалось это всё студией, ибо только от неё symstore понимает .pdb; потом запускаем сию вещь на виртуалке, к которой приаттачен windbg с livekd. На консоли нет ещё надписей заданных (просто в начале стоит sleep на 10с, чтоб успеть переключиться, потом выводится что-нибудь, чтобы показать, что выполнение продолжилось). Ок, делаем break, ищем process 0 0 наш процесс, .process /i успешно к нему аттачимся, загружаем символы для него, ставим успешно бряк (как-то bp my_app_name!_imp__OpenThread), замечаем, что OpenThread ещё не выполнился - никаких надписей ещё нет на консоли), волшебная команда g... и получаем падение отлаживаемого приложения при исполнении кода в kernel32.dll (если верить ольге) - она не может одним вариантом провести дизасм кода, а потому код коряв и делает обращение по адресу 0-0xFFFF. Хотя если ту же процедуру проделаем с тем же блокнотом (bp notepad!LoadFile), то бряк успешно срабатывает, но когда пытаешься продожить исполнение, блокнот падает, но не в kernel32, причём на бессмысленной инструкции - add dword [edx],0; Интересно, что буквально пол часа назад тот же блокнот не падал, а успешно продолжал выполнение. Если не сложно, подкиньте инфы по отладке subj. Вот код, может пригодится. Код (Text): #include <windows.h> #include <Tlhelp32.h> #include <stdlib.h> #include <iostream> VOID CALLBACK apc_function_1(ULONG_PTR dwParam) { MessageBox(0,0,0,0);//вообще не важно что здесь - я прекрасно знаю, что из-за dll //base address randomisation прыгнем куда-то не туда, но это не важно } int parser() { char* str=GetCommandLine(); for(str; *(str)!=0; str++){std::cout<<*(str);}; while(*(str)!=' ')str--; str++; return atoi(str); } int main() { Sleep(10000); DWORD thread_id; DWORD pid=parser(); THREADENTRY32 te; std::cout<<'\n'<<pid<<'\n'; HANDLE h=CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD,0); te.dwSize=sizeof(te); Thread32First(h,&te); while(te.th32OwnerProcessID!=pid){te.dwSize=sizeof(te); Thread32Next(h,&te);} thread_id=te.th32ThreadID; HANDLE thread_handle = OpenThread(THREAD_ALL_ACCESS,0,thread_id); if (thread_handle==INVALID_HANDLE_VALUE){Beep(500,500);return -1;} Sleep(1000); send_apc: QueueUserAPC(apc_function_1, thread_handle,0); return(0); }
Попробуй это: Controlling the User-Mode Debugger from the Kernel Debugger И в частности команда !bpid должна помочь в твоём случае. Я пользовался, работает замечательно, только задержку надо, это да.
Да, действительно удобно (ну кроме того, что нет отдельного окошка для дизасм-листинга для ntsd в самом windbg)... Хотя это довольно большие заморочки ради бряка
Вопрос: из-за того, что с символами что-то не так (на tm запускаю ntsd, управление передаётся в windbg на hm - kd заменяется на Input, т.е контролируем юзермодный дебаггер уже, ставим бряк на тот же OpenThread, но пролетаем почему-то мимо), решил самостоятельно дойти дебаггером до вожделенной функции. Сначала модуль загружается в память, настраивается ldr и прочее, потом управление передаётся main thread - NtContinue, что сводится к sysenter. Ок, мы должны использовать кд для такого. Делаем .breakin, оказываемся в коде выхода из сервиса дебаггера (ну, по крайней мере я так думаю). Можно попытаться вклиниться в отлажеваемый юзермодный процесс .process /i eprocess_addr, попадём опять в юзермод дебаггер, снова делаем .breakin и опять мы на выходе из сервиса дебаггера... И ещё заметил, что кд отказывается по sysenter'у идти, просто делает trace_over. x64 Вы сказали про !bpid, но -a просто говорит, что поставил бряк в процессе с пидом таким-то, а тем временем процесс уже исполняется и заканчивает исполнение, -s, кажется не совсем то, а назначение параметра -w не совсем понял. Можете немного растолковать, что к чему? UPD:Хотя стоп, с -s попробую... UPD:Перепробовал все параметры !bpid, выводит что-то вроде Код (Text): Waiting for winlogon.exe to break. This can take a couple of minutes... Break instruction exception - code 80000003 (first chance) Stepping to g_BreakinProcessId check... Break into process 1048 set. The next break should be in the desired process. и просто продолжает выполнение вм.
Ок, переформулирую вопрос: вот дошли мы юзер-дебаггером до sysenter'a, делаем .breakin, ищем процесс отлаживаемый, делаем .process /i eprocess_addr, жмакаем g, но запускается снова юзермодный дебаггер. Как этого избежать?