Open wbenny opened 6 years ago
Hey wbenny! After several years of crawling the hub, this project was the first one that actually inspired me to make an account. Not to beat a dead horse, but I was also wondering if you could maybe give a small tip as to getting this working with kernel pages. Simply allocating and page aligning in the kernel instead of usermode doesn't seem to work as I thought it would. Perhaps you'd be willing to give us an early Christmas present and share some advice on what we can do? I can't speak for others, but I would be thrilled to understand what I am doing wrong.
I got this working, but not sure if he wants me to share how, I can say though it's extremely simple.
As a side note, the following examples might help as well: https://github.com/tandasat/DdiMon https://github.com/Bareflank/extended_apis_example_hook
Cheers,
On Wed, Dec 5, 2018 at 2:09 PM DebugBuggin notifications@github.com wrote:
I got this working, but not sure if he wants me to share how, I can say though it's extremely simple.
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/wbenny/hvpp/issues/7#issuecomment-444649015, or mute the thread https://github.com/notifications/unsubscribe-auth/AFqD4xOncO59rrpl0-1MtHXgHefwS9s1ks5u2DX7gaJpZM4WUUyc .
@assemblyw0t Hello! There are several ways to do it. The naive approach is to use the exact same steps as for UM hooking - which kinda requires you to port Detours-like behavior to KM - patch the first instruction(s) with jump to your routine and create trampoline to call the original function. Second approach is much easier and is used in DdiMon (pointed out by @rianquinn) - use int3 + redirect RIP in the handler and create "micro-trampoline" (first original instruction, jmp + address). Third approach might be using DR - which, if placed at right position, can give you easily all Nt* calls with single DR register.
@DebugBuggin We're on github, I can't prevent anyone who wants to fork this repo :) Quite the opposite, I highly encourage it.
@DebugBuggin Maybe he wouldn't mind if it was in private? Would you mind helping a fellow out? My email is adrianpaza89@gmail.com. I would really appreciate it if I could get in contact with you and have a few minutes of your time.
I did the first method wbenny just listed and it works great.
That's what I tried to do. I allocate kernel buffers and pass them through the same way as you did in the usermode example, but it just ends up in a kernel security check BSOD. I didn't even actually hook anything yet.
That's what I tried to do. I allocate kernel buffers and pass them through the same way as you did in the usermode example, but it just ends up in a kernel security check BSOD. I didn't even actually hook anything yet.
Well currently I still need to rely on the usermode code(that loops through the cpu and issues vm calls) to then call my kernel code that hides the kernel pages. I don't know why but can't get the kernel equivalent that I borrowed from hyperplatform(and is below) to work without bluescreen yet. It's not that big of deal for me though. Anyway just try your stuff with the usermode program, and first replace these with your kernel buffers
Data->PageRead = MmGetPhysicalAddress(Context->RdxAsPointer);
Data->PageExec = MmGetPhysicalAddress(Context->R8AsPointer);
hyperplatform func
NTSTATUS UtilForEachProcessor(NTSTATUS(*callback_routine)(void *), void *context) {
PAGED_CODE();
const auto number_of_processors =
KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
for (ULONG processor_index = 0; processor_index < number_of_processors;
processor_index++) {
PROCESSOR_NUMBER processor_number = {0};
auto status =
KeGetProcessorNumberFromIndex(processor_index, &processor_number);
if (!NT_SUCCESS(status)) {
return status;
}
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "cpu index %d\n", processor_index);
// Switch the current processor
GROUP_AFFINITY affinity = {0};
affinity.Group = processor_number.Group;
affinity.Mask = 1ull << processor_number.Number;
GROUP_AFFINITY previous_affinity = {0};
KeSetSystemGroupAffinityThread(&affinity, &previous_affinity);
// Execute callback
status = callback_routine(context);
KeRevertToUserGroupAffinityThread(&previous_affinity);
if (!NT_SUCCESS(status)) {
return status;
}
}
return STATUS_SUCCESS;
}
Maybe I am just dumb. But I don't see what I am doing wrong.
pfnIofCallDriver IofCallDriveFn = (pfnIofCallDriver)GetSystemFunctionAddress(L"IofCallDriver");
PVOID OriginalFunction = (PVOID)IofCallDriveFn; PVOID OriginalFunctionAligned = PAGE_ALIGN(OriginalFunction);
PVOID OriginalFunctionBackup = KernelAllocateMem(PAGE_SIZE * 2); PVOID OriginalFunctionBackupAligned = PAGE_ALIGN((ULONG_PTR)OriginalFunctionBackup + PAGE_SIZE); memcpy(OriginalFunctionBackupAligned, OriginalFunctionAligned, PAGE_SIZE);
Just as the usermode example does, and then I pass these addresses in the same way as usermode example does.
Maybe I am just dumb. But I don't see what I am doing wrong.
pfnIofCallDriver IofCallDriveFn = (pfnIofCallDriver)GetSystemFunctionAddress(L"IofCallDriver");
PVOID OriginalFunction = (PVOID)IofCallDriveFn; PVOID OriginalFunctionAligned = PAGE_ALIGN(OriginalFunction);
PVOID OriginalFunctionBackup = KernelAllocateMem(PAGE_SIZE * 2); PVOID OriginalFunctionBackupAligned = PAGE_ALIGN((ULONG_PTR)OriginalFunctionBackup + PAGE_SIZE); memcpy(OriginalFunctionBackupAligned, OriginalFunctionAligned, PAGE_SIZE);
Just as the usermode example does, and then I pass these addresses in the same way as usermode example does.
looks fine assuming GetSystemFunctionAddress returning proper address. Make sure you don't do those calls in, HvppHandleExecuteVmcall callback, but do them beforehand. thne can look like
Data->PageRead = MmGetPhysicalAddress(OriginalFunctionBackupAligned);
Data->PageExec = MmGetPhysicalAddress(OriginalFunctionAligned);
Addresses seem fine. Debug output:
13:45:31.395 INF #3 4 32 System OriginalFunctionBackupAligned 77e0a000 13:45:31.395 INF #3 4 32 System OriginalFunctionAligned fc4c9000
But once I try to pass them through,
ia32_asm_vmx_vmcall(0xc1, (uint64_t)OriginalFunctionBackupAligned, (uint64_t)OriginalFunctionAligned, 0);
Big fat BSOD.
Edit: I found my problem. As I thought, I am actually dumb. I wasn't properly calling it for each core. Thank you all for your help.
literally just replacing
Data->PageRead = MmGetPhysicalAddress(Context->RdxAsPointer);
Data->PageExec = MmGetPhysicalAddress(Context->R8AsPointer);
with
Data->PageRead = MmGetPhysicalAddress(OriginalFunctionBackupAligned);
Data->PageExec = MmGetPhysicalAddress(OriginalFunctionAligned);
then using the usermod tool, worked fine for me. The example btw only hides 1 page so after you get this working you have to modify the code to support multiple hidden pages, which i'm working on rn.
@wbenny Sorry to bother you again. I ran into a bit of a dilemma and was hoping to get some insight. I decided to go the HyperPlatform method route you recommended with the software breakpoint hooking, but I can't seem to catch the exception? I BSOD at the 0xCC instruction without being able to redirect execution to my detour function. I'm doing as follows:
void vmexit_custom_handler::handle_exception_or_nmi(vcpu_t& vp) noexcept
{
auto interrupt = vp.exit_interrupt_info();
switch (interrupt.type())
{
case vmx::interrupt_type::software_exception:
switch (interrupt.vector())
{
case exception_vector::breakpoint:
if (vp.guest_rip() == IofCallDriver_Address)
{
vp.guest_rip(reinterpret_cast<uintptr_t>(&Detoured_IofCallDriver));
}
break;
default:
break;
}
default:
break;
}
vp.inject(interrupt);
vp.suppress_rip_adjust();
}
Is there something obvious that I am missing here?
I see two possible issues:
First, ensure that that breakpoint
is set in the exception bitmap:
// Inside vmexit_handler::setup() method:
auto exception_bitmap = vmx::exception_bitmap_t{};
exception_bitmap.breakpoint = true;
vp.exception_bitmap(exception_bitmap);
Second, you don't probably want to reinject the breakpoint exception, when you handle it your way:
if (vp.guest_rip() == IofCallDriver_Address)
{
vp.guest_rip(reinterpret_cast<uintptr_t>(&Detoured_IofCallDriver));
vp.suppress_rip_adjust();
return;
}
break;
That is some crazy fast response time. :) Thank you! I made the changes you suggested. Unfortunately, now I am freezing immediately into an eventual DPC_WATCHDOG_VIOLATION BSOD. But it has at least given me some more wiggle room to experiment. Much appreciated!
I ruled out the problem being in the function I'm attempting to detour into. Seems that regardless of what I change the instruction pointer to I just immediately freeze permanently. Strange...
@wbenny Any plans to implement this feature or should we implement it locally? It's been a few months and just wondering if you'll be pushing out an official version or if I should just start implementing a local version.
I got this working, but not sure if he wants me to share how, I can say though it's extremely simple.
Hi, I'm work on kernel hook and I just got multi pages, can u help me with kernel hook stuff?
Hi! I have already experimental version of this in my local branch, but since this project got lots of focus in the game-cheating scene, I decided to wait out a little bit with releasing and let those people figure some basic stuff for themselves. :)