Last active
July 22, 2018 10:41
-
-
Save Barakat/4d7e6b69ff0c954515d4699b35155e4e to your computer and use it in GitHub Desktop.
Import Address Table hook
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// مثال لخطف دالة عن طريق استبدال عنوانها في جدول عناوين الدوال المستوردة | |
// https://twitter.com/barakatsoror/status/1020710139475759105 | |
#include <Windows.h> | |
#include <winternl.h> | |
#include <cstdio> | |
#include <cassert> | |
#include <winnt.h> | |
#include <cstring> | |
#include <cwchar> | |
typedef | |
NTSTATUS | |
NTAPI | |
(*NtCreateFile_t)(OUT PHANDLE FileHandle, | |
IN ACCESS_MASK DesiredAccess, | |
IN POBJECT_ATTRIBUTES ObjectAttributes, | |
OUT PIO_STATUS_BLOCK IoStatusBlock, | |
IN PLARGE_INTEGER AllocationSize OPTIONAL, | |
IN ULONG FileAttributes, | |
IN ULONG ShareAccess, | |
IN ULONG CreateDisposition, | |
IN ULONG CreateOptions, | |
IN PVOID EaBuffer OPTIONAL, | |
IN ULONG EaLength); | |
static NtCreateFile_t NtCreateFile_original; | |
NTSTATUS | |
NTAPI | |
NtCreateFile_hook(OUT PHANDLE FileHandle, | |
IN ACCESS_MASK DesiredAccess, | |
IN POBJECT_ATTRIBUTES ObjectAttributes, | |
OUT PIO_STATUS_BLOCK IoStatusBlock, | |
IN PLARGE_INTEGER AllocationSize OPTIONAL, | |
IN ULONG FileAttributes, | |
IN ULONG ShareAccess, | |
IN ULONG CreateDisposition, | |
IN ULONG CreateOptions, | |
IN PVOID EaBuffer OPTIONAL, | |
IN ULONG EaLength) | |
{ | |
// طباعة المسار | |
auto nt_path = ObjectAttributes->ObjectName; | |
std::wprintf(L"%.*ls", nt_path->Length, nt_path->Buffer); | |
// إعادة توجيه الاستدعاء للدالة الأصلية | |
return NtCreateFile_original(FileHandle, | |
DesiredAccess, | |
ObjectAttributes, | |
IoStatusBlock, | |
AllocationSize, | |
FileAttributes, | |
ShareAccess, | |
CreateDisposition, | |
CreateOptions, | |
EaBuffer, | |
EaLength); | |
} | |
void * | |
hook_function(const wchar_t *module_name, const char *procedure_name, void *replace_by); | |
int | |
main() | |
{ | |
NtCreateFile_original = reinterpret_cast<NtCreateFile_t >(hook_function(L"kernelbase.dll", | |
"NtCreateFile", | |
reinterpret_cast<void *>(NtCreateFile_hook))); | |
assert(NtCreateFile_original != nullptr); | |
// تجربة الخطف | |
auto fp = fopen(R"(D:\file.txt)", "w"); | |
if (fp) | |
{ | |
fclose(fp); | |
} | |
} | |
void * | |
hook_function(const wchar_t *module_name, const char *procedure_name, void *replace_by) | |
{ | |
// القيمة التي تعيدها هذه الدالة تمثل العنوان الذي حُمّلت عنده المكتبة | |
auto module_base_address = reinterpret_cast<const char *>(GetModuleHandleW(module_name)); | |
// إيجاد ترويسة DOS | |
auto image_dos_header = reinterpret_cast<const IMAGE_DOS_HEADER *>(module_base_address); | |
assert(image_dos_header->e_magic == IMAGE_DOS_SIGNATURE); | |
// إيجاد ترويسة NT | |
auto image_nt_headers = reinterpret_cast<const IMAGE_NT_HEADERS *>( | |
module_base_address + image_dos_header->e_lfanew | |
); | |
assert(image_nt_headers->Signature == IMAGE_NT_SIGNATURE); | |
// إيجاد المكان المخزّنة عنه جدول الدوال المستوردة | |
auto data_directory = &image_nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; | |
assert(data_directory->Size != 0 && data_directory->VirtualAddress != 0); | |
// أول مٌدخل | |
auto image_import_descriptor = reinterpret_cast<const IMAGE_IMPORT_DESCRIPTOR *>( | |
module_base_address + data_directory->VirtualAddress | |
); | |
// نمرّ على كل المكتبات المستوردة | |
for (; image_import_descriptor->FirstThunk; ++image_import_descriptor) | |
{ | |
#if 0 | |
// اسم المكتبة المستوردة | |
const char *imported_module_name = module_base_address + image_import_descriptor->Name; | |
std::printf("\n%s:\n", imported_module_name); | |
#endif | |
// أسماء الدوال المستوردة سنحصل عليها من هذا الجدول | |
auto image_thunk_data_names = reinterpret_cast<const IMAGE_THUNK_DATA *>( | |
module_base_address + image_import_descriptor->OriginalFirstThunk | |
); | |
// وعناوين الدوال المستوردة سنحصل عليها من هذا الجدول | |
auto image_thunk_data_address = reinterpret_cast<const IMAGE_THUNK_DATA *>( | |
module_base_address + image_import_descriptor->FirstThunk | |
); | |
// نمر على الدوال المستوردة | |
for (; image_thunk_data_address->u1.Function; ++image_thunk_data_address, ++image_thunk_data_names) | |
{ | |
// سنتجاهل الدوال المصدرة بالترتيب، نريد الدوال المصدرة بالاسم فقط | |
if ((image_thunk_data_names->u1.Ordinal & IMAGE_ORDINAL_FLAG) == 0) | |
{ | |
// نوجد اسم الدالة والعنوان الذي سيضع فيه المُحمّل العنوان | |
const auto *image_import_by_name = reinterpret_cast<const IMAGE_IMPORT_BY_NAME *>( | |
module_base_address + image_thunk_data_names->u1.AddressOfData); | |
auto imported_function_name = reinterpret_cast<const char *>(image_import_by_name->Name); | |
auto imported_function_load_address = const_cast<void *>( | |
reinterpret_cast<const void *>(&image_thunk_data_address->u1.Function) | |
); | |
#if 0 | |
std::printf(" 0x%p %s\n", imported_function_load_address, imported_function_name); | |
#endif | |
// نقارن اسم الدالة | |
if (std::strcmp(procedure_name, imported_function_name) == 0) | |
{ | |
auto original_address = *reinterpret_cast<void **>(imported_function_load_address); | |
// نستبدل العنوان بعنوان دالتنا | |
DWORD old_page_protection; | |
VirtualProtect(imported_function_load_address, sizeof(void *), PAGE_EXECUTE_READWRITE, &old_page_protection); | |
std::memcpy(imported_function_load_address, &replace_by, sizeof(replace_by)); | |
DWORD dummy; | |
VirtualProtect(imported_function_load_address, sizeof(void *), old_page_protection, &dummy); | |
return original_address; | |
} | |
} | |
} | |
} | |
return nullptr; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment