R0 CREW

(Phrack 65): phook - The PEB Hooker

Авторы: Shearer и Dreg
Переводчик: Izg0y
Оригинал (EN): www.phrack.org

phook - The PEB Hooker

------[ 0.- Предисловие

Номенклатуры:

  • [T.Index]: соответствующих работ (section 10).
  • [R.Index]: ссылки (section 11).

Индекс это идентификатор из номенклатуры.

Для понимания документа требуются знания по win32:

  • Форматы исполняемых файлов:

    • PE32 [R.3]: DLLs, EXE…
  • Программирование:

    • Использование APIs [R.20]: LoadLibrary, GetModuleHandle …
    • Hooks [R.10] [R.8] […]
  • Win32 ASM [R.21].

Термины которые часто используются в документе:

  1. DLL_FAKE: DLL которая будет подменять системную DLL (DLL_REAL).
  2. DLL_REAL: DLL которая будет подменяться DLL_FAKE.

Если неуказанно иначе, hook/s будет всегда ссылаться на hook/s в win32.

------[ 1.- Введение

Перехват в win32 обычно используются для обратного проектирования, обычно для анализа работы malware и пакеров, систем защиты программного обеспечения.

Перехват также используются для наблюдения за действиями части программ: доступ к файлам, сокетам, модификацией реестра и т д…

Большинство известных методов реализации перехвата под ring3 (см. пункт 2.5) имеют различные проблемы (см. пункт 2.5.1). Наиболее актуальная для нас заключается в том, что специальные программы могут обнаружить их…

Некоторые защитные программы (фаерволы, антивирусы, антируткиты и т. д.), в состоянии приостановить поток, снять неизвестные ей перхваты и продолжить нормальное выполнение потока.

Другая проблема возникает при попытке реализовать перехват в вирусе, который отслеживает API адреса в памяти, отключая такие типы перехвата, как IAT HOOKING (см. пункт 2.5). Есть так же защитное ПО использующие вирусные
технологии и наоборот.

Из-за этих проблем мы создали phook, который использует несколько документированных методов при реализации перехвата в ring3 и даже реализует некоторые вирусные технологи используя наш перехват.

Этот документ объясняет как работает phook и PEB HOOKING [T.1].

phook - это инструмент, который использует PEB PEB HOOKING [T.1] для реализации перехвата в DLL, он также позволяет реализовать другие задачи в интерактивном режиме:

  • Показать список загружаемых модулей.
  • Загрузить DLL.
  • Скачать DLL.

PEB HOOKING [T.1] выполняет замену DLL_REAL в памяти на DLL_FAKE, поэтому все модули процесса, которые используют DLL_REAL теперь будут использовать DLL_FAKE.

------[ 2 - Предыдущая концепций

Для понимания работы PEB HOOKING [T.1] метода и phook, необходимо четко понимать некоторые понятия.

------[ 2.1 - Process Environment Block

Process Environment Block (PEB) это структура [R.1] расположенная в пользовательском пространстве, которая содержит данные окружающей среды процесса : [R.2]:

  • Переменные среды.
  • Список загруженных модулей.
  • Адреса в памяти Heap.
  • If the process is being depurated.
   
    typedef struct _PEB
    {   
        BOOLEAN InheritedAddressSpace;
        BOOLEAN ReadImageFileExecOptions;
        BOOLEAN BeingDebugged;
        BOOLEAN Spare;
        HANDLE  Mutant;
        PVOID ImageBaseAddress;
        PPEB_LDR_DATA LoaderData;
        PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
        PVOID SubSystemData;
        PVOID ProcessHeap;
        PVOID FastPebLock;
        PPEBLOCKROUTINE FastPebLockRoutine;
        PPEBLOCKROUTINE FastPebUnlockRoutine;
        ...
       
    } PEB, *PPEB;

Для реализации PEB HOOKING, нужно использовать поле LoaderData [T.1].

------[ 2.1.1 - LoaderData

Оно представляет собой структуру [R.1], в которой есть данные о модулях в процессе. Это двойной связанный список, и он может быть отсортированы по трём критериям [R.2]:

  • Порядок загрузки
  • Порядок в памяти
  • Порядок инициализации
    typedef struct _PEB_LDR_DATA
    {
        ULONG Length;
        BOOLEAN Initialized;
        PVOID SsHandle;
        LIST_ENTRY InLoadOrderModuleList;
        LIST_ENTRY InMemoryOrderModuleList;
        LIST_ENTRY InInitializationOrderModuleList;
   

    } PEB_LDR_DATA, *PPEB_LDR_DATA;

Все flink и blink поля в LIST_ENTRY указывает на LDR_MODULE.

    typedef struct _LIST_ENTRY {
        struct _LIST_ENTRY * Flink;
        struct _LIST_ENTRY * Blink;
       
    } LIST_ENTRY,*PLIST_ENTRY;

Данные, которые нам понадобятся из LDR_MODULE, реализовывая PEB HOOKING это [T.1]:

  • BaseAddress: Адрес модуля в памяти…
  • EntryPoint : Адрес где содержится первая инструкция для выполнения модуля.
  • SizeOfImage: Размер модуля в памяти.
    typedef struct _LDR_MODULE
    {
        LIST_ENTRY InLoadOrderModuleList;
        LIST_ENTRY InMemoryOrderModuleList;
        LIST_ENTRY InInitializationOrderModuleList;
        PVOID BaseAddress;
        PVOID EntryPoint;
        ULONG SizeOfImage;
        UNICODE_STRING FullDllName;
        UNICODE_STRING BaseDllName;
        ULONG Flags;
        SHORT LoadCount;
        SHORT TlsIndex;
        LIST_ENTRY HashTableEntry;
        ULONG TimeDateStamp;

    } LDR_MODULE, *PLDR_MODULE;

------[ 2.2 - Import Address Table

Import Address Table (IAT) это таблица где содержится PE32 [R.3], который заполняет win32 загрузчик, когда модуль[R.4] загружен и также на дальнейшей загрузке, используя stub в IAT.

Внешние символы, в которых нуждается модуль, называются импортом, а символы, которые модуль предоставляет другим модулям, называются экспортом.

В IAT [R.3] модуля есть адрес его импорта, это значит, что в IAT [R.3] модуля есть адрес экспорта используемых из других модулей.

------[ 2.2.1 - Загрузка из Import Address Table

Для win32 загрузчика, который может получить экспорт, нужно узнать: модуль в котором он расположен, имя экспорта и/или ordinal [R.3].

В PE32 имеет структура IMAGE_IMPORT_DESCRIPTOR [R.5], где мы можем выделить 3 области:

    - Name                    : Имя модуля где находится экспорт.
    - OriginalFirstThunk  : Адрес таблицы импорта
    - FirstThunk             : Адрес таблицы, идентичной OriginalFirstThunk,
                                    куда win32 загрузчик помещает адреса импорта.
           
   
    typedef struct _IMAGE_IMPORT_DESCRIPTOR {
        DWORD OriginalFirstThunk;
        DWORD TimeDateStamp;
        DWORD ForwarderChain;
        DWORD Name;
        DWORD FirstThunk;
       
    } IMAGE_IMPORT_DESCRIPTOR,*PIMAGE_IMPORT_DESCRIPTOR;

Каждая запись в таблице FirstThunk и OriginalFirstThunk имеет 2 поля[R.3]:

    - Hint: если первые 31/63 bits составляют 0x80000000, то импорт будет
              произведён по ordinal, в противном случаи нет.
              Биты 15-0 это ordinal.
    - Name: Адрес, где хранятся имена экспорта.
   
    typedef struct _IMAGE_IMPORT_BY_NAME {
        WORD Hint;
        BYTE Name[1];
       
    } IMAGE_IMPORT_BY_NAME,*PIMAGE_IMPORT_BY_NAME;

------[ 2.3 - Запуск процесса в приостановленном состоянии

Когда мы хотим создать процесс в приостановленном состоянии, то нам необходимо знать, какого типа он [R.6]:

  • Console
  • GUI

Консольные тип процесса могут быть созданы с помощью API CreateProcess и флага CREATE_SUSPENDED.

Если GUI процесс открывается с флагом CREATE_SUSPENDED, то он может работать не корректно, поэтому он должен быть создан с помощью API:

    1.- CreateProcess   : Процесс создаётся без флага CREATE_SUSPENDED.
    2.- WaitForInputIdle: Дождаться корректной загрузки [R.6] процесса.
    3.- SuspendThread   : Приостановить главный поток.

------[ 2.4 - Инъекция DLL в процесс

Существует много способов внедрения DLL в процесс [R.7], самый простой это использовать связку API:

    1.- VirtualAllocEx    : Зарезервировать память в процессе.
    2.- WriteProcessMemory: Записать в зарезервированное место код
    который загрузит DLL.
    3.- CreateRemoteThread: Создать поток в процессе каторый выполнит
    записанный код.
    4.- VirtualFreeEx     : Освободить зарезервированную память после
    подгрузки DLL.

------[ 2.5 - Hooks в ring3

Всегда существует куча форм для реализации перехвата в win32 как в ринг0 так и в ринг3. Проблема при работе в ring0 заключается в том, что если код работает не стабильно, то это отразиться на всей ОС. Самый стабильный метод для OS реализовать перехват из ring3.

Самые известные методы:

  • IAT HOOKING: Запись IAT [R.3] изменяется, так чтоб загрузчик win32, указывал на другую область [R.8].
  • PUSH + RET: В область кода PUSH DIRECTION и RET вставляется jump, чтоб передать управление своему коду, но приходится восстанавливать оригинальный код в определённый момент [R.9].
  • SetWindowHook…: С помощью этих API, вызов своего кода может быть зарегистрирован для различных событий в системе.

------[ 2.5.1 - Проблемы

Некоторые проблемы при реализации перехвата в ring3:

+-------------------------------------------------------------------------+
| Метод                  | Проблема                                       |
+------------------------+------------------------------------------------+
| IAT HOOKING [R.8]      | 1.- IAT [R.3] для всех загружаемых модулей     |
|                        |     должен быть изменён.                       |
|                        | 2.- Модулю не нужен IAT [R.3] для              |
|                        |     использования символов экспортируемых      |
|                        |     другими.                                   |
|                        | 3.- Это всем хорошо известно.                  |
|                        | 4.- Легко восстановить.                        |                   
|                        | 5.- Можно обнаружить.                          |   
|                        | 6.- Не даёт полный контроль сразу после старта.|                   
|------------------------+------------------------------------------------|
| PUSH + RET [R.9]       | 1.- Метод не универсален.                      |
|                        | 2.- Сложно в применении.                       |
|                        | 3.- Легко восстановить.                        |
|                        | 4.- Можно обнаружить.                          |
|                        | 5.- Не даёт полный контроль сразу после старта.|
|------------------------+------------------------------------------------|    
| Otros "hooks":         | 1.- Не даёт полного контроля.                  |
| SetWindowHook... [R.10]| 2.- Легко восстановить.                        |
|                        | 3.- Можно обнаружить.                          |
|------------------------+------------------------------------------------|    
| PEB HOOKING [T.1]      | 1.- Сложно в применении.                       |
|                        | 2.- Оригинальная DLL и внедрённая, должна      |
|                        |     экспортировать теже символы в том же       |
|                        |     объеме (как минимум).                      |
|                        | 3.- Можно обнаружить.                          | 
|                        | 4.- Не даёт полный контроль сразу после старта.| 
+------------------------+------------------------------------------------+

Примечание: Эта таблица только мнение авторов.

Вызовы из ring3 в ring0 используя SYSENTER не могут управляться только с помощью предыдущих методов. Системны вызов из ring3 могут быть реализованы SYSENTER [R.11] без каких либо других DLL, таких образом, предыдущие методы сделались непригодным для использования, это довольно редкая ситуация.

Из-за предыдущих проблем, мы решили использовать PEB HOOKING [T.1], чтобы создать механизм, который делает больше чем хук : phook - The PEB Hooker.

Примечание: Преимущества и недостатки PEB HOOKING [T.1] разъясняются в section 7.

------[ 3.- Разработка

В этом разделе будет говориться о базовой концепции и реализации PEB HOOKING [T.1]. Реализация не сложная, но только тогда, когда понимаешь для чего и зачем применяется тот или иной код.

Шаги:

  • Загрузить DLL_FAKE и DLL_REAL.
  • В списке, используемым загрузчиком вин32, в котором перечислены все загруженные в данный момент модули, нужно поменять поля между DLL_FAKE и DLL_REAL
  • Необходимо чтобы IAT [R.3] всех загруженных модулей, кроме DLL_REAL и возможно DLL_FAKE указывали функциям, что DLL_FAKE экспорт.

------[ 3.1 - Первый шаг к PEB HOOKING

Прежде чем что-то сделать, необходимо загрузить DLL_FAKE в память процесса, к которому это требуется что-бы использовать PEB HOOKING [T.1]. DLL_FAKE должен иметь по крайней мере тот же самый экспорт что и DLL_REAL.

------[ 3.2 - Обмен данными в LoaderData

Необходимо найти в DLL_FAKE и DLL_REAL некоторые идентификаторы LDR_MODULE, после чего обменяться следующей информацией:

  • EntryPoint
  • BaseAddress
  • SizeOfImage (почти всегда)

Поиск с использованием поля BaseDllName будет получать данные о “LDR_MODULE”, относящиеся к DLL_FAKE. Некоторые вирусы, упаковщики и API используют эту форму поиска, чтобы найти BaseAddress или EntryPoint для модуля.

Необходимо изменить поле SizeOfImage если DLL_FAKE и DLL_REAL, не имеют равный размера в памяти.

Поиск BaseAddress из kernel32.dll без “PEB HOOKING”:

                     0     +---------------------------------+
   [ process ] ---------+  | Process Environment Block (PEB) |
                        |  |---------------------------------|
                        |  | InheritedAddressSpace           |
                        |  | ReadImageFileExecOptions        |
                        |  | BeingDebugged                   |
                        |  | Spare                           |
                        |  | Mutant                          |
                        |  | ImageBaseAddress                |
                        +->| LoaderData                      |--+
                           | ...                             |  |                      
                           +---------------------------------+  | 1
                                                                |
                                                                |
 +--------------------------------------------------------------+
 |  +----------------------------+     +----------------------------+  
 |  |          LoaderData        |     |         LDR_MODULE         |
 |  +----------------------------+     |----------------------------| flink
 |  | Length                     |     | InLoadOrderModList         |-----+
 |  | Initialized                |     | InMemoryOrderModList       |     |
 |  | SsHandle                   |     | InInitOrderModList         |     |
 +->| InLoadOrderModList         |  2  | ...                        |     |
    | InMemoryOrderModList       |---->| BaseDllName   "ntdll.dll"  |---+ |   
    | InInitOrderModList - Flink |     +----------------------------+   | |
    +----------------------------+ +------------------------------------+ |
                                   |   +----------------------------+     |
                                   |   |   LDR_MODULE (DLL_REAL)    |     |
                                   |   |----------------------------|     |
                                   |   | InLoadOrderModList         |   6 |
    +---------------------+     3  |   | InMemoryOrderModList       |     |
    | ¿Es "kernel32.dll"? |<-------+   | InInitOrderModList         |     |
    +---------------------+            | BaseAddress  7C801000      |     |
        8 |     |4       ^        7    | ...                        |     |
     Si <-+     +-> No   +-------------| BaseDllName "kernel32.dll" |<----+
     |               | 5               | ...                        | 
   9 |               v                 +----------------------------+  
     |            NextLdrModule(); 
     v     
 kernel32.dll = 7C801000

Поиск BaseAddress из kernel32.dll с использованием PEB HOOKING [T.1]:

                     0     +---------------------------------+
   [ process ] ---------+  | Process Environment Block (PEB) |
                        |  |---------------------------------|
                        |  | InheritedAddressSpace           |
                        |  | ReadImageFileExecOptions        |
                        |  | BeingDebugged                   |
                        |  | Spare                           |
                        |  | Mutant                          |
                        |  | ImageBaseAddress                |
                        +->| LoaderData                      |--+
                           | ...                             |  |                      
                           +---------------------------------+  | 1
                                                                |
                                                                |
 +--------------------------------------------------------------+
 |  +----------------------------+     +----------------------------+  
 |  |          LoaderData        |     |         LDR_MODULE         |
 |  +----------------------------+     |----------------------------| flink 
 |  | Length                     |     | InLoadOrderModList         |-----+
 |  | Initialized                |     | InMemoryOrderModList       |     |
 |  | SsHandle                   |     | InInitOrderModList         |     |
 +->| InLoadOrderModList         |  2  | ...                        |     |
    | InMemoryOrderModList       |---->| BaseDllName   "ntdll.dll"  |---+ |   
    | InInitOrderModList - Flink |     +----------------------------+   | |
    +----------------------------+ +------------------------------------+ |
                                   |   +----------------------------+     |
                                   |   |   LDR_MODULE (DLL_REAL)    |     |
                                   |   |----------------------------|   6 |
                                   |   | InLoadOrderModList         |     |
    +---------------------+     3  |   | InMemoryOrderModList       |flink|
    | ¿Es "kernel32.dll"? |<-------+   | InInitOrderModList         |--+  |
    +---------------------+            | BaseAddress 7C801000       |  |  |
       12 |     |4-8   ^ ^        7    | ...                        |  |  |
     Si <-+     +-> No | +-------------| BaseDllName "old_k32.dll"  |<-|--+
     |           5-9 | +------------+  | ...                        |  |
  13 |               v              |  +----------------------------+  |
     |            NextLdrModule();  +-+                                |
     v                                | +----------------------------+ |
 kernel32.dll = 005C5000              | |   LDR_MODULE (DLL_FAKE)    | | 10
                                      | |----------------------------| |
                                  11  | | InLoadOrderModList         | |
                                      | | InMemoryOrderModList       | |
                                      | | InInitOrderModList         | |
                                      | | BaseAddress 005C5000       | |
                                      | | ...                        | |
                                      +-| BaseDllName "kernel32.dll" |<+
                                        | ...                        |
                                        +----------------------------+

Результаты поиска:

  1. BaseAddress без использования PEB HOOKING [T.1]: 7C801000 (DLL_REAL)
  2. BaseAddress с использованием PEB HOOKING [T.1]: 005C5000 (DLL_FAKE)

PD: В поиске по InLoadOrderModList, первое поле показывает, что LDR_MODULE соответствует основному модулю. В примере он был опущен для ясности.

------[ 3.3 - Динамическая загрузка модулей

Кoгда процесс, PEB HOOKING [T.1] будет выполнен, динамически [R.12] загруженные модули будут иметь импорт DLL_REAL, его IAT [R.3] будет автоматически загружен с необходимым экспортом DLL_FAKE.

------[ 3.4 - Восстановление IAT

Кроме модулей DLL_FAKE и DLL_REAL, все IAT [R.3] экспортирующие DLL_REAL, должны быть заменены DLL_FAKE. IAT [R.3] DLL_FAKE не должен изменяться в случаи если DLL_REAL необходимо использовать.

Если IAT из DLL_FAKE модифицирована таким образом, что экспорты DLL_REAL совпадают с DLL_FAKE, вызов экспорта из DLL_REAL из такого же экспорта DLL_FAKE войдет в непрерывный бесконечный цикл, вызывающий переполнение стека.

    +--------------------------+     +--------------------------------+
    |      .text DLL_FAKE      |     |               IAT              |
    |--------------------------|     |--------------------------------|                                
    | ...                      |     | LocalAlloc  1 (Nr_LocalAlloc)  |         
    | PUSH EBP                 |  +->| LoadLibrary 2 (Nr_LoadLibrary) |--+        
    | MOV EBP, ESP             |  |  |  ....                          |  |
    | ...                      |  |  +--------------------------------+  |
    | LoadLibrary_FAKE:        |  |                                      |
 +->| PUSH original_lib_name   |  | 0                                    |
 |  | CALL IAT[Nr_LoadLibrary] |--+                                      |
 |  | ...                      |                                         |
 |  | POP EBP                  |                                         |
 |  | RET                      |                                         |
 |  | ...                      |                                         |
 |  +--------------------------+                                         |
 |                                          1                            |
 +-----------------------------------------------------------------------+  

Реальную проблему составляет то, что мы обращаемся сами к себе или одной из других DLL. Это не должно восстанавливать IAT [R.3] любого другова модуля (DLL_ANY), когда DLL_FAKE вызывает экспорт DLL_ANY который в свою очередь обращается к экспорту DLL_FAKE, который снова обращается к экспорту DLL_ANY.

Вызов RtlHeapAlloc, когда PEB HOOKING [T.1] выполнен через NTDLL.DLL и IAT kernel32.dll был изменён:

Пример:

[ proceso ]
 |
 | CALL RtlHeapAlloc                         CALL LoadLibrary
 +-------------------> [DLL_FAKE ntdll.dll] ------------------+  
              0         ^                           1         |
                        | CALL RtlInitUnicodeString           v
                        +--------------------------- [DLL_ANY kernel32.dll]
                                          2           

Вызов RtlHeapAlloc, когда PEB HOOKING [T.1] выполнен через NTDLL.DLL и IAT [R.3] kernel32.dll не был изменен:

[ proceso ]<----------------+ 
 |                       4  |
 | CALL RtlHeapAlloc        |                 CALL LoadLibrary
 +-------------------> [ DLL_FAKE ntdll.dll] ------------------+  
    0                       ^                       1          |
         +------------------+                                  |
         |    3                                                |
         |                CALL RtlInitUnicodeString            v
[DLL_REAL old_nt.dll] <--------------------------- [DLL_ANY kernel32.dll]
                                          2  

Примечание: Схема была упрощенна, исключив другие вызовы DLL_FAKE.

Нормальный вызов LoadLibrary из процесса (без PEB HOOKING [T.1]):

            CALL IAT[Nr_LoadLibrary]  +--------------------------------+
[process] -------------------------+  |                IAT             |
   ^                0              |  |--------------------------------|
   |                               |  | LocalAlloc  1 (Nr_LocalAlloc)  |
   |    +-----------------------+  +->| LoadLibrary 2 (Nr_LoadLibrary) |-+
   |    | DLL_REAL kernel32.dll |     |  ....                          | |
   |    |-----------------------|     +--------------------------------+ |
   |    | ...                   |                  1                     |
   |    | LoadLibrary:          | <--------------------------------------+
   | 2  | PUSH EBP              |                       
   |    | MOV EBP, ESP          |
   |    | ...                   |
   |    | POP EBP               |
   +----| RET                   | 
        | ...                   |
        +-----------------------+

Вызов проходит нормально без захода в DLL_REAL.

Вызов LoadLibrary в процессе с PEB HOOKING [T.1]:

            CALL IAT[Nr_LoadLibrary]  +--------------------------------+
[process] -------------------------+  |                IAT             |
   ^                0              |  |--------------------------------|
   |                               |  | LocalAlloc  1 (Nr_LocalAlloc)  |
   |  +-------------------------+  +->| LoadLibrary 2 (Nr_LoadLibrary) |-+
   |  | DLL_FAKE  kernel32.dll  |     |  ....                          | |
   |  |-------------------------|     +--------------------------------+ |
 4 |  | ...                     |                     1                  |
   |  | Own_LoadLibrary:        | <--------------------------------------+
   |  | PUSH EBP                |                       
   |  | MOV EBP, ESP            |       +-----------------------------+
   |  | // Own functions...     |   2   | DLL_REAL  old_k32.dll       |
   |  | CALL IAT[Nr_LoadLibrary]|----+  |-----------------------------|
   |  | POP EBP                 |<-+ |  | ...                         | 
   +--| RET                     |  | +->| LoadLibrary:                |
      |   ...                   |  |    | PUSH EBP                    |
      +-------------------------+  |    | MOV EBP, ESP                |
                                   |    | ...                         |
                                 3 |    | POP EBP                     |
                                   |    | RET                         |--+
                                   |    | ...                         |  |
                                   |    +-----------------------------+  |
                                   +-------------------------------------+ 

Рассмотрев схему можно увидеть, что вызов проходит сначало через DLL_FAKE. Затем DLL_FAKE вызывает оригинальную LoadLibrary (DLL_REAL).

------[ 3.5 - Начало выполнения

Как только предыдущие шаги выполнены, настал момент для началa выполнения процесса и слежения за его работоспособностью.

------[ 3.6 - API для работы с модулями

API - LoadLibrary, GetModuleHandle, EnumProcessModules [R.12] … используют поле LoaderData из PEB [T.1]. Это означает, что каждый раз, они вызывают что-то из DLL_REAL, которая вызывает что-то из DLL_FAKE, например:

PEB HOOKING [T.1] был выполнен для USER32.DLL:
    - DLL_FAKE
        - Name in memory:    USER32.DLL
        - BaseAddress:       00435622
    - DLL_REAL
        - Name in memory:    OLD_U32.DLL
        - BaseAddress:       77D10000

Процесс пытается получить базу USER32.DLL:
    - HMODULE user32 = GetModuleHandle( "user32.dll" );

После выполнения GetModuleHandle [R.12] в переменной user32 будет: 00435622 (BaseAddress из DLL_FAKE). Если процесс выполнен позже GetProcAddress [R.12] на некоторые функции экспорта USER32.DLL, они получат функции из DLL_FAKE.

Блогадоря PEB HOOKING [T.1] больше нет необходимости изменять API, которые работают с модулями, так чтоб они использовали DLL_FAKE.

------[ 3.7 - Новая разработка: DLL MINIFILTER

DLL MINIFILTER это название, которые мы дали способности, вызывать экспорт проходя через несколько DLL_FAKE. Одной из самых важных особностей метода является, ограничение или расширение функциональных возможностей к запросу на экспорт.

Когда PEB HOOKING [T.1] выполнен с DLL_FAKE, то термин DLL_REAL для новых DLL_FAKE становится предыдущий DLL_FAKE. Поток пойдёт по форме последней DLL_FAKE, над которым взял контроль PEB HOOKING [T.1] по отношению к DLL_REAL, в случаи если все DLL_FAKEs приводят к оригинальному экспорту.

Поток запроса процесса, с PEB HOOKING [T.1], только с одним DLL_FAKE:

           0              1
[proceso] --> [DLL_FAKE] --> [DLL_REAL]
    ^                            |
    |             2              |
    +----------------------------+

Поток запроса процесса, с PEB HOOKING [T.1], с тремя DLL_FAKEs:

           0                1                2                3
[proceso] --> [DLL_FAKE 3] --> [DLL_FAKE 2] --> [DLL_FAKE 1] --> [DLL_REAL]
    ^                                                               |
    |                               4                               |
    +---------------------------------------------------------------+

В предыдущем примере все DLL_FAKEs получают контроль соответствующий DLL_REAL.

------[ 3.8 - Частые проблемы

На данный момент при реализации PEB HOOKING [T.1] выявлены, следующие проблемы:

+-------------------------------------------------------------------------+
| Проблема                      | Возможные решения                       |
|-------------------------------+-----------------------------------------|
| - PEB HOOKING [T.1] fails     | - Проверьте, могут ли необходимые поля  | 
|                               |   PEB [T.1] обмениваться.               |
|                               | - Проверьте, есть ли доступ             |
|                               |   для изменения в IATs [R.3]            |
|-------------------------------+-----------------------------------------|
| - Выполнение процесса не      | - Проверьте корректность PEB [R.1]      |
|   происходит                  | - Проверьте значения IATs [R.3]         |
|                               |   модуля во всех процессах              |  
|                               | - Проверьте были ли восстановлены       |
|                               |   изменения в памяти PEB HOOKING [T.1]  |  
+-------------------------------------------------------------------------+

------[ 4.- phook

phook способен реализовать PEB HOOKING [T.1] (и кое что ещё). phook это проект из различных модулей:

  • InjectorDLL: Создаёт приостановленный процесс и внедряет в него DLL.
  • Console Control: Внедрённая DLL позволяет выполнит PEB HOOKING [T.1]. и другие задачи в интерактивном режиме посредством команд консоли через sockets.
  • CreateExp: Программа создающая из DLL_REAL код, нужный для DLL_FAKE.
  • ph_ker32.dll: DLL_FAKE из kernel32.dll. ph_ker32.dll смотрит за доступом к API: CreateFileA and CreateFileW [R.14].

------[ 4.1 - InjectorDLL

Программа создаёт приостановленный процесс и внедряет в него DLL. Для внедрения DLL C:\console.dll в процесс C:\poc.exe:

    • Тип процесса:

        • CONSOLE:

            • InjectorDLL.exe C:\console.dll -c C:\poc.exe
        • GUI:

            • InjectorDLL.exe C:\console.dll -g C:\poc.exe
    • Неизвестный тип:

        • InjectorDLL.exe C:\console.dll -u C:\poc.exe

InjectorDLL, с параметром -u, пытается обнаружить GUI или Console чтобы знать как создавать приостановленный поток (см пунтк 2.3). Этот метод создаёт процесс при помощи API CreateProcess и флага CREATE_SUSPENDED [R.6]. Потом вызывает WaitForInputIdle, если это не приносит результата то это консольный процесс, иначе GUI.

    CreateProcess
    ( 
        program_name                          ,
        NULL                                  ,
        NULL                                  ,
        NULL                                  ,
        FALSE                                 ,
        CREATE_SUSPENDED | CREATE_NEW_CONSOLE ,
        NULL                                  ,
        NULL                                  ,
        pstart_inf                            ,
        ppro_inf
    )
   
    // Необходимо проверить тип созданного процесса
   
    if ( WaitForInputIdle( ppro_inf->hProcess, 0 ) == WAIT_FAILED )
        // "Console процесс"
    else
        // "GUI процесс"

Если известен тип процесса мы знаем как его правельно остановить (см. пункт 2.3).

Примечание: метод не всегда работает, например если “Console процесс” будет опознан как “GUI процесс”.

Код который загружает DLL помещён в структуру под названием LOADER_DLL_s (см. пункт 2.3). LOADER_DLL_s состоит из команд на ассемблере и всеми необходимыми данными. В созданном процессе необходимо описать структуру LOADER_DLL_s и объявить CreateRemoteThread, как точку запуска структуры. Она будет выполняться в коде LOADER_DLL_s.

Как только DLL загружена и поток приостановлен, LOADER_DLL_s начинает выполнение и устанавливает флаг для “опознания”.

    typedef struct LOADER_DLL_s
    {
        /* - CODE ------------------------------------------------------ */
        PUSH_ASM_t      push_name_dll;           /* PUSH "DLL_INJECT.DLL"*/
        CALL_ASM_t      call_load_library;       /* CALL  LoadLibraryA   */
       
        CALL_ASM_t      call_get_current_thread; /* CALL GetCurrentThread*/
        INC_BYTE_MEM_t  inc_flag;                /* INC [FLAG]           */
        char            PUSH_EAX;                /* PUSH EAX             */
        CALL_ASM_t      call_suspendthread;      /* CALL SuspendThread   */
       
        /* - DATA ------------------------------------------------------ */
        char            name_dll[MAX_PATH];      /* DLL_INJECT.DLL'\0'   */
        char            flag;                    /* [FLAG]               */
       
    } LOADER_DLL_t;

------[ 4.2 - Консоль управления

Консолью управления является DLL, которая внедрена в процессе, в котором вы хотели бы реализовать PEB HOOKING [T.1]. Это позволяет сделать PEB HOOKING [T.1] и другие задачи в интерактивном режиме с помощью команд консоли через sockets. Через прослушиваемый порт, в файл C:\ph_listen_ports.log записывается, PID - PORT. Например процесс с PID 2456, прослушивать на 1234 порт: 2456 - 1234.

На данный момент поддерживаются следующие команды:

    help                      - Показать справку
    exit                      - Закрыть и выгрузить консоль
    suspend                   - Приостановить выполнение программы
    resume                    - Возобновить выполнение программы
    showmodules               - Показать список модулей
    load [param1]             - Загрузить в память библиотеку указанную
                                в [param1]
    unload [param1]           - Выгрузить из памяти библиотеку указанную
                                в [param1]
    pebhook [param1] [param2] - Реализовать PEB HOOKING [T.1] над dll
                                [param1]: Имя оригинальной dll
                                [param2]: путь до DLL_FAKE

Эти команды легки для понимания, но мы обьясним как работают “showmodules”, “pebhook” и “suspend”.

Команда “showmodules” выполняет поиск по PEB [R.1] из загружаемых модулей, без использования API.

pebhook которая реализовывает весь процесс PEB HOOKING (см. пункт 3).

Если требуется выполнить PEB HOOKING [T.1] для kernel32.dll , используйте DLL_FAKE “C:\phook\bin\windows_xp_sp2\ph_ker32.dll”, для ОС Windows XP SP2, требуется только отправить команду:

  • pebhook kernel32.dll c:\phook\bin\windows_xp_sp2\ph_ker32.dll

Команда “suspend” способна приостановить выполнение главного потока процесса. TID основного потока получен, просматривая THREADENTRY32 [R.13] этой системы, можно достигнуть первого из процесса:

    BOOL GetMainThreadId( DWORD * thread_id )
    {
        HANDLE        hThreadSnap;
        THREADENTRY32 th32;
        BOOL          return_function;
        DWORD         process_id;
       
        process_id      = GetCurrentProcessId();
        hThreadSnap     = INVALID_HANDLE_VALUE;
        return_function = FALSE;
   
        hThreadSnap = \
            CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, process_id );
       
        if( hThreadSnap == INVALID_HANDLE_VALUE )
        {
            ShowGetLastErrorString
                ( " GetMainThreadId() - CreateToolhelp32Snapshot()" );
            return FALSE;
        }
       
        th32.dwSize = sizeof( THREADENTRY32 );
        if( !Thread32First( hThreadSnap, & th32 ) )
            ShowGetLastErrorString( "GetMainThreadId() - Thread32First()");
       
        do
        {
            if ( th32.th32OwnerProcessID == process_id )
            {
                * thread_id     = th32.th32ThreadID;
                return_function = TRUE;
            }
           
        }
        while
        (
            Thread32Next( hThreadSnap, & th32 ) && return_function != TRUE
        );
       
        CloseHandle( hThreadSnap );
       
        return return_function;
    }

------[ 4.3 - CreateExp

CreateExp это программа создает исходный код, необходимый для реализации DLL_FAKE из a DLL_REAL. На данный момент она способна создавать .c и .def, для использования с mingw.

Для создания DLL_FAKE для kernel32.dll необходимо выполнить:

  • CreateExp C:\WINDOWS\SYSTEM32\KERNEL32.DLL C:\ph_ker32

После успешного выполнения создадутся C:\ph_ker32.c и C:\ph_ker32.def.

ph_ker32.c содержит в себе экспорт из kernel32.dll и автоматически jumps для оригиналов.

ph_ker32.def содержит псевдонимы и имена из экспорта kernel32.dll.

По умолчанию экспорт из DLL_FAKE приведёт к экспорту из DLL_REAL.

------[ 4.3.1 - Forwarder DLL

CreateExp преобразовывает Forwarder DLL [R.3] в экспорт PEB HOOKING таким образом функция Forwarder может быть создана.

Пример: kernel32.dll имеет Forwarder HeapAlloc который идет в экспорте RtlAllocateHeap of NTDL.DLL. Когда модуль импортирует HeapAlloc из kernel32.dll, загрузчик win32 автоматически помещает адрес экспорта NTDLL.DLL и никогда не проходит через kernel32.dll:

                    CALL HeapAlloc
        [proceso] ------------------> [NTDLL.DLL]
            ^               0               | 
            +-------------------------------+      
                            1

Если DLL_FAKE из kernel32.dll создается с CreateExp, то поток будет:

            CALL HeapAlloc      (DLL_FAKE)
[proceso] ------------------> [KERNEL32.DLL] --------> [NTDLL.DLL]
    ^              0                            1         | 
    +-----------------------------------------------------+                
                             2

В такой форме мы можем осуществить хук HeapAlloc (kernel32.dll).

------[ 4.4 - ph_ker32.dll

ph_ker32.dll была создана для реализации PEB HOOKING [T.1] из kernel32.dll; Наблюдает за APIs “CreateFileA” и “CreateFileW” [R.14], и когда их вызывают, их ( или любые другие ) перенаправляют на оригинальные.

Чтобы ослаблять прыжок к API, бал создан макрос JMP, он должно передать название DLL и оригинальный экспорт (см. пункт 4.4.2).

ph_ker32.c созданный с CreateExp (JMP макрос был пропущен):

    #define FAKE_LIB "ph_ker32.dll"

    DLLEXPORT void _ActivateActCtx ( void )
    {
        JMP( FAKE_LIB, 1 );
    }
   
    DLLEXPORT void _AddAtomA ( void )
    {
        JMP( FAKE_LIB, 2 );
    }
   
    DLLEXPORT void _AddAtomW ( void )
    {
        JMP( FAKE_LIB, 3 );
    }
   
    DLLEXPORT void _AddConsoleAliasA ( void )
    {
        JMP( FAKE_LIB, 4 );
    }
    ....

Необходимо помнить, что после выполнения PEB HOOKING [T.1], kernel32.dll будет называться ph_ker32.dll, поэтому ph_ker32.dll обозначен как константа FAKE_LIB.

ph_ker32.def созданный с CreateExp:

    LIBRARY    default
    EXPORTS   
    ActivateActCtx=_ActivateActCtx           @ 1
    AddAtomA=_AddAtomA                       @ 2
    AddAtomW=_AddAtomW                       @ 3
    ...

Причинами ясности выполнение APIs CreateFileA и CreateFileW [R.14] были помещены в файл owns.c. Когда сделан запрос к CreateFileA, и к CreateFileW [R.14] то записывается параметр lpFileName в файле C:\CreateFile.log

    owns.c:
           
    #define FILE_LOG C:\CreateFile.log
   
    DLLEXPORT
    HANDLE _stdcall _CreateFileW
    (
        LPCWSTR lpFileName,
        DWORD dwDesiredAccess,
        DWORD dwShareMode,
        LPSECURITY_ATTRIBUTES lpSecurityAttributes,
        DWORD dwCreationDistribution,
        DWORD dwFlagsAndAttributes,
        HANDLE hTemplateFile
    )
    {
        char   asc_str[MAX_PATH];
       
        if ( UnicodeToANSI( (WCHAR *) lpFileName, asc_str ) == 0 )
            CreateFileLogger( asc_str );
       
        return CreateFileW(
            lpFileName,
            dwDesiredAccess,
            dwShareMode,
            lpSecurityAttributes,
            dwCreationDistribution,
            dwFlagsAndAttributes,
            hTemplateFile );
    }
   
    DLLEXPORT
    HANDLE _stdcall _CreateFileA
    (
        LPCSTR lpFileName,
        DWORD dwDesiredAccess,
        DWORD dwShareMode,
        LPSECURITY_ATTRIBUTES lpSecurityAttributes,
        DWORD dwCreationDistribution,
        DWORD dwFlagsAndAttributes,
        HANDLE hTemplateFile
    )
    {
        char   asc_str[MAX_PATH];
       
        CreateFileLogger( lpFileName );
       
        return CreateFileA(
            lpFileName,
            dwDesiredAccess,
            dwShareMode,
            lpSecurityAttributes,
            dwCreationDistribution,
            dwFlagsAndAttributes,
            hTemplateFile );
    }
   
    static void
    CreateFileLogger( const char * file_to_log )
    {
        HANDLE file;
        DWORD  chars;
       
        file = \
            CreateFileA
            (
                FILE_LOG                            ,
                GENERIC_WRITE    | GENERIC_READ     ,
                0                                   ,
                NULL                                ,
                OPEN_ALWAYS                         ,
                0                                   ,
                NULL
            );
           
        if ( file != INVALID_HANDLE_VALUE )
        {       
            if ( SetFilePointer( file, 0, NULL, FILE_END ) != -1 )
            {
                WriteFile
                (
                    file, file_to_log, strlen( file_to_log ), &chars, NULL
                );
                WriteFile( file, "\x0D\x0A", 2, &chars, NULL );
            }
            CloseHandle( file );
        }
    }

------[ 4.4.1 - Проблемы стэка

Когда требуется непосредственно передать контроль к API, необходимо передать его неповрежденный стек оригиналу API. Нужно в mingw выбрать compilator-fomit-frame-pointer [R.15] и JMP (ASM) к оригиналу API.

Функции, которые были осуществлены, должны быть помещены образец и должны иметь тип _stdcall. Функции типа _stdcall имеют различный синтаксис в файле .def:

  • Name_exportation=Alias@arguments * 4 @ Ordinal

Пример файла .def с APIs типа _stdcall CreateFileA и CreateFileW [R.14] (оба имеют семь аргументов):

    LIBRARY    ph_ker32
    EXPORTS
   
    ; Name Exp | Alias      | No Args * 4    | Ordinal Windows XP SP2
    CreateFileW=_CreateFileW@28              @ 83
    CreateFileA=_CreateFileA@28              @ 80

Функции типа _stdcall не должны быть скомпилированы с опцией с-fomit-frame-pointer [R.15].

------[ 4.4.2 - Проблемы регистра

Не только необходимо передать стек с неповреждённым экспортом, экспортирование должно быть с целостностью регистраторов. Перед прохождением контроля к оригинальному экспортированию, необходимо чтобы регистры не были повреждены, это достигается использованием в коде инструкции PUSHAD и POPAD:

  • [PUSHAD] [ CODE NEEDED TO JUMP TO THE EXPORTATION ] [POPAD]

Пример экспортирования с использованием регистров _chkstk в NTDLL.DLL:

_chkstk in NTDLL.DLL (WINDOWS XP SP2):
   
    7C911A09 >/$ 3D 00100000    CMP EAX,1000
    7C911A0E  |. 73 0E          JNB SHORT ntdll.7C911A1E
    7C911A10  |. F7D8           NEG EAX
    7C911A12  |. 03C4           ADD EAX,ESP
    7C911A14  |. 83C0 04        ADD EAX,4
    7C911A17  |. 8500           TEST DWORD PTR DS:[EAX],EAX
    7C911A19  |. 94             XCHG EAX,ESP
    7C911A1A  |. 8B00           MOV EAX,DWORD PTR DS:[EAX]
    7C911A1C  |. 50             PUSH EAX
    7C911A1D  |. C3             RETN
    7C911A1E  |> 51             PUSH ECX
    7C911A1F  |. 8D4C24 08      LEA ECX,DWORD PTR SS:[ESP+8]
    7C911A23  |> 81E9 00100000  /SUB ECX,1000
    7C911A29  |. 2D 00100000    |SUB EAX,1000
    7C911A2E  |. 8501           |TEST DWORD PTR DS:[ECX],EAX
    7C911A30  |. 3D 00100000    |CMP EAX,1000
    7C911A35  |.^73 EC          \JNB SHORT ntdll.7C911A23
    7C911A37  |. 2BC8           SUB ECX,EAX
    7C911A39  |. 8BC4           MOV EAX,ESP
    7C911A3B  |. 8501           TEST DWORD PTR DS:[ECX],EAX
    7C911A3D  |. 8BE1           MOV ESP,ECX
    7C911A3F  |. 8B08           MOV ECX,DWORD PTR DS:[EAX]
    7C911A41  |. 8B40 04        MOV EAX,DWORD PTR DS:[EAX+4]
    7C911A44  |. 50             PUSH EAX
    7C911A45  \. C3             RETN

------[ 4.4.3 - JMP макрос

Макрос JMP необходим так, как не всегда весь DLL (файл .h) имеются в его header’e. С макросом JMP адрес экспорта получается с GetProcAddress [R.12] во времени выполнения.

    unsigned long tmp;
   
    #define JMP( lib, func )        \
       asm ( "pushad" );           \
       asm                           \
       (                             \
           " push edx             \n"      \
           " push %1              \n"      \
           " call eax             \n"      \
           " pop edx              \n"      \
           " push %2              \n"      \
           " push eax             \n"      \
           " call edx             \n"      \
           " mov %4, eax          \n"      \
           " popad                \n"      \
                                              \
           : :                                \
           "a" (GetModuleHandle) ,         \
           "g" (lib)             ,         \
           "g" (func)            ,         \
           "d" (GetProcAddress)  ,         \
           "g" (tmp)                       \
        );                                   \
       asm ( "jmp %0" : : "g" (tmp) );

Это код для mingw [R.16], компилировать с опцией -masm=intel.

------[ 4.4.4 - Версии

Мы включили в phook различные версии ph_ker32 для систем:

    - Windows XP SP2                 v5.1.2600
    - Windows Server 2003 R2         v5.2.3790
    - Windows Vista                  v6.0.6000

Исходный код в ph_ker32/SO и бинарники в bin/OS.

------[ 4.5 - Использование phook

Далее рассмотрено что можно делать с PEB HOOKING [T.1] для kernel32.dll к ph_ker32.dll, программа poc.exe была выбрана для примера (лежит в папке bin\ of phook).

Шаги для следования:

1.- Запустите InjectorDLL с указанием программы для инжекта DLL, для для этого введите в консоли:

  • InjectorDLL.exe console.dll -u poc.exe

Процесс будет в приостановленном виде и будет возможность для прослушки порта, записанном в файле C:\ph_listen_ports.log

        C:\phook\bin>InjectorDll.exe console.dll -u poc.exe 
          ________________________________________________________________
         |                       InjectorDLL v1.0                         |
         |                                                                |
         | Juan Carlos Montes   eunimedes@hotmail.com                     |
         | David Reguera Garcia Dreg@fr33project.org / Dreg@7a69ezine.org |
         | -------------------------------------------------------------- |
         |                   http://www.fr33project.org                   |
         |________________________________________________________________|
        
         Showing injection data .....
             Program to inject : poc.exe
             Library to inject: console.dll
        
         [OK]   - CONSOLE.
         [OK]   - Create process:
             [INFO] PID:       0x0960
             [INFO] P. HANDLE: 0x000007B8
             [INFO] TID:       0x0AE0
             [INFO] T. HANDLE: 0x000007B0
         [INFO] - Injecting DLL...
             [OK]   - Allocate memory in the extern process.
             [INFO] - Address reserved on the other process: 0x00240000
             [INFO] - Space requested: 306
             [OK]   - Creating structure for the dll load.
             [OK]   - Writing structure for the dll load.
             [OK]   - Creating remote thread.
             [INFO] - Thread created with TID: 0x0B28
             [INFO] - Attempt: 1
             [INFO] - Thread has entered suspension mode.
             [OK]   - Injection thread ended.
             [OK]   - Memory in remote thread freed.
         [OK]   -  DLL injected.
        
         [OK]   -  Injection ended.

2.- Необходимо соединиться с клиентом через netcat к открытому порту, в нашем случаи: 1234.

    C:\>nc 127.0.0.1 1234
      ________________________________________________________________
     |                        Phook Prompt v1.0                       |
     | Juan Carlos Montes   [email]eunimedes@hotmail.com[/email]                     |
     | David Reguera Garcia [email]Dreg@fr33project.org[/email] / [email]Dreg@7a69ezine.org[/email] |
     | -------------------------------------------------------------- |
     |                   [url]http://www.fr33project.org[/url]                   |
     |________________________________________________________________|
    
    
     ph > help
      _________________________________________________________________
     |                       Phook Prompt v1.0                         |
     |                                                                 |
     | Command list:                                                   |
     | --------------------------------------------------------------- |
     | help                      - Shows this screen                   |
     | exit                      - Closes and unloads the console      |
     | suspend                   - Pauses the programs execution       |
     | resume                    - Resumes the programs execution      |
     | showmodules               - Shows the modules list              |
     | load [param1]             - Loads in memory the library         |
     |                             especified in [param1]              |
     | unload [param1]           - Unloads a librery in memory         |
     |                             especified in [param1]              |
     | pebhook [param1] [param2] - Performs PEB Hook over a dll        |
     |                             [param1]: Name of the original dll  |
     |                             [param2]: Path to the DLL hook      |
     |_________________________________________________________________|

3.- PEB HOOKING [T.1] для kernel32.dll осуществляется с ph_ker32.dll:

    ph > pebhook kernel32.dll C:\phook\bin\windows_xp_sp2\ph_ker32.dll

4.- Команда resume продолжает выполнение процесса.

ph > resume
    ph >    
    C:\phook\bin>

5.- poc.exe creates the files in C:\

    - file
    - file2
    - file3

6.- ph_ker32.dll регистрирует успешные API вызовы CreateFileA и CreateFileW [R.14] в файле C:\CreateFile.log

7.- C:>more CreateFile.log

    C:\file1
    C:\file2
    C:\file3

------[ 4.5.1 - DLL MINIFILTER

phook позволяет также реализовать и DLL MINIFILTER (см. пункт 3.7). Он только должен выполнить PEB HOOKING [T.1], с помощью команды pebhook, с необходимым именем DLL_FAKE, тоесть той что была DLL_REAL.

Предположим что у нас есть две DLL_FAKE:

  • ph_ker32_1.dll: Следит за доступом к API CreateFile [R.14].
  • ph_ker32_2.dll: Следит за доступом к API ReadFile [R.17].

Выполнения DLL MINIFILTER очень просто:

    C:\>nc 127.0.0.1 1234
      ________________________________________________________________
     |                        Phook Prompt v1.0                       |
     | Juan Carlos Montes   eunimedes@hotmail.com                     |
     | David Reguera Garcia Dreg@fr33project.org / Dreg@7a69ezine.org |
     | -------------------------------------------------------------- |
     |                   http://www.fr33project.org                   |
     |________________________________________________________________|
    
    
     ph > pebhook kernel32.dll C:\phook\bin\windows_xp_sp2\ph_ker32_1.dll
     ph > pebhook kernel32.dll C:\phook\bin\windows_xp_sp2\ph_ker32_2.dll

Поступает вызов от процесса к kernel32.dll:

               0                    1                   2
    [proceso] --> [ph_ker32_2.dll] --> [ph_ker32_2.dll] -> [kernel32.dll]
        ^                                                      |
        |                          3                           |
        +------------------------------------------------------+

------[ 4.6 - Частые проблемы

Помимо проблем описанных в section 3.8, есть и другие:

+------------------------------------------------------------------------+
|           Problem            |                 Possible/s Solution/s   |
|------------------------------+-----------------------------------------|
| - DLL_FAKE ошибка компиляции | - Проверьте, что функции, которые       |
|                              |   выходят непосредственно на DLL_REAL   |
|                              |   не повторялись, и реализуются.        |
|                              | - Проверьте, что выполнены функций      |
|                              |   (которые должны быть _stdcall типа)   |
|                              |   хорошо определено в .def файле        |
|                              |   (см. пункт 4.4.1).                    |
|------------------------------+-----------------------------------------|
| - Выполнение процесса        | - Проверьте, что функции, которые       |
|   не происходит              |   выходят непосредственно на DLL_REAL   |
|                              |   были составлены с помощью опции       |
|                              |   -fomit-frame-pointer (см. пункт       |
|                              |    4.4.1).                              |
|                              | - Проверьте, что выполнены функции      |
|                              |   имеют _stdcall типа.                  |
|                              | - Проверьте, что DLL_FAKE были созданы  |
|                              |   от DLL_REAL, а не от другой.          |
|                              | - Проверьте, если InjectorDLL правильно |
|                              |   обнаружен реальный тип процесса       |
|                              |   (GUI или CONSOLE).                    |
|------------------------------+-----------------------------------------|
| - Не удалось подключиться    | - Проверьте что порт 1234 открыт        |
|   к консоли                  |   перед вызовом PEB HOOKING [T.1].      |
|                              | - Проверьте что фаервол не блокирует... |
|                              | - Убедитесь в том, что полный путь      |
|                              |   console.dll было указано              |
|                              |   в InjectorDLL.                        |
|------------------------------+-----------------------------------------|
| - InjectorDLL не работает    | - Проверьте что есть привилегии для     |
|                              |   внедрения DLL (CreateRemoteThread..)  |
|                              |                                         |
|                              | - Проверьте не блокирует ли антивирус.. |
|------------------------------+-----------------------------------------|
| - CreateExp не работает      |- Проверьте DLL_REAL на правильность     |
|                              |  PE32 и EXPORT DIRECTORY [R.3].         |
+------------------------------------------------------------------------+

Некоторые другие проблемы могут возникнуть из-за проектирования или других несвязанных с phook ошибок программиста.

------[ 5.- Что делаем

На данный момент мы работаем над:

    • Реализацией PEB HOOKING [T.1] до выполнения:

      • TLS Table и DLLMain [R.3].
      • Создать отладочные файлы конфигурации и для консоли.
      • Правила для восстановления IATs [R.4].
      • Список прослушивающих портов.
    • Улучшить InjectorDLL:

      • Автоматическое распознавание “GUI процессов” и “Console процессов”.

------[ 6.- Тестирование

Тестирование phook было произведено в различных версиях Windows и программах.

Windows:
    - Windows XP SP2              v5.1.2600
    - Windows Server 2003 R2      v5.2.3790
    - Windows Vista               v6.0.6000

Теоретически должно работать и в Windows 2000, но мы не можем подтвердить это.

Программы:
    - Microsoft Word        10.0.2627.0
    - Regedit               5.1.2600.2180
    - Notepad               5.1.2600.2180
    - Calc                  5.1.2600.0
    - CMD                   5.1.2600.2180
    - piathook              1.4
    - pebtry                Beta 5
    - pe32analyzer          Beta 2

------[ 7.- Преимущества и возможности

Главное преимущества PEB HOOKING перед другими в том что, он применяется только 1 раз.К моменту когда выполнен хук длл, любой загружаемый модуль автоматически получает в своей IAT экспорт DLL_FAKE. Остальные модули должны применять хук каждый раз когда модуль загружается.

Другие преимущества PEB HOOKING [T.1]:

  • Поиск PEB (используя BaseDllName) чтоб найти DLL_REAL, будет находится в DLL_FAKE.
  • PEB HOOKING является более стабильным для ОС чем использование ring0.
  • Некоторые упаковщики не обнаруживают PEB HOOKING [T.1] так как это не документированный способ.
  • Нет необходимости менять поведение работы API с модулями. Когда модуль обращается к DLL_REAL, то он автоматически обращается к DLL_FAKE.
  • Возможность реализовать DLL MINIFILTER (см. пункт 3.7).
  • PEB HOOKING может экспортировать Forwarder [R.3] не делая PEB HOOKING к Forwarder DLL.

Спектр возможностей PEB HOOKING [T.1] и phook достаточно большой, вот несколько примеров применения:

    - Мониторинг/виртуализация доступа процесса к реестру:
        - POC [R.18]:
            1.- Запустите CreateExp (см. пункт 4.3) с
                "advapi32.dll".
            2.- Взависимости от того, что вы хотите сделать необходимо
        наблюдать/виртуализовать следующие API:
                - RegCloseKey
                - RegCreateKeyA/RegCreateKeyW
                - RegCreateKeyExA/RegCreateKeyExW
                - RegDeleteKeyA/RegDeleteKeyW
                - RegLoadKeyA/RegLoadKeyW
                - RegOpenKeyA/RegOpenKeyW
                - RegOpenKeyExA/RegOpenKeyExW
                - RegQueryValueA/RegQueryValueW
                - RegQueryValueExA/RegQueryValueExW
                - RegReplaceKeyA/RegReplaceKeyW
                - RegRestoreKeyA/RegRestoreKeyW
                - RegSaveKeyA/RegSaveKeyW
                - RegSaveKeyExA/RegSaveKeyExW
                - RegSetValueA/RegSetValueW
                - RegSetValueExA/RegSetValueExW
                - RegUnLoadKeyA/RegUnLoadKeyW
                ...
   
    - Наблюдение/виртуализация подключений.
        - POC [R.20]:
            1.- Запустите CreateExp (см. пункт 4.3) с "ws2_32.dll".
            2.- Взависимости от того, что вы хотите сделать необходимо наблюдать/виртуализовать следующие API:
                - accept
                - bind
                - closesocket
                - connect
                - listen
                - recv
                - recvfrom
                - send
                - sendto
                - socket
                - WSAAccept
                - WSAConnect
                - WSARecv
                - WSARecvFrom
                - WSASend
                - WSASendTo
                - WSASocketA/W
                ...
   
    - Syscall Proxy of files:
        - POC [R.19]:
            1.- Запустите CreateExp (см. пункт 4.3) с "kernel32.dll".
            2.- Взависимоти от того, что вы хотите сделать необходимо перенаправлять следующие API:
                - CreateFileA/CreateFileW
                - CreateFileExA/CreateFileExW
                - ReadFile
                - ReadFileEx
                - WriteFile
                - WriteFileEx
                ...
   
    - ... и конечно ваши идеи ;-)

------[ 8.- Заключение

Если необходимо выполнить hook на API/экспорта, можно использовать любые методы. Но если необходимо наблюдать или виртуализировать доступ к различным API/экспорту, то с phook это намного проще осуществить.

Кроме того, это - метод, ориентируемый к обратному проектированию программного обеспечения и malware систем защиты, это как альтернативные методы поиска экспорта и устранения хуков.

------[ 9.- Благодарности

Recommendations for the paper:

  • phrack staff
  • Tarako

Translation to English of the chains of phook:

  • Southern
  • LogicMan
  • XENMAX

Translations of the paper to English:

  • BETA : Ana Hijosa
  • BETA 2: delcoyote
  • ACTUAL: LogicMan

Virii scene:

  • GriYo, zert, Slow, pluf, xezaw, sha0 …

Reversing scene:

  • pOpE, JKD, ilo, Ripe, int27h, at4r, uri, numitor, vikt0ry, kania, remains, S-P-A-R-K …

Other scene:

  • sync, ryden, xenmax, ozone/membrive, ^snake^, topo, fixgrain, ia64, overdrive, success, scorpionn, oyzzo, simkin, !dSR …

ALL vx.7a69ezine.org and 7a69ezine.org people :wink:

And specially thanks to YJesus - http://www.security-projects.com

------[ 10.- Похожие работы

  • [T.1] .- Нам неизвестно о каких-то других работах с использованием phook, но есть статья с упоминанием PEB HOOKING написанная Deroko: “PEB DLL Hooking Novel method to Hook DLLs”. Статья была опубликованна в ARTeam-Ezine выпуск 2.

------[ 11.- Ссылки

------[ 12.- Исходный код

Download “Source Code phook”

Izg0y © CORU, r0 Crew

Товарищи, у кого-то получилось удачно перехватить какие-то функции с помощью скомпиленных бинарников этого чуда? Я вчера проводил опыты - вначале на одной своей консольной программе, потом на стандартном гуишном блокноте - эффекта ноль: и то, и то так и остаётся в замороженном состоянии, т.е. главный поток либо так и остаётся в SUSPENDED состоянии, либо WaitForInputIdle используется неправильно - я не знаю, но лог перехвата получить мне не удалось.

На Windows SP2 у меня работало.

А можно подробнее? Работало, когда применял netcat для управления? Если да, то как? Я просто хочу на основе этого творения статейку замутить до начала челенджа - потом некогда будет.

Выполнял все шаги описанные в статье. Может ты забыл продолжить выполнение процесса (команда “resume”)? Или запустить еще одну консоль (cmd.exe), для запуска “nc.exe”?

Как делал я:

  • Взял папку “bin”, забросил на “Рабочий стол”;
  • Скопировал туда “cmd.exe”, “nc.exe”, ph_ker32.dll;
  • Запустил cmd.exe;
  • Ввел: injectordll console.dll -c poc
  • Получил:
  • Запустил еще один cmd.exe;
    • Ввел: nc 127.0.0.1 1234
    • Получил:
  • Подменил DLL, введя: ph > pebhook kernel32.dll ph_ker32.dll
  • Возобновил выполнение: ph > resume
  • Посмотрел на корень: C:\ (файлы создались), там же и CreateFile.log

Что бы запустить под SP3, надо с бубном потанцевать.

Разобрался. Блин, результат превзошёл все ожидания. Отпишусь в статье, но вначале надо бы до разрабов RKU - есть разговор к ним.

но вначале надо бы до разрабов RKU - есть разговор к ним.

kernelmode.info тут сможишь связаться с ними

http://www.kernelmode.info/forum/viewtopic.php?f=11&t=407

Ждём результатов…

Что-то глухо. Короче, статья выйдет независимо от того, когда там проснутся.

Уже должны были ответить…

PS: Никогда не нужно спешить, если что-то сделал. Статья никуда не улетит за несколько дней…

Да, это правда. Я что-то расторопился. :slight_smile: Хотя забываю, что и сам мсяцами могу он-лайн не появляться. Кстати, девелопер - вполне адекватный человек, оставивший приятное впечатление - откликнулся и, возможно, баги будут пофиксены.