· Начало · Отвђтить · Статистика · Поиск · FAQ · Правила · Установки · Язык · Выход · WASM.RU · Noir.Ru ·

 WASM Phorum —› WASM.RESEARCH —› Только для спецев! PEB.BeingDebugged

Посл.отвђт Сообщен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