A forum for reverse engineering, OS internals and malware analysis 

Forum for discussion about user-mode development.
 #26568  by Microwave89
 Thu Aug 20, 2015 4:23 pm
Hi Kernelmode.info!

[PoC] Bypassing UM Hooks By Bruteforcing Intel Syscalls

Results: This PoC is supposed to demonstrate how one can +- reliably completely bypass all user mode hooks (IAT, EAT, (deep)inline, PEB?)
in order to get access to a pristine on-disk ntdll.dll, assuming the on-disk DLL has not been tampered with.
If the read of the ntdll.dll file succeeds you must see a message stating that a certain copy succeeded. Then, if you started the PoC
as an administrator it will terminate the most processes leading to a crash on Windows 7 and to a hang (or so) on Windows 10.
The results were achieved by leveraging my own universal stub for issuing Intel syscalls and creating a pristine system table for looking up these numbers.
The PoC was tested successfully on Windows 7 SP1 x64, WINPE 3.0, Windows 10 x64 and WINPE for Windows 10.
It was tested with and without administrator rights.

Introduction:
Although it might be well known that user mode hooking can be easily detected and avoided by just leveraging a kernel driver,
I have not come across any user mode tools which are capable of bypassing my former user mode rootkit which simply blocks access to
the on-disk ntdll.dll. Neither PC Hunter 64, nor HookShark64, nor GMER were able to counter this (tested on Windows 7 SP1 x64).
If they can't load a pristine image they can't bypass UM hooks residing in there own image and they have not a comparison base for verifying their own
and the other processes images... Uroburos... the snake bites its tail...
An outbreak would be to load a kernel mode driver in order to let the system process open and read a valid ntdll.dll file...but what if NtLoadDriver is also patched?
You can use NtDeviceIoControlFile to send a FLT_LOAD_FILTER request to fltmgr.sys then, but that API could also be hooked. And you need to call NtOpenFile with
a telltale \\??\\fltmgrmsg string. ;)

So I thought if it wouldn't be possible to use direct Intel 0F 05 syscall instructions to essentially construct your own NTAPI stubs
which, of course, are not patched. I saw three possible approaches. The first one was to have hardcoded the needed numbers
into the executable. But I never liked the fact that the numbers are really volatile and DO change with every new Windows service pack
or version. This would, as for now, lead to the program not running anymore on fictive Windows 11.

With these clear shortcomings, I was like "Why not just bruteforcing those numbers? Why would I need to know which number a certain syscall is corresponding to
when I just can feed it with the correct parameters and let the kernel decide for which number all parameters fit so it can perform the wanted operation?"
With that in mind I started initial tests in March...April. I could, however, not achieve promising results since I had to counter many problems.
Not only that I struggled coding a universal system call interface which easily lets you provide any number of parameters
but it was also almost quite impossible to perform bruteforcing the syscall numbers in the shellcode (or assembly) itself.
All sorts of possible, credible, impossible and incredible things happened to my program while trying perform the wanted operations.
When one number opened a handle to a file the next call just closed it again, the 234th call then let my program run into a NtWaitForXxx loop...etc.
This happened since I had no chance to define rules in assembly of when to deem a system call as successful and break the loop.
Hint: Using NTSTATUS values does not work at all since there are a few APIs which almost always return STATUS_SUCCESS such as NtYieldExecution.

And talk about the issues with the stack, the overwritten parameters due to failing syscall attempts, the few nonvolatile registers which must be preserved,
but I just want to use THAT registers to save my arguments and preserving those registers would shift the stack or unalign it...or I would
need to save a sufficient count of parameters in the memory I'm just executing instructions of...
Hence, with the simple, assembly based approach it was just not feasible and I stopped the project.

Now, a few months later, I wanted to fuzz the lower syscall interface (0x0...0x1000) and in order to be able to supply arbitrary parameters I needed a syscall interface of the form:
syscallStub(ULONG syscallNum, ...). I then just reversed what it looked like if I called printf("blah, %x%x%x%x%x%x", var1, var2, var3, var4, var5, var6).
I saw that the compiler does all the hard work and that the va_list or va_xxx stuff is only of interest when operating on these format strings.
So it was no problem to define a universal syscall interface similar to printf(). But I had some small problems on the other (assembly) side because the syscall number
occupied the former rcx register, the registers were all shifted by 1 and the r9 parameter was now on stack. This was quickly solved by moving
rcx to rax, (my syscall number) and then rdx to rcx, and so forth I then shifted the stack, then I issued a 0F 05 instruction
and then backshifted the stack and my job was done.
The small stub is in the auxfuncs.asm file.

Then I thought, why not just using the fuzzer interface to fuzz the system calls with NtOpenFile parameters until I get a handle to ntdll.dll?
That way I would completely bypass any NtOpenFile hooks. I tried it and due to a proper system call stub I succeeded.
But when I tried to query information on the file it failed because the NtClose call appeared before NtQueryInformationFile and thus closed my handle
I just opened. I solved that and some other problems later but basically I could see that it was feasible after all to use syscall bruteforcing in order to
read a pristine ntdll.dll into my VA space and then to use some basic PE math in order to correlate a NtXxx API name to the correct syscall number.

Having now the numbers of both NtCreateSection and NtMapViewOfSection, it would be a walk in the park to again load the ntdll.dll
but this time as an image file and execute almost ALL functions (RtlXxx, LdrXxx, DbgXxx, etc.) of it.

If there are any questions, feel free to ask! The same holds true if you have any suggestions.
The bruteforce part of the main.c file should be commented quite well so it should be pretty self-explaining.

Please take care if you execute the file with admin rights. It will most certainly crash your computer.

Of course, there are many possible improvements, one could for example use the NtOpenFile - NtCreateSection - NtMapViewOfSection approach directly
if that is possible with syscall bruteforcing.


Best Regards

Microwave89
Attachments
(250.64 KiB) Downloaded 71 times
pwd: standard pw
(3.59 KiB) Downloaded 48 times
 #26571  by Brock
 Fri Aug 21, 2015 6:40 am
Hi MicroWave89,

I can only assume part of your interests in this subject matter lies here based on your mentioned time frame of interest http://www.kernelmode.info/forum/viewto ... 3&start=10 ? Thanks for the shared code, it's still interesting considering such bruteforce behavior is still a force to be reckoned with. Remember PID bruteforcing? Originally, BlackLight used it and conquered a lot of malware in its day ;) I've used bruteforcing for many tasks since maybe 2003/2004 when it came to similar tasks. Good job
 #26608  by Munsta
 Thu Aug 27, 2015 9:34 am
Brock wrote:Hi MicroWave89,

I can only assume part of your interests in this subject matter lies here based on your mentioned time frame of interest http://www.kernelmode.info/forum/viewto ... 3&start=10 ? Thanks for the shared code, it's still interesting considering such bruteforce behavior is still a force to be reckoned with. Remember PID bruteforcing? Originally, BlackLight used it and conquered a lot of malware in its day ;) I've used bruteforcing for many tasks since maybe 2003/2004 when it came to similar tasks. Good job
I have one question. Is the only 'legit' usage of handle bruteforce when we need to delete used files/hanging handle?
 #26610  by Brock
 Thu Aug 27, 2015 10:32 am
No. You can also "discover" values through bruteforcing and test function arguments forcing some functions to validate things for you, not just handles but any value you'd generally pass to a function that would be a valid argument (window handles, process handles, process ids, thread ids etc. list goes on). Since I mentioned process bruteforcing here is a small example of such
Code: Select all
#define MAX_PID 100000 // Some high value to bruteforce

	ULONG PID;
	ULONG ExitCode;
	WCHAR lpFileName[MAX_PATH];

	for (PID = 0; PID < MAX_PID; PID += 4) 
	{
		HANDLE hProcess = OpenProcess(MAXIMUM_ALLOWED, FALSE, PID);
		if (hProcess)
		{
			if (GetExitCodeProcess(hProcess, &ExitCode) && ExitCode == 0x103) // STILL_ACTIVE
			{
				ZeroMemory(&lpFileName, sizeof(lpFileName));
				if (!GetModuleFileNameExW(hProcess, 0, lpFileName, MAX_PATH))
					lstrcpyW(lpFileName, L"Lack Rights or Privileges");
				printf("Discovered Active Process [%u]%ws\n", PID, lpFileName);
			}
			CloseHandle(hProcess);
		}
	}
 #26614  by Microwave89
 Fri Aug 28, 2015 9:18 pm
Brock wrote:Hi MicroWave89,

I can only assume part of your interests in this subject matter lies here based on your mentioned time frame of interest http://www.kernelmode.info/forum/viewto ... 3&start=10 ? Thanks for the shared code, it's still interesting considering such bruteforce behavior is still a force to be reckoned with. Remember PID bruteforcing? Originally, BlackLight used it and conquered a lot of malware in its day ;) I've used bruteforcing for many tasks since maybe 2003/2004 when it came to similar tasks. Good job
Yes, it is pretty much the timeframe of interest, however, I started the first bruteforce attempts not until end of February...

Best Regards - Microwave89
 #26617  by EP_X0FF
 Sat Aug 29, 2015 4:45 pm
Microwave89 wrote:I have not come across any user mode tools which are capable of bypassing my former user mode rootkit which simply blocks access to
the on-disk ntdll.dll. Neither PC Hunter 64, nor HookShark64, nor GMER were able to counter this (tested on Windows 7 SP1 x64).
What you listed is comedy section tools created by noobs. Well I see it is x64, so it doesn't matter anyway. TDL2 blocked I/O for example too. Next Gmer integrated a "workaround" crutch to solve this. If your rootkit will be available at market there will be workaround for it. It is simple - no one cares about such proof-of-concept unless they become itw.
 #26618  by Brock
 Sun Aug 30, 2015 5:59 am
This post is better being called "Bypassing Usermode Hooks within Usermode" to avoid confusion perhaps. Obviously, anything with kernel/ring0 access doesn't apply unless they're uninformed to map an NTDLL image from disk in usermode or not take precautions to validate the image at a privileged ring/level. Seems this is a "What If" scenario and then we can wrap our heads around remote servers that mirror the same exact NTDLL version and/or a LiveCD requirement. Interesting concept but definitely used and (ab)used before many years ago