Авторские статьи Перехват.Модификация ИАТ.

Discussion in 'Статьи' started by DooD, 19 Apr 2012.

  1. DooD

    DooD Elder - Старейшина

    Joined:
    30 Sep 2010
    Messages:
    1,168
    Likes Received:
    450
    Reputations:
    288
    Привет уважаемые античатовцы. После месяца,грубо говоря,морального разложения :) (ну и немного работы) я решил снова че нить написать.

    Сегодня речь пойдет снова о перехвате функций в ring3

    Арсенал:

    1)Delphi
    2)Masm
    3)что то еще по желанию:)

    План:

    1)Немного теории (соовсем мало))
    2)Внедрение
    3)Патчинг IAT


    Начнем-с

    ТЕОРИЯ

    Как известно, в ring 3 есть несколько способов хука АПИ функций,как:

    1)Сплайсинг
    2)Модификация ИАТ таблиц
    3)Непосредственная подмена dll

    Собственно у нас речь пойдет о патчинге ИАТ.
    Что собой представляет данный метод.

    ИАТ это таблица адресов импорта. Она используется в ПЕ файлах в качестве таблицы для поиска, когда происходит вызов функции из другого модуля. Когда динамический компоновщик загружает модули и объединяет их, он записывает действительные адреса в область IAT так, чтобы они указали на ячейки памяти соответствующих библиотечных функций.Суть будет заключаться в правке этих самых значений и переходе на вызов нашей функции.

    Рассмотрим некоторые плюсы и минусы данного метода:

    +

    1)Довольно простой метод перехватить какую-либо функцию. Имеет локальный характер,что позволяет осуществлять перехват в каком-либо едином модуле.
    2)Потокобезопасен.

    -

    1)Внедрение длл в отличие от сплайсинга, хотя сплайсинг дает глобальный перехват.
    2)Простое обнаружение ввиду внедрения динамической библиотеки.

    В целом теория окончена.

    ---------------------------------------------------------------------------------------------------------------------

    ВНЕДРЕНИЕ ДЛЛ

    Существует несколько методов внедрения длл, некоторые из которых я опишу.
    В юзермоде (ring 3) есть несколько методов внедрения ДЛЛ, наиболее популярными являются:

    1)Метод внедрения с помощью реестра.
    2)Метод внедрения с помощью хуков
    3)Метод внедрения удаленными потоками.

    Мы будем рассматривать самый, более гибкий и удобный метод- внедрение удаленными потоками,но пройдемся по каждому в кратце.

    Метод внедрения с помощью реестра.

    Работает этот метод только на линейке НТ систем( >= win 2000)
    Суть в том что при загрузке любого приложения, использующего библиотеку user32.dll (таких приложений 98%) все dll содержащиеся в ключе HKLM\Software\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs
    загружаются в адресное пространство этого приложения.Дальше не трудно понять что все программы использующие user32.dll получат и нашу библиотеку.

    Плюсы: легко реализуемо
    Минусы: так же легко обнаруживаемо




    Метод внедрения с помощью хуков

    Как известно, приложения получают много сообщений о событиях,так вот суть в том что бы перехватывать сообщения чужого процесса,для чего применяется функция SetWindowsHookEx, прочесть о которой более подробно можно в тырнете:).



    Метод внедрения удаленными потоками.

    Наиболее труден в реализации, зато наиболее гибок и мощен.Создается удаленный поток с помощью CreateRemoteThread . Алгоритм будет таковым:
    1)Получение дескриптора процесса в котором мы хотим создать поток,используя OpenProcess.
    2)Передача адреса функции LoadLibrary
    3)Выделение памяти в адресном пространстве процесса при помощи функции VirtualAllocEx
    4)Записать имя библиотеки через WriteProcessMemory
    5)Создание потока.

    Так как внедрение длл для патчинга ИАТ нам нужно,то напишем простенький инжектор на асме.Инжектор будет глобальный.Проходить будем по алгоритму что описан выше+не большой бонусик будет:)

    код:

    Code:
    .586
    option casemap:none								
    .model flat,stdcall								
    include include\windows.inc
    include include\kernel32.inc
    include include\user32.inc
    include include\advapi32.inc
    include include\ntdll.inc
    
    includelib lib\kernel32.lib
    includelib lib\ntdll.lib
    includelib lib\user32.lib
    
    includelib lib\advapi32.lib
    
    .data										
    	lib db 'c:\hook.dll',0; длл-ка которую внедряем
    	Size dd $-lib; размер строки
    	krnl db 'kernel32.dll',0; 
    	loadlibrary db "LoadLibraryA",0;
    	LL dd 0; тут будет храниться адрес ф-ии LoadLibrary
    	Param dd 0; а тут адрес строки с именем dll
    	szPriv db 'SeDebugPrivilege',0 
    .data?										
    	ThreadId dd ?; ид потока				
    	hSnap dd ?
    	hProcess dd ?
    	ProcEntry PROCESSENTRY32 <?> ; структура
    
    .code
    ThreadProc proc
    	invoke Sleep, 10000000
    	ret
    ThreadProc endp ; поток
    
    EnableDebugPrivilege proc
        local hTokenNew:HANDLE
        local tkpNew:TOKEN_PRIVILEGES
    
        invoke GetCurrentProcess
        mov ecx,eax
        invoke OpenProcessToken,ecx,TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY,addr hTokenNew
        .if eax != 0
          invoke LookupPrivilegeValue,0, addr szPriv,addr tkpNew.Privileges.Luid
          .if eax != 0
            mov tkpNew.PrivilegeCount,1
            mov tkpNew.Privileges.Attributes,SE_PRIVILEGE_ENABLED
            invoke AdjustTokenPrivileges,hTokenNew,0,addr tkpNew,0,0,0
            .if eax != 0
              invoke GetLastError
              .if eax == ERROR_SUCCESS
                mov eax,1
              .else
                xor eax,eax
              .endif
            .endif
          .endif
          push eax
          invoke CloseHandle,hTokenNew
          pop eax
        .endif
        ret
    EnableDebugPrivilege endp ; тот бонус что я говорил, получаем привилегии отладчика
    ;для внедрения в системные процессы.Как ни крути,а сидеть в winlogon’e или т.п. это уже ;что то.Дальше идем по алгоритму.
    
    start:
    	invoke CreateToolhelp32Snapshot,TH32CS_SNAPPROCESS,0; создаем снимок сис.
    	mov hSnap,eax
    	mov ProcEntry.dwSize,sizeof PROCESSENTRY32 ; заполняем структуру
    	invoke Process32First,hSnap,addr ProcEntry
    NextProcess:
    	invoke OpenProcess,PROCESS_CREATE_THREAD or PROCESS_VM_WRITE or PROCESS_VM_OPERATION,0,ProcEntry.th32ProcessID;открытие проц.куда внедрять длл 
    	mov hProcess,eax
    	invoke GetModuleHandle,addr krnl; получаем хэндл 
    	invoke GetProcAddress,eax,addr loadlibrary; получаем адрес ф-ии
    	mov LL,eax
    	invoke VirtualAllocEx,hProcess,NULL,Size,MEM_RESERVE or MEM_COMMIT,PAGE_READWRITE; отводим память в удаленном процессе.
    	mov Param,eax
    
    	invoke WriteProcessMemory,hProcess,eax,addr lib,Size,NULL;записываем имя длл 
            call EnableDebugPrivilege ; получаем привилегии отладчика
            invoke CreateRemoteThread,hProcess,NULL,NULL,LL,Param,NULL,addr ThreadId;удаленный поток вызывает loadlibrary и инжектит нашу dll
    	invoke Process32Next,hSnap,addr ProcEntry ; идем дальше по всем проц.
    	.if eax!=0
    		jmp NextProcess
    	.endif
    	invoke ExitProcess,0
    end start
    

    Разберем:
    1)Открытие процесса,куда будем внедряться
    2)Получаем адрес loadlibrary
    3)выделяем память в удаленном процессе
    4)Записываем строку с именем библиотеки в чужой процесс
    5)Создаем удаленный поток который вызывает loadlibrary и инжектит длл.

    В общем то так,есть еще одна фича,если получить debug privilege и вызывать перед внедрением, то можно будет внедряться в системные процессы,например стандартный демон венды svchost.exe, а это уже чего то ,да стоит.

    Достоинства и недостатки метода:

    +
    Стабильная работа как на 32 разрядных так и на 64 разрядных вендах.
    Локальный характер
    Не требуется трамплинов
    Не происходит модификации файла.

    -
    Довольно сложный метод реализации.(хотя не очень))
    Если нужен глобальный хук, то придется во всех ДЛЛ это делать.


    Про инжекты мы закончили.

    ---------------------------------------------------------------------------------------------------------------------

    Патчинг ИАТ

    Вообще сама техника проста.Работа вся начинается с поиска ИАТ определенного модуля.Ищем с помощью ф-ии ImageDirectoryEntryToData, описание которой можно найти в мсдн.В кач-ве параметра передадим запрос на получение ИАТ.Затем, выполняется просмотр всех секций импорта, параллельно сравнивается имя dll.Если обнаруживается совпадение, то старый адрес заменяется на новый.
    Пишем код на делфи, в виде ДЛЛ (вкратце объяснено в комментах к коду):
    Code:
    type
      TImageImportDescriptor = packed record  
        OriginalFirstThunk : DWORD; 
        TimeDateStamp      : DWORD;
        ForwarderChain     : DWORD; 
        Name               : DWORD; 
        FirstThunk         : DWORD
      end;
      PImageImportDescriptor=^TImageImportDescriptor;
    
    TMessageBoxA = function (hWnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): Integer; stdcall;
    
    function ImageDirectoryEntryToData(Base: Pointer; MappedAsImage: ByteBool;
      DirectoryEntry: Word; var Size: DWORD): Pointer; stdcall;
        external 'imagehlp.dll' name 'ImageDirectoryEntryToData'; // импортируем статически для определения дескриптора таблицы импорта.
    
    var
     OldMessageBoxA : TMessageBoxA;
    
    procedure PATCHIAT(AModule: hModule; ALibName : string; Old, New: Pointer);
    var
      SzIAT           : ULONG;                  // размер таблицы 
      IDP : PImageImportDescriptor; // указатель на таблицу
      LID: PImageImportDescriptor; // указатель на запись длл
      ThunkPtr            : LPDWORD;
      OldProtect, Tmp     : dword;
    begin
    
    // ищем ИАТ IMAGE_DIRECTORY_ENTRY_IMPORT показывает что запрос на ИАТ
    IDP  := ImageDirectoryEntryToData(Pointer(AModule), TRUE,
        IMAGE_DIRECTORY_ENTRY_IMPORT, SzIAT);
    
    if IDP  = nil then exit; // не нашли?-выход
    LID := nil;
    
    while IDP.Name <> 0 do
     begin
      if (lstrcmpiA(PChar(AModule + IDP.Name), PChar(ALibName)) = 0) then 
    begin
       LID := IDP; // ищем импорт с совпадающим именем
    
    ThunkPtr := LPDWORD(AModule + LID.FirstThunk);
       while ThunkPtr^ <> 0 do 
    begin // ищем адрес надобной фу-ии в таблице.
    
    if (pointer(ThunkPtr^) = Old) then 
    begin
         // разрешаем запись в страницу
         VirtualProtect(ThunkPtr, 4, PAGE_READWRITE, OldProtect);
         // Запись
         WriteProcessMemory(GetCurrentProcess, ThunkPtr, @New, 4, Tmp);
         // производим запись
         VirtualProtect(ThunkPtr, 4, OldProtect, Tmp);
    // восстанавливаем как было
        end;
        Inc(ThunkPtr);
       end;
      end;
      Inc(IDP);
     end;
    end; // нашли?-производим замену.
    
    procedure waist(ALibName : string; Old, New: Pointer);
    var
      hSnap : THandle;
      m      : TModuleEntry32;
    begin
    
     // снимаем текушие процессы
     hSnap := CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId);
     if hSnap = INVALID_HANDLE_VALUE then
      exit;
     m.dwSize := SizeOf(TModuleEntry32);
     if (Module32First(hSnap, m)) then
      repeat
       // патчим ИАТ
       PATCHIAT(m.hModule, ALibName, Old, New);
      until not(Module32Next(hSnap, m));
     CloseHandle(hSnap);
    
    end;
    
    // остался перехватчик
    
    function NewMessageBoxA(hWnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): Integer; stdcall;
    begin
     Result := OldMessageBoxA(hWnd, 'FUCK YOU ASSHOLE!!!', 'Мразиш ему в очко ты влазишь!', uType);
    end;
    
    begin
     @OldMessageBoxA := GetProcAddress(GetModuleHandle('user32.dll'), 'MessageBoxA');
     waist('user32.dll',@OldMessageBoxA,@NewMessageBoxA);
    
    end.
    с этим покончено.

    [​IMG]


    [​IMG]


    [​IMG]

    Что осталось вне статьи.

    Скажем так,для познавательных целей я опустил кое-какие детали перехвата(то есть не все указал)
    Для того что бы приложение не смогло получить реальные адреса перехваченных ф-ий, должен производиться перехват LoadLibrary и GetProcAddress (можно по той же технике,можно по другой),и должно возвращаться нужное нам значение.
    На этом все.Спасибо за внимание.Не кидайте помидорами:)

    Лит-ра:
    Васм.
    МСДН.
    левые сайты с гугла.
     
    #1 DooD, 19 Apr 2012
    Last edited: 19 Apr 2012
    3 people like this.
  2. DooD

    DooD Elder - Старейшина

    Joined:
    30 Sep 2010
    Messages:
    1,168
    Likes Received:
    450
    Reputations:
    288
    ребята,что скажите?мб пожелания или замечания?зря делал?
     
    2 people like this.
  3. shadowrun

    shadowrun Banned

    Joined:
    29 Aug 2010
    Messages:
    842
    Likes Received:
    170
    Reputations:
    84
    Поменяй заголовок месейжбокса =(...
    Бегло просмотрел, тк с асмом у меня никак. Интересный метод, но много не догнал изза своего незнания. Комбинируя 2 ЯП можно получить мнего полезных рюшек...
    Держи +