I am trying to parse the import address table of NTDLL, I have done this previously trying to iterate over each module, but I was getting a strange base address. I scrapped that approach and have done the below, but I get the exact same base address.
For NTDLL I am getting the base address 0x217000
from the field DllBase
on the LDR_DATA_TABLE_ENTRY
struct.
I have followed all the addresses (PEB
& PEB_LDR_DATA
) and they seem right in windbg. Accessing the base address of 0x217000
gives me a memory access violation.
The value I'm reading of 0x217000
is consistent on both my attempts, so I'm lead to believe I'm reading the correct value. I also understand the address here i'snt an RVA, but the actual VA of the base address. I have tried however treating it as an offset, but that also gave me a memory access violation.
use windows::Win32::Foundation::{HANDLE, NTSTATUS, UNICODE_STRING};use windows::Win32::System::LibraryLoader::LoadLibraryA;use windows::Win32::System::SystemServices::{IMAGE_IMPORT_DESCRIPTOR, IMAGE_NT_SIGNATURE};use windows::Win32::System::Threading::{PEB, PROCESS_ALL_ACCESS};use windows::Win32::System::Diagnostics::Debug::{SetUnhandledExceptionFilter, EXCEPTION_POINTERS, IMAGE_OPTIONAL_HEADER64};use windows::Win32::System::WindowsProgramming::LDR_DATA_TABLE_ENTRY;fn read_iat() { unsafe { let peb = get_peb_ptr(); if peb.is_null() { eprintln!("Failed to get PEB"); return; } if let Some(ntdll_entry) = find_ntdll(peb) { let base_address = (*ntdll_entry).DllBase as *const u8; if base_address.is_null() { eprintln!("Invalid base address"); return; } println!("Base address: {:p}", base_address); let nt_headers_offset = *(base_address.add(0x3C) as *const u32) as usize; let nt_headers = base_address.add(nt_headers_offset) as *const IMAGE_OPTIONAL_HEADER64; if nt_headers.is_null() { eprintln!("Invalid NT headers"); return; } // THIS DOESNT PRINT, ACCESS VIOLATION IN THE PREVIOUS STEP println!("NT Headers: {:p}", nt_headers); let data_directory = &(*nt_headers).DataDirectory; let import_directory = data_directory[1]; // IMAGE_DIRECTORY_ENTRY_IMPORT is 1 if import_directory.VirtualAddress == 0 { eprintln!("No import directory"); return; } let import_table = base_address.add(import_directory.VirtualAddress as usize) as *const IMAGE_IMPORT_DESCRIPTOR; if import_table.is_null() { eprintln!("Invalid import table"); return; } let mut import_descriptor = import_table; while (*import_descriptor).Name != 0 { let dll_name = base_address.add((*import_descriptor).Name as usize) as *const i8; println!("Importing: {}", CStr::from_ptr(dll_name).to_str().unwrap_or("Invalid UTF-8")); let thunk_ref = base_address.add((*import_descriptor).Anonymous.OriginalFirstThunk as usize) as *const usize; let iat_ref = base_address.add((*import_descriptor).FirstThunk as usize) as *const usize; if thunk_ref.is_null() || iat_ref.is_null() { eprintln!("Invalid thunk or IAT reference"); import_descriptor = import_descriptor.add(1); continue; } let mut i = 0; while *thunk_ref.add(i) != 0 { let func_name_ptr = base_address.add(*thunk_ref.add(i) as usize + 2) as *const i8; println!("Imported function: {}", CStr::from_ptr(func_name_ptr).to_str().unwrap_or("Invalid UTF-8")); i += 1; } import_descriptor = import_descriptor.add(1); } } else { eprintln!("NTDLL.dll not found"); } }}unsafe fn get_peb_ptr() -> *const PEB { let peb: *const PEB; asm!("mov {}, gs:[0x60]", out(reg) peb); peb}unsafe fn find_ntdll(peb: *const PEB) -> Option<*const LDR_DATA_TABLE_ENTRY> { let ldr = (*peb).Ldr; if ldr.is_null() { return None; } let mut module_list = (*ldr).InMemoryOrderModuleList.Flink; while module_list != &(*ldr).InMemoryOrderModuleList as *const _ as *mut _ { let entry = module_list as *const LDR_DATA_TABLE_ENTRY; let dll_name = (*entry).FullDllName.Buffer; if !dll_name.is_null() { let name = std::slice::from_raw_parts(dll_name.0, (*entry).FullDllName.Length as usize / 2); if name == "ntdll.dll".encode_utf16().collect::<Vec<u16>>() { return Some(entry); } } module_list = (*module_list).Flink; } None}
The code at:
println!("NT Headers: {:p}", nt_headers);
doesn't print, the access violation occurs immediatley before this.