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:
- 2 Prototypy funkcji pow:
- wskazujący na starą funkcję
- wskazujący na nową funkcję
- Napisana własna "redefinicja" funkcji pow
- 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. ;)
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