mirror of
https://github.com/ufrisk/MemProcFS.git
synced 2026-10-12 02:23:53 +00:00
Version 5.18.3
This commit is contained in:
@@ -265,3 +265,4 @@ Latest:
|
||||
* Bug fixes.
|
||||
* Fix: Heap recovery now works on Windows 11 24H2 and later.
|
||||
* Fix: Pool and Heap parsing improved.
|
||||
* Fix: Compressed memory recovery rates improved.
|
||||
|
||||
+11
-11
@@ -292,17 +292,17 @@ BOOL LcRead(
|
||||
* request to the target.
|
||||
*/
|
||||
typedef DWORD LC_READ_PAGE_RESULT, *PLC_READ_PAGE_RESULT;
|
||||
#define LC_READ_PAGE_RESULT_NONE 0
|
||||
#define LC_READ_PAGE_RESULT_SUCCESS 1
|
||||
#define LC_READ_PAGE_RESULT_SUCCESS_AFTER_RETRY 2
|
||||
#define LC_READ_PAGE_RESULT_UNSUPPORTED_REQUEST 3
|
||||
#define LC_READ_PAGE_RESULT_COMPLETER_ABORT 4
|
||||
#define LC_READ_PAGE_RESULT_NO_COMPLETION 5
|
||||
#define LC_READ_PAGE_RESULT_PARTIAL_COMPLETION 6
|
||||
#define LC_READ_PAGE_RESULT_TRANSPORT_ERROR 7
|
||||
#define LC_READ_PAGE_RESULT_PROTOCOL_ERROR 8
|
||||
#define LC_READ_PAGE_RESULT_UNSPECIFIED_ERROR 9
|
||||
#define LC_READ_PAGE_RESULT_NOT_ISSUED 10
|
||||
#define LC_READ_PAGE_RESULT_NONE 0x00
|
||||
#define LC_READ_PAGE_RESULT_SUCCESS 0x01
|
||||
#define LC_READ_PAGE_RESULT_SUCCESS_AFTER_RETRY 0x02
|
||||
#define LC_READ_PAGE_RESULT_UNSUPPORTED_REQUEST 0x03
|
||||
#define LC_READ_PAGE_RESULT_COMPLETER_ABORT 0x04
|
||||
#define LC_READ_PAGE_RESULT_NO_COMPLETION 0x05
|
||||
#define LC_READ_PAGE_RESULT_PARTIAL_COMPLETION 0x06
|
||||
#define LC_READ_PAGE_RESULT_TRANSPORT_ERROR 0x07
|
||||
#define LC_READ_PAGE_RESULT_PROTOCOL_ERROR 0x08
|
||||
#define LC_READ_PAGE_RESULT_UNSPECIFIED_ERROR 0x09
|
||||
#define LC_READ_PAGE_RESULT_NOT_ISSUED 0x0A
|
||||
|
||||
/*
|
||||
* Read memory in a scattered non-contiguous way and return a typed result for
|
||||
|
||||
+2
-2
@@ -3,8 +3,8 @@
|
||||
|
||||
#define VERSION_MAJOR 5
|
||||
#define VERSION_MINOR 18
|
||||
#define VERSION_REVISION 2
|
||||
#define VERSION_BUILD 241
|
||||
#define VERSION_REVISION 3
|
||||
#define VERSION_BUILD 242
|
||||
|
||||
#define VER_FILE_DESCRIPTION_STR "MemProcFS : Plugin vmemd"
|
||||
#define VER_FILE_VERSION VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, VERSION_BUILD
|
||||
|
||||
+2
-2
@@ -3,8 +3,8 @@
|
||||
|
||||
#define VERSION_MAJOR 5
|
||||
#define VERSION_MINOR 18
|
||||
#define VERSION_REVISION 2
|
||||
#define VERSION_BUILD 241
|
||||
#define VERSION_REVISION 3
|
||||
#define VERSION_BUILD 242
|
||||
|
||||
#define VER_FILE_DESCRIPTION_STR "MemProcFS"
|
||||
#define VER_FILE_VERSION VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, VERSION_BUILD
|
||||
|
||||
+8
-5
@@ -1039,9 +1039,6 @@ VOID MmVad_ExtendedInfoFetch(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess
|
||||
PVMMOB_SCATTER hObScatter = NULL;
|
||||
DWORD cbRead, cb32 = f32 ? 4 : 8;
|
||||
pVadMap = pProcess->Map.pObVad;
|
||||
if(tp == VMM_VADMAP_TP_FULL) {
|
||||
if(!(psmOb = ObStrMap_New(H, 0))) { goto cleanup; }
|
||||
}
|
||||
// count max potential vads and allocate.
|
||||
{
|
||||
for(i = 0, cMax = pVadMap->cMap; i < cMax; i++) {
|
||||
@@ -1125,6 +1122,10 @@ VOID MmVad_ExtendedInfoFetch(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess
|
||||
pVadMap->tp = tp;
|
||||
goto cleanup;
|
||||
}
|
||||
// [ alloc strmap for full VAD parse ]
|
||||
if(!(psmOb = ObStrMap_New(H, 0))) {
|
||||
goto cleanup;
|
||||
}
|
||||
// [ heap map parse ]
|
||||
if(VmmMap_GetHeap(H, pProcess, &pObHeapMap)) {
|
||||
for(i = 0; i < pObHeapMap->cSegments; i++) {
|
||||
@@ -1172,14 +1173,16 @@ VOID MmVad_ExtendedInfoFetch(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProcess
|
||||
);
|
||||
}
|
||||
}
|
||||
// cleanup
|
||||
// Finalize all strings before publishing the full map.
|
||||
f = ObStrMap_FinalizeAllocU_DECREF_NULL(&psmOb, &pVadMap->pbMultiText, &pVadMap->cbMultiText);
|
||||
if(!f) { goto cleanup; }
|
||||
pVadMap->tp = tp;
|
||||
cleanup:
|
||||
ObStrMap_FinalizeAllocU_DECREF_NULL(&psmOb, &pVadMap->pbMultiText, &pVadMap->cbMultiText);
|
||||
Ob_DECREF(pObThreadMap);
|
||||
Ob_DECREF(pObHeapMap);
|
||||
Ob_DECREF(pObPteMap);
|
||||
Ob_DECREF(hObScatter);
|
||||
Ob_DECREF(psmOb);
|
||||
LocalFree(pva);
|
||||
}
|
||||
|
||||
|
||||
+164
-125
@@ -25,7 +25,7 @@
|
||||
#define MMWINX86PAE_PTE_TRANSITION(pte) (((pte & 0x0c01) == 0x0800) ? ((pte & 0x0000003ffffff000) | 0x005) : 0)
|
||||
#define MMWINX86PAE_PTE_PROTOTYPE(pte) (((pte & 0x8000000700000401) == 0x8000000000000400) ? (pte >> 32) : 0)
|
||||
#define MMWINX86PAE_PTE_PAGE_FILE_NUMBER(H, pte) ((pte >> (((H->vmm.kernel.dwVersionBuild >= 17134) ? 12 : 1))) & 0x0f)
|
||||
#define MMWINX86PAE_PTE_PAGE_FILE_OFFSET(pte) ((pte >> 32) ^ (!(pte & PTE_SWIZZLE_BIT) ? PTE_SWIZZLE_MASK : 0))
|
||||
#define MMWINX86PAE_PTE_PAGE_FILE_OFFSET(pte) ((DWORD)(pte >> 32) & ~(((H->vmm.kernel.dwVersionBuild >= 17134) && !(pte & PTE_SWIZZLE_BIT)) ? PTE_SWIZZLE_MASK : 0))
|
||||
#define MMWINX86PAE_PTE_PAGE_KEY_COMPRESSED(H, pte) (DWORD)(((MMWINX86PAE_PTE_PAGE_FILE_NUMBER(H, pte) << 0x1c) | MMWINX86PAE_PTE_PAGE_FILE_OFFSET(pte)))
|
||||
|
||||
#define MMWINX64_PTE_IS_HARDWARE(pte) (pte & 0x01)
|
||||
@@ -33,7 +33,7 @@
|
||||
#define MMWINX64_PTE_TRANSITION(pte) (((pte & 0x0c01) == 0x0800) ? ((pte & 0xffffdffffffff000) | 0x005) : 0)
|
||||
#define MMWINX64_PTE_PROTOTYPE(pte) (((pte & 0x8000000000070401) == 0x8000000000000400) ? ((pte >> 16) | 0xffff000000000000) : 0)
|
||||
#define MMWINX64_PTE_PAGE_FILE_NUMBER(H, pte) ((pte >> (((H->vmm.kernel.dwVersionBuild >= 17134) ? 12 : 1))) & 0x0f)
|
||||
#define MMWINX64_PTE_PAGE_FILE_OFFSET(pte) ((pte >> 32) ^ (!(pte & PTE_SWIZZLE_BIT) ? PTE_SWIZZLE_MASK : 0))
|
||||
#define MMWINX64_PTE_PAGE_FILE_OFFSET(pte) ((DWORD)(pte >> 32) & ~(((H->vmm.kernel.dwVersionBuild >= 17134) && !(pte & PTE_SWIZZLE_BIT)) ? PTE_SWIZZLE_MASK : 0))
|
||||
#define MMWINX64_PTE_PAGE_KEY_COMPRESSED(H, pte) (DWORD)(((MMWINX64_PTE_PAGE_FILE_NUMBER(H, pte) << 0x1c) | MMWINX64_PTE_PAGE_FILE_OFFSET(pte)))
|
||||
|
||||
typedef struct tdMMWIN_MEMCOMPRESS_OFFSET {
|
||||
@@ -124,67 +124,39 @@ BOOL MmWin_BTree64_Search(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QW
|
||||
_Success_(return)
|
||||
BOOL MmWin_BTree32_SearchLeaf(_In_ PVMM_PROCESS pSystemProcess, _In_ P_BTREE32 pT, _In_ DWORD dwKey, _Out_ PDWORD pdwValue, _In_ QWORD fVmmRead)
|
||||
{
|
||||
BOOL fSearchPreFail = FALSE;
|
||||
DWORD i, dwSearchStep, dwSearchIndex = 1;
|
||||
// 2: search tree for leaf
|
||||
for(i = 1; (i < 12) && ((pT->cEntries - 1) >> i); i++);
|
||||
dwSearchIndex = dwSearchStep = min(1 << (i - 1), pT->cEntries);
|
||||
while(TRUE) {
|
||||
dwSearchStep = dwSearchStep >> 1;
|
||||
if(pT->LeafEntries[dwSearchIndex].k == dwKey) {
|
||||
*pdwValue = pT->LeafEntries[dwSearchIndex].v;
|
||||
DWORD i, iMin = 0, iMax = pT->cEntries;
|
||||
while(iMin < iMax) {
|
||||
i = iMin + ((iMax - iMin) >> 1);
|
||||
if(pT->LeafEntries[i].k == dwKey) {
|
||||
*pdwValue = pT->LeafEntries[i].v;
|
||||
return TRUE;
|
||||
}
|
||||
if(dwSearchStep == 0) {
|
||||
if(fSearchPreFail) {
|
||||
return FALSE;
|
||||
}
|
||||
fSearchPreFail = TRUE;
|
||||
dwSearchStep = 1;
|
||||
}
|
||||
if(pT->LeafEntries[dwSearchIndex].k < dwKey) {
|
||||
if(dwSearchIndex + dwSearchStep < pT->cEntries) {
|
||||
dwSearchIndex += dwSearchStep;
|
||||
}
|
||||
if(pT->LeafEntries[i].k < dwKey) {
|
||||
iMin = i + 1;
|
||||
} else {
|
||||
if(dwSearchStep <= dwSearchIndex) {
|
||||
dwSearchIndex -= dwSearchStep;
|
||||
}
|
||||
iMax = i;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
_Success_(return)
|
||||
BOOL MmWin_BTree64_SearchLeaf(_In_ PVMM_PROCESS pSystemProcess, _In_ P_BTREE64 pT, _In_ DWORD dwKey, _Out_ PDWORD pdwValue, _In_ QWORD fVmmRead)
|
||||
{
|
||||
BOOL fSearchPreFail = FALSE;
|
||||
DWORD i, dwSearchStep, dwSearchIndex = 1;
|
||||
// 2: search tree for leaf
|
||||
for(i = 1; (i < 12) && ((pT->cEntries - 1) >> i); i++);
|
||||
dwSearchIndex = dwSearchStep = min(1 << (i - 1), pT->cEntries);
|
||||
while(TRUE) {
|
||||
dwSearchStep = dwSearchStep >> 1;
|
||||
if(pT->LeafEntries[dwSearchIndex].k == dwKey) {
|
||||
*pdwValue = pT->LeafEntries[dwSearchIndex].v;
|
||||
DWORD i, iMin = 0, iMax = pT->cEntries;
|
||||
while(iMin < iMax) {
|
||||
i = iMin + ((iMax - iMin) >> 1);
|
||||
if(pT->LeafEntries[i].k == dwKey) {
|
||||
*pdwValue = pT->LeafEntries[i].v;
|
||||
return TRUE;
|
||||
}
|
||||
if(dwSearchStep == 0) {
|
||||
if(fSearchPreFail) {
|
||||
return FALSE;
|
||||
}
|
||||
fSearchPreFail = TRUE;
|
||||
dwSearchStep = 1;
|
||||
}
|
||||
if(pT->LeafEntries[dwSearchIndex].k < dwKey) {
|
||||
if(dwSearchIndex + dwSearchStep < pT->cEntries) {
|
||||
dwSearchIndex += dwSearchStep;
|
||||
}
|
||||
if(pT->LeafEntries[i].k < dwKey) {
|
||||
iMin = i + 1;
|
||||
} else {
|
||||
if(dwSearchStep <= dwSearchIndex) {
|
||||
dwSearchIndex -= dwSearchStep;
|
||||
}
|
||||
iMax = i;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
_Success_(return)
|
||||
@@ -292,7 +264,7 @@ BOOL MmWin_BTree64_Search(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _In_ QW
|
||||
if(!f) { return FALSE; }
|
||||
if(pT->fLeaf) {
|
||||
// Leaf
|
||||
if(pT->cEntries > 0x1ff) { return FALSE; }
|
||||
if(pT->cEntries > 0x1fe) { return FALSE; }
|
||||
return MmWin_BTree64_SearchLeaf(pProcess, pT, dwKey, pdwValue, fVmmRead);
|
||||
} else {
|
||||
// Node
|
||||
@@ -737,10 +709,16 @@ typedef struct td_SMHP_CHUNK_METADATA64 {
|
||||
|
||||
typedef struct td_ST_PAGE_RECORD {
|
||||
DWORD Key;
|
||||
DWORD CompressedSize;
|
||||
DWORD NextKey;
|
||||
// Normal records store a WORD size at +4; redirects store a DWORD key at +4.
|
||||
union {
|
||||
WORD CompressedSize;
|
||||
DWORD NextKey;
|
||||
} u;
|
||||
DWORD Reserved;
|
||||
} _ST_PAGE_RECORD, *P_ST_PAGE_RECORD;
|
||||
|
||||
#define MMWIN_MEMCOMPRESS_MAX_PAGE_RECORD_REDIRECTS 0x20
|
||||
|
||||
/*
|
||||
* Log a memory compression error.
|
||||
* -- H
|
||||
@@ -825,6 +803,60 @@ BOOL MmWin_MemCompress2_SmkmStoreMetadata64(_In_ VMM_HANDLE H, _In_ PMMWINX64_CO
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve the PageRecord address from the region key and the already loaded
|
||||
* SmkmStore. Page records with Key == 0xffffffff may redirect to another
|
||||
* region key, so this calculation is also used while following redirects.
|
||||
* -- H
|
||||
* -- ctx
|
||||
* -- return
|
||||
*/
|
||||
_Success_(return)
|
||||
BOOL MmWin_MemCompress3_PageRecordAddress32(_In_ VMM_HANDLE H, _In_ PMMWINX64_COMPRESS_CONTEXT ctx)
|
||||
{
|
||||
QWORD cbChunkEntry;
|
||||
DWORD vaPageRecordArray;
|
||||
DWORD i, dwEncodedMetadata, iChunkPtr = 0, iChunkArray, dwPoolHdr = 0;
|
||||
P_SMHP_CHUNK_METADATA32 pc;
|
||||
PMMWIN_MEMCOMPRESS_OFFSET po = &H->vmm.pMmContext->MemCompress.O;
|
||||
// Get page record and calculate:
|
||||
// - chunk "encoded metadata"
|
||||
// - index into chunk metadata array (= highest non-zero bit position of encoded_metadata)
|
||||
// - index into chunk array (pointed to by chunk metadata array)
|
||||
pc = (P_SMHP_CHUNK_METADATA32)(ctx->e.pbSmkm + po->SMKM_STORE.ChunkMetaData);
|
||||
if((pc->dwBitValue & 0xff) >= 32) {
|
||||
return MmWin_MemCompress_LogError(H, ctx, "#35 InvalidChunkMetadata");
|
||||
}
|
||||
dwEncodedMetadata = ctx->e.dwRegionKey >> (pc->dwBitValue & 0xff);
|
||||
if(!dwEncodedMetadata) {
|
||||
return MmWin_MemCompress_LogError(H, ctx, "#35 InvalidChunkMetadata");
|
||||
}
|
||||
for(i = 0; i < 32; i++) {
|
||||
if(!(dwEncodedMetadata >> i)) { break; }
|
||||
iChunkPtr = i;
|
||||
}
|
||||
iChunkArray = (1U << iChunkPtr) ^ dwEncodedMetadata;
|
||||
// Validate and fetch page record address
|
||||
if(iChunkArray > 0x400) {
|
||||
return MmWin_MemCompress_LogError(H, ctx, "#35 ChunkArrayTooLarge");
|
||||
}
|
||||
if(!VMM_KADDR32_8(pc->avaChunkPtr[iChunkPtr])) {
|
||||
return MmWin_MemCompress_LogError(H, ctx, "#36 ChunkPtrNoKADDR");
|
||||
}
|
||||
if(pc->avaChunkPtr[iChunkPtr] & 0xfff) {
|
||||
if(!VmmRead2(H, ctx->pSystemProcess, pc->avaChunkPtr[iChunkPtr] - 4, (PBYTE)&dwPoolHdr, 4, ctx->fVmmRead) || (dwPoolHdr != 'ABms')) {
|
||||
return MmWin_MemCompress_LogError(H, ctx, "#37 ChunkBadPoolHdr");
|
||||
}
|
||||
}
|
||||
// Windows 10 1607 uses two DWORDs per chunk entry; 1703+ uses three.
|
||||
cbChunkEntry = (H->vmm.kernel.dwVersionBuild >= 15063) ? 0x0cULL : 0x08ULL;
|
||||
if(!VmmRead2(H, ctx->pSystemProcess, pc->avaChunkPtr[iChunkPtr] + cbChunkEntry * iChunkArray, (PBYTE)&vaPageRecordArray, sizeof(DWORD), ctx->fVmmRead) || !VMM_KADDR32_PAGE(vaPageRecordArray)) {
|
||||
return MmWin_MemCompress_LogError(H, ctx, "#38 PageRecordArray");
|
||||
}
|
||||
ctx->e.vaPageRecord = (DWORD)((QWORD)vaPageRecordArray + pc->dwChunkPageHeaderSize + ((QWORD)pc->dwPageRecordSize * (ctx->e.dwRegionKey & pc->dwPageRecordsPerChunkMask)));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve the SmkmStore and the PageRecord.
|
||||
* -- H
|
||||
@@ -834,9 +866,6 @@ BOOL MmWin_MemCompress2_SmkmStoreMetadata64(_In_ VMM_HANDLE H, _In_ PMMWINX64_CO
|
||||
_Success_(return)
|
||||
BOOL MmWin_MemCompress3_SmkmStoreAndPageRecord32(_In_ VMM_HANDLE H, _In_ PMMWINX64_COMPRESS_CONTEXT ctx)
|
||||
{
|
||||
DWORD vaPageRecordArray;
|
||||
DWORD i, dwEncodedMetadata, iChunkPtr = 0, iChunkArray, dwPoolHdr = 0;
|
||||
P_SMHP_CHUNK_METADATA32 pc;
|
||||
PMMWIN_MEMCOMPRESS_OFFSET po = &H->vmm.pMmContext->MemCompress.O;
|
||||
// 1: Load SmkmStore
|
||||
if(!VmmRead2(H, ctx->pSystemProcess, ctx->e.vaSmkmStore, ctx->e.pbSmkm, sizeof(ctx->e.pbSmkm), ctx->fVmmRead)) {
|
||||
@@ -853,34 +882,9 @@ BOOL MmWin_MemCompress3_SmkmStoreAndPageRecord32(_In_ VMM_HANDLE H, _In_ PMMWINX
|
||||
if(!MmWin_BTree_Search(H, ctx->pSystemProcess, *(PDWORD)(ctx->e.pbSmkm + po->SMKM_STORE.PagesTree), ctx->e.dwPageKey, &ctx->e.dwRegionKey, ctx->fVmmRead)) {
|
||||
return MmWin_MemCompress_LogError(H, ctx, "#34 RegionKeyBTreeSearch");
|
||||
}
|
||||
// 4: Get page record and calculate:
|
||||
// - chunk "encoded metadata"
|
||||
// - index into chunk metadata array (= highest non-zero bit position of encoded_metadata)
|
||||
// - index into chunk array (pointed to by chunk metadata array)
|
||||
pc = (P_SMHP_CHUNK_METADATA32)(ctx->e.pbSmkm + po->SMKM_STORE.ChunkMetaData);
|
||||
dwEncodedMetadata = ctx->e.dwRegionKey >> (pc->dwBitValue & 0xff);
|
||||
for(i = 0; i < 32; i++) {
|
||||
if(!(dwEncodedMetadata >> i)) { break; }
|
||||
iChunkPtr = i;
|
||||
}
|
||||
iChunkArray = (1 << iChunkPtr) ^ dwEncodedMetadata;
|
||||
// 5: Validate and fetch page record address
|
||||
if(iChunkArray > 0x400) {
|
||||
return MmWin_MemCompress_LogError(H, ctx, "#35 ChunkArrayTooLarge");
|
||||
}
|
||||
if(!VMM_KADDR32_8(pc->avaChunkPtr[iChunkPtr])) {
|
||||
return MmWin_MemCompress_LogError(H, ctx, "#36 ChunkPtrNoKADDR");
|
||||
}
|
||||
if(pc->avaChunkPtr[iChunkPtr] & 0xfff) {
|
||||
if(!VmmRead2(H, ctx->pSystemProcess, pc->avaChunkPtr[iChunkPtr] - 4, (PBYTE)&dwPoolHdr, 4, ctx->fVmmRead) || (dwPoolHdr != 'ABms')) {
|
||||
return MmWin_MemCompress_LogError(H, ctx, "#37 ChunkBadPoolHdr");
|
||||
}
|
||||
}
|
||||
if(!VmmRead2(H, ctx->pSystemProcess, pc->avaChunkPtr[iChunkPtr] + 0x0cULL * iChunkArray, (PBYTE)&vaPageRecordArray, sizeof(DWORD), ctx->fVmmRead) || !VMM_KADDR32_PAGE(vaPageRecordArray)) {
|
||||
return MmWin_MemCompress_LogError(H, ctx, "#38 PageRecordArray");
|
||||
}
|
||||
ctx->e.vaPageRecord = (DWORD)((QWORD)vaPageRecordArray + pc->dwChunkPageHeaderSize + ((QWORD)pc->dwPageRecordSize * (ctx->e.dwRegionKey & pc->dwPageRecordsPerChunkMask)));
|
||||
// 6: Get owner EPROCESS
|
||||
// 4: Get page record address
|
||||
if(!MmWin_MemCompress3_PageRecordAddress32(H, ctx)) { return FALSE; }
|
||||
// 5: Get owner EPROCESS
|
||||
ctx->e.vaOwnerEPROCESS = *(PDWORD)(ctx->e.pbSmkm + po->SMKM_STORE.OwnerProcess);
|
||||
if(ctx->e.vaOwnerEPROCESS != H->vmm.pMmContext->MemCompress.vaEPROCESS) {
|
||||
return MmWin_MemCompress_LogError(H, ctx, "#39 OwnerEPROCESS");
|
||||
@@ -888,6 +892,55 @@ BOOL MmWin_MemCompress3_SmkmStoreAndPageRecord32(_In_ VMM_HANDLE H, _In_ PMMWINX
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve the PageRecord address from the region key and the already loaded SmkmStore.
|
||||
* -- H
|
||||
* -- ctx
|
||||
* -- return
|
||||
*/
|
||||
_Success_(return)
|
||||
BOOL MmWin_MemCompress3_PageRecordAddress64(_In_ VMM_HANDLE H, _In_ PMMWINX64_COMPRESS_CONTEXT ctx)
|
||||
{
|
||||
QWORD vaPageRecordArray;
|
||||
DWORD i, dwEncodedMetadata, iChunkPtr = 0, iChunkArray, dwPoolHdr = 0;
|
||||
P_SMHP_CHUNK_METADATA64 pc;
|
||||
PMMWIN_MEMCOMPRESS_OFFSET po = &H->vmm.pMmContext->MemCompress.O;
|
||||
// Get page record and calculate:
|
||||
// - chunk "encoded metadata"
|
||||
// - index into chunk metadata array (= highest non-zero bit position of encoded_metadata)
|
||||
// - index into chunk array (pointed to by chunk metadata array)
|
||||
pc = (P_SMHP_CHUNK_METADATA64)(ctx->e.pbSmkm + po->SMKM_STORE.ChunkMetaData);
|
||||
if((pc->dwBitValue & 0xff) >= 32) {
|
||||
return MmWin_MemCompress_LogError(H, ctx, "#35 InvalidChunkMetadata");
|
||||
}
|
||||
dwEncodedMetadata = ctx->e.dwRegionKey >> (pc->dwBitValue & 0xff);
|
||||
if(!dwEncodedMetadata) {
|
||||
return MmWin_MemCompress_LogError(H, ctx, "#35 InvalidChunkMetadata");
|
||||
}
|
||||
for(i = 0; i < 32; i++) {
|
||||
if(!(dwEncodedMetadata >> i)) { break; }
|
||||
iChunkPtr = i;
|
||||
}
|
||||
iChunkArray = (1U << iChunkPtr) ^ dwEncodedMetadata;
|
||||
// Validate and fetch page record address
|
||||
if(iChunkArray > 0x400) {
|
||||
return MmWin_MemCompress_LogError(H, ctx, "#35 ChunkArrayTooLarge");
|
||||
}
|
||||
if(!VMM_KADDR64_16(pc->avaChunkPtr[iChunkPtr])) {
|
||||
return MmWin_MemCompress_LogError(H, ctx, "#36 ChunkPtrNoKADDR");
|
||||
}
|
||||
if(pc->avaChunkPtr[iChunkPtr] & 0xfff) {
|
||||
if(!VmmRead2(H, ctx->pSystemProcess, pc->avaChunkPtr[iChunkPtr] - 12, (PBYTE)&dwPoolHdr, 4, ctx->fVmmRead) || (dwPoolHdr != 'ABms')) {
|
||||
return MmWin_MemCompress_LogError(H, ctx, "#37 ChunkBadPoolHdr");
|
||||
}
|
||||
}
|
||||
if(!VmmRead2(H, ctx->pSystemProcess, pc->avaChunkPtr[iChunkPtr] + 0x10ULL * iChunkArray, (PBYTE)&vaPageRecordArray, sizeof(QWORD), ctx->fVmmRead) || !VMM_KADDR64_PAGE(vaPageRecordArray)) {
|
||||
return MmWin_MemCompress_LogError(H, ctx, "#38 PageRecordArray");
|
||||
}
|
||||
ctx->e.vaPageRecord = (QWORD)(vaPageRecordArray + pc->dwChunkPageHeaderSize + ((QWORD)pc->dwPageRecordSize * (ctx->e.dwRegionKey & pc->dwPageRecordsPerChunkMask)));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve the SmkmStore and the PageRecord.
|
||||
* -- H
|
||||
@@ -897,9 +950,6 @@ BOOL MmWin_MemCompress3_SmkmStoreAndPageRecord32(_In_ VMM_HANDLE H, _In_ PMMWINX
|
||||
_Success_(return)
|
||||
BOOL MmWin_MemCompress3_SmkmStoreAndPageRecord64(_In_ VMM_HANDLE H, _In_ PMMWINX64_COMPRESS_CONTEXT ctx)
|
||||
{
|
||||
QWORD vaPageRecordArray;
|
||||
DWORD i, dwEncodedMetadata, iChunkPtr = 0, iChunkArray, dwPoolHdr = 0;
|
||||
P_SMHP_CHUNK_METADATA64 pc;
|
||||
PMMWIN_MEMCOMPRESS_OFFSET po = &H->vmm.pMmContext->MemCompress.O;
|
||||
// 1: Load SmkmStore
|
||||
if(!VmmRead2(H, ctx->pSystemProcess, ctx->e.vaSmkmStore, ctx->e.pbSmkm, sizeof(ctx->e.pbSmkm), ctx->fVmmRead)) {
|
||||
@@ -916,34 +966,9 @@ BOOL MmWin_MemCompress3_SmkmStoreAndPageRecord64(_In_ VMM_HANDLE H, _In_ PMMWINX
|
||||
if(!MmWin_BTree_Search(H, ctx->pSystemProcess, *(PQWORD)(ctx->e.pbSmkm + po->SMKM_STORE.PagesTree), ctx->e.dwPageKey, &ctx->e.dwRegionKey, ctx->fVmmRead)) {
|
||||
return MmWin_MemCompress_LogError(H, ctx, "#34 RegionKeyBTreeSearch");
|
||||
}
|
||||
// 4: Get page record and calculate:
|
||||
// - chunk "encoded metadata"
|
||||
// - index into chunk metadata array (= highest non-zero bit position of encoded_metadata)
|
||||
// - index into chunk array (pointed to by chunk metadata array)
|
||||
pc = (P_SMHP_CHUNK_METADATA64)(ctx->e.pbSmkm + po->SMKM_STORE.ChunkMetaData);
|
||||
dwEncodedMetadata = ctx->e.dwRegionKey >> (pc->dwBitValue & 0xff);
|
||||
for(i = 0; i < 32; i++) {
|
||||
if(!(dwEncodedMetadata >> i)) { break; }
|
||||
iChunkPtr = i;
|
||||
}
|
||||
iChunkArray = (1 << iChunkPtr) ^ dwEncodedMetadata;
|
||||
// 5: Validate and fetch page record address
|
||||
if(iChunkArray > 0x400) {
|
||||
return MmWin_MemCompress_LogError(H, ctx, "#35 ChunkArrayTooLarge");
|
||||
}
|
||||
if(!VMM_KADDR64_16(pc->avaChunkPtr[iChunkPtr])) {
|
||||
return MmWin_MemCompress_LogError(H, ctx, "#36 ChunkPtrNoKADDR");
|
||||
}
|
||||
if(pc->avaChunkPtr[iChunkPtr] & 0xfff) {
|
||||
if(!VmmRead2(H, ctx->pSystemProcess, pc->avaChunkPtr[iChunkPtr] - 12, (PBYTE)&dwPoolHdr, 4, ctx->fVmmRead) || (dwPoolHdr != 'ABms')) {
|
||||
return MmWin_MemCompress_LogError(H, ctx, "#37 ChunkBadPoolHdr");
|
||||
}
|
||||
}
|
||||
if(!VmmRead2(H, ctx->pSystemProcess, pc->avaChunkPtr[iChunkPtr] + 0x10ULL * iChunkArray, (PBYTE)&vaPageRecordArray, sizeof(QWORD), ctx->fVmmRead) || !VMM_KADDR64_PAGE(vaPageRecordArray)) {
|
||||
return MmWin_MemCompress_LogError(H, ctx, "#38 PageRecordArray");
|
||||
}
|
||||
ctx->e.vaPageRecord = (QWORD)(vaPageRecordArray + pc->dwChunkPageHeaderSize + ((QWORD)pc->dwPageRecordSize * (ctx->e.dwRegionKey & pc->dwPageRecordsPerChunkMask)));
|
||||
// 6: Get owner EPROCESS
|
||||
// 4: Get page record address
|
||||
if(!MmWin_MemCompress3_PageRecordAddress64(H, ctx)) { return FALSE; }
|
||||
// 5: Get owner EPROCESS
|
||||
ctx->e.vaOwnerEPROCESS = *(PQWORD)(ctx->e.pbSmkm + po->SMKM_STORE.OwnerProcess);
|
||||
if(ctx->e.vaOwnerEPROCESS != H->vmm.pMmContext->MemCompress.vaEPROCESS) {
|
||||
return MmWin_MemCompress_LogError(H, ctx, "#39 OwnerEPROCESS");
|
||||
@@ -960,40 +985,54 @@ _Success_(return)
|
||||
BOOL MmWin_MemCompress4_CompressedRegionData(_In_ VMM_HANDLE H, _In_ PMMWINX64_COMPRESS_CONTEXT ctx)
|
||||
{
|
||||
QWORD vaRegionPtr = 0;
|
||||
DWORD dwRegionIndexMask, dwRegionIndex;
|
||||
DWORD i, dwRegionIndexMask, dwRegionIndex;
|
||||
_ST_PAGE_RECORD PageRecord;
|
||||
PMMWIN_MEMCOMPRESS_OFFSET po = &H->vmm.pMmContext->MemCompress.O;
|
||||
// 1: Read page record
|
||||
if(!VmmRead2(H, ctx->pSystemProcess, ctx->e.vaPageRecord, (PBYTE)&PageRecord, sizeof(PageRecord), ctx->fVmmRead)) {
|
||||
return MmWin_MemCompress_LogError(H, ctx, "#41 ReadPageRecord");
|
||||
// 1: Read page record and follow any redirect records.
|
||||
for(i = 0; i <= MMWIN_MEMCOMPRESS_MAX_PAGE_RECORD_REDIRECTS; i++) {
|
||||
if(!VmmRead2(H, ctx->pSystemProcess, ctx->e.vaPageRecord, (PBYTE)&PageRecord, sizeof(PageRecord), ctx->fVmmRead)) {
|
||||
return MmWin_MemCompress_LogError(H, ctx, "#41 ReadPageRecord");
|
||||
}
|
||||
if(PageRecord.Key != 0xffffffff) { break; }
|
||||
if((i == MMWIN_MEMCOMPRESS_MAX_PAGE_RECORD_REDIRECTS) || (PageRecord.u.NextKey == ctx->e.dwRegionKey)) {
|
||||
return MmWin_MemCompress_LogError(H, ctx, "#42 InvalidPageRecordRedirect");
|
||||
}
|
||||
ctx->e.dwRegionKey = PageRecord.u.NextKey;
|
||||
if(H->vmm.f32) {
|
||||
if(!MmWin_MemCompress3_PageRecordAddress32(H, ctx)) { return FALSE; }
|
||||
} else {
|
||||
if(!MmWin_MemCompress3_PageRecordAddress64(H, ctx)) { return FALSE; }
|
||||
}
|
||||
}
|
||||
if(PageRecord.Key == 0xffffffff) {
|
||||
// TODO: implement support
|
||||
return MmWin_MemCompress_LogError(H, ctx, "#42 UnsupportedPageRecord");
|
||||
ctx->e.cbCompressedData = (PageRecord.u.CompressedSize == 0x1000) ? 0x1000 : PageRecord.u.CompressedSize & 0xfff;
|
||||
dwRegionIndexMask = *(PDWORD)(ctx->e.pbSmkm + po->SMKM_STORE.RegionIndexMask) & 0xff;
|
||||
if(dwRegionIndexMask >= 32) {
|
||||
return MmWin_MemCompress_LogError(H, ctx, "#47 InvalidRegionIndexMask");
|
||||
}
|
||||
ctx->e.cbCompressedData = (PageRecord.CompressedSize == 0x1000) ? 0x1000 : PageRecord.CompressedSize & 0xfff;
|
||||
if(H->vmm.f32) {
|
||||
// 2: Get pointer to region (32-bit)
|
||||
dwRegionIndexMask = *(PDWORD)(ctx->e.pbSmkm + po->SMKM_STORE.RegionIndexMask) & 0xff;
|
||||
dwRegionIndex = PageRecord.Key >> dwRegionIndexMask;
|
||||
vaRegionPtr = *(PDWORD)(ctx->e.pbSmkm + po->SMKM_STORE.CompressedRegionPtrArray) + dwRegionIndex * sizeof(DWORD);
|
||||
// 3: Get region and offset (32-bit)
|
||||
if(!VmmRead2(H, ctx->pSystemProcess, vaRegionPtr, (PBYTE)&ctx->e.vaRegion, sizeof(DWORD), ctx->fVmmRead)) {
|
||||
return MmWin_MemCompress_LogError(H, ctx, "#43 ReadRegionVA");
|
||||
}
|
||||
if(!ctx->e.vaRegion || (ctx->e.vaRegion & 0x8000ffff)) {
|
||||
// High bit and low 16 bits contain entry state; regions are 64KB aligned.
|
||||
ctx->e.vaRegion &= 0x7fff0000;
|
||||
if(!VMM_UADDR32(ctx->e.vaRegion)) {
|
||||
return MmWin_MemCompress_LogError(H, ctx, "#44 InvalidRegionVA");
|
||||
}
|
||||
} else {
|
||||
// 2: Get pointer to region (64-bit)
|
||||
dwRegionIndexMask = *(PDWORD)(ctx->e.pbSmkm + po->SMKM_STORE.RegionIndexMask) & 0xff;
|
||||
dwRegionIndex = PageRecord.Key >> dwRegionIndexMask;
|
||||
vaRegionPtr = *(PQWORD)(ctx->e.pbSmkm + po->SMKM_STORE.CompressedRegionPtrArray) + dwRegionIndex * sizeof(QWORD);
|
||||
// 3: Get region and offset (64-bit)
|
||||
if(!VmmRead2(H, ctx->pSystemProcess, vaRegionPtr, (PBYTE)&ctx->e.vaRegion, sizeof(QWORD), ctx->fVmmRead)) {
|
||||
return MmWin_MemCompress_LogError(H, ctx, "#45 ReadRegionVA");
|
||||
}
|
||||
if(!ctx->e.vaRegion || (ctx->e.vaRegion & 0xffff80000000ffff)) {
|
||||
// High bit and low 16 bits contain entry state; regions are 64KB aligned.
|
||||
ctx->e.vaRegion &= 0x7fffffffffff0000;
|
||||
if(!VMM_UADDR64(ctx->e.vaRegion)) {
|
||||
return MmWin_MemCompress_LogError(H, ctx, "#46 InvalidRegionVA");
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -377,7 +377,7 @@ next_check:
|
||||
peVadEx->pte = pte;
|
||||
peVadEx->iPML = iPML;
|
||||
*piVadEx = *piVadEx + 1;
|
||||
if((iPML == 1) && (iPte < 0x3ff) && (iVadEx + 1 < pVadEx->cMap) && (peVadEx->va + 0x1000 == pVadEx->pMap[iVadEx + 1].va)) { goto next_entry; }
|
||||
if((iPML == 1) && (iPte < 0x1ff) && (iVadEx + 1 < pVadEx->cMap) && (peVadEx->va + 0x1000 == pVadEx->pMap[iVadEx + 1].va)) { goto next_entry; }
|
||||
Ob_DECREF(pObPTEs);
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -3,8 +3,8 @@
|
||||
|
||||
#define VERSION_MAJOR 5
|
||||
#define VERSION_MINOR 18
|
||||
#define VERSION_REVISION 2
|
||||
#define VERSION_BUILD 241
|
||||
#define VERSION_REVISION 3
|
||||
#define VERSION_BUILD 242
|
||||
|
||||
#define VER_FILE_DESCRIPTION_STR "MemProcFS : Core"
|
||||
#define VER_FILE_VERSION VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, VERSION_BUILD
|
||||
|
||||
+1
-1
@@ -649,7 +649,7 @@ DWORD VmmWinInit_FindNtosScan32(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSystemProc
|
||||
if(pNtHeader->Signature != IMAGE_NT_SIGNATURE) { continue; } // NT header signature
|
||||
for(o = 0; o < 0x800; o += 8) {
|
||||
if(*(PQWORD)(pb + ova + o) == 0x45444F434C4F4F50) { // POOLCODE
|
||||
if(!PE_GetModuleNameEx(H, pSystemProcess, (QWORD)vaBase + ova, FALSE, pb + ova, szModuleName, _countof(szModuleName), NULL)) {
|
||||
if(!PE_GetModuleNameEx(H, pSystemProcess, vaBase, FALSE, pb + ova, szModuleName, _countof(szModuleName), NULL)) {
|
||||
vaNtosTry = vaBase;
|
||||
continue;
|
||||
}
|
||||
|
||||
+1
-1
@@ -1284,7 +1284,7 @@ BOOL VmmWinObjFile_ReadAlloc(_In_ VMM_HANDLE H, _In_ POB_VMMWINOBJ_FILE pFile, _
|
||||
cbFile = VmmWinObjFile_Size(H, pFile, tp);
|
||||
if(!cbFile || (cbFile > 0x80000000)) { return FALSE; }
|
||||
if(cbFileMaxSize && (cbFile > cbFileMaxSize)) { return FALSE; }
|
||||
if(!(pbFile = LocalAlloc(LMEM_ZEROINIT, cbFile))) { return FALSE; }
|
||||
if(!(pbFile = LocalAlloc(LMEM_ZEROINIT, (SIZE_T)cbFile))) { return FALSE; }
|
||||
// read file:
|
||||
if(!(cbRead = VmmWinObjFile_Read(H, pFile, 0, pbFile, (DWORD)cbFile, fVmmRead, tp))) {
|
||||
LocalFree(pbFile);
|
||||
|
||||
+98
-35
@@ -15,7 +15,8 @@
|
||||
#include "vmmwin.h"
|
||||
#include "vmmwinobj.h"
|
||||
|
||||
#define REG_SIGNATURE_HBIN 0x6e696268
|
||||
#define REG_SIGNATURE_HBIN 0x6e696268
|
||||
#define VMMWINREG_KEY_MAX_DEPTH 0x200
|
||||
|
||||
typedef struct tdVMMWIN_REGISTRY_OFFSET {
|
||||
QWORD vaHintCMHIVE;
|
||||
@@ -214,7 +215,7 @@ VOID VmmWinReg_ReadScatter(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcessRegistry
|
||||
for(i = 0; i < cpMEMsReg; i++) {
|
||||
pMEM = ppMEMsReg[i];
|
||||
MEM_SCATTER_STACK_PUSH(pMEM, pMEM->qwA);
|
||||
if(pMEM->f || !VmmWinReg_Reg2Virt(H, pProcessRegistry, pRegistryHive, (DWORD)pMEM->qwA, &pMEM->qwA)) {
|
||||
if(pMEM->f || (pMEM->qwA > 0xffffffff) || !VmmWinReg_Reg2Virt(H, pProcessRegistry, pRegistryHive, (DWORD)pMEM->qwA, &pMEM->qwA)) {
|
||||
pMEM->qwA = -1;
|
||||
}
|
||||
}
|
||||
@@ -248,7 +249,7 @@ VOID VmmWinReg_ReadScatter(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcessRegistry
|
||||
}
|
||||
ctxHiveFileScatterRead.pFile = pObHiveFile;
|
||||
ctxHiveFileScatterRead.tp = VMMWINOBJ_FILE_TP_DATA | VMMWINOBJ_FILE_TP_CACHE;
|
||||
VmmWinObjFile_ReadScatter(H, &ctxHiveFileScatterRead, ppMEMsReg, cpMEMsReg, flags);
|
||||
VmmWinObjFile_ReadScatter(H, &ctxHiveFileScatterRead, ppMEMsFile, cMEMsFile, flags);
|
||||
for(i = 0; i < cMEMsFile; i++) {
|
||||
pMEM = ppMEMsFile[i];
|
||||
pMEM->qwA = MEM_SCATTER_STACK_POP(pMEM);
|
||||
@@ -279,7 +280,7 @@ VOID VmmWinReg_HiveReadEx(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pRegistryHiv
|
||||
PMEM_SCATTER pMEMs, *ppMEMs;
|
||||
QWORD i, oVA;
|
||||
if(pcbReadOpt) { *pcbReadOpt = 0; }
|
||||
if(!cb) { return; }
|
||||
if(!cb || (cb >= 0x80000000) || ((QWORD)cb > 0x100000000ULL - ra)) { return; }
|
||||
cMEMs = (DWORD)(((ra & 0xfff) + cb + 0xfff) >> 12);
|
||||
pbBuffer = (PBYTE)LocalAlloc(LMEM_ZEROINIT, 0x2000 + cMEMs * (sizeof(MEM_SCATTER) + sizeof(PMEM_SCATTER)));
|
||||
if(!pbBuffer) {
|
||||
@@ -365,7 +366,7 @@ BOOL VmmWinReg_HiveWrite(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pRegistryHive
|
||||
DWORD cbWrite;
|
||||
BOOL fSuccess = TRUE;
|
||||
PVMM_PROCESS pObProcessRegistry = NULL;
|
||||
if(!cb || !(pObProcessRegistry = VmmWinReg_GetRegistryProcess(H))) { return FALSE; }
|
||||
if(!cb || ((QWORD)cb > 0x100000000ULL - ra) || !(pObProcessRegistry = VmmWinReg_GetRegistryProcess(H))) { return FALSE; }
|
||||
while(cb) {
|
||||
cbWrite = min(cb, 0x1000 - (ra & 0xfff));
|
||||
if(VmmWinReg_Reg2Virt(H, pObProcessRegistry, pRegistryHive, ra, &vaWrite) && vaWrite) {
|
||||
@@ -690,6 +691,8 @@ BOOL VmmWinReg_LocateRegistryHive(_In_ VMM_HANDLE H)
|
||||
}
|
||||
}
|
||||
}
|
||||
LcMemFree(ppMEMs);
|
||||
ppMEMs = NULL;
|
||||
}
|
||||
}
|
||||
// 2: As a fallback - try locate registry by scanning lower physical memory.
|
||||
@@ -887,7 +890,7 @@ VOID VmmWinReg_EnumHive32_Post(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _I
|
||||
pHiveMap &&
|
||||
(*(PDWORD)(pbData + po->CM.Signature) == 0xBEE0BEE0) && // Signature match
|
||||
!(*(PDWORD)(pbData + po->CM.BaseBlock) & 0xfff) && // _CMHIVE.BaseBlock on page boundary
|
||||
(*(PQWORD)(pbData + po->CM.StorageMap0)) && // _CMHIVE.Hive.Storage.Map
|
||||
(*(PDWORD)(pbData + po->CM.StorageMap0)) && // _CMHIVE.Hive.Storage.Map
|
||||
(*(PDWORD)(pbData + po->CM.Length0)) && // Length > 0
|
||||
(*(PDWORD)(pbData + po->CM.Length0) <= 0x40000000); // Length < 1GB
|
||||
if(!f) { return; }
|
||||
@@ -960,8 +963,9 @@ VOID VmmWinReg_EnumHive32_Post(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _I
|
||||
(szHiveFileNameShort[0] ? szHiveFileNameShort : "unknown"),
|
||||
(szHiveFileNameLong[0] ? szHiveFileNameLong : "unknown"));
|
||||
// 4: Attach and Return
|
||||
ObMap_Push(pHiveMap, pObHive->vaCMHIVE, pObHive); // pRegistry->pmHive takes responsibility for pObHive reference
|
||||
ObMap_Push(pHiveMap, pObHive->vaCMHIVE, pObHive);
|
||||
VmmLog(H, MID_REGISTRY, LOGLEVEL_DEBUG, "HIVE_ENUM: %04i: %s", ObMap_Size(pHiveMap), pObHive->uszName);
|
||||
Ob_DECREF(pObHive);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1071,6 +1075,8 @@ BOOL VmmWinReg_HiveSnapshotEnsure(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHiv
|
||||
if(!pHive) { return FALSE; }
|
||||
if(pHive->Snapshot.fInitialized) { return TRUE; }
|
||||
if(pHive->cbLength > 0x10000000) { return FALSE; } // max 256MB hive
|
||||
if((pHive->_DUAL[0].cb & 0xfff) || (pHive->_DUAL[0].cb > 0x10000000) || (pHive->_DUAL[0].cb < 0x1000)) { return FALSE; }
|
||||
if((pHive->_DUAL[1].cb & 0xfff) || (pHive->_DUAL[1].cb > 0x10000000)) { return FALSE; }
|
||||
// 2: lock and retry retrieve cached
|
||||
EnterCriticalSection(&pHive->LockUpdate);
|
||||
if(pHive->Snapshot.fInitialized) {
|
||||
@@ -1323,7 +1329,7 @@ DWORD VmmWinReg_KeyHashName(_In_ PREG_CM_KEY_NODE pnk, _In_ DWORD iSuffix)
|
||||
CharUtil_FixFsName(uszBuffer, sizeof(uszBuffer), NULL, NULL, pnk->wszName, pnk->NameLength, iSuffix, TRUE);
|
||||
if(c) { c--; }
|
||||
for(i = 0; i < c; i++) {
|
||||
dwHash = ((dwHash >> 13) | (dwHash << 19)) + uszBuffer[i];
|
||||
dwHash = ((dwHash >> 13) | (dwHash << 19)) + (UCHAR)uszBuffer[i];
|
||||
}
|
||||
return dwHash;
|
||||
}
|
||||
@@ -1417,7 +1423,7 @@ POB_REGISTRY_KEY VmmWinReg_KeyInitializeCreateKey(_In_ VMM_HANDLE H, _In_ POB_RE
|
||||
// 3: get parent key
|
||||
pObKeyParent = ObMap_GetByKey(pHive->Snapshot.pmKeyOffset, pnk->Parent);
|
||||
if(!pObKeyParent) {
|
||||
if(iLevel < 0x10) {
|
||||
if(iLevel < VMMWINREG_KEY_MAX_DEPTH - 1) {
|
||||
pObKeyParent = VmmWinReg_KeyInitializeCreateKey(H, pHive, pnk->Parent, iLevel + 1);
|
||||
}
|
||||
if(!pObKeyParent) {
|
||||
@@ -1508,17 +1514,25 @@ POB_REGISTRY_KEY VmmWinReg_KeyInitializeRootKeyDummy(_In_ VMM_HANDLE H, _In_ POB
|
||||
_Success_(return)
|
||||
BOOL VmmWinReg_KeyInitializeRootKey(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive)
|
||||
{
|
||||
BOOL f;
|
||||
PREG_CM_KEY_NODE pnk;
|
||||
DWORD i, oRootKey = -1, cbCell, cbKey;
|
||||
DWORD i, oRootKey = -1, cbCell, cbKey, cbSnapshot, cbFirstPage;
|
||||
QWORD qwKeyRootHash = 0;
|
||||
cbSnapshot = pHive->Snapshot._DUAL[0].cb;
|
||||
cbFirstPage = min(cbSnapshot, 0x1000);
|
||||
// 1: get root key offset from regf-header (this is most often 0x20)
|
||||
if(!VmmRead(H, PVMM_PROCESS_SYSTEM, pHive->vaHBASE_BLOCK + 0x24, (PBYTE)&oRootKey, sizeof(DWORD)) || !oRootKey || (oRootKey > pHive->Snapshot._DUAL[0].cb - REG_CM_KEY_NODE_SIZEOF)) {
|
||||
f = !VmmRead(H, PVMM_PROCESS_SYSTEM, pHive->vaHBASE_BLOCK + 0x24, (PBYTE)&oRootKey, sizeof(DWORD)) ||
|
||||
!oRootKey ||
|
||||
(cbSnapshot < sizeof(DWORD) + REG_CM_KEY_NODE_SIZEOF) ||
|
||||
(oRootKey > cbSnapshot - sizeof(DWORD) - REG_CM_KEY_NODE_SIZEOF);
|
||||
if(f) {
|
||||
// regf base block unreadable or corrupt - try locate root key in 1st hive page
|
||||
oRootKey = -1;
|
||||
i = 0x20;
|
||||
while(TRUE) {
|
||||
while((i <= cbFirstPage) && (sizeof(DWORD) <= cbFirstPage - i)) {
|
||||
cbCell = REG_CELL_SIZE_EX(pHive->Snapshot._DUAL[0].pb, i);
|
||||
cbKey = (cbCell > 4) ? cbCell - 4 : 0;
|
||||
if((cbKey < sizeof(REG_CM_KEY_NODE)) || (i + cbCell > 0x1000)) { break; }
|
||||
if((cbKey < sizeof(REG_CM_KEY_NODE)) || (cbCell > cbFirstPage - i)) { break; }
|
||||
pnk = (PREG_CM_KEY_NODE)(pHive->Snapshot._DUAL[0].pb + i + 4);
|
||||
if((pnk->Signature != REG_CM_KEY_SIGNATURE_KEYNODE) || !(pnk->Flags & REG_CM_KEY_NODE_FLAGS_HIVE_ENTRY) || !(pnk->Flags & REG_CM_KEY_NODE_FLAGS_COMP_NAME)) {
|
||||
i += cbCell;
|
||||
@@ -1562,7 +1576,7 @@ BOOL VmmWinReg_KeyInitialize(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive)
|
||||
}
|
||||
cbHbin = *(PDWORD)(pHive->Snapshot._DUAL[iSV].pb + iHbin + 8);
|
||||
cbHbin = min(cbHbin, pHive->Snapshot._DUAL[iSV].cb - iHbin);
|
||||
if((cbHbin & 0xfff) || (cbHbin > 0x10000)) { cbHbin = 0x1000; }
|
||||
if((cbHbin < 0x1000) || (cbHbin & 0xfff) || (cbHbin > 0x10000)) { cbHbin = 0x1000; }
|
||||
oCell = 0x20;
|
||||
while(oCell + 4 < cbHbin) {
|
||||
cbCell = REG_CELL_SIZE_EX(pHive->Snapshot._DUAL[iSV].pb, (QWORD)iHbin + oCell);
|
||||
@@ -1672,7 +1686,7 @@ VOID VmmWinReg_ValueQueryInternal_BigDataCell(_In_ POB_REGISTRY_HIVE pHive, _In_
|
||||
cbDataCell = REG_CELL_SIZE_EX(pbSnapshot, oDataCellRaw);
|
||||
f = (cbDataCell <= cbSnapshot - oDataCellRaw) &&
|
||||
(cbDataCell <= REG_CM_BIGDATA_SEGMENT_CELL_SIZE) &&
|
||||
(cbDataCell > 8) &&
|
||||
(cbDataCell >= 8) &&
|
||||
!(!fDataCellLast && (cbDataCell != REG_CM_BIGDATA_SEGMENT_CELL_SIZE));
|
||||
if(!f) { return; }
|
||||
cbDataCellPayload = cbDataCell - 4;
|
||||
@@ -1734,7 +1748,7 @@ BOOL VmmWinReg_ValueQueryInternal_BigDataList(_In_ POB_REGISTRY_HIVE pHive, _In_
|
||||
);
|
||||
if(pbData) { pbData += cbReadDataCell; }
|
||||
cbData -= cbReadDataCell;
|
||||
cbDataOffset -= min(cbReadDataCell, cbDataOffset);
|
||||
cbDataOffset = 0;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
@@ -1757,7 +1771,10 @@ BOOL VmmWinReg_ValueQueryInternal(_In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTR
|
||||
*pdwLength = cbDataLength;
|
||||
}
|
||||
if(!pbData) { goto success; }
|
||||
if(!cbData || (cbDataOffset >= cbDataLength)) { return FALSE; }
|
||||
if(!cbData || (cbDataOffset >= cbDataLength)) {
|
||||
if(cbDataOffset == cbDataLength) { goto success; }
|
||||
return FALSE;
|
||||
}
|
||||
cbDataRead = min(cbData, cbDataLength - cbDataOffset);
|
||||
if(pKeyValue->pValue->DataLength & 0x80000000) {
|
||||
// "small data" stored within keyvalue
|
||||
@@ -1772,11 +1789,13 @@ BOOL VmmWinReg_ValueQueryInternal(_In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTR
|
||||
if(cbCell < 8) { return FALSE; }
|
||||
// "big data" table
|
||||
if(*(PWORD)(pHive->Snapshot._DUAL[iCellSV].pb + oCellRaw + 4) == REG_CM_KEY_SIGNATURE_BIGDATA) {
|
||||
return VmmWinReg_ValueQueryInternal_BigDataList(
|
||||
pHive,
|
||||
*(PWORD)(pHive->Snapshot._DUAL[iCellSV].pb + oCellRaw + 4 + 2),
|
||||
*(PDWORD)(pHive->Snapshot._DUAL[iCellSV].pb + oCellRaw + 4 + 4),
|
||||
pbData, cbDataRead, pcbDataRead, cbDataOffset);
|
||||
if((cbDataLength > REG_CM_BIGDATA_SEGMENT_DATA_SIZE) && (cbCell >= 4 + sizeof(WORD) + sizeof(WORD) + sizeof(DWORD))) {
|
||||
return VmmWinReg_ValueQueryInternal_BigDataList(
|
||||
pHive,
|
||||
*(PWORD)(pHive->Snapshot._DUAL[iCellSV].pb + oCellRaw + 4 + 2),
|
||||
*(PDWORD)(pHive->Snapshot._DUAL[iCellSV].pb + oCellRaw + 4 + 4),
|
||||
pbData, cbDataRead, pcbDataRead, cbDataOffset);
|
||||
}
|
||||
}
|
||||
// "ordinary" data
|
||||
if(cbDataOffset > cbCell - 4) { return FALSE; }
|
||||
@@ -1794,6 +1813,24 @@ success:
|
||||
// EXTERNAL REGISTRY KEY AND VALUE FUNCTIONALITY:
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* Check whether a string contains an exact '-' delimited token.
|
||||
*/
|
||||
BOOL VmmWinReg_StrContainsDelimitedToken(_In_ LPCSTR usz, _In_ LPCSTR uszToken)
|
||||
{
|
||||
LPCSTR uszStart = usz;
|
||||
SIZE_T cchToken = strlen(uszToken);
|
||||
while(*usz) {
|
||||
if(((usz == uszStart) || (usz[-1] == '-')) &&
|
||||
!_strnicmp(usz, uszToken, cchToken) &&
|
||||
(!usz[cchToken] || (usz[cchToken] == '-'))) {
|
||||
return TRUE;
|
||||
}
|
||||
usz++;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve registry hive and key/value path from a "full" path starting with:
|
||||
* '0x...', 'by-hive\0x...' or 'HKLM\'
|
||||
@@ -1809,7 +1846,7 @@ BOOL VmmWinReg_PathHiveGetByFullPath(_In_ VMM_HANDLE H, _In_ LPCSTR uszPathFull,
|
||||
{
|
||||
BOOL fHKLM = FALSE, fUser = FALSE, fUserSystem = FALSE, fOrphan = FALSE;
|
||||
DWORD i;
|
||||
LPCSTR usz, uszPath2;
|
||||
LPCSTR usz, uszPath2, uszHiveNameLast;
|
||||
CHAR uszPath1[MAX_PATH];
|
||||
POB_REGISTRY_HIVE pObHive = NULL;
|
||||
POB_REGISTRY_KEY pObKey = NULL;
|
||||
@@ -1849,13 +1886,15 @@ BOOL VmmWinReg_PathHiveGetByFullPath(_In_ VMM_HANDLE H, _In_ LPCSTR uszPathFull,
|
||||
}
|
||||
if(fHKLM) {
|
||||
while((pObHive = VmmWinReg_HiveGetNext(H, pObHive))) {
|
||||
if(CharUtil_StrContains(pObHive->uszNameShort, uszPath1, TRUE)) {
|
||||
uszHiveNameLast = CharUtil_PathSplitLast(pObHive->uszNameShort);
|
||||
if(CharUtil_StrEquals(uszHiveNameLast, uszPath1, TRUE)) {
|
||||
*ppHive = pObHive;
|
||||
return TRUE; // CALLER DECREF: *ppHive
|
||||
}
|
||||
}
|
||||
while((pObHive = VmmWinReg_HiveGetNext(H, pObHive))) {
|
||||
if(CharUtil_StrContains(pObHive->uszHiveRootPath, uszPath1, TRUE)) {
|
||||
uszHiveNameLast = CharUtil_PathSplitLast(pObHive->uszHiveRootPath);
|
||||
if(CharUtil_StrEquals(uszHiveNameLast, uszPath1, TRUE)) {
|
||||
*ppHive = pObHive;
|
||||
return TRUE; // CALLER DECREF: *ppHive
|
||||
}
|
||||
@@ -2021,7 +2060,7 @@ VOID VmmWinReg_KeyInfo2(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive, _In_ PO
|
||||
int status;
|
||||
DWORD cuszPath = 0;
|
||||
CHAR szHiveShortName[33] = { 0 };
|
||||
CHAR uszPath[MAX_PATH] = { 0 };
|
||||
CHAR uszPath[MAX_PATH*2] = { 0 };
|
||||
VmmWinReg_KeyInfo(pHive, pKey, pKeyInfo);
|
||||
if(!(ps = ObSet_New(H))) { return; }
|
||||
ObSet_Push(ps, (QWORD)Ob_INCREF(pKey));
|
||||
@@ -2046,6 +2085,9 @@ VOID VmmWinReg_KeyInfo2(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive, _In_ PO
|
||||
cuszPath += status;
|
||||
}
|
||||
}
|
||||
while((pObKey = (POB_REGISTRY_KEY)ObSet_Pop(ps))) {
|
||||
Ob_DECREF(pObKey);
|
||||
}
|
||||
Ob_DECREF(ps);
|
||||
if(cuszPath) {
|
||||
pKeyInfo->cbuName = cuszPath + 1;
|
||||
@@ -2158,6 +2200,7 @@ BOOL VmmWinReg_ValueQuery1(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive, _In_
|
||||
POB_REGISTRY_KEY pObKey = NULL;
|
||||
POB_REGISTRY_VALUE pObKeyValue = NULL;
|
||||
if(pcbRead) { *pcbRead = 0; }
|
||||
if(pb && (cbOffset > 0xffffffff)) { return FALSE; }
|
||||
f = VmmWinReg_HiveSnapshotEnsure(H, pHive) &&
|
||||
(uszValueName = CharUtil_PathSplitLastEx(uszPathKeyValue, uszPathKey, sizeof(uszPathKey))) &&
|
||||
(pObKey = VmmWinReg_KeyGetByPath(H, pHive, uszPathKey)) &&
|
||||
@@ -2222,7 +2265,9 @@ _Success_(return)
|
||||
BOOL VmmWinReg_ValueQuery4(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_VALUE pKeyValue, _Out_opt_ PDWORD pdwType, _Out_writes_opt_(cbData) PBYTE pbData, _In_ DWORD cbData, _Out_opt_ PDWORD pcbData)
|
||||
{
|
||||
if(VmmWinReg_HiveSnapshotEnsure(H, pHive)) {
|
||||
return VmmWinReg_ValueQueryInternal(pHive, pKeyValue, pdwType, NULL, NULL, pbData, cbData, pcbData, 0);
|
||||
return pbData
|
||||
? VmmWinReg_ValueQueryInternal(pHive, pKeyValue, pdwType, NULL, NULL, pbData, cbData, pcbData, 0)
|
||||
: VmmWinReg_ValueQueryInternal(pHive, pKeyValue, pdwType, NULL, pcbData, NULL, 0, NULL, 0);
|
||||
}
|
||||
if(pdwType) { *pdwType = 0; }
|
||||
if(pcbData) { *pcbData = 0; }
|
||||
@@ -2272,10 +2317,11 @@ BOOL VmmWinReg_ValueQueryString4(_In_ VMM_HANDLE H, _In_ POB_REGISTRY_HIVE pHive
|
||||
DWORD cbRegData = 0, cbRegDataRead = 0;
|
||||
if(!cbuData) { goto fail; }
|
||||
uszData[0] = 0;
|
||||
if(sizeof(pbRegDataBuffer) < cbuData * 2) {
|
||||
if(cbuData <= sizeof(pbRegDataBuffer) / 2) {
|
||||
cbRegData = sizeof(pbRegDataBuffer);
|
||||
pbRegData = pbRegDataBuffer;
|
||||
} else {
|
||||
if(cbuData > 0x01000000) { goto fail; }
|
||||
cbRegData = cbuData * 2;
|
||||
pbRegData = LocalAlloc(0, cbRegData);
|
||||
if(!pbRegData) { goto fail; }
|
||||
@@ -2305,10 +2351,11 @@ BOOL VmmWinReg_ValueQueryString2(_In_ VMM_HANDLE H, _In_ LPCSTR uszFullPathKeyVa
|
||||
DWORD cbRegData = 0, cbRegDataRead = 0;
|
||||
if(!cbuData) { goto fail; }
|
||||
uszData[0] = 0;
|
||||
if(sizeof(pbRegDataBuffer) < cbuData * 2) {
|
||||
if(cbuData <= sizeof(pbRegDataBuffer) / 2) {
|
||||
cbRegData = sizeof(pbRegDataBuffer);
|
||||
pbRegData = pbRegDataBuffer;
|
||||
} else {
|
||||
if(cbuData > 0x01000000) { goto fail; }
|
||||
cbRegData = cbuData * 2;
|
||||
pbRegData = LocalAlloc(0, cbRegData);
|
||||
if(!pbRegData) { goto fail; }
|
||||
@@ -2328,18 +2375,30 @@ fail:
|
||||
* -- uszHivePrefix
|
||||
* -- uszHiveName
|
||||
* -- uszFullPath
|
||||
* -- return
|
||||
*/
|
||||
VOID VmmWinReg_KeyFullPath(_In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_KEY pKey, _In_ LPSTR uszHivePrefix, _In_ LPSTR uszHiveName, _Out_writes_(1024) LPSTR uszFullPath)
|
||||
_Success_(return)
|
||||
BOOL VmmWinReg_KeyFullPath(_In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_KEY pKey, _In_ LPSTR uszHivePrefix, _In_ LPSTR uszHiveName, _Out_writes_(1024) LPSTR uszFullPath)
|
||||
{
|
||||
CONST BYTE pbTEXT_ROOT[] = { '\\', 0, 'R', 0, 'O', 0, 'O', 0, 'T', 0 };
|
||||
BOOL fResult = TRUE, fSkip = TRUE;
|
||||
SIZE_T cch;
|
||||
DWORD o = 0, iKey = 0, cbName;
|
||||
POB_REGISTRY_KEY pk, ppObKey[0x40];
|
||||
// fetch parents (max depth: 0x40)
|
||||
POB_REGISTRY_KEY pk, pObKeyParent, ppObKey[VMMWINREG_KEY_MAX_DEPTH + 1];
|
||||
// fetch parents (max registry depth + synthetic ROOT)
|
||||
ppObKey[iKey++] = Ob_INCREF(pKey);
|
||||
while((iKey < 0x40) && (ppObKey[iKey] = ObMap_GetByKey(pHive->Snapshot.pmKeyHash, ppObKey[iKey - 1]->qwHashKeyParent))) {
|
||||
iKey++;
|
||||
while(iKey < _countof(ppObKey)) {
|
||||
pObKeyParent = ObMap_GetByKey(pHive->Snapshot.pmKeyHash, ppObKey[iKey - 1]->qwHashKeyParent);
|
||||
if(!pObKeyParent) { break; }
|
||||
ppObKey[iKey++] = pObKeyParent;
|
||||
}
|
||||
// reject malformed paths deeper than the supported registry maximum
|
||||
if(iKey == _countof(ppObKey)) {
|
||||
pObKeyParent = ObMap_GetByKey(pHive->Snapshot.pmKeyHash, ppObKey[iKey - 1]->qwHashKeyParent);
|
||||
if(pObKeyParent) {
|
||||
Ob_DECREF(pObKeyParent);
|
||||
fResult = FALSE;
|
||||
}
|
||||
}
|
||||
// unwind, copy name
|
||||
cch = strlen(uszHivePrefix);
|
||||
@@ -2368,6 +2427,7 @@ VOID VmmWinReg_KeyFullPath(_In_ POB_REGISTRY_HIVE pHive, _In_ POB_REGISTRY_KEY p
|
||||
fSkip = FALSE;
|
||||
}
|
||||
uszFullPath[fResult ? o : 0] = 0;
|
||||
return fResult;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2419,7 +2479,10 @@ VOID VmmWinReg_ForensicGetAllKeysAndValues(
|
||||
c = ObMap_Size(pHive->Snapshot.pmKeyOffset);
|
||||
for(i = 0; ((i < c) && !H->fAbort); i++) {
|
||||
if((pObKey = ObMap_GetByIndex(pHive->Snapshot.pmKeyOffset, i))) {
|
||||
VmmWinReg_KeyFullPath(pHive, pObKey, uszHivePrefix, pHive->uszHiveRootPath + oHive, uszFullPath);
|
||||
if(!VmmWinReg_KeyFullPath(pHive, pObKey, uszHivePrefix, pHive->uszHiveRootPath + oHive, uszFullPath)) {
|
||||
Ob_DECREF(pObKey);
|
||||
continue;
|
||||
}
|
||||
// registry timeline:
|
||||
pfnKeyCB(H, hCallback1, hCallback2, uszFullPath, pHive->vaCMHIVE, pObKey->oCell, pObKey->pKey->Parent, pObKey->pKey->LastWriteTime);
|
||||
// registry json data:
|
||||
|
||||
+73
-42
@@ -150,7 +150,10 @@ VOID VmmWinSvc_ListHeadFromPDB(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pSvcProcess,
|
||||
if(!VmmRead(H, pSvcProcess, peModuleServices->vaBase + dwoSymSvcDB, pbSymSvcDB, sizeof(pbSymSvcDB))) { goto fail; }
|
||||
pvaListHead[0] = (QWORD)VMM_PTR_OFFSET_DUAL(f32, pbSymSvcDB, 4, 8);
|
||||
pvaListHead[1] = (QWORD)VMM_PTR_OFFSET_DUAL(f32, pbSymSvcDB, 8, 16);
|
||||
if(!VMM_UADDR_4_8(f32, pvaListHead[0]) || !VMM_UADDR_4_8(f32, pvaListHead[1])) { goto fail; }
|
||||
if(!VMM_UADDR_4_8(f32, pvaListHead[0]) || !VMM_UADDR_4_8(f32, pvaListHead[1])) {
|
||||
pvaListHead[0] = 0;
|
||||
pvaListHead[1] = 0;
|
||||
}
|
||||
fail:
|
||||
Ob_DECREF(pObModuleMap);
|
||||
}
|
||||
@@ -165,7 +168,7 @@ fail:
|
||||
VOID VmmWinSvc_ListHeadFromVAD(_In_ VMM_HANDLE H, _In_ PVMMWINSVC_CONTEXT ctx, _In_ PVMM_PROCESS pSvcProcess, _Inout_updates_(2) PQWORD pvaListHead)
|
||||
{
|
||||
BOOL f32 = H->vmm.f32;
|
||||
QWORD va1, va2;
|
||||
QWORD va1, va2, cbVad64;
|
||||
DWORD i, o, dwTag, cbVad;
|
||||
BYTE pb2[0x10], *pb = NULL;
|
||||
PVMM_MAP_VADENTRY pe;
|
||||
@@ -173,8 +176,9 @@ VOID VmmWinSvc_ListHeadFromVAD(_In_ VMM_HANDLE H, _In_ PVMMWINSVC_CONTEXT ctx, _
|
||||
if(!VmmMap_GetVad(H, pSvcProcess, &pObVadMap, VMM_VADMAP_TP_CORE)) { goto finish; }
|
||||
// 1: if address exist -> prefetch vad and finish
|
||||
if(pvaListHead[0] && (pe = VmmMap_GetVadEntry(H, pObVadMap, pvaListHead[0]))) {
|
||||
cbVad = (DWORD)(pe->vaEnd + 1 - pe->vaStart);
|
||||
if(cbVad <= 0x00200000) {
|
||||
if((pe->vaEnd >= pe->vaStart) && ((pe->vaEnd - pe->vaStart) < 0x00200000)) {
|
||||
cbVad64 = pe->vaEnd - pe->vaStart + 1;
|
||||
cbVad = (DWORD)cbVad64;
|
||||
VmmCachePrefetchPages4(H, pSvcProcess, 1, &pe->vaStart, cbVad, 0);
|
||||
}
|
||||
goto finish;
|
||||
@@ -184,16 +188,21 @@ VOID VmmWinSvc_ListHeadFromVAD(_In_ VMM_HANDLE H, _In_ PVMMWINSVC_CONTEXT ctx, _
|
||||
for(i = 0; i < pObVadMap->cMap; i++) {
|
||||
pe = pObVadMap->pMap + i;
|
||||
if(!pe->fPrivateMemory || (pe->CommitCharge < 0x10)) { continue; }
|
||||
cbVad = (DWORD)(pe->vaEnd + 1 - pe->vaStart);
|
||||
if((cbVad > 0x00200000) || (cbVad < 0x00010000)) { continue; }
|
||||
if(pe->vaEnd < pe->vaStart) { continue; }
|
||||
if((pe->vaEnd - pe->vaStart) >= 0x00200000) { continue; }
|
||||
cbVad64 = pe->vaEnd - pe->vaStart + 1;
|
||||
if(cbVad64 < 0x00010000) { continue; }
|
||||
cbVad = (DWORD)cbVad64;
|
||||
VmmReadEx(H, pSvcProcess, pe->vaStart, pb, cbVad, NULL, VMM_FLAG_ZEROPAD_ON_FAIL);
|
||||
dwTag = _byteswap_ulong(ctx->dwTag);
|
||||
for(o = 0x1000; o < 0x00200000; o += 4) {
|
||||
for(o = 0x1000; o <= cbVad - sizeof(DWORD); o += 4) {
|
||||
if(dwTag == *(PDWORD)(pb + o)) {
|
||||
if(ctx->fSc19) { // sErv / Sc19 entry - Win8.0+
|
||||
if((ctx->oSc19._Size > cbVad) || (o < ctx->oSc19.Tag) || ((o - ctx->oSc19.Tag) > cbVad - ctx->oSc19._Size)) { continue; }
|
||||
va1 = VMM_PTR_OFFSET(f32, pb + o - ctx->oSc19.Tag, ctx->oSc19.BLink);
|
||||
va2 = VMM_PTR_OFFSET(f32, pb + o - ctx->oSc19.Tag, ctx->oSc19.FLink);
|
||||
} else { // serH entry
|
||||
if(o > cbVad - (f32 ? 0x10 : 0x18)) { continue; }
|
||||
va1 = VMM_PTR_OFFSET_DUAL(f32, pb + o, 0x0c, 0x10); // TODO: verify 32-bit version
|
||||
if(!VMM_UADDR_4_8(f32, va1)) { continue; }
|
||||
if(!VmmRead(H, pSvcProcess, va1, pb2, 0x10)) { continue; }
|
||||
@@ -228,22 +237,23 @@ POB_MAP VmmWinSvc_MainListWalk(_In_ VMM_HANDLE H, _In_ PVMMWINSVC_CONTEXT ctx, _
|
||||
DWORD dwOrdinal, dwStartType;
|
||||
QWORD i, va, va1, va2, va3;
|
||||
BYTE pb[0x200] = { 0 };
|
||||
POB_SET psA = NULL;
|
||||
POB_SET psA = NULL, psSeen = NULL;
|
||||
POB_MAP pmSvc = NULL;
|
||||
PVMM_MAP_SERVICEENTRY pe;
|
||||
PVMMWINSVC_OFFSET_SC19 o = &ctx->oSc19;
|
||||
if(!(psA = ObSet_New(H))) { goto fail; }
|
||||
if(!(psSeen = ObSet_New(H))) { goto fail; }
|
||||
if(!(pmSvc = ObMap_New(H, OB_MAP_FLAGS_OBJECT_LOCALFREE))) { goto fail; }
|
||||
for(i = 0; i < cVaListHead; i++) {
|
||||
ObSet_Push(psA, pvaListHead[i]);
|
||||
}
|
||||
while((va = ObSet_Pop(psA))) {
|
||||
// read & sanity check
|
||||
if(ObMap_ExistsKey(pmSvc, va)) { continue; }
|
||||
if(!ObSet_Push(psSeen, va)) { continue; }
|
||||
if(!VmmRead(H, pProcessSvc, va, pb, o->_Size)) { continue; }
|
||||
if(o->fTag && !VMM_POOLTAG(*(PDWORD)(pb + o->Tag), o->TagV)) { continue; }
|
||||
if((dwOrdinal = *(PDWORD)(pb + o->Ordinal)) > 0xffff) { continue; }
|
||||
if((dwStartType = *(PDWORD)(pb + o->SvcTp)) > SERVICE_TYPE_ALL) { continue; }
|
||||
if((dwStartType = *(PDWORD)(pb + o->SvcTp)) > SERVICE_DISABLED) { continue; }
|
||||
// BLink / FLink
|
||||
va1 = VMM_PTR_OFFSET(f32, pb, o->BLink);
|
||||
va2 = VMM_PTR_OFFSET(f32, pb, o->FLink);
|
||||
@@ -252,15 +262,19 @@ POB_MAP VmmWinSvc_MainListWalk(_In_ VMM_HANDLE H, _In_ PVMMWINSVC_CONTEXT ctx, _
|
||||
if(!va1 && !va2) { continue; }
|
||||
ObSet_Push(psA, va1);
|
||||
ObSet_Push(psA, va2);
|
||||
if(!VMM_UADDR(f32, VMM_PTR_OFFSET(f32, pb, o->NmShort))) { continue; }
|
||||
va3 = VMM_PTR_OFFSET(f32, pb, o->NmShort);
|
||||
if((va3 < 0x10000) || !VMM_UADDR(f32, va3)) { continue; }
|
||||
// allocate & assign
|
||||
if(!(pe = LocalAlloc(LMEM_ZEROINIT, sizeof(VMM_MAP_SERVICEENTRY)))) { continue; }
|
||||
ObMap_Push(pmSvc, va, pe);
|
||||
if(!ObMap_Push(pmSvc, va, pe)) {
|
||||
LocalFree(pe);
|
||||
goto fail;
|
||||
}
|
||||
pe->vaObj = va;
|
||||
pe->dwOrdinal = dwOrdinal;
|
||||
pe->dwStartType = dwStartType;
|
||||
memcpy(&pe->ServiceStatus, pb + o->SvcStatus, sizeof(SERVICE_STATUS));
|
||||
pe->_vaReservedServiceName = VMM_PTR_OFFSET(f32, pb, o->NmShort);
|
||||
pe->_vaReservedServiceName = va3;
|
||||
pe->_vaReservedDisplayName = VMM_PTR_OFFSET(f32, pb, o->NmLong);
|
||||
if((pe->ServiceStatus.dwServiceType & SERVICE_KERNEL_DRIVER) || (pe->ServiceStatus.dwServiceType & SERVICE_FILE_SYSTEM_DRIVER)) {
|
||||
pe->_vaReservedPath = VMM_PTR_OFFSET(f32, pb, o->ExtInfo);
|
||||
@@ -272,6 +286,7 @@ POB_MAP VmmWinSvc_MainListWalk(_In_ VMM_HANDLE H, _In_ PVMMWINSVC_CONTEXT ctx, _
|
||||
Ob_INCREF(pmSvc);
|
||||
fail:
|
||||
Ob_DECREF(psA);
|
||||
Ob_DECREF(psSeen);
|
||||
return Ob_DECREF(pmSvc);
|
||||
}
|
||||
|
||||
@@ -323,26 +338,26 @@ VOID VmmWinSvc_GetExtendedInfo(_In_ VMM_HANDLE H, _In_ PVMMWINSVC_CONTEXT ctx, _
|
||||
* -- psm
|
||||
* -- puszText
|
||||
* -- qwA
|
||||
* -- fNullOnFail = set pwszText to NULL on fail (i.e. don't include in OB_STRMAP psm)
|
||||
* -- fNullOnFail = set puszText to NULL on fail (i.e. don't include in OB_STRMAP psm)
|
||||
* -- return
|
||||
*/
|
||||
VOID VmmWinSvc_ResolveStrAddSingle(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcessSvc, _In_ POB_STRMAP psm, _Out_ LPSTR *puszText, _In_ QWORD qwA, _In_ BOOL fNullOnFail)
|
||||
_Success_(return)
|
||||
BOOL VmmWinSvc_ResolveStrAddSingle(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcessSvc, _In_ POB_STRMAP psm, _Out_ LPSTR *puszText, _In_ QWORD qwA, _In_ BOOL fNullOnFail)
|
||||
{
|
||||
WCHAR wsz[2048] = { 0 };
|
||||
*puszText = NULL;
|
||||
if((qwA < 0x10000) || !VMM_UADDR(H->vmm.f32, qwA)) { goto fail; }
|
||||
VmmRead2(H, pProcessSvc, qwA, (PBYTE)wsz, sizeof(wsz) - 2, VMM_FLAG_FORCECACHE_READ);
|
||||
if(!VmmRead2(H, pProcessSvc, qwA, (PBYTE)wsz, sizeof(wsz) - 2, VMM_FLAG_FORCECACHE_READ)) { goto fail; }
|
||||
if(!wsz[0]) { goto fail; }
|
||||
if(wsz[0] > 0xff || wsz[1] > 0xff || wsz[2] > 0xff) { goto fail; }
|
||||
ObStrMap_PushPtrWU(psm, wsz, puszText, NULL);
|
||||
return;
|
||||
return ObStrMap_PushPtrWU(psm, wsz, puszText, NULL);
|
||||
fail:
|
||||
if(fNullOnFail) {
|
||||
*puszText = NULL;
|
||||
} else {
|
||||
ObStrMap_PushPtrWU(psm, NULL, puszText, NULL);
|
||||
}
|
||||
if(fNullOnFail) { return TRUE; }
|
||||
return ObStrMap_PushPtrWU(psm, NULL, puszText, NULL);
|
||||
}
|
||||
|
||||
VOID VmmWinSvc_ResolveStrRegistry(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcessSvc, _In_ PVMMOB_MAP_SERVICE pSvcMap, _In_ POB_STRMAP psm)
|
||||
_Success_(return)
|
||||
BOOL VmmWinSvc_ResolveStrRegistry(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcessSvc, _In_ PVMMOB_MAP_SERVICE pSvcMap, _In_ POB_STRMAP psm)
|
||||
{
|
||||
DWORD i, dwType, cbData = 0;
|
||||
PVMM_MAP_SERVICEENTRY pe;
|
||||
@@ -355,17 +370,21 @@ VOID VmmWinSvc_ResolveStrRegistry(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcessS
|
||||
cbData = 0;
|
||||
if(pObHive) {
|
||||
_snprintf_s(usz, MAX_PATH, _TRUNCATE, "ROOT\\ControlSet001\\Services\\%s\\parameters\\ServiceDll", pe->uszServiceName);
|
||||
if(!VmmWinReg_ValueQuery3(H, pObHive, usz, &dwType, (PBYTE)wsz, MAX_PATH * 2, &cbData) || (dwType != REG_EXPAND_SZ)) {
|
||||
if(!VmmWinReg_ValueQuery3(H, pObHive, usz, &dwType, (PBYTE)wsz, MAX_PATH * 2, &cbData) || ((dwType != REG_SZ) && (dwType != REG_EXPAND_SZ))) {
|
||||
_snprintf_s(usz, MAX_PATH, _TRUNCATE, "ROOT\\ControlSet001\\Services\\%s\\ImagePath", pe->uszServiceName);
|
||||
if(!VmmWinReg_ValueQuery3(H, pObHive, usz, &dwType, (PBYTE)wsz, MAX_PATH * 2, &cbData) || (dwType != REG_EXPAND_SZ)) {
|
||||
if(!VmmWinReg_ValueQuery3(H, pObHive, usz, &dwType, (PBYTE)wsz, MAX_PATH * 2, &cbData) || ((dwType != REG_SZ) && (dwType != REG_EXPAND_SZ))) {
|
||||
cbData = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
wsz[cbData >> 1] = 0;
|
||||
ObStrMap_PushPtrWU(psm, wsz, &pe->uszImagePath, NULL);
|
||||
if(!ObStrMap_PushPtrWU(psm, wsz, &pe->uszImagePath, NULL)) {
|
||||
Ob_DECREF(pObHive);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
Ob_DECREF(pObHive);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -379,7 +398,7 @@ _Success_(return)
|
||||
BOOL VmmWinSvc_ResolveStrAll(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcessSvc, _In_ PVMMOB_MAP_SERVICE pSvcMap)
|
||||
{
|
||||
DWORD i;
|
||||
BOOL fProcessUser;
|
||||
BOOL fFail, fProcessUser;
|
||||
CHAR usz[MAX_PATH];
|
||||
PVMM_PROCESS pObProcessUser = NULL;
|
||||
PVMM_MAP_SERVICEENTRY pe;
|
||||
@@ -403,11 +422,16 @@ BOOL VmmWinSvc_ResolveStrAll(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcessSvc, _
|
||||
// 3.1: fetch strings - general
|
||||
for(i = 0; i < pSvcMap->cMap; i++) {
|
||||
pe = pSvcMap->pMap + i;
|
||||
VmmWinSvc_ResolveStrAddSingle(H, pProcessSvc, pObStrMap, &pe->uszServiceName, pe->_vaReservedServiceName, FALSE);
|
||||
VmmWinSvc_ResolveStrAddSingle(H, pProcessSvc, pObStrMap, &pe->uszDisplayName, pe->_vaReservedDisplayName, FALSE);
|
||||
VmmWinSvc_ResolveStrAddSingle(H, pProcessSvc, pObStrMap, &pe->uszPath, pe->_vaReservedPath, FALSE);
|
||||
VmmWinSvc_ResolveStrAddSingle(H, pProcessSvc, pObStrMap, &pe->uszUserTp, pe->_vaReservedUserTp, FALSE);
|
||||
VmmWinSvc_ResolveStrAddSingle(H, pProcessSvc, pObStrMap, &pe->uszUserAcct, pe->_vaReservedUserAcct, TRUE);
|
||||
fFail =
|
||||
!VmmWinSvc_ResolveStrAddSingle(H, pProcessSvc, pObStrMap, &pe->uszServiceName, pe->_vaReservedServiceName, FALSE) ||
|
||||
!VmmWinSvc_ResolveStrAddSingle(H, pProcessSvc, pObStrMap, &pe->uszDisplayName, pe->_vaReservedDisplayName, FALSE) ||
|
||||
!VmmWinSvc_ResolveStrAddSingle(H, pProcessSvc, pObStrMap, &pe->uszPath, pe->_vaReservedPath, FALSE) ||
|
||||
!VmmWinSvc_ResolveStrAddSingle(H, pProcessSvc, pObStrMap, &pe->uszUserTp, pe->_vaReservedUserTp, FALSE) ||
|
||||
!VmmWinSvc_ResolveStrAddSingle(H, pProcessSvc, pObStrMap, &pe->uszUserAcct, pe->_vaReservedUserAcct, TRUE);
|
||||
if(fFail) {
|
||||
Ob_DECREF(pObStrMap);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
// 3.2: fetch strings - user (if does not exist already)
|
||||
for(i = 0; i < pSvcMap->cMap; i++) {
|
||||
@@ -418,15 +442,21 @@ BOOL VmmWinSvc_ResolveStrAll(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcessSvc, _
|
||||
(pObProcessUser = VmmProcessGetEx(H, NULL, pe->dwPID, VMM_FLAG_PROCESS_TOKEN)) &&
|
||||
pObProcessUser->win.Token && pObProcessUser->win.Token->fSidUserValid &&
|
||||
VmmWinUser_GetName(H, &pObProcessUser->win.Token->SidUser.SID, usz, sizeof(usz), NULL);
|
||||
ObStrMap_PushPtrUU(pObStrMap, fProcessUser ? usz : NULL, &pe->uszUserAcct, NULL);
|
||||
fFail = !ObStrMap_PushPtrUU(pObStrMap, fProcessUser ? usz : NULL, &pe->uszUserAcct, NULL);
|
||||
Ob_DECREF_NULL(&pObProcessUser);
|
||||
if(fFail) {
|
||||
Ob_DECREF(pObStrMap);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 3.3: fetch strings - image path from registry
|
||||
VmmWinSvc_ResolveStrRegistry(H, pProcessSvc, pSvcMap, pObStrMap);
|
||||
if(!VmmWinSvc_ResolveStrRegistry(H, pProcessSvc, pSvcMap, pObStrMap)) {
|
||||
Ob_DECREF(pObStrMap);
|
||||
return FALSE;
|
||||
}
|
||||
// 4: resolve strmap and return
|
||||
ObStrMap_FinalizeAllocU_DECREF_NULL(&pObStrMap, &pSvcMap->pbMultiText, &pSvcMap->cbMultiText);
|
||||
return TRUE;
|
||||
return ObStrMap_FinalizeAllocU_DECREF_NULL(&pObStrMap, &pSvcMap->pbMultiText, &pSvcMap->cbMultiText);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -444,10 +474,11 @@ VOID VmmWinSvc_CloseObCallback(_In_ PVOID pVmmServiceMap)
|
||||
*/
|
||||
int VmmWinSvc_CmpSort(PVMM_MAP_SERVICEENTRY a, PVMM_MAP_SERVICEENTRY b)
|
||||
{
|
||||
if(a->dwOrdinal != b->dwOrdinal) {
|
||||
return a->dwOrdinal - b->dwOrdinal;
|
||||
}
|
||||
return (int)(a->vaObj - b->vaObj);
|
||||
if(a->dwOrdinal < b->dwOrdinal) { return -1; }
|
||||
if(a->dwOrdinal > b->dwOrdinal) { return 1; }
|
||||
if(a->vaObj < b->vaObj) { return -1; }
|
||||
if(a->vaObj > b->vaObj) { return 1; }
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -491,7 +522,7 @@ PVMMOB_MAP_SERVICE VmmWinSvc_Initialize_DoWork(_In_ VMM_HANDLE H)
|
||||
VmmWinSvc_GetExtendedInfo(H, &InitCtx, pObSvcProcess, pmObSvc);
|
||||
// 3: allocate, assign and sort services map
|
||||
cSvc = ObMap_Size(pmObSvc);
|
||||
if(!(pObServiceMap = Ob_AllocEx(H, OB_TAG_MAP_SERVICE, 0, sizeof(VMMOB_MAP_SERVICE) + cSvc * sizeof(VMM_MAP_SERVICEENTRY), VmmWinSvc_CloseObCallback, NULL))) { goto fail; }
|
||||
if(!(pObServiceMap = Ob_AllocEx(H, OB_TAG_MAP_SERVICE, LMEM_ZEROINIT, sizeof(VMMOB_MAP_SERVICE) + cSvc * sizeof(VMM_MAP_SERVICEENTRY), VmmWinSvc_CloseObCallback, NULL))) { goto fail; }
|
||||
pObServiceMap->cMap = cSvc;
|
||||
for(i = 0; i < cSvc; i++) {
|
||||
if((pe = ObMap_GetByIndex(pmObSvc, i))) {
|
||||
|
||||
+7
-7
@@ -491,6 +491,7 @@ BOOL VmmWinThreadCs_RspUnwinder(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _
|
||||
//Restoring former stack allocation, (the number of bytes is given by new slot and carried by FrameOffset)
|
||||
case UWOP_ALLOC_LARGE:
|
||||
if(pUnwindCodes[dwUnwdIter].OpInfo == 0x00) {
|
||||
if(dwNbslot - dwUnwdIter < 2) { goto end; }
|
||||
offset = (PFRAME_OFFSET_SH)&pUnwindCodes[dwUnwdIter + 1];
|
||||
FrameOffset = (offset->FrameOffset)*8;
|
||||
qwCurrentRSP = qwCurrentRSP + FrameOffset;
|
||||
@@ -499,6 +500,7 @@ BOOL VmmWinThreadCs_RspUnwinder(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _
|
||||
break;
|
||||
}
|
||||
else if(pUnwindCodes[dwUnwdIter].OpInfo == 0x01) {
|
||||
if(dwNbslot - dwUnwdIter < 3) { goto end; }
|
||||
offset_l = (PFRAME_OFFSET_L)&pUnwindCodes[dwUnwdIter + 1];
|
||||
FrameOffset = (USHORT)offset_l->FrameOffset;
|
||||
printf("Frame offset is %02x\n", FrameOffset);
|
||||
@@ -517,18 +519,16 @@ BOOL VmmWinThreadCs_RspUnwinder(_In_ VMM_HANDLE H, _In_ PVMM_PROCESS pProcess, _
|
||||
// vaRSP is left untouched
|
||||
case UWOP_SET_FPREG:
|
||||
break;
|
||||
// the save is only made on stack space already allocated, RSP is left untouched but next slot is used for this register so we go over it
|
||||
// the save is only made on stack space already allocated, RSP is left untouched but the offset slots must be skipped
|
||||
case UWOP_SAVE_NONVOL:
|
||||
case UWOP_SAVE_XMM128:
|
||||
if(dwNbslot - dwUnwdIter < 2) { goto end; }
|
||||
dwUnwdIter++;
|
||||
break;
|
||||
// the save is only made on stack already allocated, RSP is left untouched
|
||||
case UWOP_SAVE_NONVOL_FAR:
|
||||
break;
|
||||
// the save is only made on stack already allocated, RSP is left untouched
|
||||
case UWOP_SAVE_XMM128:
|
||||
break;
|
||||
// the save is only made on stack already allocated, RSP is left untouched
|
||||
case UWOP_SAVE_XMM128_FAR:
|
||||
if(dwNbslot - dwUnwdIter < 3) { goto end; }
|
||||
dwUnwdIter += 2;
|
||||
break;
|
||||
case UWOP_PUSH_MACHFRAME:
|
||||
if(pUnwindCodes[dwUnwdIter].OpInfo == 0x00) {
|
||||
|
||||
+1
-1
@@ -331,7 +331,7 @@ BOOL VmmWork_ProcessActionForeachParallel_Void(
|
||||
// 1: select processes to queue using criteria function
|
||||
if(!(pObProcessSelectedSet = ObSet_New(H))) { goto fail; }
|
||||
while((pObProcess = VmmProcessGetNext(H, pObProcess, VMM_FLAG_PROCESS_SHOW_TERMINATED))) {
|
||||
if(!pfnCriteria || pfnCriteria(H, pObProcess, ctxOb)) {
|
||||
if(!pfnCriteria || pfnCriteria(H, pObProcess, ctxAction)) {
|
||||
ObSet_Push(pObProcessSelectedSet, pObProcess->dwPID);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -3,8 +3,8 @@
|
||||
|
||||
#define VERSION_MAJOR 5
|
||||
#define VERSION_MINOR 18
|
||||
#define VERSION_REVISION 2
|
||||
#define VERSION_BUILD 241
|
||||
#define VERSION_REVISION 3
|
||||
#define VERSION_BUILD 242
|
||||
|
||||
#define VER_FILE_DESCRIPTION_STR "MemProcFS : Python API"
|
||||
#define VER_FILE_VERSION VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, VERSION_BUILD
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "leechcore_example"
|
||||
version = "5.18.2"
|
||||
version = "5.18.3"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "m_example_plugin"
|
||||
version = "5.18.2"
|
||||
version = "5.18.3"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "memprocfs"
|
||||
version = "5.18.2"
|
||||
version = "5.18.3"
|
||||
edition = "2021"
|
||||
description = "MemProcFS - Physical Memory Analysis Framework"
|
||||
documentation = "https://docs.rs/memprocfs"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "memprocfs_example"
|
||||
version = "5.18.2"
|
||||
version = "5.18.3"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
|
||||
@@ -32,5 +32,5 @@ using System.Runtime.Versioning;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("5.18.2.241")]
|
||||
[assembly: AssemblyFileVersion("5.18.2.241")]
|
||||
[assembly: AssemblyVersion("5.18.3.242")]
|
||||
[assembly: AssemblyFileVersion("5.18.3.242")]
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
<None Include="logo.png" Pack="true" Visible="true" PackagePath="" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<Version>5.18.2</Version>
|
||||
<Version>5.18.3</Version>
|
||||
<RepositoryUrl>https://github.com/ufrisk/MemProcFS</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||
|
||||
Reference in New Issue
Block a user