Skip to content

Instantly share code, notes, and snippets.

@olliencc
Created January 1, 2022 08:28
Show Gist options
  • Save olliencc/7c722386aa94b37fe621da4f894f7cb1 to your computer and use it in GitHub Desktop.
Save olliencc/7c722386aa94b37fe621da4f894f7cb1 to your computer and use it in GitHub Desktop.
/*
VEH using process enumerator for Microsoft Windows
Released as open source by NCC Group Plc - http://www.nccgroup.com/
Developed by Ollie Whitehouse, ollie dot whitehouse at nccgroup dot com
Released under AGPL see LICENSE for more information
*/
// Sources
// https://dimitrifourny.github.io/2020/06/11/dumping-veh-win10.html
// https://www.unknowncheats.me/forum/c-and-c-/160827-internals-addvectoredexceptionhandler.html
// http://rinseandrepeatanalysis.blogspot.com/p/peb-structure.html
// https://bytepointer.com/resources/tebpeb32.htm
// https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/pebteb/peb/crossprocessflags.htm
// https://github.com/processhacker/processhacker/blob/master/phnt/include/ntpsapi.h
// Includes
#include "stdafx.h"
// Globals
TCHAR strErrMsg[1024];
DWORD dwModuleRelocs = 0;
void* eventWrite = GetProcAddress(LoadLibraryA("ntdll"), "EtwEventWrite");
DWORD dwCountError = 0;
DWORD dwCountOK = 0;
DWORD dwVEH = 0;
DWORD dwVCH = 0;
// Structures to hold process information
#pragma pack(push, 1)
struct procNfoStuct {
DWORD PID;
TCHAR Name[MAX_PATH];
unsigned long long TotalExecMem = 0;
};
#pragma pack(pop)
procNfoStuct Procs[4098];
DWORD NumOfProcs = 0;
// Manual imports
_NtQueryInformationProcess __NtQueryInformationProcess = (_NtQueryInformationProcess)GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "NtQueryInformationProcess");
typedef BOOL(WINAPI* LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
LPFN_ISWOW64PROCESS fnIsWow64Process = fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle(TEXT("kernel32")), "IsWow64Process");
// VEH Stuff
typedef struct _VECTORED_HANDLER_ENTRY {
_VECTORED_HANDLER_ENTRY* next;
_VECTORED_HANDLER_ENTRY* previous;
ULONG refs;
PVECTORED_EXCEPTION_HANDLER handler;
} VECTORED_HANDLER_ENTRY;
typedef struct _VECTORED_HANDLER_LIST {
void* mutex_exception;
VECTORED_HANDLER_ENTRY* first_exception_handler;
VECTORED_HANDLER_ENTRY* last_exception_handler;
void* mutex_continue;
VECTORED_HANDLER_ENTRY* first_continue_handler;
VECTORED_HANDLER_ENTRY* last_continue_handler;
} VECTORED_HANDLER_LIST;
//
// Function : SetDebugPrivilege
// Role : Gets privs for our process
// Notes :
//
BOOL SetPrivilege(HANDLE hProcess, LPCTSTR lPriv)
{
LUID luid;
TOKEN_PRIVILEGES privs;
HANDLE hToken = NULL;
DWORD dwBufLen = 0;
char buf[1024];
ZeroMemory(&luid, sizeof(luid));
if (!LookupPrivilegeValue(NULL, lPriv, &luid)) return false;
privs.PrivilegeCount = 1;
privs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
memcpy(&privs.Privileges[0].Luid, &luid, sizeof(privs.Privileges[0].Luid));
if (!OpenProcessToken(hProcess, TOKEN_ALL_ACCESS, &hToken))
return false;
if (!AdjustTokenPrivileges(hToken, FALSE, &privs,
sizeof(buf), (PTOKEN_PRIVILEGES)buf, &dwBufLen))
return false;
CloseHandle(hProcess);
CloseHandle(hToken);
return true;
}
DWORD GetPEB(HANDLE hProcess, PEB *outPEB, DWORD64 *CrossProcessFlags) {
NTSTATUS Status;
PROCESS_BASIC_INFORMATION ProcessInformation;
Status = __NtQueryInformationProcess(hProcess, ProcessBasicInformation, (DWORD_PTR *)&ProcessInformation, sizeof(ProcessInformation), NULL);
if (Status != 0)
{
return 0;
}
SIZE_T dwRead =0;
ReadProcessMemory(hProcess, ProcessInformation.PebBaseAddress, outPEB, sizeof(PEB), &dwRead);
PPEB pPEB = (PPEB)ProcessInformation.PebBaseAddress;
ReadProcessMemory(hProcess, (PBYTE)pPEB + 0x50, (LPVOID)CrossProcessFlags, sizeof(DWORD64), &dwRead);
return dwRead;
}
/// <summary>
/// Analyze the process and its memory regions
/// </summary>
/// <param name="dwPID">Process ID</param>
void AnalyzeProc(DWORD dwPID)
{
DWORD dwRet, dwMods;
HANDLE hProcess;
HMODULE hModule[4096];
TCHAR cProcess[MAX_PATH]; // Process name
BOOL bIsWow64 = FALSE;
BOOL bIsWow64Other = FALSE;
DWORD dwRES = 0;
// Get process handle by hook or by crook
hProcess = OpenProcess(PROCESS_ALL_ACCESS | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwPID);
if (hProcess == NULL)
{
if (GetLastError() == 5) {
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwPID);
if (hProcess == NULL) {
hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, dwPID);
if (hProcess == NULL) {
fwprintf(stderr, _TEXT("[!] [%d][UNKNOWN] Failed to OpenProcess - %d\n"), dwPID, GetLastError());
dwCountError++;
return;
}
}
}
else {
fwprintf(stderr, _TEXT("[!] [%d][UNKNOWN] Failed to OpenProcess - %d\n"), dwPID, GetLastError());
dwCountError++;
return;
}
}
// Enumerate the process modules
if (EnumProcessModules(hProcess, hModule, 4096 * sizeof(HMODULE), &dwRet) == FALSE)
{
if (GetLastError() == 299) {
//fprintf(stderr, "64bit process and we're 32bit - sad panda! skipping PID %d\n", dwPID);
}
else {
//fprintf(stderr, "Error in EnumProcessModules(%d),%d\n", dwPID, GetLastError());
}
dwCountError++;
return;
}
dwMods = dwRet / sizeof(HMODULE);
// Get the processes name from the first module returned by the above
GetModuleBaseName(hProcess, hModule[0], cProcess, MAX_PATH);
Procs[NumOfProcs].PID = dwPID;
_tcscpy_s(Procs[NumOfProcs].Name, MAX_PATH, cProcess);
NumOfProcs++;
PEB myPEB;
DWORD64 CrossProcessFlags = -1;
if (GetPEB(hProcess, &myPEB, &CrossProcessFlags) > 0) {
if (myPEB.BeingDebugged == 1) {
fwprintf(stdout, _TEXT("[i] [%d][%s] is being debugged\n"), dwPID, cProcess);
}
if (CrossProcessFlags & 0x4) {
fwprintf(stdout, _TEXT("[i] [%d][%s] is using VEH - Vectored Exception Handler\n"), dwPID, cProcess);
dwVEH++;
}
if (CrossProcessFlags & 0x8) {
fwprintf(stdout, _TEXT("[i] [%d][%s] is using VCH - Vectored Continue Handler\n"), dwPID, cProcess);
dwVCH++;
}
if (CrossProcessFlags & 0x80) {
fwprintf(stdout, _TEXT("[i] [%d][%s] is hot patched\n"), dwPID, cProcess);
}
}
else {
fwprintf(stderr, _TEXT("[!] [%d][UNKNOWN] Failed to get PEB\n"), dwPID);
}
dwCountOK++;
CloseHandle(hProcess);
}
/// <summary>
/// Enumerate all the processes on the system and
/// pass off to the analysis function
/// </summary>
void EnumerateProcesses()
{
DWORD dwPIDArray[4096], dwRet, dwPIDS, intCount;
NumOfProcs = 0;
// Privs
SetPrivilege(GetCurrentProcess(), SE_DEBUG_NAME);
// Be clean
memset(Procs, 0x00, sizeof(Procs));
//
// Enumerate
//
if (EnumProcesses(dwPIDArray, 4096 * sizeof(DWORD), &dwRet) == 0)
{
DWORD dwRet = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError(), 0, strErrMsg, 1023, NULL);
if (dwRet != 0) {
_ftprintf(stderr, TEXT("[!] EnumProcesses() failed - %s"), strErrMsg);
}
else
{
_ftprintf(stderr, TEXT("[!] EnumProcesses() - Error: %d\n"), GetLastError());
}
return;
}
// Total nuber of process IDs
dwPIDS = dwRet / sizeof(DWORD);
//
// Analyze
//
for (intCount = 0; intCount < dwPIDS; intCount++)
{
//fwprintf(stdout, _TEXT("[i] Analyzing PID %d\n"), dwPIDArray[intCount]);
AnalyzeProc(dwPIDArray[intCount]);
}
fwprintf(stdout, _TEXT("[i] Total of %d processes %d use VEH and %d use VCH \n"), dwPIDS,dwVEH,dwVCH);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment