Hi,
Como havia dito algum tempo, irei postar hoje um exemplo da técnica API Hooking. Existem diferentes formas de realizar tal técnica, como por exemplo substituir a chamada a uma determinada função pela instrução JMP contendo um endereço específico para onde o programa irá saltar. No entanto, vou mostrar uma das maneiras mais simples e eficientes de implementação: IAT (Import Address Table) Patching.
Antes de mostrar o exemplo, gostaria de esclarecer algumas coisas. Basicamente, API Hooking é uma técnica que consiste em interceptar as chamadas à API do sistema feitas por um determinado aplicativo. O hooking de API é muito usado por programas que filtram as funções CreateProcess(), CreateFile() e DeleteFile() por exemplo.
Se você já escreveu algum programa para Windows, seja ele em C, C++, Delphi, Visual Basic e até mesmo Assembly, já deve ter utilizado funções como MessageBox, Sleep, FindWindow, CopyFile, dentre outras. Essas funções fazem parte da API do Windows e estão presentes em DLLs (kernel32.dll, user32.dll). Quando você usa uma função da API, o endereço da mesma é importado da DLL e armazenado na tabela de endereços de importação (IAT) do executável. Após executá-lo, o sistema irá carregá-lo na memória justamente com as DLL's nas quais estão as funções são importadas por ele. Neste processo, os endereços das funções importadas são obtidos e escritos na tabela para que o aplicativo possa chamá-las.
A essência do IAT Hooking está justamente neste aspecto. Modificando o endereço associado a cada função importada para um endereço de uma função definida por nós, podemos fazer com que o programa sempre chame por nossa função em vez da função original importada.
Então, declaramos uma função com o mesmo protótipo e escrevemos seu endereço no lugar do endereço da função original. Assim, podemos interceptar as chamadas, filtrá-las e, opcionalmente, passar os parâmetros interceptados à função legítima.
Contudo, as funções que iremos declarar para monitorar as chamadas à API devem estar no mesmo espaço de memória do aplicativo alvo para que este último possa acessá-las. Por isso, iremos injetar uma DLL no processo contendo uma função que será executada imediatamente após a injeção para realizar o Hook. Contendo, também, as nossas funções de monitoração.
Bem, isso foi apenas uma pequena introdução sobre API Hooking, sobretudo, IAT Hooking. Antes de visualizar o código, sugiro que você procure mais informações a respeito.
Vejamos então o código de exemplo:
DLL.h
#define EXPORT __declspec(dllexport)
#define NO_IMPORT_DESCRIPTOR -2
#define MODULE_NOT_FOUND -1
#define FUNCTION_NOT_FOUND 0
#define REPLACE_SUCCESS 1
typedef struct FuncList
{
LPCSTR lpszModuleName;
LPCSTR lpszFunctionName;
LPVOID lpNewAddress;
}* PFUNCLIST;
EXPORT int HookFunctions();
EXPORT int ReplaceIATEntries(PFUNCLIST, HMODULE, LPDWORD);
DLL.c
#include <string.h>
#include <windows.h>
#include <tlhelp32.h>
#include <imagehlp.h>
#include "dll.h"
#include "HookFunctions.h"
#pragma comment(lib,"ws2_32.lib")
#pragma comment(lib,"imagehlp.lib")
static HINSTANCE hApiHookDLL = 0;
struct FuncList Functions[] =
{
{"kernel32.dll","LoadLibraryA",LoadLibraryAHooked},
{"wsock32.dll","recv",RecvHooked},
{"wsock32.dll","send",SendHooked},
{"ws2_32.dll","recv",RecvHooked},
{"ws2_32.dll","send",SendHooked}
};
BOOL APIENTRY DllMain (HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
hApiHookDLL = hInstance;
switch(HookFunctions())
{
case -1:
MessageBox(0,"Erro ao monitorar as funções especificadas.","Erro",0x10);
FreeLibrary(hInstance);
break;
case 0:
MessageBox(0,"Uma ou mais funções não puderam ser monitoradas.","Aviso",0x30);
break;
case 1:
MessageBox(0,"As funções especificadas estão sendo monitoradas.","OK",0x40);
break;
}
break;
case DLL_PROCESS_DETACH:
FreeLibrary(hInstance);
break;
}
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////////////
EXPORT int HookFunctions()
{
DWORD dwPID, dwHooked, dwNumOfFunctions, dwMatches, i;
HANDLE hSnapShot;
MODULEENTRY32 mModuleEntry;
PFUNCLIST pFuncList;
dwPID = GetCurrentProcessId();
hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID);
if(hSnapShot == INVALID_HANDLE_VALUE)
return -1;
mModuleEntry.dwSize = sizeof(MODULEENTRY32);
if(!Module32First(hSnapShot, &mModuleEntry))
return -1;
dwNumOfFunctions = sizeof(Functions) / sizeof(struct FuncList);
dwHooked = dwMatches = 0;
do
{
if(mModuleEntry.hModule != hApiHookDLL)
{
for(pFuncList = Functions, i = 0; i < dwNumOfFunctions; pFuncList++, i++)
{
if(ReplaceIATEntries(pFuncList, mModuleEntry.hModule, &dwMatches) == REPLACE_SUCCESS)
dwHooked++;
}
}
}while(Module32Next(hSnapShot,&mModuleEntry));
CloseHandle(hSnapShot);
if(!dwMatches)
return -1;
if(dwHooked == dwMatches)
return 1;
else
return 0;
}
/////////////////////////////////////////////////////////////////////////////////////
EXPORT int ReplaceIATEntries(PFUNCLIST pFuncList, HMODULE hModuleBase, LPDWORD lpMatches)
{
LPCSTR lpszModuleName;
DWORD dwSize, dwOld;
HANDLE hProcess;
PIMAGE_IMPORT_DESCRIPTOR pImportDesc;
PIMAGE_THUNK_DATA pThunk;
PROC * pfnFunc, pfnTarget;
hProcess = GetCurrentProcess();
pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)
ImageDirectoryEntryToData(hModuleBase,
TRUE,
IMAGE_DIRECTORY_ENTRY_IMPORT,
&dwSize);
if(!pImportDesc)
return NO_IMPORT_DESCRIPTOR;
while(pImportDesc->Name)
{
lpszModuleName = (LPSTR)((LPBYTE)hModuleBase + pImportDesc->Name);
if(!_strcmpi(lpszModuleName, pFuncList->lpszModuleName))
break;
pImportDesc++;
}
if(!pImportDesc->Name)
return MODULE_NOT_FOUND;
pThunk = (PIMAGE_THUNK_DATA)((LPBYTE) hModuleBase + pImportDesc->FirstThunk);
while(pThunk->u1.Function)
{
pfnFunc = (PROC*)&pThunk->u1.Function;
pfnTarget = GetProcAddress(GetModuleHandle(pFuncList->lpszModuleName),
pFuncList->lpszFunctionName);
if(pfnFunc && pfnTarget && *pfnFunc == pfnTarget)
{
if(lpMatches)
(*lpMatches)++;
if(VirtualProtect(pfnFunc, sizeof(pfnFunc), PAGE_EXECUTE_READWRITE, &dwOld) &&
(WriteProcessMemory(hProcess, pfnFunc, &pFuncList->lpNewAddress, sizeof(LPVOID), NULL)))
{
return REPLACE_SUCCESS;
}
}
pThunk++;
}
return FUNCTION_NOT_FOUND;
}
/////////////////////////////////////////////////////////////////////////////////////
HookFunctions.h
HINSTANCE WINAPI LoadLibraryAHooked(LPCSTR);
int WINAPI SendHooked(SOCKET, const char *, int, int);
int WINAPI RecvHooked(SOCKET, char *, int, int);
HookFunctions.c
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include "HookFunctions.h"
#include "DLL.h"
///////////////////////////////////////////////////////////////////////////////
HINSTANCE WINAPI LoadLibraryAHooked(LPCSTR lpszModuleName)
{
HINSTANCE hModule = LoadLibraryA(lpszModuleName);
if(!hModule)
return NULL;
HookFunctions();
return hModule;
}
///////////////////////////////////////////////////////////////////////////////
int WINAPI RecvHooked(SOCKET sock, char * buffer, int len, int flags)
{
struct sockaddr_in addr;
int bytes, size;
char * IP;
FILE * fp;
bytes = recv(sock,buffer,len,flags);
if(bytes == -1)
return -1;
if(getpeername(sock,(struct sockaddr*)&addr,&size) == 0)
{
if(addr.sin_addr.s_addr != inet_addr("127.0.0.1"))
{
fp = fopen("c:\\log.txt","a+");
if(fp)
{
IP = inet_ntoa(addr.sin_addr);
fputs("**********************************************************\n",fp);
fprintf(fp,"-> Dados recebidos\n\n[+] Origem: %s\n",IP);
fputs("**********************************************************\n\n",fp);
fwrite(buffer,1,bytes,fp);
fputs("\n\n",fp);
fclose(fp);
}
}
}
return bytes;
}
///////////////////////////////////////////////////////////////////////////////
int WINAPI SendHooked(SOCKET sock, const char * buffer, int len, int flags)
{
struct sockaddr_in addr;
int bytes, size;
char * IP;
FILE * fp;
bytes = send(sock,buffer,len,flags);
if(bytes == -1)
return -1;
if(getpeername(sock,(struct sockaddr*)&addr,&size) == 0)
{
if(addr.sin_addr.s_addr != inet_addr("127.0.0.1"))
{
fp = fopen("c:\\log.txt","a+");
if(fp)
{
IP = inet_ntoa(addr.sin_addr);
fputs("**********************************************************\n",fp);
fprintf(fp,"->Dados enviados\n\n[+] Destino: %s\n",IP);
fputs("**********************************************************\n\n",fp);
fwrite(buffer,1,bytes,fp);
fputs("\n\n",fp);
fclose(fp);
}
}
}
return bytes;
}
///////////////////////////////////////////////////////////////////////////////
No exemplo, interceptamos as funções send() e recv() da biblioteca do WinSock. Cada chamada a uma destas funções fará com que o programa abra o arquivo c:\log.txt, armazene os dados enviados/recebidos nele e repasse os parâmetros às funções verdadeiras.
Observe a seguinte linha:
if(addr.sin_addr.s_addr != inet_addr("127.0.0.1"))Bem, resolvi incluir algo assim no código apenas para mostrar como podemos fazer um filtro simples na função. No caso, se o endereço associado ao socket não for o de loopback, loga-se a chamada à função

Exemplo:
(//http://one.xthost.info/darkside17/projetos/c-cpp/Api_Hooking/api_hook1.png)
(//http://one.xthost.info/darkside17/projetos/c-cpp/Api_Hooking/api_hook2.png)
(//http://one.xthost.info/darkside17/projetos/c-cpp/Api_Hooking/api_hook3.png)
Para injetar a DLL no processo acima, eu utilizei um DLL Injector escrito em Delphi. O código fonte e o executável do mesmo foi postado no seguinte tópico:
http://www.darkers.com.br/forum/index.p ... 644.0.html (http://www.darkers.com.br/forum/index.php/topic,8644.0.html)
Download do source + binário da DLL:
http://one.xthost.info/darkside17/proje ... ooking.rar (http://one.xthost.info/darkside17/projetos/c-cpp/Api_Hooking/Api_Hooking.rar)
Alguns links externos úteis:
http://en.wikipedia.org/wiki/Hooking (http://en.wikipedia.org/wiki/Hooking)
http://www.windowsitlibrary.com/Content/356/11/5.html (http://www.windowsitlibrary.com/Content/356/11/5.html)
http://www.internals.com/articles/apispy/apispy.htm (http://www.internals.com/articles/apispy/apispy.htm)
http://www.numaboa.com.br/informatica/oiciliS/PE/ (http://www.numaboa.com.br/informatica/oiciliS/PE/)
http://sandsprite.com/CodeStuff/Underst ... ports.html (http://sandsprite.com/CodeStuff/Understanding_imports.html)
http://www.ntcore.com/Files/inject2it.htm (http://www.ntcore.com/Files/inject2it.htm)
http://cio.uiowa.edu/ITSecurity/resourc ... otkits.ppt (http://cio.uiowa.edu/ITSecurity/resources/windowsrootkits.ppt)
Muito bom velho.. Terei que estudar C pra entender, porém já ajuda bastante a entender como funciona na prática e pesquisar métodos para realizar o Hooking em determinada "linguagem"..
Só para completar, outro site interessante que simplesmente explica de forma bem simples sobre API Hooking:
http://www.projetobms.net/artigos.php?id=2 (http://www.projetobms.net/artigos.php?id=2)
Ponto positivo
[]s
bastante interessante, a microsoft possui a detours lib, alguém já usou?
Hum...
Esses floods me são familiar... ^^
Losdive, bem vindo novamente!
Acho que não preciso nem falar neh... rsrs
Outra coisinha... por favor, reduza o tamanho da sua assinatura por gentileza.
(maiores informações veja na Regra de Conduta do fórum)
Bye!
Quote from: "#phobia"Losdive, bem vindo novamente!
Acho que não preciso nem falar neh... rsrs
Esse cara naum desiste, ele deve msm gostar desse forum...

LOL