1 Star 0 Fork 0

phy0292/cheat-engine

加入 Gitee
与超过 1400万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
ultimap2.c 42.12 KB
一键复制 编辑 原始数据 按行查看 历史
Dark Byte 提交于 2019-07-08 16:50 +08:00 . Commit some changes for kerneldebug
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707
#pragma warning( disable: 4100 4706)
#include <ntifs.h>
#include <ntddk.h>
#include <minwindef.h>
#include <wdm.h>
#include <windef.h>
#include "Ntstrsafe.h"
#include "DBKFunc.h"
#include "ultimap2\apic.h"
#include "ultimap2.h"
PSSUSPENDPROCESS PsSuspendProcess;
PSSUSPENDPROCESS PsResumeProcess;
KDPC RTID_DPC;
BOOL LogKernelMode;
BOOL LogUserMode;
PEPROCESS CurrentTarget;
UINT64 CurrentCR3;
HANDLE Ultimap2Handle;
volatile BOOLEAN UltimapActive = FALSE;
volatile BOOLEAN isSuspended = FALSE;
volatile BOOLEAN flushallbuffers = FALSE; //set to TRUE if all the data should be flushed
KEVENT FlushData;
BOOL SaveToFile;
WCHAR OutputPath[200];
int Ultimap2RangeCount;
PURANGE Ultimap2Ranges = NULL;
PVOID *Ultimap2_DataReady;
#if (NTDDI_VERSION < NTDDI_VISTA)
//implement this function for XP
unsigned int KeQueryMaximumProcessorCount()
{
CCHAR cpunr;
KAFFINITY cpus, original;
ULONG cpucount;
cpucount = 0;
cpus = KeQueryActiveProcessors();
original = cpus;
while (cpus)
{
if (cpus % 2)
cpucount++;
cpus = cpus / 2;
}
return cpucount;
}
#endif
typedef struct
{
PToPA_ENTRY ToPAHeader;
PToPA_ENTRY ToPAHeader2;
PVOID ToPABuffer;
PVOID ToPABuffer2;
PMDL ToPABufferMDL;
PMDL ToPABuffer2MDL;
PRTL_GENERIC_TABLE ToPALookupTable;
PRTL_GENERIC_TABLE ToPALookupTable2;
KEVENT Buffer2ReadyForSwap;
KEVENT InitiateSave;
KEVENT DataReady;
KEVENT DataProcessed;
UINT64 CurrentOutputBase;
UINT64 CurrentSaveOutputBase;
UINT64 CurrentSaveOutputMask;
UINT64 MappedAddress; //set by WaitForData , use with continue
UINT64 Buffer2FlushSize; //used by WaitForData
KDPC OwnDPC;
HANDLE WriterThreadHandle;
//for saveToFile mode
HANDLE FileHandle;
KEVENT FileAccess;
UINT64 TraceFileSize;
volatile BOOL Interrupted;
} ProcessorInfo, *PProcessorInfo;
volatile PProcessorInfo *PInfo;
int Ultimap2CpuCount;
KMUTEX SuspendMutex;
KEVENT SuspendEvent;
HANDLE SuspendThreadHandle;
volatile int suspendCount;
BOOL ultimapEnabled = FALSE;
BOOL singleToPASystem = FALSE;
BOOL NoPMIMode = FALSE;
void suspendThread(PVOID StartContext)
/* Thread responsible for suspending the target process when the buffer is getting full */
{
NTSTATUS wr;
__try
{
while (UltimapActive)
{
wr = KeWaitForSingleObject(&SuspendEvent, Executive, KernelMode, FALSE, NULL);
if (!UltimapActive) return;
DbgPrint("suspendThread event triggered");
KeWaitForSingleObject(&SuspendMutex, Executive, KernelMode, FALSE, NULL);
if (!isSuspended)
{
if (CurrentTarget == 0)
{
if (PsSuspendProcess(CurrentTarget) == 0)
isSuspended = TRUE;
else
DbgPrint("Failed to suspend target\n");
}
}
KeReleaseMutex(&SuspendMutex, FALSE);
}
}
__except (1)
{
DbgPrint("Exception in suspendThread thread\n");
}
}
NTSTATUS ultimap2_continue(int cpunr)
{
NTSTATUS r = STATUS_UNSUCCESSFUL;
if ((cpunr < 0) || (cpunr >= Ultimap2CpuCount))
{
DbgPrint("ultimap2_continue(%d)", cpunr);
return STATUS_UNSUCCESSFUL;
}
if (PInfo)
{
PProcessorInfo pi = PInfo[cpunr];
if (pi->MappedAddress)
{
MmUnmapLockedPages((PVOID)(UINT_PTR)pi->MappedAddress, pi->ToPABuffer2MDL); //unmap this memory
pi->MappedAddress = 0;
r = STATUS_SUCCESS;
}
else
DbgPrint("MappedAddress was 0");
DbgPrint("%d DataProcessed", cpunr);
KeSetEvent(&pi->DataProcessed, 0, FALSE); //let the next swap happen if needed
}
return r;
}
NTSTATUS ultimap2_waitForData(ULONG timeout, PULTIMAP2DATAEVENT data)
{
NTSTATUS r=STATUS_UNSUCCESSFUL;
//Wait for the events in the list
//If an event is triggered find out which one is triggered, then map that block into the usermode space and return the address and block
//That block will be needed to continue
if (UltimapActive)
{
NTSTATUS wr = STATUS_UNSUCCESSFUL;
LARGE_INTEGER wait;
PKWAIT_BLOCK waitblock;
int cpunr;
waitblock = ExAllocatePool(NonPagedPool, Ultimap2CpuCount*sizeof(KWAIT_BLOCK));
wait.QuadPart = -10000LL * timeout;
if (timeout == 0xffffffff) //infinite wait
wr = KeWaitForMultipleObjects(Ultimap2CpuCount, Ultimap2_DataReady, WaitAny, UserRequest, UserMode, TRUE, NULL, waitblock);
else
wr = KeWaitForMultipleObjects(Ultimap2CpuCount, Ultimap2_DataReady, WaitAny, UserRequest, UserMode, TRUE, &wait, waitblock);
ExFreePool(waitblock);
DbgPrint("ultimap2_waitForData wait returned %x", wr);
cpunr = wr - STATUS_WAIT_0;
if ((cpunr < Ultimap2CpuCount) && (cpunr>=0))
{
PProcessorInfo pi = PInfo[cpunr];
if (pi->Buffer2FlushSize)
{
if (pi->ToPABuffer2MDL)
{
__try
{
data->Address = (UINT64)MmMapLockedPagesSpecifyCache(pi->ToPABuffer2MDL, UserMode, MmCached, NULL, FALSE, NormalPagePriority);
DbgPrint("MmMapLockedPagesSpecifyCache returned address %p\n", data->Address);
if (data->Address)
{
data->Size = pi->Buffer2FlushSize;
data->CpuID = cpunr;
pi->MappedAddress = data->Address;
r = STATUS_SUCCESS;
}
}
__except (1)
{
DbgPrint("ultimap2_waitForData: Failure mapping memory into waiter process. Count=%d", (int)MmGetMdlByteCount(pi->ToPABuffer2MDL));
}
}
else
{
DbgPrint("ToPABuffer2MDL is NULL. Not even gonna try");
}
}
else
{
DbgPrint("ultimap2_waitForData flushsize was 0");
}
}
}
DbgPrint("ultimap2_waitForData returned %x\n", r);
return r;
}
void createUltimap2OutputFile(int cpunr)
{
NTSTATUS r;
PProcessorInfo pi = PInfo[cpunr];
UNICODE_STRING usFile;
OBJECT_ATTRIBUTES oaFile;
IO_STATUS_BLOCK iosb;
WCHAR Buffer[200];
#ifdef AMD64
DbgPrint("OutputPath=%S", OutputPath);
swprintf_s(Buffer, 200, L"%sCPU%d.trace", OutputPath, cpunr);
#else
RtlStringCbPrintfW(Buffer, 200, L"%sCPU%d.trace", OutputPath, cpunr);
#endif
DbgPrint("Buffer=%S", Buffer);
RtlInitUnicodeString(&usFile, Buffer);
InitializeObjectAttributes(&oaFile, &usFile, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
DbgPrint("Creating file %S", usFile.Buffer);
pi->FileHandle = 0;
ZwDeleteFile(&oaFile);
r = ZwCreateFile(&pi->FileHandle, SYNCHRONIZE | FILE_READ_DATA | FILE_APPEND_DATA | GENERIC_ALL, &oaFile, &iosb, 0, FILE_ATTRIBUTE_NORMAL, 0, FILE_SUPERSEDE, FILE_SEQUENTIAL_ONLY | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
DbgPrint("%d: ZwCreateFile=%x\n", (int)cpunr, r);
}
void WriteThreadForSpecificCPU(PVOID StartContext)
{
int cpunr = (int)(UINT_PTR)StartContext;
PProcessorInfo pi = PInfo[cpunr];
IO_STATUS_BLOCK iosb;
NTSTATUS r = STATUS_UNSUCCESSFUL;
//DbgPrint("WriteThreadForSpecificCPU %d alive", (int)StartContext);
if (SaveToFile)
{
if (KeWaitForSingleObject(&pi->FileAccess, Executive, KernelMode, FALSE, NULL) == STATUS_SUCCESS)
{
createUltimap2OutputFile(cpunr);
KeSetEvent(&pi->FileAccess, 0, FALSE);
}
else
createUltimap2OutputFile(cpunr);
}
KeSetSystemAffinityThread((KAFFINITY)(1 << cpunr));
while (UltimapActive)
{
NTSTATUS wr = KeWaitForSingleObject(&pi->InitiateSave, Executive, KernelMode, FALSE, NULL);
//DbgPrint("WriteThreadForSpecificCPU %d: wr=%x", (int)StartContext, wr);
if (!UltimapActive)
break;
if (wr == STATUS_SUCCESS)
{
UINT64 Size;
ToPA_LOOKUP tl;
PToPA_LOOKUP result;
//DbgPrint("%d: writing buffer", (int)StartContext);
//figure out the size
tl.PhysicalAddress = pi->CurrentSaveOutputBase;
tl.index = 0;
result = RtlLookupElementGenericTable(pi->ToPALookupTable2, &tl);
if (result)
{
//write...
//DbgPrint("%d: result->index=%d CurrentSaveOutputMask=%p", (int)StartContext, result->index, pi->CurrentSaveOutputMask);
if (singleToPASystem)
Size = pi->CurrentSaveOutputMask >> 32;
else
Size = ((result->index * 511) + ((pi->CurrentSaveOutputMask & 0xffffffff) >> 7)) * 4096 + (pi->CurrentSaveOutputMask >> 32);
if (Size > 0)
{
if (SaveToFile)
{
wr = KeWaitForSingleObject(&pi->FileAccess, Executive, KernelMode, FALSE, NULL);
if (wr==STATUS_SUCCESS)
{
if (pi->FileHandle==0) //a usermode flush has happened
createUltimap2OutputFile(cpunr);
r = ZwWriteFile(pi->FileHandle, NULL, NULL, NULL, &iosb, pi->ToPABuffer2, (ULONG)Size, NULL, NULL);
pi->TraceFileSize += Size;
//DbgPrint("%d: ZwCreateFile(%p, %d)=%x\n", (int)StartContext, pi->ToPABuffer2, (ULONG)Size, r);
KeSetEvent(&pi->FileAccess, 0, FALSE);
}
}
else
{
//map ToPABuffer2 into the CE process
//wake up a worker thread
pi->Buffer2FlushSize = Size;
DbgPrint("%d: WorkerThread(%p, %d)=%x\n", (int)(UINT_PTR)StartContext, pi->ToPABuffer2, (ULONG)Size, r);
KeSetEvent(&pi->DataReady, 0, TRUE); //a ce thread waiting in ultimap2_waitForData should now wake and process the data
//and wait for it to finish
r=KeWaitForSingleObject(&pi->DataProcessed, Executive, KernelMode, FALSE, NULL);
DbgPrint("KeWaitForSingleObject(DataProcessed)=%x", r);
}
//DbgPrint("%d: Writing %x bytes\n", (int)StartContext, Size);
}
}
else
DbgPrint("Unexpected physical address while writing results for cpu %d (%p)", (int)(UINT_PTR)StartContext, pi->CurrentSaveOutputBase);
KeSetEvent(&pi->Buffer2ReadyForSwap, 0, FALSE);
}
}
KeSetSystemAffinityThread(KeQueryActiveProcessors());
if (pi->FileHandle)
ZwClose(pi->FileHandle);
KeSetEvent(&pi->Buffer2ReadyForSwap, 0, FALSE);
}
void ultimap2_LockFile(int cpunr)
{
if ((cpunr < 0) || (cpunr >= Ultimap2CpuCount))
return;
if (PInfo)
{
NTSTATUS wr;
PProcessorInfo pi = PInfo[cpunr];
//DbgPrint("AcquireUltimap2File()");
wr = KeWaitForSingleObject(&pi->FileAccess, Executive, KernelMode, FALSE, NULL);
if (wr == STATUS_SUCCESS)
{
//DbgPrint("Acquired");
if (pi->FileHandle)
{
ZwClose(pi->FileHandle);
pi->FileHandle = 0;
}
}
}
}
void ultimap2_ReleaseFile(int cpunr)
{
if ((cpunr < 0) || (cpunr >= Ultimap2CpuCount))
return;
if (PInfo)
{
PProcessorInfo pi = PInfo[cpunr];
KeSetEvent(&pi->FileAccess, 0, FALSE);
//DbgPrint("Released");
}
}
UINT64 ultimap2_GetTraceFileSize()
//Gets an aproximation of the filesize. Don't take this too exact
{
UINT64 size = 0;
if (PInfo)
{
int i;
for (i = 0; i < Ultimap2CpuCount; i++)
size += PInfo[i]->TraceFileSize;
}
return size;
}
void ultimap2_ResetTraceFileSize()
{
if (PInfo)
{
int i;
for (i = 0; i < Ultimap2CpuCount; i++)
PInfo[i]->TraceFileSize = 0;
}
}
void SwitchToPABuffer(struct _KDPC *Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
/*
DPC routine that switches the Buffer pointer and marks buffer2 that it's ready for data saving
Only called when buffer2 is ready for flushing
*/
{
//write the contents of the current cpu buffer
PProcessorInfo pi = PInfo[KeGetCurrentProcessorNumber()];
//DbgPrint("SwitchToPABuffer for cpu %d\n", KeGetCurrentProcessorNumber());
if (pi)
{
UINT64 CTL = __readmsr(IA32_RTIT_CTL);
UINT64 Status = __readmsr(IA32_RTIT_STATUS);
PVOID temp;
if ((Status >> 5) & 1) //Stopped
DbgPrint("%d Not all data recorded\n", KeGetCurrentProcessorNumber());
if ((Status >> 4) & 1)
DbgPrint("ALL LOST");
//only if the buffer is bigger than 2 pages. That you can check in IA32_RTIT_OUTPUT_MASK_PTRS and IA32_RTIT_OUTPUT_BASE
//if (KeGetCurrentProcessorNumber() == 0)
// DbgPrint("%d: pi->CurrentOutputBase=%p __readmsr(IA32_RTIT_OUTPUT_BASE)=%p __readmsr(IA32_RTIT_OUTPUT_MASK_PTRS)=%p", KeGetCurrentProcessorNumber(), pi->CurrentOutputBase, __readmsr(IA32_RTIT_OUTPUT_BASE), __readmsr(IA32_RTIT_OUTPUT_MASK_PTRS));
if (pi->Interrupted == FALSE)
{
//return; //debug test. remove me when released
if (!singleToPASystem)
{
if ((!flushallbuffers) && (((__readmsr(IA32_RTIT_OUTPUT_MASK_PTRS) & 0xffffffff) >> 7) < 2))
return; //don't flush yet
}
else
{
INT64 offset = __readmsr(IA32_RTIT_OUTPUT_MASK_PTRS);
/*if (KeGetCurrentProcessorNumber() == 0)
{
DbgPrint("pi->CurrentOutputBase=%p", pi->CurrentOutputBase);
DbgPrint("offset=%p", offset);
}*/
offset = offset >> 32;
//if (KeGetCurrentProcessorNumber() == 0)
// DbgPrint("offset=%p", offset);
if ((!flushallbuffers) && (((pi->CurrentOutputBase == 0) || (offset < 8192))))
return; //don't flush yet
}
}
else
{
DbgPrint("%d:Flushing because of interrupt", KeGetCurrentProcessorNumber());
}
DbgPrint("%d: Flush this data (%p)", KeGetCurrentProcessorNumber(), __readmsr(IA32_RTIT_OUTPUT_MASK_PTRS));
//DbgPrint("%d: pi->CurrentOutputBase=%p __readmsr(IA32_RTIT_OUTPUT_BASE)=%p __readmsr(IA32_RTIT_OUTPUT_MASK_PTRS)=%p", KeGetCurrentProcessorNumber(), pi->CurrentOutputBase, __readmsr(IA32_RTIT_OUTPUT_BASE), __readmsr(IA32_RTIT_OUTPUT_MASK_PTRS));
__writemsr(IA32_RTIT_CTL, 0); //disable packet generation
__writemsr(IA32_RTIT_STATUS, 0);
//DbgPrint("%d: pi->CurrentOutputBase=%p __readmsr(IA32_RTIT_OUTPUT_BASE)=%p __readmsr(IA32_RTIT_OUTPUT_MASK_PTRS)=%p", KeGetCurrentProcessorNumber(), pi->CurrentOutputBase, __readmsr(IA32_RTIT_OUTPUT_BASE), __readmsr(IA32_RTIT_OUTPUT_MASK_PTRS));
//switch the pointer to the secondary buffers
KeClearEvent(&pi->Buffer2ReadyForSwap);
//swap the buffer
temp = pi->ToPABuffer;
pi->ToPABuffer = pi->ToPABuffer2;
pi->ToPABuffer2 = temp;
//swap the MDL that describes it
temp = pi->ToPABufferMDL;
pi->ToPABufferMDL = pi->ToPABuffer2MDL;
pi->ToPABuffer2MDL = temp;
//swap the header
temp = pi->ToPAHeader;
pi->ToPAHeader = pi->ToPAHeader2;
pi->ToPAHeader2 = temp;
//swap the lookup table
temp = pi->ToPALookupTable;
pi->ToPALookupTable = pi->ToPALookupTable2;
pi->ToPALookupTable2 = temp;
//lookup which entry it's pointing at
pi->CurrentSaveOutputBase = __readmsr(IA32_RTIT_OUTPUT_BASE);
pi->CurrentSaveOutputMask = __readmsr(IA32_RTIT_OUTPUT_MASK_PTRS);
KeSetEvent(&pi->InitiateSave,0,FALSE);
pi->Interrupted = FALSE;
//reactivate packet generation
pi->CurrentOutputBase = MmGetPhysicalAddress(pi->ToPAHeader).QuadPart;
__writemsr(IA32_RTIT_OUTPUT_BASE, pi->CurrentOutputBase);
__writemsr(IA32_RTIT_OUTPUT_MASK_PTRS, 0);
__writemsr(IA32_RTIT_CTL, CTL);
}
}
void WaitForWriteToFinishAndSwapWriteBuffers(BOOL interruptedOnly)
{
int i;
for (i = 0; i < Ultimap2CpuCount; i++)
{
PProcessorInfo pi = PInfo[i];
if ((pi->ToPABuffer2) && ((pi->Interrupted) || (!interruptedOnly)))
{
KeWaitForSingleObject(&pi->Buffer2ReadyForSwap, Executive, KernelMode, FALSE, NULL);
if (!UltimapActive) return;
KeInsertQueueDpc(&pi->OwnDPC, NULL, NULL);
}
}
KeFlushQueuedDpcs();
}
void bufferWriterThread(PVOID StartContext)
{
//passive mode
//wait for event
LARGE_INTEGER Timeout;
NTSTATUS wr;
DbgPrint("bufferWriterThread active");
while (UltimapActive)
{
if (NoPMIMode)
Timeout.QuadPart = -1000LL; //- 10000LL=1 millisecond //-100000000LL = 10 seconds -1000000LL= 0.1 second
else
Timeout.QuadPart = -10000LL; //- 10000LL=1 millisecond //-100000000LL = 10 seconds -1000000LL= 0.1 second
//DbgPrint("%d : Wait for FlushData", cpunr());
wr = KeWaitForSingleObject(&FlushData, Executive, KernelMode, FALSE, &Timeout);
//DbgPrint("%d : After wait for FlushData", cpunr());
//wr = KeWaitForSingleObject(&FlushData, Executive, KernelMode, FALSE, NULL);
//DbgPrint("bufferWriterThread: Alive (wr==%x)", wr);
if (!UltimapActive)
{
DbgPrint("bufferWriterThread: Terminating");
return;
}
//if (wr != STATUS_SUCCESS) continue; //DEBUG code so PMI's get triggered
if ((wr == STATUS_SUCCESS) || (wr == STATUS_TIMEOUT))
{
if ((wr == STATUS_SUCCESS) && (!isSuspended))
{
//woken up by a dpc
DbgPrint("FlushData event set and not suspended. Suspending target process\n");
KeWaitForSingleObject(&SuspendMutex, Executive, KernelMode, FALSE, NULL);
if (!isSuspended)
{
DbgPrint("Still going to suspend target process");
if (PsSuspendProcess(CurrentTarget)==0)
isSuspended = TRUE;
}
KeReleaseMutex(&SuspendMutex, FALSE);
DbgPrint("After the target has been suspended (isSuspended=%d)\n", isSuspended);
}
if (wr == STATUS_SUCCESS) //the filled cpu's must take preference
{
unsigned int i;
BOOL found = TRUE;
//DbgPrint("bufferWriterThread: Suspended");
//first flush the CPU's that complained their buffers are full
DbgPrint("Flushing full CPU\'s");
while (found)
{
WaitForWriteToFinishAndSwapWriteBuffers(TRUE);
if (!UltimapActive) return;
//check if no interrupt has been triggered while this was busy ('could' happen as useless info like core ratio is still recorded)
found = FALSE;
for (i = 0; i < KeQueryMaximumProcessorCount(); i++)
{
if (PInfo[i]->Interrupted)
{
DbgPrint("PInfo[%d]->Interrupted\n", PInfo[i]->Interrupted);
found = TRUE;
break;
}
}
}
}
//wait till the previous buffers are done writing
//DbgPrint("%d: Normal flush", cpunr());
WaitForWriteToFinishAndSwapWriteBuffers(FALSE);
//DbgPrint("%d : after flush", cpunr());
if (isSuspended)
{
KeWaitForSingleObject(&SuspendMutex, Executive, KernelMode, FALSE, NULL);
if (isSuspended)
{
DbgPrint("Resuming target process");
PsResumeProcess(CurrentTarget);
isSuspended = FALSE;
}
KeReleaseMutex(&SuspendMutex, FALSE);
}
//an interrupt could have fired while WaitForWriteToFinishAndSwapWriteBuffers was busy, pausing the process. If that happened, then the next KeWaitForSingleObject will exit instantly due to it being signaled
}
else
DbgPrint("Unexpected wait result");
}
}
NTSTATUS ultimap2_flushBuffers()
{
if (!UltimapActive)
return STATUS_UNSUCCESSFUL;
DbgPrint("ultimap2_flushBuffers");
KeWaitForSingleObject(&SuspendMutex, Executive, KernelMode, FALSE, NULL);
if (CurrentTarget)
{
if (!isSuspended)
{
PsSuspendProcess(CurrentTarget);
isSuspended = TRUE;
}
}
KeReleaseMutex(&SuspendMutex, FALSE);
flushallbuffers = TRUE;
DbgPrint("wait1");
WaitForWriteToFinishAndSwapWriteBuffers(FALSE); //write the last saved buffer
DbgPrint("wait2");
WaitForWriteToFinishAndSwapWriteBuffers(FALSE); //write the current buffer
flushallbuffers = FALSE;
DbgPrint("after wait");
KeWaitForSingleObject(&SuspendMutex, Executive, KernelMode, FALSE, NULL);
if (CurrentTarget)
{
if (isSuspended)
{
PsResumeProcess(CurrentTarget);
isSuspended = FALSE;
}
}
KeReleaseMutex(&SuspendMutex, FALSE);
DbgPrint("ultimap2_flushBuffers exit");
return STATUS_SUCCESS;
}
void RTIT_DPC_Handler(__in struct _KDPC *Dpc, __in_opt PVOID DeferredContext, __in_opt PVOID SystemArgument1,__in_opt PVOID SystemArgument2)
{
//Signal the bufferWriterThread
KeSetEvent(&SuspendEvent, 0, FALSE);
KeSetEvent(&FlushData, 0, FALSE);
}
void PMI(__in struct _KINTERRUPT *Interrupt, __in PVOID ServiceContext)
{
//check if caused by me, if so defer to dpc
DbgPrint("PMI");
__try
{
if ((__readmsr(IA32_PERF_GLOBAL_STATUS) >> 55) & 1)
{
UINT64 Status = __readmsr(IA32_RTIT_STATUS);
DbgPrint("PMI: caused by me");
__writemsr(IA32_PERF_GLOBAL_OVF_CTRL, (UINT64)1 << 55); //clear ToPA full status
if ((__readmsr(IA32_PERF_GLOBAL_STATUS) >> 55) & 1)
{
DbgPrint("PMI: Failed to clear the status\n");
}
DbgPrint("PMI: IA32_RTIT_OUTPUT_MASK_PTRS=%p\n", __readmsr(IA32_RTIT_OUTPUT_MASK_PTRS));
DbgPrint("PMI: IA32_RTIT_STATUS=%p\n", Status);
if ((Status >> 5) & 1) //Stopped
DbgPrint("PMI %d: Not all data recorded (AT THE PMI!)\n", KeGetCurrentProcessorNumber());
DbgPrint("PMI: IA32_RTIT_OUTPUT_MASK_PTRS %p\n", __readmsr(IA32_RTIT_OUTPUT_MASK_PTRS));
PInfo[KeGetCurrentProcessorNumber()]->Interrupted = TRUE;
KeInsertQueueDpc(&RTID_DPC, NULL, NULL);
//clear apic state
apic_clearPerfmon();
}
else
{
DbgPrint("Unexpected PMI");
}
}
__except (0)
{
DbgPrint("PMI exception");
}
}
void *pperfmon_hook2 = (void *)PMI;
void ultimap2_disable_dpc(struct _KDPC *Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
{
DbgPrint("ultimap2_disable_dpc for cpu %d\n", KeGetCurrentProcessorNumber());
__try
{
if (DeferredContext) //only pause
{
RTIT_CTL ctl;
DbgPrint("temp disable\n");
ctl.Value = __readmsr(IA32_RTIT_CTL);
ctl.Bits.TraceEn = 0;
__writemsr(IA32_RTIT_CTL, ctl.Value);
}
else
{
DbgPrint("%d: disable all\n", KeGetCurrentProcessorNumber());
__writemsr(IA32_RTIT_CTL, 0);
__writemsr(IA32_RTIT_STATUS, 0);
__writemsr(IA32_RTIT_CR3_MATCH, 0);
__writemsr(IA32_RTIT_OUTPUT_BASE, 0);
__writemsr(IA32_RTIT_OUTPUT_MASK_PTRS, 0);
}
}
__except (1)
{
DbgPrint("ultimap2_disable_dpc exception");
}
}
void ultimap2_setup_dpc(struct _KDPC *Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
{
RTIT_CTL ctl;
RTIT_STATUS s;
int i = -1;
__try
{
ctl.Value = __readmsr(IA32_RTIT_CTL);
}
__except (1)
{
DbgPrint("ultimap2_setup_dpc: IA32_RTIT_CTL in unreadable");
return;
}
ctl.Bits.TraceEn = 1;
if (LogKernelMode)
ctl.Bits.OS = 1;
else
ctl.Bits.OS = 0;
if (LogUserMode)
ctl.Bits.USER = 1;
else
ctl.Bits.USER = 0;
if (CurrentCR3)
ctl.Bits.CR3Filter = 1;
else
ctl.Bits.CR3Filter = 0;
ctl.Bits.ToPA = 1;
ctl.Bits.TSCEn = 0;
ctl.Bits.DisRETC = 0;
ctl.Bits.BranchEn = 1;
if (PInfo == NULL)
return;
if (PInfo[KeGetCurrentProcessorNumber()]->ToPABuffer == NULL)
{
DbgPrint("ToPA for cpu %d not setup\n", KeGetCurrentProcessorNumber());
return;
}
__try
{
int cpunr = KeGetCurrentProcessorNumber();
i = 0;
PInfo[cpunr]->CurrentOutputBase = MmGetPhysicalAddress(PInfo[cpunr]->ToPAHeader).QuadPart;
__writemsr(IA32_RTIT_OUTPUT_BASE, PInfo[cpunr]->CurrentOutputBase);
i = 1;
__writemsr(IA32_RTIT_OUTPUT_MASK_PTRS, 0);
i = 2;
__try
{
__writemsr(IA32_RTIT_CR3_MATCH, CurrentCR3);
}
__except (1)
{
CurrentCR3 = CurrentCR3 & 0xfffffffffffff000ULL;
DbgPrint("Failed to set the actual CR3. Using a sanitized CR3: %llx\n", CurrentCR3);
}
i = 3;
//ranges
if (Ultimap2Ranges && Ultimap2RangeCount)
{
for (i = 0; i < Ultimap2RangeCount; i++)
{
ULONG msr_start = IA32_RTIT_ADDR0_A + (2 * i);
ULONG msr_stop = IA32_RTIT_ADDR0_B + (2 * i);
UINT64 bit = 32 + (i * 4);
DbgPrint("Range %d: (%p -> %p)", i, (PVOID)(UINT_PTR)(Ultimap2Ranges[i].StartAddress), (PVOID)(UINT_PTR)(Ultimap2Ranges[i].EndAddress));
DbgPrint("Writing range %d to msr %x and %x", i, msr_start, msr_stop);
__writemsr(msr_start, Ultimap2Ranges[i].StartAddress);
__writemsr(msr_stop, Ultimap2Ranges[i].EndAddress);
DbgPrint("bit=%d", bit);
DbgPrint("Value before=%llx", ctl.Value);
if (Ultimap2Ranges[i].IsStopAddress)
ctl.Value |= (UINT64)2ULL << bit; //TraceStop This stops all tracing on this cpu. Doesn't get reactivated
else
ctl.Value |= (UINT64)1ULL << bit; //FilterEn //not supported in the latest windows build
DbgPrint("Value after=%llx", ctl.Value);
}
}
i = 4;
__writemsr(IA32_RTIT_STATUS, 0);
i = 5;
//if (KeGetCurrentProcessorNumber() == 0)
__writemsr(IA32_RTIT_CTL, ctl.Value);
i = 6;
s.Value=__readmsr(IA32_RTIT_STATUS);
if (s.Bits.Error)
DbgPrint("Setup for cpu %d failed", KeGetCurrentProcessorNumber());
else
DbgPrint("Setup for cpu %d succesful", KeGetCurrentProcessorNumber());
}
__except (1)
{
DbgPrint("Error in ultimap2_setup_dpc. i=%d",i);
DbgPrint("ctl.Value=%p\n", ctl.Value);
DbgPrint("CR3=%p\n", CurrentCR3);
//DbgPrint("OutputBase=%p", __readmsr(IA32_RTIT_OUTPUT_BASE));
}
}
int getToPAHeaderCount(ULONG _BufferSize)
{
return 1 + (_BufferSize / 4096) / 511;
}
int getToPAHeaderSize(ULONG _BufferSize)
{
//511 entries per ToPA header (4096*511=2093056 bytes per ToPA header)
//BufferSize / 2093056 = Number of ToPA headers needed
return getToPAHeaderCount(_BufferSize) * 4096;
}
RTL_GENERIC_COMPARE_RESULTS NTAPI ToPACompare(__in struct _RTL_GENERIC_TABLE *Table, __in PToPA_LOOKUP FirstStruct, __in PToPA_LOOKUP SecondStruct)
{
//DbgPrint("Comparing %p with %p", FirstStruct->PhysicalAddress, FirstStruct->PhysicalAddress);
if (FirstStruct->PhysicalAddress == SecondStruct->PhysicalAddress)
return GenericEqual;
else
{
if (SecondStruct->PhysicalAddress < FirstStruct->PhysicalAddress)
return GenericLessThan;
else
return GenericGreaterThan;
}
}
PVOID NTAPI ToPAAlloc(__in struct _RTL_GENERIC_TABLE *Table, __in CLONG ByteSize)
{
return ExAllocatePool(NonPagedPool, ByteSize);
}
VOID NTAPI ToPADealloc(__in struct _RTL_GENERIC_TABLE *Table, __in __drv_freesMem(Mem) __post_invalid PVOID Buffer)
{
ExFreePool(Buffer);
}
void* setupToPA(PToPA_ENTRY *Header, PVOID *OutputBuffer, PMDL *BufferMDL, PRTL_GENERIC_TABLE *gt, ULONG _BufferSize, int NoPMI)
{
ToPA_LOOKUP tl;
PToPA_ENTRY r;
UINT_PTR Output, Stop;
ULONG ToPAIndex = 0;
int PABlockSize = 0;
int BlockSize;
PRTL_GENERIC_TABLE x;
int i;
if (singleToPASystem)
{
PHYSICAL_ADDRESS la,ha, boundary;
ULONG newsize;
BlockSize = _BufferSize; //yup, only 1 single entry
//get the closest possible
if (BlockSize > 64 * 1024 * 1024)
{
PABlockSize = 15;
BlockSize = 128 * 1024 * 1024;
}
else
if (BlockSize > 32 * 1024 * 1024)
{
PABlockSize = 14;
BlockSize = 64 * 1024 * 1024;
}
else
if (BlockSize > 16 * 1024 * 1024)
{
PABlockSize = 13;
BlockSize = 32 * 1024 * 1024;
}
else
if (BlockSize > 8 * 1024 * 1024)
{
PABlockSize = 12;
BlockSize = 16 * 1024 * 1024;
}
else
if (BlockSize > 4 * 1024 * 1024)
{
PABlockSize = 11;
BlockSize = 8 * 1024 * 1024;
}
else
if (BlockSize > 2 * 1024 * 1024)
{
PABlockSize = 10;
BlockSize = 4 * 1024 * 1024;
}
else
if (BlockSize > 1 * 1024 * 1024)
{
PABlockSize = 9;
BlockSize = 2 * 1024 * 1024;
}
else
if (BlockSize > 512 * 1024)
{
PABlockSize = 8;
BlockSize = 1 * 1024 * 1024;
}
else
if (BlockSize > 256 * 1024)
{
PABlockSize = 7;
BlockSize = 512 * 1024;
}
else
if (BlockSize > 128 * 1024)
{
PABlockSize = 6;
BlockSize = 256 * 1024;
}
else
if (BlockSize > 64 * 1024)
{
PABlockSize = 5;
BlockSize = 128 * 1024;
}
else
if (BlockSize > 32 * 1024)
{
PABlockSize = 4;
BlockSize = 64 * 1024;
}
else
if (BlockSize > 16*1024)
{
PABlockSize = 3;
BlockSize = 32 * 1024;
}
else
if (BlockSize > 8 * 1024)
{
PABlockSize = 2;
BlockSize = 16 * 1024;
}
else
if (BlockSize > 4 * 1024)
{
PABlockSize = 1;
BlockSize = 8 * 1024;
}
else
{
PABlockSize = 0;
BlockSize = 4096;
}
//adjust the buffersize so it is dividable by the blocksize
newsize = BlockSize;
DbgPrint("BufferSize=%x\n", _BufferSize);
DbgPrint("BlockSize=%x (PABlockSize=%d)\n", BlockSize, PABlockSize);
DbgPrint("newsize=%x\n", newsize);
la.QuadPart = 0;
ha.QuadPart = 0xFFFFFFFFFFFFFFFFULL;
boundary.QuadPart = BlockSize;
*OutputBuffer=MmAllocateContiguousMemorySpecifyCache(newsize, la, ha, boundary, MmCached);
//*OutputBuffer=MmAllocateContiguousMemory(newsize, ha);
DbgPrint("Allocated OutputBuffer at %p", MmGetPhysicalAddress(*OutputBuffer).QuadPart);
_BufferSize = newsize;
if (*OutputBuffer == NULL)
{
DbgPrint("setupToPA (Single ToPA System): Failure allocating output buffer");
return NULL;
}
r = ExAllocatePool(NonPagedPool, 4096);
if (r == NULL)
{
MmFreeContiguousMemory(*OutputBuffer);
*OutputBuffer = NULL;
DbgPrint("setupToPA (Single ToPA System): Failure allocating header for buffer");
return NULL;
}
}
else
{
//Not a single ToPA system
BlockSize = 4096;
*OutputBuffer = ExAllocatePool(NonPagedPool, _BufferSize);
if (*OutputBuffer == NULL)
{
DbgPrint("setupToPA: Failure allocating output buffer");
return NULL;
}
r = ExAllocatePool(NonPagedPool, getToPAHeaderSize(_BufferSize));
if (r == NULL)
{
ExFreePool(*OutputBuffer);
*OutputBuffer = NULL;
DbgPrint("setupToPA: Failure allocating header for buffer");
return NULL;
}
}
*Header = r;
*gt=ExAllocatePool(NonPagedPool, sizeof(RTL_GENERIC_TABLE));
if (*gt == NULL)
{
DbgPrint("Failure allocating table");
if (singleToPASystem)
MmFreeContiguousMemory(*OutputBuffer);
else
ExFreePool(*OutputBuffer);
*OutputBuffer = NULL;
ExFreePool(*Header);
*Header = NULL;
return NULL;
}
x = *gt;
RtlInitializeGenericTable(x, ToPACompare, ToPAAlloc, ToPADealloc, NULL);
tl.index = 0;
tl.PhysicalAddress = MmGetPhysicalAddress(&r[0]).QuadPart;
RtlInsertElementGenericTable(x, &tl, sizeof(tl), NULL);
Output = (UINT_PTR)*OutputBuffer;
Stop = Output+_BufferSize;
*BufferMDL = IoAllocateMdl(*OutputBuffer, _BufferSize, FALSE, FALSE, NULL);
MmBuildMdlForNonPagedPool(*BufferMDL);
if (singleToPASystem)
{
r[0].Value = (UINT64)MmGetPhysicalAddress((PVOID)Output).QuadPart;
r[0].Bits.Size = PABlockSize;
if (NoPMI)
r[0].Bits.INT = 0;
else
r[0].Bits.INT = 1;
r[0].Bits.STOP = 1;
r[1].Value = MmGetPhysicalAddress(&r[0]).QuadPart;
r[1].Bits.END = 1;
}
else
{
while (Output < Stop)
{
//fill in the topa entries pointing to eachother
if ((ToPAIndex + 1) % 512 == 0)
{
//point it to the next ToPA table
r[ToPAIndex].Value = MmGetPhysicalAddress(&r[ToPAIndex + 1]).QuadPart;
r[ToPAIndex].Bits.END = 1;
tl.index = tl.index++;
tl.PhysicalAddress = MmGetPhysicalAddress(&r[ToPAIndex + 1]).QuadPart;
RtlInsertElementGenericTable(x, &tl, sizeof(tl), NULL);
}
else
{
r[ToPAIndex].Value = (UINT64)MmGetPhysicalAddress((PVOID)Output).QuadPart;
r[ToPAIndex].Bits.Size = 0;
Output += 4096;
}
ToPAIndex++;
}
ToPAIndex--;
r[ToPAIndex].Bits.STOP = 1;
i = (ToPAIndex * 90) / 100; //90%
if ((i == (int)ToPAIndex) && (i > 0)) //don't interrupt on the very last entry (if possible)
i--;
if ((i > 0) && ((i + 1) % 512 == 0))
i--;
DbgPrint("Interrupt at index %d", i);
if (NoPMI)
r[i].Bits.INT = 0;
else
r[i].Bits.INT = 1; //Interrupt after filling this entry
//and every 2nd page after this. (in case of a rare situation where resume is called right after suspend)
if (ToPAIndex > 0)
{
while (i < (int)(ToPAIndex - 1))
{
if (((i + 1) % 512) && (NoPMI==0)) //anything but 0
r[i].Bits.INT = 1;
i += 2;
}
}
}
return (void *)r;
}
NTSTATUS ultimap2_pause()
{
if (ultimapEnabled)
{
forEachCpu(ultimap2_disable_dpc, (PVOID)1, NULL, NULL, NULL);
if (UltimapActive)
{
flushallbuffers = TRUE;
WaitForWriteToFinishAndSwapWriteBuffers(FALSE); //write the last saved buffer
WaitForWriteToFinishAndSwapWriteBuffers(FALSE); //write the current buffer
flushallbuffers = FALSE;
}
}
return STATUS_SUCCESS;
}
NTSTATUS ultimap2_resume()
{
if ((ultimapEnabled) && (PInfo))
forEachCpu(ultimap2_setup_dpc, NULL, NULL, NULL, NULL);
return STATUS_SUCCESS;
}
void *clear = NULL;
BOOL RegisteredProfilerInterruptHandler;
void SetupUltimap2(UINT32 PID, UINT32 BufferSize, WCHAR *Path, int rangeCount, PURANGE Ranges, int NoPMI, int UserMode, int KernelMode)
{
//for each cpu setup tracing
//add the PMI interupt
int i;
NTSTATUS r= STATUS_UNSUCCESSFUL;
int cpuid_r[4];
if (Path)
DbgPrint("SetupUltimap2(%x, %x, %S, %d, %p,%d,%d,%d\n", PID, BufferSize, Path, rangeCount, Ranges, NoPMI, UserMode, KernelMode);
else
DbgPrint("SetupUltimap2(%x, %x, %d, %p,%d,%d,%d\n", PID, BufferSize, rangeCount, Ranges, NoPMI, UserMode, KernelMode);
__cpuidex(cpuid_r, 0x14, 0);
if ((cpuid_r[2] & 2) == 0)
{
DbgPrint("Single ToPA System");
singleToPASystem = TRUE;
}
NoPMIMode = NoPMI;
LogKernelMode = KernelMode;
LogUserMode = UserMode;
DbgPrint("Path[0]=%d\n", Path[0]);
SaveToFile = (Path[0] != 0);
if (SaveToFile)
{
wcsncpy(OutputPath, Path, 199);
OutputPath[199] = 0;
DbgPrint("Ultimap2: SaveToFile==TRUE: OutputPath=%S",OutputPath);
}
else
{
DbgPrint("Ultimap2: Runtime processing");
}
if (rangeCount)
{
if (Ultimap2Ranges)
{
ExFreePool(Ultimap2Ranges);
Ultimap2Ranges = NULL;
}
Ultimap2Ranges = ExAllocatePool(NonPagedPool, rangeCount*sizeof(URANGE));
for (i = 0; i < rangeCount; i++)
Ultimap2Ranges[i] = Ranges[i];
Ultimap2RangeCount = rangeCount;
}
else
Ultimap2RangeCount = 0;
//get the EProcess and CR3 for this PID
if (PID)
{
if (PsLookupProcessByProcessId((PVOID)PID, &CurrentTarget) == STATUS_SUCCESS)
{
//todo add specific windows version checks and hardcode offsets/ or use scans
if (getCR3() & 0xfff)
{
DbgPrint("Split kernel/usermode pages\n");
//uses supervisor/usermode pagemaps
CurrentCR3 = *(UINT64 *)((UINT_PTR)CurrentTarget + 0x278);
if ((CurrentCR3 & 0xfffffffffffff000ULL) == 0)
{
DbgPrint("No usermode CR3\n");
CurrentCR3 = *(UINT64 *)((UINT_PTR)CurrentTarget + 0x28);
}
DbgPrint("CurrentCR3=%llx\n", CurrentCR3);
}
else
{
KAPC_STATE apc_state;
RtlZeroMemory(&apc_state, sizeof(apc_state));
__try
{
KeStackAttachProcess((PVOID)CurrentTarget, &apc_state);
CurrentCR3 = getCR3();
KeUnstackDetachProcess(&apc_state);
}
__except (1)
{
DbgPrint("Failure getting CR3 for this process");
return;
}
}
}
else
{
DbgPrint("Failure getting the EProcess for pid %d", PID);
return;
}
}
else
{
CurrentTarget = 0;
CurrentCR3 = 0;
}
DbgPrint("CurrentCR3=%llx\n", CurrentCR3);
if ((PsSuspendProcess == NULL) || (PsResumeProcess == NULL))
{
DbgPrint("No Suspend/Resume support");
return;
}
KeInitializeDpc(&RTID_DPC, RTIT_DPC_Handler, NULL);
KeInitializeEvent(&FlushData, SynchronizationEvent, FALSE);
KeInitializeEvent(&SuspendEvent, SynchronizationEvent, FALSE);
KeInitializeMutex(&SuspendMutex, 0);
Ultimap2CpuCount = KeQueryMaximumProcessorCount();
PInfo = ExAllocatePool(NonPagedPool, Ultimap2CpuCount*sizeof(PProcessorInfo));
Ultimap2_DataReady = ExAllocatePool(NonPagedPool, Ultimap2CpuCount*sizeof(PVOID));
if (PInfo == NULL)
{
DbgPrint("PInfo alloc failed");
return;
}
if (Ultimap2_DataReady == NULL)
{
DbgPrint("Ultimap2_DataReady alloc failed");
return;
}
for (i = 0; i < Ultimap2CpuCount; i++)
{
PInfo[i] = ExAllocatePool(NonPagedPool, sizeof(ProcessorInfo));
RtlZeroMemory(PInfo[i], sizeof(ProcessorInfo));
KeInitializeEvent(&PInfo[i]->InitiateSave, SynchronizationEvent, FALSE);
KeInitializeEvent(&PInfo[i]->Buffer2ReadyForSwap, NotificationEvent, TRUE);
setupToPA(&PInfo[i]->ToPAHeader, &PInfo[i]->ToPABuffer, &PInfo[i]->ToPABufferMDL, &PInfo[i]->ToPALookupTable, BufferSize, NoPMI);
setupToPA(&PInfo[i]->ToPAHeader2, &PInfo[i]->ToPABuffer2, &PInfo[i]->ToPABuffer2MDL, &PInfo[i]->ToPALookupTable2, BufferSize, NoPMI);
DbgPrint("cpu %d:", i);
DbgPrint("ToPAHeader=%p ToPABuffer=%p Size=%x", PInfo[i]->ToPAHeader, PInfo[i]->ToPABuffer, BufferSize);
DbgPrint("ToPAHeader2=%p ToPABuffer2=%p Size=%x", PInfo[i]->ToPAHeader2, PInfo[i]->ToPABuffer2, BufferSize);
KeInitializeEvent(&PInfo[i]->DataReady, SynchronizationEvent, FALSE);
KeInitializeEvent(&PInfo[i]->DataProcessed, SynchronizationEvent, FALSE);
KeInitializeEvent(&PInfo[i]->FileAccess, SynchronizationEvent, TRUE);
Ultimap2_DataReady[i] = &PInfo[i]->DataReady;
KeInitializeDpc(&PInfo[i]->OwnDPC, SwitchToPABuffer, NULL);
KeSetTargetProcessorDpc(&PInfo[i]->OwnDPC, (CCHAR)i);
}
UltimapActive = TRUE;
ultimapEnabled = TRUE;
PsCreateSystemThread(&SuspendThreadHandle, 0, NULL, 0, NULL, suspendThread, NULL);
PsCreateSystemThread(&Ultimap2Handle, 0, NULL, 0, NULL, bufferWriterThread, NULL);
for (i = 0; i < Ultimap2CpuCount; i++)
PsCreateSystemThread(&PInfo[i]->WriterThreadHandle, 0, NULL, 0, NULL, WriteThreadForSpecificCPU, (PVOID)i);
if ((NoPMI == FALSE) && (RegisteredProfilerInterruptHandler == FALSE))
{
DbgPrint("Registering PMI handler\n");
pperfmon_hook2 = (void *)PMI;
r = HalSetSystemInformation(HalProfileSourceInterruptHandler, sizeof(PVOID*), &pperfmon_hook2); //hook the perfmon interrupt
if (r == STATUS_SUCCESS)
RegisteredProfilerInterruptHandler = TRUE;
DbgPrint("HalSetSystemInformation returned %x\n", r);
if (r != STATUS_SUCCESS)
DbgPrint("Failure hooking the permon interrupt. Ultimap2 will not be able to use interrupts until you reboot (This can happen when the perfmon interrupt is hooked more than once. It has no restore/undo hook)\n");
}
forEachCpu(ultimap2_setup_dpc, NULL, NULL, NULL, NULL);
}
void UnregisterUltimapPMI()
{
NTSTATUS r;
DbgPrint("UnregisterUltimapPMI()\n");
if (RegisteredProfilerInterruptHandler)
{
pperfmon_hook2 = NULL;
r = HalSetSystemInformation(HalProfileSourceInterruptHandler, sizeof(PVOID*), &pperfmon_hook2);
DbgPrint("1: HalSetSystemInformation to disable returned %x\n", r);
if (r == STATUS_SUCCESS)
return;
r = HalSetSystemInformation(HalProfileSourceInterruptHandler, sizeof(PVOID*), &clear); //unhook the perfmon interrupt
DbgPrint("2: HalSetSystemInformation to disable returned %x\n", r);
if (r == STATUS_SUCCESS)
return;
r = HalSetSystemInformation(HalProfileSourceInterruptHandler, sizeof(PVOID*), 0);
DbgPrint("3: HalSetSystemInformation to disable returned %x\n", r);
}
else
DbgPrint("UnregisterUltimapPMI() not needed\n");
}
void DisableUltimap2(void)
{
int i;
DbgPrint("-------------------->DisableUltimap2<------------------");
if (!ultimapEnabled)
return;
DbgPrint("-------------------->DisableUltimap2:Stage 1<------------------");
forEachCpuAsync(ultimap2_disable_dpc, NULL, NULL, NULL, NULL);
UltimapActive = FALSE;
if (SuspendThreadHandle)
{
DbgPrint("Waiting for SuspendThreadHandle");
KeSetEvent(&SuspendEvent, 0, FALSE);
ZwWaitForSingleObject(SuspendThreadHandle, FALSE, NULL);
ZwClose(SuspendThreadHandle);
SuspendThreadHandle = NULL;
}
if (PInfo)
{
for (i = 0; i < Ultimap2CpuCount; i++)
{
KeSetEvent(&PInfo[i]->DataProcessed, 0, FALSE);
KeSetEvent(&PInfo[i]->DataReady, 0, FALSE);
}
}
if (Ultimap2Handle)
{
DbgPrint("Waiting for Ultimap2Handle");
KeSetEvent(&FlushData, 0, FALSE);
ZwWaitForSingleObject(Ultimap2Handle, FALSE, NULL);
ZwClose(Ultimap2Handle);
Ultimap2Handle = NULL;
}
if (PInfo)
{
DbgPrint("going to deal with the PInfo data");
for (i = 0; i < Ultimap2CpuCount; i++)
{
if (PInfo[i])
{
PToPA_LOOKUP li;
KeSetEvent(&PInfo[i]->Buffer2ReadyForSwap, 0, FALSE);
KeSetEvent(&PInfo[i]->InitiateSave, 0, FALSE);
DbgPrint("Waiting for WriterThreadHandle[%d]",i);
ZwWaitForSingleObject(PInfo[i]->WriterThreadHandle, FALSE, NULL);
ZwClose(PInfo[i]->WriterThreadHandle);
PInfo[i]->WriterThreadHandle = NULL;
if (PInfo[i]->ToPABufferMDL)
{
IoFreeMdl(PInfo[i]->ToPABufferMDL);
PInfo[i]->ToPABufferMDL = NULL;
}
if (PInfo[i]->ToPABuffer)
{
if (singleToPASystem)
MmFreeContiguousMemory(PInfo[i]->ToPABuffer);
else
ExFreePool(PInfo[i]->ToPABuffer);
PInfo[i]->ToPABuffer = NULL;
}
if (PInfo[i]->ToPABuffer2MDL)
{
IoFreeMdl(PInfo[i]->ToPABuffer2MDL);
PInfo[i]->ToPABufferMDL = NULL;
}
if (PInfo[i]->ToPABuffer2)
{
if (singleToPASystem)
MmFreeContiguousMemory(PInfo[i]->ToPABuffer2);
else
ExFreePool(PInfo[i]->ToPABuffer2);
PInfo[i]->ToPABuffer2 = NULL;
}
if (PInfo[i]->ToPAHeader)
{
ExFreePool(PInfo[i]->ToPAHeader);
PInfo[i]->ToPAHeader = NULL;
}
if (PInfo[i]->ToPAHeader2)
{
ExFreePool(PInfo[i]->ToPAHeader2);
PInfo[i]->ToPAHeader2 = NULL;
}
while (li = RtlGetElementGenericTable(PInfo[i]->ToPALookupTable, 0))
RtlDeleteElementGenericTable(PInfo[i]->ToPALookupTable, li);
ExFreePool(PInfo[i]->ToPALookupTable);
PInfo[i]->ToPALookupTable = NULL;
while (li = RtlGetElementGenericTable(PInfo[i]->ToPALookupTable2, 0))
RtlDeleteElementGenericTable(PInfo[i]->ToPALookupTable2, li);
ExFreePool(PInfo[i]->ToPALookupTable2);
PInfo[i]->ToPALookupTable2 = NULL;
ExFreePool(PInfo[i]);
PInfo[i] = NULL;
}
}
ExFreePool(PInfo);
ExFreePool(Ultimap2_DataReady);
PInfo = NULL;
DbgPrint("Finished terminating ultimap2");
}
if (Ultimap2Ranges)
{
ExFreePool(Ultimap2Ranges);
Ultimap2Ranges = NULL;
Ultimap2RangeCount = 0;
}
DbgPrint("-------------------->DisableUltimap2:Finish<------------------");
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/phy0292/cheat-engine.git
git@gitee.com:phy0292/cheat-engine.git
phy0292
cheat-engine
cheat-engine
master

搜索帮助