Files
MemProcFS/vmm/modules/m_sys_obj.c
2026-01-04 15:00:03 +01:00

237 lines
9.4 KiB
C

// m_sys_obj.c : implementation related to the sys/objects built-in module.
//
// The 'sys/objects' module is responsible for displaying information about
// the kernel object maanger.
//
// (c) Ulf Frisk, 2021-2026
// Author: Ulf Frisk, pcileech@frizk.net
//
#include "modules.h"
#include "../vmmwinobj.h"
#define MSYSOBJ_LINELENGTH 200ULL
#define MSYSOBJ_LINEHEADER " # Object Address Type Description"
/*
* Retrieve the sought after object manager object together with information
* about a possible meta-data directory '$_INFO'. And also of it points to a
* file as per below:
* -- pObjMap
* -- wszPath
* -- ppe = object manager object output
* -- pfMeta = path contains '\\$_INFO'
* -- pfEnd = path ends with '\\$_INFO'
* -- pfTxt = path ends with '\\obj-data.txt', '\\obj-header.txt', '\\obj-addr.txt', '\\obj-type.txt'
* -- pfMem = path ends with '\\obj-data.mem'
*/
_Success_(return)
BOOL MSysObj_Path2Entry(_In_ PVMMOB_MAP_OBJECT pObjMap, _In_ LPSTR uszPath, _Out_ PVMM_MAP_OBJECTENTRY *ppe, _Out_ PBOOL pfMeta, _Out_ PBOOL pfEnd, _Out_ PBOOL pfTxt, _Out_ PBOOL pfMem)
{
LPCSTR usz;
DWORD dwHash;
CHAR usz1[MAX_PATH];
PVMM_MAP_OBJECTENTRY pe;
if(!pObjMap->cMap) { return FALSE; }
pe = pObjMap->pMap;
*pfTxt = CharUtil_StrEndsWith(uszPath, "\\obj-data.txt", TRUE) || CharUtil_StrEndsWith(uszPath, "\\obj-header.txt", TRUE) || CharUtil_StrEndsWith(uszPath, "\\obj-address.txt", TRUE) || CharUtil_StrEndsWith(uszPath, "\\obj-type.txt", TRUE);;
*pfMem = CharUtil_StrEndsWith(uszPath, "\\obj-data.mem", TRUE);
*pfEnd = CharUtil_StrEndsWith(uszPath, "\\$_INFO", TRUE);
*pfMeta = *pfTxt || *pfMem || *pfEnd;
usz = CharUtil_PathSplitFirst(uszPath, usz1, MAX_PATH); dwHash = CharUtil_HashNameFsU(usz1, 0);
while(pe) {
if(!_stricmp(usz1, "$_INFO")) {
*pfMeta = TRUE;
if(usz[0] == 0) { goto finish; }
usz = CharUtil_PathSplitFirst(usz, usz1, MAX_PATH); dwHash = CharUtil_HashNameFsU(usz1, 0);
}
if(pe->dwHash == dwHash) {
if(usz[0] == 0) { goto finish; }
if(!_stricmp(usz, "$_INFO") || !_stricmp(usz, "obj-data.mem") || !_stricmp(usz, "obj-data.txt") || !_stricmp(usz, "obj-header.txt") || !_stricmp(usz, "obj-address.txt") || !_stricmp(usz, "obj-type.txt")) { goto finish; }
usz = CharUtil_PathSplitFirst(usz, usz1, MAX_PATH); dwHash = CharUtil_HashNameFsU(usz1, 0);
pe = pe->pChild;
} else {
pe = pe->pNextByParent;
}
}
return FALSE;
finish:
*ppe = pe;
return TRUE;
}
/*
* Retrieve the full path of an object entry.
*/
VOID MSysObj_GetFullPath(_In_opt_ PVMM_MAP_OBJECTENTRY pe, _Out_writes_(MAX_PATH) LPSTR uszPath)
{
DWORD i = 0;
PVMM_MAP_OBJECTENTRY pea[0x20];
uszPath[0] = 0;
if(pe) {
pea[i++] = pe;
while((pe = pe->pParent) && (pea[i++] = pe) && (i < 0x20));
while(i && (pe = pea[--i])) {
strncat_s(uszPath, MAX_PATH, pe->uszName, _TRUNCATE);
if(i) { strncat_s(uszPath, MAX_PATH, "\\", _TRUNCATE); }
}
}
}
VOID MSysObj_ReadLineCB(_In_ VMM_HANDLE H, _Inout_opt_ PVOID ctx, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVMM_MAP_OBJECTENTRY pe, _Out_writes_(cbLineLength + 1) LPSTR usz)
{
CHAR uszPath[MAX_PATH];
MSysObj_GetFullPath(pe, uszPath);
Util_usnprintf_ln(usz, cbLineLength,
"%04x %016llx %-13s %s%s%s%s",
ie,
pe->va,
pe->pType->usz,
uszPath,
pe->ExtInfo.usz[0] ? " [" : "",
pe->ExtInfo.usz,
pe->ExtInfo.usz[0] ? "]" : ""
);
}
NTSTATUS MSysObj_Read(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Out_writes_to_(cb, *pcbRead) PBYTE pb, _In_ DWORD cb, _Out_ PDWORD pcbRead, _In_ QWORD cbOffset)
{
NTSTATUS nt = VMMDLL_STATUS_FILE_INVALID;
PVMMOB_MAP_OBJECT pObObjMap = NULL;
PVMM_MAP_OBJECTENTRY pe;
BOOL fMeta, fEnd, fTxt, fMem;
if(!VmmMap_GetObject(H, &pObObjMap)) { goto finish; }
if(!_stricmp(ctxP->uszPath, "objects.txt")) {
nt = Util_VfsLineFixed_Read(
H, (UTIL_VFSLINEFIXED_PFN_CB)MSysObj_ReadLineCB, NULL, MSYSOBJ_LINELENGTH, MSYSOBJ_LINEHEADER,
pObObjMap->pMap, pObObjMap->cMap, sizeof(VMM_MAP_OBJECTENTRY),
pb, cb, pcbRead, cbOffset
);
goto finish;
}
if(MSysObj_Path2Entry(pObObjMap, ctxP->uszPath, &pe, &fMeta, &fEnd, &fTxt, &fMem)) {
if(fMeta) {
nt = VmmWinObjDisplay_VfsRead(H, ctxP->uszPath, pe->pType->iType, pe->va, pb, cb, pcbRead, cbOffset);
} else {
nt = Util_VfsReadFile_FromMEM(H, PVMM_PROCESS_SYSTEM, pe->va, pe->pType->cb, VMM_FLAG_ZEROPAD_ON_FAIL, pb, cb, pcbRead, cbOffset);
}
}
finish:
Ob_DECREF(pObObjMap);
return nt;
}
VOID MSysObj_ListDirectory(_In_ VMM_HANDLE H, _In_ PVMMOB_MAP_OBJECT pObjMap, _In_ LPSTR uszPath, _Inout_ PHANDLE pFileList)
{
PVMM_MAP_OBJECTENTRY pe;
BOOL fMeta, fEnd, fTxt, fMem;
if(!MSysObj_Path2Entry(pObjMap, uszPath, &pe, &fMeta, &fEnd, &fTxt, &fMem)) { return; }
if(fMeta && !fEnd) {
VmmWinObjDisplay_VfsList(H, pe->pType->iType, pe->va, pFileList);
return;
}
pe = pe->pChild;
if(!pe) { return; }
if(!fMeta) {
VMMDLL_VfsList_AddDirectory(pFileList, "$_INFO", NULL);
}
while(pe) {
if((pe->pType->iType == 3) || fEnd) {
VMMDLL_VfsList_AddDirectory(pFileList, pe->uszName, NULL);
} else {
VMMDLL_VfsList_AddFile(pFileList, pe->uszName, pe->pType->cb, NULL);
}
pe = pe->pNextByParent;
}
}
BOOL MSysObj_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList)
{
PVMMOB_MAP_OBJECT pObObjMap = NULL;
if(!VmmMap_GetObject(H, &pObObjMap)) { goto finish; }
if(!ctxP->uszPath[0]) {
VMMDLL_VfsList_AddDirectory(pFileList, "ROOT", NULL);
VMMDLL_VfsList_AddFile(pFileList, "objects.txt", UTIL_VFSLINEFIXED_LINECOUNT(H, pObObjMap->cMap) * MSYSOBJ_LINELENGTH, NULL);
goto finish;
}
if(!_strnicmp(ctxP->uszPath, "ROOT", 4)) {
MSysObj_ListDirectory(H, pObObjMap, ctxP->uszPath, pFileList);
goto finish;
}
finish:
Ob_DECREF(pObObjMap);
return TRUE;
}
VOID MSysObj_Timeline(
_In_ VMM_HANDLE H,
_In_opt_ PVOID ctxfc,
_In_ HANDLE hTimeline,
_In_ VOID(*pfnAddEntry)(_In_ VMM_HANDLE H, _In_ HANDLE hTimeline, _In_ QWORD ft, _In_ DWORD dwAction, _In_ DWORD dwPID, _In_ DWORD dwData32, _In_ QWORD qwData64, _In_ LPCSTR uszText),
_In_ VOID(*pfnEntryAddBySql)(_In_ VMM_HANDLE H, _In_ HANDLE hTimeline, _In_ DWORD cEntrySql, _In_ LPCSTR *pszEntrySql)
) {
DWORD i, cType, iTypeBase;
CHAR uszPath[MAX_PATH];
PVMM_MAP_OBJECTENTRY pe;
PVMMOB_MAP_OBJECT pObObjMap = NULL;
if(VmmMap_GetObject(H, &pObObjMap)) {
cType = pObObjMap->cType[H->vmm.ObjectTypeTable.tpSymbolicLink];
iTypeBase = pObObjMap->iTypeSortBase[H->vmm.ObjectTypeTable.tpSymbolicLink];
for(i = 0; i < cType; i++) {
pe = &pObObjMap->pMap[iTypeBase + i];
if(pe->ExtInfo.ft) {
MSysObj_GetFullPath(pe, uszPath);
pfnAddEntry(H, hTimeline, pe->ExtInfo.ft, FC_TIMELINE_ACTION_CREATE, 0, 0, pe->va, uszPath);
}
}
Ob_DECREF(pObObjMap);
}
}
VOID MSysObj_FcLogJSON(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VOID(*pfnLogJSON)(_In_ VMM_HANDLE H, _In_ PVMMDLL_FORENSIC_JSONDATA pData))
{
PVMMDLL_FORENSIC_JSONDATA pd;
PVMMOB_MAP_OBJECT pObObjMap = NULL;
PVMM_MAP_OBJECTENTRY pe;
DWORD i;
CHAR usz[MAX_PATH];
CHAR uszPath[MAX_PATH];
if(ctxP->pProcess || !(pd = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMDLL_FORENSIC_JSONDATA)))) { return; }
pd->dwVersion = VMMDLL_FORENSIC_JSONDATA_VERSION;
pd->szjType = "kobj";
if(VmmMap_GetObject(H, &pObObjMap)) {
for(i = 0; i < pObObjMap->cMap; i++) {
pe = pObObjMap->pMap + i;
MSysObj_GetFullPath(pe, uszPath);
_snprintf_s(usz, _countof(usz), _TRUNCATE, "%s %s%s%s",
uszPath,
pe->ExtInfo.usz[0] ? " [" : "",
pe->ExtInfo.usz,
pe->ExtInfo.usz[0] ? "]" : "");
pd->i = i;
pd->vaObj = pe->va;
pd->usz[0] = pe->pType->usz;
pd->usz[1] = usz;
pfnLogJSON(H, pd);
}
}
Ob_DECREF(pObObjMap);
LocalFree(pd);
}
VOID M_SysObj_Initialize(_In_ VMM_HANDLE H, _Inout_ PVMMDLL_PLUGIN_REGINFO pRI)
{
if((pRI->magic != VMMDLL_PLUGIN_REGINFO_MAGIC) || (pRI->wVersion != VMMDLL_PLUGIN_REGINFO_VERSION)) { return; }
if((pRI->tpSystem != VMMDLL_SYSTEM_WINDOWS_64) && (pRI->tpSystem != VMMDLL_SYSTEM_WINDOWS_32)) { return; }
if(pRI->sysinfo.dwVersionBuild < 7600) { return; } // WIN7+ required
strcpy_s(pRI->reg_info.uszPathName, 128, "\\sys\\objects"); // module name
pRI->reg_info.fRootModule = TRUE; // module shows in root directory
pRI->reg_fn.pfnList = MSysObj_List; // List function supported
pRI->reg_fn.pfnRead = MSysObj_Read; // Read function supported
pRI->reg_fnfc.pfnTimeline = MSysObj_Timeline; // Timeline supported
pRI->reg_fnfc.pfnLogJSON = MSysObj_FcLogJSON; // JSON log function supported
memcpy(pRI->reg_info.sTimelineNameShort, "KObj", 5);
strncpy_s(pRI->reg_info.uszTimelineFile, 32, "timeline_kernelobject", _TRUNCATE);
pRI->pfnPluginManager_Register(H, pRI);
}