Created
January 1, 2022 08:28
-
-
Save olliencc/7c722386aa94b37fe621da4f894f7cb1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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