Активная антиотладка и антиинжект

Дата публикации 7 сен 2017 | Редактировалось 10 янв 2018
И вновь продолжается бой
И сердцу тревожно в груди..

(Из песни времен СССР.)​
Активная антиотладка и антиинжект по Рихтеру
Далее будет использован синтаксис Microsoft Си. Проекты в конце статьи – под
Microsoft Visual Studio v.6.0 . Разговор далее пойдет только о Ring3.
Недавно работая над написанием плагина под Sysinternals Process Explorer, стлучайно столкнулся с функцией RtlQueryProcessDebugInformation из ntdll.dll, которая оказывается использует удаленные потоки для получения информации о стороннем процессе. Т.к. мой плагин был реализован в виде DLL, сразу вспомнились далекие годы, когда я читал Рихтера и его описание функции DllMain, а именно уведомление DLL_THREAD_ATTACH, получаемое этой процедурой при инициализации нового потока в процессе, обычно довольно редко используемое. Как оказалось вызов DllMain с этим уведомлением происходит именно из контекста вновь создаваемого потока. Это натолкунуло на естественную, в данном случае, мысль о возможности защиты своего и не только своего приложения от инжекта и выполнения чужеродного кода в своем адресном пространстве методом создания удаленнных потоков без всяких глобальных перехватов ZwWriteProcessmemory и ZwCreateThread, (как это делают многие антивирусы и программные сетевые экраны (фаерволлы)). Так для однопоточного приложения достаточно нижеприведенного кода для получения невозможности создания потока в нем:
Код (C++):
  1.  BOOL APIENTRY DllMain(HMODULE hModule, ULONG ul_reason_for_call,LPVOID lpReserved)
  2. {
  3. if(ul_reason_for_call==DLL_THREAD_ATTACH) NtSleep(INFINITE);
  4. //или RtlExitUserThread () или еще чего..
  5. }
где NtSleep – это макрос, аналог Sleep из kernel32.dll (я в основном использую нативные функции):
Код (C++):
  1.  void WINAPI NtSleepEx(ULONG DurationMs,ULONG Alertable)
  2. { struct {ULONG Low;
  3. ULONG Hi;
  4. } MLI={{-10000*DurationMs},{0xFFFFFFFF}};
  5. NtDelayExecution(Alertable,(PLARGE_INTEGER)&MLI);
  6. }
  7. #define NtSleep(_x) NtSleepEx(_x,0)
В данном примере мы просто замораживаем созданный поток на неопределенный период.
Как же быть в многопоточных приложениях, где мы рискуем «не разрешить» свой собственный (нужный нам поток). Здесь есть два простых варианта:
  1. Вызывать какую-либо созданную нами функцию из нашей DLL при создании нового потока для того что бы передать в нее ThreadID создаваемого потока, с последующем сравнении в функции DllMain с текущим (думаю все поняли, расписывать этот метод нет смысла).
  2. Более продвинутый метод, позволяющий защищать не только свои приложения, – это перехват функции NtCreateThread в своем процессе для получения ThreadID потоков создаваемых именно нашим приложением (сторонние потоки будут созданы из вне, а т.к. там ничего нами не перехвачено ThreadID нами получено не будет) для последующей проверки соответствия полученного ThreadID и ThreadID который мы получим в функции DllMain в контексте создаваемого потока из структуры TEB или GetCurrentThreadID. В общем нагляднее все выглядит в коде.
Вот практически полный исходный код нашей dll:
© sysenter 2012 sysenter@jabber.no

3 3.994
RET

RET
Well-Known Member

Регистрация:
5 янв 2008
Публикаций:
17

Комментарии


      1. galenkane 1 мар 2020
        Кода не осталось посмотреть? RET
      2. RET 7 сен 2017
        ADD: сорян, кодес я на руткитсах выкладывал, которого уже нету. Но думаю принцип понятен.
      3. yashechka 7 сен 2017
        Помню этого товарища.