poniedziałek, 11 lutego 2013

Hook EAT/IAT: Przykład


Tak więc mając poprzedni kod i rozumiejąc go trochę pokażę w prosty sposób co możemy osiągnąć używając go.

Klasa którą stworzyłem w 1 części będzie służyła za podstawę i zostanie z czasem rozbudowana o więcej rzeczy. Może nawet udostępniona ;) Who knows.

Tak więc załóżmy sobie przykładowego hooka na funkcję pow(z biblioteki cmath) w tablicy eksportów biblioteki msvcrt.dll , tak że każde użycie GetProcAddress będzie teraz zwracało adres naszej funkcji, a nie oryginalnej.

Potrzebne do tego będą nam 3 rzeczy, a mianowicie:
  1. 2 Prototypy funkcji pow:
    • wskazujący na starą funkcję
    • wskazujący na nową funkcję
  2. Napisana własna "redefinicja" funkcji pow
  3. Adres naszej nowej funkcji w pamięci

Kod z komentarzami:

#include "dlldumper.h"
#include <iostream>

using namespace std;

typedef double (*mypow)(double a, double b);

// Prototypy funkcji OldPow - stara, MyPow - nowa
mypow OldPow = NULL, MyPow = NULL;


// Nasza redefiniowana funkcja ktora posluzy za hooka
double fpow(double a, double b)
{
    printf("Hooked POW Result: ");
    return OldPow(a,b);
}

int main()
{
    DLLDumper dll;
    if(!dll.setDLL(L"msvcrt.dll",EAT))
        return 0;

    // Sprawdzamy oryginalny adres pobierajac go prosto z tablicy EAT //
    HMODULE hMod = LoadLibraryA("msvcrt.dll");
    printf("Before overwriting: pow = 0x%p\n",
           GetProcAddress(LoadLibraryA("msvcrt.dll"), "pow"));

    // Zakladamy hooka na pow przekazujac adres naszej nowej funkcji fpow
    // hooEAT zwraca nam oryginalny adres funkcji pow.
    OldPow = (mypow)dll.hookEAT("pow",(void*)&fpow);

    
    // Ponowne sprawdzenie adresu juz po zalozeniu hooka
    printf("After overwriting: pow  = 0x%p\n",
           GetProcAddress(LoadLibraryA("msvcrt.dll"), "pow"));
    // ========================= //

    // Pobranie i przypisanie juz podmienionego adresu z EAT
    MyPow = (mypow)GetProcAddress(hMod, "pow");
    
    // Wywolujemy "oryginalna" funkcje pow i tyle
    cout << MyPow(2,3) << '\n';
    return 0;
}

Listing z wykonania kodu:

Before overwriting: pow = 0x7681b91f
After overwriting: pow  = 0x00401524
Hooked POW Result: 8

Jak widac przy wywolaniu funkcji najpierw wypisuje się na ekran część z naszej funkcji fpow potem dopiero  wykonuje się oryginalna funkcja.

Domyślny flow: call pow -> pow
Nasze obejście: call pow -> call fpow -> pow

Wystarczy zrobić to samo w przypadku funkcji send, recv i voila mamy własny sniffer ;)

Takie podejście jest o tyle lepsze od zwykłego jmp patcha, że po pierwsze jmp patch jest bardzo łatwo wykrywalny przez porównanie adresów funkcji, a po drugie eat jest bardziej uniwersalny i trudniejszy do wykrycia, ponieważ jeśli proces pobiera adres przez GetProcAddress to i tak otrzyma adres naszej funkcji.

W następnej części pokaże przykładowy hook na IAT, a nastepnie sniffer, ale to po dll injectingu, bo takie rzeczy robić najlepiej z "wnętrza" procesu. ;)

Brak komentarzy:

Prześlij komentarz