Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Infinite-Loop #15

Open
Bix3 opened this issue Feb 11, 2020 · 15 comments
Open

Infinite-Loop #15

Bix3 opened this issue Feb 11, 2020 · 15 comments

Comments

@Bix3
Copy link

Bix3 commented Feb 11, 2020

Hello, i did some testing with the library, it seems good so far, altough i have a little error.

I modified the ExHook like this, the reason is, that the given sample can only activate on processes which are already running. so i moved the code for activation to the
"InitTarget" Function, which works so far. on the main i activate it on a process ("activator.exe") trough which i can then send a command (syscall 1032) once i want it to activate on another process ("notepad.exe").
the whole thing works on my cloudvm running windows server datacenter 2019 1809 build. But when i test on my bare metal pc's (win10 pro/home 1803/1909) on none of them it works completely it initializes successfully on the activator.exe but when that thing sends the 1032 syscall it gets stuck forever in the kernel code spamming the dbgprintf of the Systemwideexceptionhandler and Sysexitintercept.

#include "NtInternals.h"
#include "ByePG.h"

void SysExitIntercept(PETHREAD Thread);
LONG SystemWideExceptionHandler(CONTEXT* ContextRecord, EXCEPTION_RECORD* ExceptionRecord);
SYSTEM_PROCESS_INFORMATION* QueryProcessInformation();
NTSTATUS InitTarget(wchar_t name[255]);


extern "C" NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
{
	UNREFERENCED_PARAMETER(DriverObject);
	UNREFERENCED_PARAMETER(RegistryPath);
	
	NTSTATUS Status = ByePgInitialize(SystemWideExceptionHandler, FALSE);
	if (!NT_SUCCESS(Status)) return Status;
	
	return InitTarget(L"activator.exe");
}



#define kprintf(...) DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, __VA_ARGS__)

void SysExitIntercept(PETHREAD Thread)
{	
	kprintf("\n1");
	// Get trap frame
	//
	KTRAP_FRAME* TrapFrame = PsGetBaseTrapFrame(Thread);
	KTRAP_FRAME* ThrTrapFrame = PsGetTrapFrame(Thread);
	if (TrapFrame != ThrTrapFrame) return;

	// Check if it's a service frame
	//
	if (TrapFrame->ExceptionActive == 2)
	{
		kprintf("\n2");
		kprintf("SYSCALL %d [%p, %p, %p, %p]\n", PsGetSystemCallNumber(Thread), TrapFrame->Rcx, TrapFrame->Rdx, TrapFrame->R8, TrapFrame->R9);
				
		if (PsGetSystemCallNumber(Thread) == 1032)
		{
			kprintf("\n3");

			InitTarget("notepad.exe");
		
			return;
		}
		kprintf("\n4");
	}
	kprintf("\n5");
	return;
}

LONG SystemWideExceptionHandler(CONTEXT* ContextRecord, EXCEPTION_RECORD* ExceptionRecord)
{
	// Only handle exceptions raised at <= DISPATCH_LEVEL (ignoring EFLAGS.IF)
	//
	kprintf("\n6");
	if (KeGetCurrentIrql() > DISPATCH_LEVEL) return EXCEPTION_EXECUTE_HANDLER;
	kprintf("\n7");
	// Access violation
	//
	if (ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION)
	{
		kprintf("\n8");
		/*
			KiCopyCountersWorker proc near
				mov     [rsp+arg_0], rbx
				mov     [rsp+arg_18], rsi
				push    rdi
				sub     rsp, 30h
				mov     rdi, rdx
				mov     rsi, rcx
				mov     rbx, [rdx+8]	<-- Exception occurs here
		*/

		// Verify that it was raised at target instruction
		//
		if (MmIsAddressValid(ExceptionRecord->ExceptionAddress))
		{
			kprintf("\n9");
			UCHAR* Instruction = (UCHAR*)ExceptionRecord->ExceptionAddress;
			if (Instruction[3] == 0x08)
			{
				kprintf("\n10");
				/*
					jmp     short $+2		<-- Epilogue start
					mov     rbx, [rsp+38h+arg_0]
					mov     rsi, [rsp+38h+arg_18]
					add     rsp, 30h
					pop     rdi
					retn
				KiCopyCountersWorker endp
				*/

				// Skip to epilogue
				//
				while (Instruction[0] != 0xEB ||
					Instruction[1] != 0x00) Instruction++;
				ContextRecord->Rip = (ULONG64)Instruction + 2;
				kprintf("\n11");
				// Inject a call to our routine
				//
				ContextRecord->Rsp -= 0x8;
				*(ULONG64*)ContextRecord->Rsp = ContextRecord->Rip;
				ContextRecord->Rip = (ULONG64)&SysExitIntercept;
				kprintf("\n12");
				// Continue execution
				//
				return EXCEPTION_CONTINUE_EXECUTION;
			}
		}
	}
	kprintf("\n13");
	return EXCEPTION_EXECUTE_HANDLER;
}

SYSTEM_PROCESS_INFORMATION* QueryProcessInformation()
{
	// Allocate buffer of estimated size
	//
	ULONG BufferSize = 0x10000;
	void* Buffer = ExAllocatePool(NonPagedPool, BufferSize);

	while (true)
	{
		// Try to query system information
		//
		NTSTATUS Status = ZwQuerySystemInformation(SystemProcessInformation, Buffer, BufferSize, &BufferSize);

		// If size is too small:
		//
		if (Status == STATUS_INFO_LENGTH_MISMATCH)
		{
			ExFreePool(Buffer);
			Buffer = ExAllocatePool(NonPagedPool, BufferSize);
		}
		else
		{
			// If failed, free the buffer and return nullptr:
			//
			if (!NT_SUCCESS(Status))
			{
				ExFreePool(Buffer);
				return nullptr;
			}
			// Else cast the buffer to relevant type and return it:
			//
			else
			{
				return PSYSTEM_PROCESS_INFORMATION(Buffer);
			}
		}
	}
}


NTSTATUS InitTarget(wchar_t name[255])
{

	UNICODE_STRING TargetImageName;
	RtlInitUnicodeString(&TargetImageName, name);
	
	SYSTEM_PROCESS_INFORMATION* Spi = QueryProcessInformation();
	if (void* Buffer = Spi)
	{
		// Iterate each process
		//
		while (Spi->NextEntryOffset)
		{
			// If matches target image:
			//
			if (!RtlCompareUnicodeString(&Spi->ImageName, &TargetImageName, FALSE))
			{
				// Resolve EPROCESS
				//
				PEPROCESS Process = nullptr;
				PsLookupProcessByProcessId(Spi->UniqueProcessId, &Process);
				if (Process)
				{
					kprintf("Target process instance [PID: %llu, EPROCESS: %p]\n", Spi->UniqueProcessId, Process);

					// Iterate each thread
					//
					for (int i = 0; i < Spi->NumberOfThreads; i++)
					{
						// Resolve ETHREAD
						//
						PETHREAD Thread = nullptr;
						PsLookupThreadByThreadId(Spi->Threads[i].ClientId.UniqueThread, &Thread);
						if (Thread)
						{
							kprintf("-- Thread [TID: %llu, ETHREAD: %p]\n", Spi->Threads[i].ClientId.UniqueThread, Thread);

							// Set CycleProfiling flag
							//
							DISPATCHER_HEADER* DpcHdr = (DISPATCHER_HEADER*)Thread;
							DpcHdr->CycleProfiling = 1;

							// Dereference ETHREAD
							//
							ObDereferenceObject(Thread);
						}
					}

					// Dereference EPROCESS
					//
					ObDereferenceObject(Process);
				}
			}

			Spi = PSYSTEM_PROCESS_INFORMATION((char*)Spi + Spi->NextEntryOffset);
		}

		// Free the buffer and report success
		//
		ExFreePool(Buffer);
		return STATUS_SUCCESS;
	}
	else
	{
		return STATUS_UNSUCCESSFUL;
	}

}
@Waterman178
Copy link

I have a question, why do you set CycleProfiling 1?

@Bix3
Copy link
Author

Bix3 commented Feb 13, 2020

@Waterman178
i didnt do much to that code, its the same as in the example

DpcHdr->CycleProfiling = 1;

@Waterman178
Copy link

多事情,与示例中的代码相同

What's the use of you setting it to 1

@Bix3
Copy link
Author

Bix3 commented Feb 13, 2020

@Waterman178 I am just getting started with this library, the code I posted is basically the ExHook example written by @can1357 from the github page with only the Initialization code moved to a function and the ability to initialize on a process without loading the driver several times. I did not modify the part where CycleProfiling is set.

@can1357
Copy link
Owner

can1357 commented Feb 13, 2020

Could you show me the exact result you are getting on the baremetal machine? Also does the original ExHook work fine on the same machine?

@can1357
Copy link
Owner

can1357 commented Feb 13, 2020

@Waterman178 CylceProfiling set to 1 without the pointer being appropriately set in the _ETHREAD structure generates a #PF on exit-to-usermode.

@Waterman178
Copy link

@Waterman178 CylceProfiling set to 1 without the pointer being appropriately set in the _ETHREAD structure generates a #PF on exit-to-usermode.

which pointer in ETHREAD?

@can1357
Copy link
Owner

can1357 commented Feb 14, 2020

_ETHREAD.Tcb.ThreadCounters

@Bix3
Copy link
Author

Bix3 commented Feb 15, 2020

Hi, this is the DbgPrints it spams out:

00002321	1.14731109	SYSCALL 1032 [000000F0525FF410, 00000000BEEFDEAD, 0000000000000000, 000002C3A3D57DC0]
00002322	1.14731205	 
00002323	1.14731216	3
00002324	1.15891695	Target process instance [PID: 14628, EPROCESS: FFFFE48954C9C4C0]
00002325	1.15892196	-- Thread [TID: 17852, ETHREAD: FFFFE48958471640]
00002326	1.15893877	 
00002327	1.15893912	6
00002328	1.15894055	 
00002329	1.15894079	7
00002330	1.15894163	 
00002331	1.15894175	8
00002332	1.15894306	 
00002333	1.15894318	9
00002334	1.15894401	 
00002335	1.15894425	10
00002336	1.15894532	 
00002337	1.15894556	11
00002338	1.15894639	 
00002339	1.15894663	12
00002340	1.15894794	 
00002341	1.15894818	1
00002342	1.15894902	 
00002343	1.15894926	2
00002344	1.15895152	SYSCALL 1032 [000000F0525FF410, 00000000BEEFDEAD, 0000000000000000, 000002C3A3D57DC0]
00002345	1.15895236	 
00002346	1.15895247	3
00002347	1.17053986	Target process instance [PID: 14628, EPROCESS: FFFFE48954C9C4C0]
00002348	1.17054427	-- Thread [TID: 17852, ETHREAD: FFFFE48958471640]
00002349	1.17056060	 
00002350	1.17056096	6
00002351	1.17056465	 
00002352	1.17056489	7
00002353	1.17056584	 
00002354	1.17056596	8
00002355	1.17056715	 
00002356	1.17056739	9
00002357	1.17056823	 
00002358	1.17056835	10
00002359	1.17056954	 
00002360	1.17056966	11
00002361	1.17057049	 
00002362	1.17057085	12
00002363	1.17057204	 
00002364	1.17057228	1
00002365	1.17057312	 
00002366	1.17057335	2
00002367	1.17057550	SYSCALL 1032 [000000F0525FF410, 00000000BEEFDEAD, 0000000000000000, 000002C3A3D57DC0]
00002368	1.17057645	 
00002369	1.17057657	3
00002370	1.18216705	Target process instance [PID: 14628, EPROCESS: FFFFE48954C9C4C0]
00002371	1.18217099	-- Thread [TID: 17852, ETHREAD: FFFFE48958471640]
00002372	1.18218625	 
00002373	1.18218672	6
00002374	1.18218803	 
00002375	1.18218827	7
00002376	1.18218899	 
00002377	1.18218935	8
00002378	1.18219030	 
00002379	1.18219054	9
00002380	1.18219125	 
00002381	1.18219161	10
00002382	1.18219268	 
00002383	1.18219292	11
00002384	1.18219376	 
00002385	1.18219388	12
00002386	1.18219531	 
00002387	1.18219554	1
00002388	1.18219626	 
00002389	1.18219662	2
and so on infinite

The normal ExHook you provided works. but i am not sure that the problem is in my code, because the exact same binaries work on the Virtual Machine.
Thanks for your help its a great library!

@Bix3
Copy link
Author

Bix3 commented Feb 18, 2020

ok just tested a bit more, seems like every real computer stucks in a loop with that code, while the same binaries work on all virtual machines i tested it on. So it even makes a difference if you have the exact same OS bare metal or Virtual

@krjan02
Copy link

krjan02 commented Feb 21, 2020

@can1357 I seem to have the same issues across my machines (amd & intel). Also tested on a Xeon Processor Machine

@can1357
Copy link
Owner

can1357 commented Mar 1, 2020

Hey guys, I'm a little busy as I'm working on the presentation for ByePg and some personal projects right now, so I apologise for my late responses.

As far as I got from this thread some sample code works on Virtual Machines but not on Baremetal?
(Very interesting as that means we can also detect a hypervisor using this method :P)

@Bix3:

  1. Which systemcall is 1032?
  2. Could you attach all of the source code related to your project? Basically everything I need to reproduce this issue?

@arannothc:

  1. Are you using ExHook source code as is?

@ everyone:

  1. Which hypervisor does the code work fine under exactly? VMWare? If so did anyone try if it works under KVM as well?
  2. To boil down the problem, when you return EXCEPTION_CONTINUE_EXECUTION from SystemWideExceptionHandler it executes the exception handler again and gets stuck?
  3. Does the system freeze or the process? If latter, can you shut down the process when it's stuck? I'm asking because if it's a system freeze IRQL >= DISPATCH_LEVEL, else its APC_LEVEL or PASSIVE_LEVEL, latter if you can still shut down the process.

Thanks!
Can

@krjan02
Copy link

krjan02 commented Mar 2, 2020

@can1357 yes i tried ExHook without any modifications

@Bix3
Copy link
Author

Bix3 commented Mar 17, 2020

for 1032 i just used it as like a "own syscall" since it is unused. i will try later with a valid call. i will upload the project

@hzqst
Copy link

hzqst commented Jul 23, 2020

ExHook works perfectly in vmware guest, but same issue with my bare metal machine (AMD Ryzen 1800X with Windows 10 20H1 buildnum 19041.388), It get me triple fault in about 2~5 seconds after loading ExHook.

tested ExceptionHookingDemo again with 8c16t processor bare metal machine got only 3 exceptions displayed in dbgview.

It looks like some of the processors hang up at KiCheckForFreezeExecution when dispatching fault.

btw, I made uninitialization/unload routine for ByePg and load/unload ExceptionHookingDemo for multiple times. as the load times increase, less and less cores get exception handled, and finally the whole system hang up at the 4th attempt.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants