Jump to content
SlicK

IAT Patching tutorial

Recommended Posts

IAT Patching Tutorial by SlicK [slick(at)rstcenter.com]

Daca v-ati mai interesat de API hooking inainte probabil ati auzit de IAT si IAT Patching, in acest tutorial

voi incerca sa explic si sa imlementez aceasta tehnica nu foarte complexa dar foarte eficienta.

Bazele acestei tehnici se bazeaza pe faptul ca execulabilele si dll'urile pe 32 de biti sunt contruite pe formatul PE

(Portable executable). Aceste fisiere contin cateva parti logice numite sectiuni, fiecare sectiune avand un

continut specific. Sectiunea de interes pentru IAT Patching se numeste ".idata", aceasta contine o tabela speciala numita

"Import Address Table"(IAT) esentiala pentru toate fisierele care folosesc librarii dinamice (dll'uri).

La rularea unui executabil, dynamic loaderul(parte din kernel) mapeaza fisierul in memorie conform headerului PE,

loaderul "priveste" in apoi IAT pentru a vedea daca fisierul foloseste librarii aditionale, daca da le mapeaza si pe acestea

in memorie. Loaderul cauta apoi toate functiile importate de catre fisier dupa nume sau dupa ordinal in fiecare librarie si

le scrie offestul in IAT. Practic un executabil nu are nevoie sa stie offsetul global pentru fiecare functie importata

in parte stiind doar adresa din IAT unde loaderul scrie acel offset, Deci de fiecare data cand fisierul apeleaza o functie

dintr-o librarie acesta va apela adresa din IAT unde loaderul a scris adresa acelei functii.

IAT Patchingul reprezinta modificarea acelui offeset in IAT cu un altul reprezentand o functie personala care practic va

intercepta fiecare call catre acel API importat putand returna un alt rezultat.

Destul cu teoria, sa trecem la implementare.

Prima conditie pentru IAT Patching este ca functia interceptoare trebuie sa fie in spatiua de memorie al procesului care o

cheama, pentru aceasta voi injecta un dll in acel proces care va patchui deasemenea si IAT'ul. Acesta va citi headerul PE

al fisierului aflat in memorie iterand prin toate sectiunile pana cand va gasi sectiunea .idata

(adresa de inceput si marimea) apoi va citi cate 4 octeti(marimea unui offset) odata pana cand va gasi adresa functiei

care va fi patchuita rescriind aceasta adresa cu adresa functiei interceptoare continuta in dll.

O sa sar peste partea cu injectarea unui dll in alt proces pentru ca exista sufient de multe tutoriale.

In urmatorul exemplu de dll voi intercepta API'ul GetTickCount astfel incat sa returneze un alt rezultat.(compilat cu Dev-Cpp)

======= START iat.cpp ====


#include <windows.h>

#define PEADDR 0x00400000 // inceputul headerului PE la 99% din executabile

DWORD WINAPI FakeGetTickCount(void); // functia interceptoare
DWORD APIOffset(LPSTR pszLibName,LPSTR pszFunkName); // returneaza adresa globala pentru un API
DWORD WINAPI Main(LPVOID); // multitrheading

extern "C" BOOL WINAPI DllMain(HINSTANCE hInst,DWORD reason,LPVOID reserved) // entry pointul in dll
{
if(reason==DLL_PROCESS_ATTACH)
{
MessageBox(NULL,"Attached to process","Injected dll",MB_OK); // optional
CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)&Main,NULL,0,NULL); // cream threadul
}
return(TRUE);
}

DWORD WINAPI FakeGetTickCount(void) //functia interceptoare trebuie sa fie definita la fel ca functia interceptata (DWORD WINAPI GetTickCount(void))
{
return(1000); // returnam mereu acelasi rezultat
}

DWORD WINAPI Main(LPVOID)
{
DWORD dwSearch=APIOffset("kernel32","GetTickCount"); // adresa functiei interceptate
DWORD dwReplace=(DWORD)*FakeGetTickCount; // adresa functiei interceptoare

DWORD dwPid=GetCurrentProcessId(); // Process id'ul procesului curent
HANDLE hProcess=OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwPid);
if(hProcess!=NULL)
{
IMAGE_DOS_HEADER image_dos_header;
IMAGE_NT_HEADERS image_nt_headers;
IMAGE_SECTION_HEADER image_section_header[20];

if(ReadProcessMemory(hProcess,(LPVOID)PEADDR,&image_dos_header,sizeof(IMAGE_DOS_HEADER),NULL)) // citim headerul DOS
{
if(ReadProcessMemory(hProcess,(LPVOID)(PEADDR+image_dos_header.e_lfanew),&image_nt_headers,sizeof(IMAGE_NT_HEADERS),NULL)) // citim headerul NT
{
DWORD dwRO_first_section=image_dos_header.e_lfanew+sizeof(IMAGE_NT_HEADERS);
DWORD SectionNum=image_nt_headers.FileHeader.NumberOfSections;
if(ReadProcessMemory(hProcess,(LPVOID)(PEADDR+dwRO_first_section),&image_section_header,SectionNum*sizeof(IMAGE_SECTION_HEADER),NULL)) // citim headerul sectiunilor
{
for(int i=0;i<SectionNum;i++) // iteram prin toate sectiunile
{
if(!strcmp((char *)image_section_header[i].Name,".idata")) // cand gasim sectiunea ".idata"
{
DWORD dwIDAddr=PEADDR+image_section_header[i].VirtualAddress; // inceputul sectiunii
DWORD dwIDSize=image_section_header[i].Misc.VirtualSize; // dimensiunea sectiunii

DWORD dwOldProtect;
if(VirtualProtect((LPVOID)dwIDAddr,dwIDSize,PAGE_READWRITE,&dwOldProtect)) // ne asiguram ca avem permisiuni de citire si scriere
{
DWORD dwVAddr=0;
BOOL bFound=FALSE;
for(int i=0;i<dwIDSize;i+=4) // citim cate 4 octeti odata pana gasim adresa functie interceptate
{
if(ReadProcessMemory(hProcess,(LPVOID)dwIDAddr,&dwVAddr,4,NULL))
{
if(dwVAddr==dwSearch) { bFound=TRUE; break; }
}
dwIDAddr+=4;
}
if(bFound==TRUE)
{
if(WriteProcessMemory(hProcess,(LPVOID)dwIDAddr,&dwReplace,4,NULL)) // inlocuim adresa functiei interceptate cu adresa functiei interceptoare
{
MessageBox(NULL,"IAT Patched","Injected dll",MB_OK); //optional
}
}
}
}
}
}
}
}
CloseHandle(hProcess);
}
ExitThread(0);
}

DWORD APIOffset(LPSTR pszLibName,LPSTR pszApiName)
{
DWORD dwRet=0;
HMODULE hmLib=LoadLibrary(pszLibName);
if(hmLib!=NULL)
{
FARPROC fpApi=GetProcAddress(hmLib,pszApiName);
if(fpApi!=NULL) { dwRet=(DWORD)fpApi; }
FreeLibrary(hmLib);
}
return(dwRet);
}

========== END ==========

Am atasat si o arhiva care contine sursa dll'ului,dll'ul compilat,un mic program de test si un program pentru injectarea dll'ului

Download: http://rootb0x.com/0X0/iatp.rar

Cam atat cu acest tutorial, sper ca nu a fost greu de citit si inteles.

Link to comment
Share on other sites

cam greu de disecat tot codu asta. Am inteles ce face. Merge si pe xp nu? Nu inteleg totushi la ce ma ajuta. Nu inteleg care este procesul in care injectez functia? si dc functia FakeGetTickCount returneaza 1000 tot timpu?

edit

aaaaaa stai ca m-am prins. test.exe dupa injectare va afisa numa 1000.

da mai am o intrebare. de ex cum fac sa injectez un cod intr-o functie din yahoo messenger sa zicem? cum afu numele functiei?

Link to comment
Share on other sites

Dupa cum am scris si acolo IAT Patching functioneaza doar cand executabilul importa functia dintr-un dll iar numele functiilor din dll'uri le poti afla cu "DumpBin" de exemplu.

Utilizarile sunt extrem de multe pentru ca pe langa faptul ca poti modifica valoarea returnata primesti si parametrii pe care programul ii paseaza functiei.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...