7- Import Address Table Hook, 32-bit, 64-bit

بسم الله الرحمن الرحيم

السلام عليكم ورحمة الله وبركاته

اللهم علمنا ما ينفعنا وانفعنا بما علمتنا ، انك انت السميع العليم 

   ==========> Import Address Table Hook, 32-bit, 64-bit <==========

الاخوة الاعزاء ، تكلمنا فيما سبق عن Trampoline Hook

واليوم سوف نتطرق الى IAT Hook
 وبالطبع يحتاج فهم هذه الـHook الي فهم ما هو اساسا PE File , وما هي PE Format، وذلك قبل الولوج الى IAT/EAT Hooks 

وبالطبع لن يتم شرح الـPE Format لان شرحه سوف يطول ويطول واشك اساسا في اننا سوف نوفيه حقه !

ويمكن القراءة عنه داخل MSDN - PE

==========> آلية عمل Import Address Table Hook <==========

كما نعلم بان الملف الـDll عبارة عن ...

كما نرى ان الملف عبارة عن 


MS-Dos Header
MS-Dos Stub
PE Header {
 PE Signature
File Header
Optional Header
Section Header
Sections ...
...

الان، داخل الـSection المعروف باسم .idata ، يوجد الـImport Address Table
والذي يحتوي على RVA - Relative Virtual Address
الخاصة بالـFunctions التي سوف يتم استيرادها من Modules - Dll Files 
اي انه عند استدعاء الـAPI يتم استدعاء الـAddress الخاص بهذه الـAPI من idata

ووظيفة هذه الـHook تغيير الـRVA الى عنوان Function الـHook الخاص بنا
حيث انه عند استدعاء الـFunction سوف يتم الولوج الى عنوان الـHook Function

اي اننا نحتاج الى الوصول الى PE Headers ، ومن ثم بعدها الى Optional Header وداخل الـSrtucture المعروف باسم IMAGE_OPTIONAL_HEADER ، سوف نلج الى  DataDirectory لنقوم بجلب الـRVA الخاص بـidata 
ومن ثم عمل loop حتى نجد عنوان الـAPI المطلوبة ، ونغير العنوان الى عنوان الـHook Function


==========>  Import Address Table Hook CODE <==========

C++ 32-bit


#include <Windows.h>
#include <iostream>

typedef int (WINAPI* MsgBoxStruct) (
    _In_opt_ HWND hWnd,
    _In_opt_ LPCSTR lpText,
    _In_opt_ LPCSTR lpCaption,
    _In_ UINT uType);

MsgBoxStruct ReCall;
BOOL Hook_IAT_x86(char LibNameBigCaseName_SmallFormat[], char FunName[], LPVOID NewFun);
int WINAPI MsgBox(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType);

BOOL WINAPI DllMain(HMODULE hDLL, DWORD Reason, LPVOID Reserved) {
    switch (Reason) {
    case DLL_PROCESS_ATTACH:
        Hook_IAT_x86("USER32.dll", "MessageBoxA", MsgBox);
        ReCall = (MsgBoxStruct)GetProcAddress(LoadLibraryA("USER32.dll"), "MessageBoxA");
    }
    return 1;
}

BOOL Hook_IAT_x86(char LibNameBigCaseName_SmallFormat[] /* USER32.dll */ ,char FunName[], LPVOID NewFun) {
    DWORD hMod = (DWORD)GetModuleHandleA(0);
    PIMAGE_DOS_HEADER DosHeader = (PIMAGE_DOS_HEADER)hMod;
    PIMAGE_NT_HEADERS NtHeaders = (PIMAGE_NT_HEADERS)(hMod + DosHeader->e_lfanew);
    PIMAGE_IMPORT_DESCRIPTOR idata = (PIMAGE_IMPORT_DESCRIPTOR)(hMod + NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);


    for (idata; idata->Name != NULL; idata++) {
        if (std::string((char*)(hMod + idata->Name)) == LibNameBigCaseName_SmallFormat) {
            PIMAGE_THUNK_DATA32 ThunkData = (PIMAGE_THUNK_DATA32)(hMod + idata->OriginalFirstThunk);
            DWORD* Address = (DWORD*)(hMod + idata->FirstThunk);
            for (int i = 0; ThunkData->u1.ForwarderString != NULL; i++) {
                std::string x = (char*)(hMod + ThunkData->u1.ForwarderString + 2);
                if (x == "MessageBoxA") {
           
                    DWORD OldProt;
                    VirtualProtect(&Address[i], 4, PAGE_READWRITE, &OldProt);
                    Address[i] = (DWORD)NewFun;
                    VirtualProtect(&Address[i], 4, OldProt, &OldProt);
                    goto RE;

                } ThunkData++;
            }
        }
    }
RE:
    return 1;
}


int WINAPI MsgBox(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) {
    return ReCall(hWnd , lpText , "Hooked Successfully" , uType);
}

نبدا من DllMain وكما قلنا تحتاج الى ان يكون لديك خبرة في PE Format، قمنا باستدعاء الـHook_IAT_x86 والتي تاخذ 3 Parameters 
الاول هو اسم المكتبة الاسم كبير والصيغة صغيرة كما كالتالي USER32.dll
الثاني اسم الـFunction
الثالث الـFunction الجديدة


تقوم الـ GetModuleHandleA API بجلب Module Handle الحالي ، ببارميتر 0
ومن ثم قمنا بجلب الـDosHeader التي تمثل اول 20Byte 
ويحتوي الـPIMAGE_DOS_HEADER او DosHeader على e_lfanew التي تعطي عنوان بداية PE Header  


typedef struct _IMAGE_DOS_HEADER
{
     WORD e_magic;
     WORD e_cblp;
     WORD e_cp;
     WORD e_crlc;
     WORD e_cparhdr;
     WORD e_minalloc;
     WORD e_maxalloc;
     WORD e_ss;
     WORD e_sp;
     WORD e_csum;
     WORD e_ip;
     WORD e_cs;
     WORD e_lfarlc;
     WORD e_ovno;
     WORD e_res[4];
     WORD e_oemid;
     WORD e_oeminfo;
     WORD e_res2[10];
     LONG e_lfanew;
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
 

وبذلك تم الوصول الى PE Header الذي يمثله الـPIMAGE_NT_HEADERS  

 typedef struct _IMAGE_NT_HEADERS {
    DWORD Signature;
    IMAGE_FILE_HEADER FileHeader;
    IMAGE_OPTIONAL_HEADER OptionalHeader;
} IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS;


وهو عبارة عن 3 Headers كما تكلمنا بالاعلى 
 ثم تم استخدام PIMAGE_IMPORT_DESCRIPTOR وهي Structure تحتوي على DataDirectory وتحتوي على معلومات القسم 


typedef struct _IMAGE_IMPORT_DESCRIPTOR {
    DWORD   OriginalFirstThunk;
    DWORD   TimeDateStamp;
    DWORD   ForwarderChain;
    DWORD   Name;
    DWORD   FirstThunk;
} IMAGE_IMPORT_DESCRIPTOR, *PIMAGE_IMPORT_DESCRIPTOR;

وتم استخدامه لجلب معلومات القسم .idata حيث تم الولوج الى Optional Header داخل NtHeaders وجلب VA لـIMPORT Tableعن طريق DataDirectory والتي ترجع الـVA الخاص برقم الـSection لنقوم بجلب معلومات .idata  وتخزينها في idata PIMAGE_IMPORT_DESCRIPTOR


وكما هو معروف اذا كان الملف يحتوي على 4 Sections فانه سوف يحتوي على 4 PIMAGE_IMPORT_DESCRIPTOR ايضا ، وهذه الـStructure تحتوي على خاصية Name التي ترجع اسم الملف الذي يحتوي على معلومات الـImport Table

لذلك نقوم بعمل Loop الى ان يكون Name = NULL داخل الـPIMAGE_IMPORT_DESCRIPTOR وبذلك نعرف انتهاء اعداد الـ Sections
بداية نقوم بالتحقق من ان اسم الـModule هو اسم المكتبة التي تحتوي على الـFunction حتى لا ياخذ وقت طويل
 ثم قمنا بتعريف الـPIMAGE_THUNK_DATA32 والتي تحتوي على اسم الـFunction داخل خاصية
ForwarderString
  وبعد ذلك قمنا بتعريف Pointer DWORD الذي يمثل نقطة بداية الـAddresses ايضا والذي يمثله خاصية FirstThunk




typedef struct _IMAGE_THUNK_DATA32 {
    union {
        DWORD ForwarderString;      // PBYTE
        DWORD Function;             // PDWORD
        DWORD Ordinal;
        DWORD AddressOfData;        // PIMAGE_IMPORT_BY_NAME
    } u1;
} IMAGE_THUNK_DATA32;
typedef IMAGE_THUNK_DATA32 * PIMAGE_THUNK_DATA32;


وبعدها نقوم بعمل Loop على ThunkData الى ان يعطي اسم الـThunk = NULL
نقوم بجلب الـstring الخاصة بالـThunk ( لان كل الخواص في Structures ترجع قيمة RVA ) 
ومقارنتها مع الـAPI المطلوبة
بعد ذلك نقوم بتغيير الحماية عن طريق VirtualProtect APIعلى عنوان الـAddress الحالي للـAPI الحالية 
ليكون PAGE_READWRITE لاننا نحتاج الى الكتابة عليه والقراءة منه
وسوف يكون مساحة التغيير المطلوب 4 Byte لانه 32-bit
بعد ذلك نقوم بتغيير العنوان الى عنوان Hook Function
ومن ثم نقوم بارجاع الحماية كما كانت عليه

اما ReCall
فكما قلنا فان هذه الـHook على IAT وحتى نحتاج لاعادة استدعاء الـAPI نحتاج الى عنوانها الصحيح 
حيث اننا قمنا بتعريف البنية الخاصة بالـMessageBoxA وبعد ذلك تعريف متغير لتخزين العنوان الخاص بالـAPI عن طريق GetProcAddress API و LoadLibraryA API
 



اما في 64 فهو نفس الاجرائات مع اختلاف الاحجام 64bit ليكون الـCode


#include <Windows.h>
#include <iostream>

typedef int (WINAPI* MsgBoxStruct) (
    _In_opt_ HWND hWnd,
    _In_opt_ LPCSTR lpText,
    _In_opt_ LPCSTR lpCaption,
    _In_ UINT uType);

MsgBoxStruct ReCall;
BOOL Hook_IAT_x64(char LibNameBigCaseName_SmallFormat[], char FunName[], LPVOID NewFun);
int WINAPI MsgBox(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType);

BOOL WINAPI DllMain(HMODULE hDLL, DWORD Reason, LPVOID Reserved) {
    switch (Reason) {
    case DLL_PROCESS_ATTACH:
        Hook_IAT_x64("USER32.dll", "MessageBoxA", MsgBox);
        ReCall = (MsgBoxStruct)GetProcAddress(LoadLibraryA("USER32.dll"), "MessageBoxA");
    }
    return 1;
}

BOOL Hook_IAT_x64(char LibNameBigCaseName_SmallFormat[] /* USER32.dll */ ,char FunName[], LPVOID NewFun) {
    DWORD64 hMod = (DWORD64)GetModuleHandleA(0);
    PIMAGE_DOS_HEADER DosHeader = (PIMAGE_DOS_HEADER)hMod;
    PIMAGE_NT_HEADERS64 NtHeaders = (PIMAGE_NT_HEADERS64)(hMod + DosHeader->e_lfanew);
    PIMAGE_IMPORT_DESCRIPTOR idata = (PIMAGE_IMPORT_DESCRIPTOR)(hMod + NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);


    for (idata; idata->Name != NULL; idata++) {
        if (std::string((char*)(hMod + idata->Name)) == LibNameBigCaseName_SmallFormat) {
            PIMAGE_THUNK_DATA64 ThunkData = (PIMAGE_THUNK_DATA64)(hMod + idata->OriginalFirstThunk);
            DWORD64* Address = (DWORD64*)(hMod + idata->FirstThunk);
            for (int i = 0; ThunkData->u1.ForwarderString != NULL; i++) {
                std::string x = (char*)(hMod + ThunkData->u1.ForwarderString + 2);
                if (x == "MessageBoxA") {
           
                    DWORD OldProt;
                    VirtualProtect(&Address[i], 8, PAGE_READWRITE, &OldProt);
                    Address[i] = (DWORD64)NewFun;
                    VirtualProtect(&Address[i], 8, OldProt, &OldProt);
                    goto RE;

                } ThunkData++;
            }
        }
    }
RE:
    return 1;
}


int WINAPI MsgBox(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) {
    return ReCall(hWnd , lpText , "Hooked Successfully" , uType);
}

 

 typedef struct _IMAGE_THUNK_DATA64 {
    union {
        ULONGLONG ForwarderString;  // PBYTE
        ULONGLONG Function;         // PDWORD
        ULONGLONG Ordinal;
        ULONGLONG AddressOfData;    // PIMAGE_IMPORT_BY_NAME
    } u1;
} IMAGE_THUNK_DATA64;
typedef IMAGE_THUNK_DATA64 * PIMAGE_THUNK_DATA64;


إن أصبت فمن الله ، وإن اخطئت فمني ومن الشيطان 
اترككم في امان الله ورعايته 

والسلام عليكم ورحمة الله وبركاته


DoneByM

عمل هوك ، صنع هوك ، فلترة دالة ، فلترة API ، القضاء على Function ، انشاء حماية ، منع استخدام Function ، كيفية عمل هوك ، كيفية عمل Hook ، هوك Detours ، هوك trampoline ، هوكات IAT , EAT ، Kernel32.dll , System32 , User32.dll , هوك Ring3 ، User Mode Hook, Kernel Mode Hook , الكتابة على الذاكرة 








هناك تعليق واحد:

يمكنك النقل من المدونة كيف ما تشاء وبدون ذكر المصدر