|
|
| Посл.отвђт | Сообщенiе |
|
|
Дата: Июл 19, 2004 16:47:46 Мой анпакер юзает Debug API для отладки проги. Нужна защита от IsDebuggerPresent. Делаю вот такую тестовую тестовую процедуру на msvс++ для проверки байта PEB.BeingDebugged: DWORD Peb_BeingDebugged; BYTE debugged; __asm{ mov eax, dword ptr fs:[18h] mov eax, dword ptr ds:[eax+30h] lea eax, [eax+2] mov Peb_BeingDebugged, eax mov al, [eax] mov debugged, al } CString buf; buf.Format("Anti IsDebuggerPresent: %d",debugged); // А это просто для вывода в лог AddListBoxItem(buf); buf.Format("IsDebuggerPresent: %d",IsDebuggerPresent()); AddListBoxItem(buf); //AntiDebug Таким образом, если в debugged=0, то отладчик не найден, а 1, то найден. И затем этот код вставляю в события CREATE_PROCESS_DEBUG_EVENT и EXCEPTION_BREAKPOINT. Запускаю анпакер, выбираю в нем прогу, которая ТОЧНО проверяет IsDebuggerPresent и в листинге выходит: Anti IsDebuggerPresent: 0 IsDebuggerPresent: 0 т.е. будто бы не найден отладчик и всё ОК. Но прога, которую дебажу сама завершается, обнаружив отладчик!! Если загрузить анпакер в оли 1.10 (без скрывающих плагинов) и также запустить прогу эту , то выйдет уже Anti IsDebuggerPresent: 1 IsDebuggerPresent: 1 т.е. отладчик найден! Такое ощущение, что смотрится это значение Peb_BeingDebugged для моего анпакера, а не для дебажной проги! Как от этого избавится? Может я где ошибаюсь? Очень надеюсь на помощь, т.к. с этим вопросом уже намаялся! |
|
|
Дата: Июл 19, 2004 19:37:07 Такое ощущение, что смотрится это значение Peb_BeingDebugged для моего анпакера, а не для дебажной проги! ну да. тебе надо править peb отлаживаемой проги через WriteProcessMemory |
|
|
Дата: Июл 19, 2004 21:25:44 Max Если ты имешь в виду так: DWORD Peb_BeingDebugged; // BYTE debugged; __asm{ mov eax, dword ptr fs:[18h] mov eax, dword ptr ds:[eax+30h] lea eax, [eax+2] mov Peb_BeingDebugged, eax // mov al, [eax] // mov debugged, al } DWORD gpag; BYTE debugged; VirtualProtectEx(hProc,(LPVOID)Peb_BeingDebugged,1,PAGE_READWRITE,&gpag); ReadProcessMemory(hProc, (LPVOID)Peb_BeingDebugged, (LPVOID)debugged, 1, NULL); VirtualProtectEx уже возвращает ошибку ERROR_INVALID_ADDRESS. А ReadProcessMemory ошибку ERROR_PARTIAL_COPY. Опять же мне кажется, что адрес где находится этот байт PEB.BeingDebugged я получил для анпакера, а для дебажного процесса этот адрес другой, поэтому и ошибка. Может быть так? |
|
|
Дата: Июл 19, 2004 22:40:47 |
|
|
Дата: Июл 20, 2004 11:59:00 Проблема решена путем мемори патча IsDebuggerPresent. |
|
|
Дата: Июл 20, 2004 12:50:39 > Проблема решена путем мемори патча IsDebuggerPresent А это что ещё за мемори патч? ;-) Ты что код самой API пропатчил, если так то неправильно это, нужно ювелирнее действовать. |
|
|
Дата: Июл 20, 2004 13:05:55 Asterix Ловлю событие LOAD_DLL и если эта длл кернел - туда пишу через WriteProcessMemory 3 байта. Всё вроде работает и не глючит. |
|
|
Дата: Июл 20, 2004 18:50:55 FEUERRADER во-первых, работать то будет, но до тех пор, пока не найдется прога, которая захочет проверить содержимое IsDebuggerPresent :) у тебя там наверняка что-то типа xor eax,eax, ret. во-вторых, прога может не вызывать IsDebuggerPresent, а лезть в peb напрямую. если твой отладчик заточен под конкретный софт - тогда да, а если он универсальный - тогда ой! по идее, тебе надо сделать следующее 1. перевести дескриптор fs селектора в линейный адрес через ф-ю GetThreadSelectorEntry. Хэндл нитки и значение fs берешь из структуры передаваемой при дебажном евенте, еще раз подчеркиваю - не твое значение fs, а именно отлаживаемой нити! на этом этапе ты получишь линейный адрес, соответствующий fs:[0] отлаживаемой нити. 2. патчишь peb по полученному адресу + нужное смещение через WriteProcessMemory |
|
|
Дата: Июл 20, 2004 20:05:55 Max Вообще я переделал и сделал патч так: mov eax, fs:18h mov eax, [eax+30h] // тут пошел патч mov byte [eax+2], 0 // обнуляю еах xor eax, eax retn Действительно, если прогу юзает напрямую, то выхода нет, надо патчить напрямую самому. Объясни, пожалста, с примерным кодом, какие конкретно парметры передвать в GetThreadSelectorEntry? BOOL GetThreadSelectorEntry( HANDLE hThread, // handle of thread that contains selector DWORD dwSelector, // number of selector value to look up LPLDT_ENTRY lpSelectorEntry // address of selector entry structure ); Что передавать в dwSelector и lpSelectorEntry. Я эту АПИ никогда не юзал :( Т.е. после выполнения этой АПИ я что получу? Можно будет сразу вызвать mov eax, fs:18h mov eax, [eax+30h] ... и т.д. ???? тогда получу этот байт для дебаг-нити. Так? P.S. Блин, ну и геморой :о) |
|
|
Дата: Июл 20, 2004 21:18:25 Max Пробую так: case CREATE_PROCESS_DEBUG_EVENT: LDT_ENTRY ldt; CONTEXT ct; WORD segm; ct.ContextFlags = CONTEXT_SEGMENTS; GetThreadContext(DebugEv.u.CreateProcessInfo.hThread, &ct); segm= ct.SegFs; GetThreadSelectorEntry(pi.hThread,segm,&ldt); BYTE debugged; __asm{ mov eax, fs:18h mov eax, [eax+30h] lea eax, [eax+2] mov al, [eax] mov debugged, al } Если процесс в отладке, то возвращает в debugged 1, а нет, то 0. Тоже самое что раньше - читается этот байт все равно из peb анпакера. Что не так? |
|
|
Дата: Июл 20, 2004 22:22:23 FEUERRADER В той ссылке что я привел выше меня уверяли что DWORD который указывает на PEB.BeingDebugged будет один и тот же для всех процессов, поэтому получив его адрес в своем процессе можно читать память по этому адресу в другом и патчить. Max, разве это не так? |
|
|
Дата: Июл 21, 2004 16:23:48 FEUERRADER Объясни, пожалста, с примерным кодом... экзампла у меня нету, точнее его не осталось - я с этим баловался давно и к тому же на делфях GetThreadContext(DebugEv.u.CreateProcessInfo.hThread, &ct); segm= ct.SegFs; GetThreadSelectorEntry(pi.hThread,segm,&ldt); это ты делаешь правильно. __asm{ mov eax, fs:18h а вот это - нет. ты берешь fs своего процесса (отладчика), а не отлаживаемой нити, и всякие там mov eax, fs:18h лезут в адресное пространство твоего процесса, а не отлаживаемого, вот поэтому и "читается этот байт все равно из peb анпакера", я ж уже объяснял. после того, как ты получил ldt, делаешь следующее linearaddress = BaseLow+BaseMid shl 16+BaseHi shl 24 получаешь линейный адрес, соответствующий fs:[0] в отлаживаемом процессе. дальше WriteProcessMemory... Asterix Max, разве это не так? так, но это не дзенно :) в том плане, что это недокументированная информация. |
|
|
Дата: Июл 21, 2004 16:47:16 FEUERRADER забыл добавить, вместо GetThreadSelectorEntry(pi.hThread,segm,&ldt), лучше(надо?) делать GetThreadSelectorEntry(DebugEv.u.CreateProcessInfo.hThread,segm,&ldt) хотя может и так работать будет... |
|
|
Дата: Июл 22, 2004 15:10:39 Max Вобщем судя по всему придется мне переделывать свой плагин на более дзенный вариант ;-) В связи с этим вопросы: Это: GetThreadSelectorEntry(DebugEv.u.CreateProcessInfo.hThread,segm,&ldt) будет валидно только при DBEvent.dwDebugEventCode==CREATE_PROCESS_DEBUG_EVENT ведь так? А вот это что за манипуляция: linearaddress = BaseLow+BaseMid shl 16+BaseHi shl 24 что мы тут ещё высчитываем и что это за параметры BaseLow, BaseMid, BaseHi |
|
|
Дата: Июл 22, 2004 16:20:14 Asterix GetThreadSelectorEntry(DebugEv.u.CreateProcessInfo.hThread,segm,&ldt) будет валидно только при DBEvent.dwDebugEventCode==CREATE_PROCESS_DEBUG_EVENT ведь так? yes, конкретно сама структура DebugEv.u.CreateProcessInfo будет валидна только при CREATE_PROCESS_DEBUG_EVENT. смысл в том, что при разных дебажных евентах тебе будут передаваться разные структуры пример описания на делфях:
_DEBUG_EVENT = record
dwDebugEventCode: DWORD;
dwProcessId: DWORD;
dwThreadId: DWORD;
case Integer of
0: (Exception: TExceptionDebugInfo);
1: (CreateThread: TCreateThreadDebugInfo);
2: (CreateProcessInfo: TCreateProcessDebugInfo);
3: (ExitThread: TExitThreadDebugInfo);
4: (ExitProcess: TExitThreadDebugInfo);
5: (LoadDll: TLoadDLLDebugInfo);
6: (UnloadDll: TUnloadDLLDebugInfo);
7: (DebugString: TOutputDebugStringInfo);
8: (RipInfo: TRIPInfo);
end;
case Integer of - это типа union в сях, если кто не знает, и hThread как параметр присутствует не во всех этих структурах. в принципе, наверное прохляет и вариант с pi.hThread (это то, что возвращает CreateProcess), хотя я не проверял. А вот это что за манипуляция GetThreadSelectorEntry(pi.hThread,segm,&ldt) тебе возвращает структуру _LDT_ENTRY, в которой присутствуют поля BaseLow, BaseMid и BaseHi (см. мсдн). а BaseLow+BaseMid shl 16+BaseHi shl 24 из этих полей формирует нормальный линейный адрес. у меня на вин2к получается 0x7FFDE000, хотя насколько это стабильная величина - я не знаю, по крайней мере, других величин я не наблюдал. ес-но все это относится к главной нитке - если ты создашь еще одну нитку в процессе и переведешь ее fs в линейный адрес ты получишь уже другое значение. сами значения линейно увеличиваются (толи через 32Кб толи через 64Кб, непомню). короче говоря, типа mov r32,[7FFDE000] это тоже самое, что и mov r32,fs:[0] (опять таки только внутри главной нити) |
|
Powered by miniBB 1.6 © 2001-2002
Время загрузки страницы (сек.): 0.074 |