text: #include "kdmapper.hpp"
  
  
  uint64_t kdmapper::AllocMdlMemory(HANDLE iqvw64e_device_handle, uint64_t size, uint64_t* mdlPtr) {
  	/*added by psec*/
  	LARGE_INTEGER LowAddress, HighAddress;
  	LowAddress.QuadPart = 0;
  	HighAddress.QuadPart = 0xffff'ffff'ffff'ffffULL;
  
  	uint64_t pages = (size / PAGE_SIZE) + 1;
  	auto mdl = intel_driver::MmAllocatePagesForMdl(iqvw64e_device_handle, LowAddress, HighAddress, LowAddress, pages * (uint64_t)PAGE_SIZE);
  	if (!mdl) {
  		Log(L"[-] Can't allocate pages for mdl" << std::endl);
  		return { 0 };
  	}
  
  	uint32_t byteCount = 0;
  	if (!intel_driver::ReadMemory(iqvw64e_device_handle, mdl + 0x028 /*_MDL : byteCount*/, &byteCount, sizeof(uint32_t))) {
  		Log(L"[-] Can't read the _MDL : byteCount" << std::endl);
  		return { 0 };
  	}
  
  	if (byteCount < size) {
  		Log(L"[-] Couldn't allocate enough memory, cleaning up" << std::endl);
  		intel_driver::MmFreePagesFromMdl(iqvw64e_device_handle, mdl);
  		intel_driver::FreePool(iqvw64e_device_handle, mdl);
  		return { 0 };
  	}
  
  	auto mappingStartAddress = intel_driver::MmMapLockedPagesSpecifyCache(iqvw64e_device_handle, mdl, nt::KernelMode, nt::MmCached, NULL, FALSE, nt::NormalPagePriority);
  	if (!mappingStartAddress) {
  		Log(L"[-] Can't set mdl pages cache, cleaning up." << std::endl);
  		intel_driver::MmFreePagesFromMdl(iqvw64e_device_handle, mdl);
  		intel_driver::FreePool(iqvw64e_device_handle, mdl);
  		return { 0 };
  	}
  
  	const auto result = intel_driver::MmProtectMdlSystemAddress(iqvw64e_device_handle, mdl, PAGE_EXECUTE_READWRITE);
  	if (!result) {
  		Log(L"[-] Can't change protection for mdl pages, cleaning up" << std::endl);
  		intel_driver::MmUnmapLockedPages(iqvw64e_device_handle, mappingStartAddress, mdl);
  		intel_driver::MmFreePagesFromMdl(iqvw64e_device_handle, mdl);
  		intel_driver::FreePool(iqvw64e_device_handle, mdl);
  		return { 0 };
  	}
  	Log(L"[+] Allocated pages for mdl" << std::endl);
  
  	if (mdlPtr)
  		*mdlPtr = mdl;
  
  	return mappingStartAddress;
  }
  
  uint64_t kdmapper::MapDriver(HANDLE iqvw64e_device_handle, BYTE* data, ULONG64 param1, ULONG64 param2, bool free, bool destroyHeader, bool mdlMode, bool PassAllocationAddressAsFirstParam, mapCallback callback, NTSTATUS* exitCode) {
  
  	const PIMAGE_NT_HEADERS64 nt_headers = portable_executable::GetNtHeaders(data);
  
  	if (!nt_headers) {
  		Log(L"[-] Invalid format of PE image" << std::endl);
  		return 0;
  	}
  
  	if (nt_headers->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
  		Log(L"[-] Image is not 64 bit" << std::endl);
  		return 0;
  	}
  
  	uint32_t image_size = nt_headers->OptionalHeader.SizeOfImage;
  
  	void* local_image_base = VirtualAlloc(nullptr, image_size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
  	if (!local_image_base)
  		return 0;
  
  	DWORD TotalVirtualHeaderSize = (IMAGE_FIRST_SECTION(nt_headers))->VirtualAddress;
  	image_size = image_size - (destroyHeader ? TotalVirtualHeaderSize : 0);
  
  	uint64_t kernel_image_base = 0;
  	uint64_t mdlptr = 0;
  	if (mdlMode) {
  		kernel_image_base = AllocMdlMemory(iqvw64e_device_handle, image_size, &mdlptr);
  	}
  	else {
  		kernel_image_base = intel_driver::AllocatePool(iqvw64e_device_handle, nt::POOL_TYPE::NonPagedPool, image_size);
  	}
  
  	do {
  		if (!kernel_image_base) {
  			Log(L"[-] Failed to allocate remote image in kernel" << std::endl);
  			break;
  		}
  
  		Log(L"[+] Image base has been allocated at 0x" << reinterpret_cast<void*>(kernel_image_base) << std::endl);
  
  		// Copy image headers
  
  		memcpy(local_image_base, data, nt_headers->OptionalHeader.SizeOfHeaders);
  
  		// Copy image sections
  
  		const PIMAGE_SECTION_HEADER current_image_section = IMAGE_FIRST_SECTION(nt_headers);
  
  		for (auto i = 0; i < nt_headers->FileHeader.NumberOfSections; ++i) {
  			auto local_section = reinterpret_cast<void*>(reinterpret_cast<uint64_t>(local_image_base) + current_image_section[i].VirtualAddress);
  			memcpy(local_section, reinterpret_cast<void*>(reinterpret_cast<uint64_t>(data) + current_image_section[i].PointerToRawData), current_image_section[i].SizeOfRawData);
  		}
  
  		uint64_t realBase = kernel_image_base;
  		if (destroyHeader) {
  			kernel_image_base -= TotalVirtualHeaderSize;
  			Log(L"[+] Skipped 0x" << std::hex << TotalVirtualHeaderSize << L" bytes of PE Header" << std::endl);
  		}
  
  		// Resolve relocs and imports
  
  		RelocateImageByDelta(portable_executable::GetRelocs(local_image_base), kernel_image_base - nt_headers->OptionalHeader.ImageBase);
  
  		if (!ResolveImports(iqvw64e_device_handle, portable_executable::GetImports(local_image_base))) {
  			Log(L"[-] Failed to resolve imports" << std::endl);
  			kernel_image_base = realBase;
  			break;
  		}
  
  		// Write fixed image to kernel
  
  		if (!intel_driver::WriteMemory(iqvw64e_device_handle, realBase, (PVOID)((uintptr_t)local_image_base + (destroyHeader ? TotalVirtualHeaderSize : 0)), image_size)) {
  			Log(L"[-] Failed to write local image to remote image" << std::endl);
  			kernel_image_base = realBase;
  			break;
  		}
  
  		// Call driver entry point
  
  		const uint64_t address_of_entry_point = kernel_image_base + nt_headers->OptionalHeader.AddressOfEntryPoint;
  
  		Log(L"[<] Calling DriverEntry 0x" << reinterpret_cast<void*>(address_of_entry_point) << std::endl);
  
  		if (callback) {
  			if (!callback(&param1, &param2, realBase, image_size, mdlptr)) {
  				Log(L"[-] Callback returns false, failed!" << std::endl);
  				kernel_image_base = realBase;
  				break;
  			}
  		}
  
  		NTSTATUS status = 0;
  		if (!intel_driver::CallKernelFunction(iqvw64e_device_handle, &status, address_of_entry_point, (PassAllocationAddressAsFirstParam ? realBase : param1), param2)) {
  			Log(L"[-] Failed to call driver entry" << std::endl);
  			kernel_image_base = realBase;
  			break;
  		}
  
  		if (exitCode)
  			*exitCode = status;
  
  		Log(L"[+] DriverEntry returned 0x" << std::hex << status << std::endl);
  
  		if (free && mdlMode) {
  			intel_driver::MmUnmapLockedPages(iqvw64e_device_handle, realBase, mdlptr);
  			intel_driver::MmFreePagesFromMdl(iqvw64e_device_handle, mdlptr);
  			intel_driver::FreePool(iqvw64e_device_handle, mdlptr);
  		}
  		else if (free) {
  			intel_driver::FreePool(iqvw64e_device_handle, realBase);
  		}
  
  
  		VirtualFree(local_image_base, 0, MEM_RELEASE);
  		return realBase;
  
  	} while (false);
  
  
  	VirtualFree(local_image_base, 0, MEM_RELEASE);
  
  	intel_driver::FreePool(iqvw64e_device_handle, kernel_image_base);
  
  	return 0;
  }
  
  void kdmapper::RelocateImageByDelta(portable_executable::vec_relocs relocs, const uint64_t delta) {
  	for (const auto& current_reloc : relocs) {
  		for (auto i = 0u; i < current_reloc.count; ++i) {
  			const uint16_t type = current_reloc.item[i] >> 12;
  			const uint16_t offset = current_reloc.item[i] & 0xFFF;
  
  			if (type == IMAGE_REL_BASED_DIR64)
  				*reinterpret_cast<uint64_t*>(current_reloc.address + offset) += delta;
  		}
  	}
  }
  
  bool kdmapper::ResolveImports(HANDLE iqvw64e_device_handle, portable_executable::vec_imports imports) {
  	for (const auto& current_import : imports) {
  		ULONG64 Module = utils::GetKernelModuleAddress(current_import.module_name);
  		if (!Module) {
  #if !defined(DISABLE_OUTPUT)
  			std::cout << "[-] Dependency " << current_import.module_name << " wasn't found" << std::endl;
  #endif
  			return false;
  		}
  
  		for (auto& current_function_data : current_import.function_datas) {
  			uint64_t function_address = intel_driver::GetKernelModuleExport(iqvw64e_device_handle, Module, current_function_data.name);
  
  			if (!function_address) {
  				//Lets try with ntoskrnl
  				if (Module != intel_driver::ntoskrnlAddr) {
  					function_address = intel_driver::GetKernelModuleExport(iqvw64e_device_handle, intel_driver::ntoskrnlAddr, current_function_data.name);
  					if (!function_address) {
  #if !defined(DISABLE_OUTPUT)
  						std::cout << "[-] Failed to resolve import " << current_function_data.name << " (" << current_import.module_name << ")" << std::endl;
  #endif
  						return false;
  					}
  				}
  			}
  
  			*current_function_data.address = function_address;
  		}
  	}
  
  	return true;
  }
  