Skip to content

Instantly share code, notes, and snippets.

@Barakat
Last active July 22, 2018 10:41
Show Gist options
  • Save Barakat/4d7e6b69ff0c954515d4699b35155e4e to your computer and use it in GitHub Desktop.
Save Barakat/4d7e6b69ff0c954515d4699b35155e4e to your computer and use it in GitHub Desktop.
Import Address Table hook
// مثال لخطف دالة عن طريق استبدال عنوانها في جدول عناوين الدوال المستوردة
// 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