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

228 lines
9.4 KiB
C

// m_sys_net.c : implementation related to the Sys/Net built-in module.
//
// The 'sys/net' module is responsible for displaying networking information
// in a 'netstat' like way at the path '/sys/net/'
//
// The module is a provider of forensic timelining information.
//
// (c) Ulf Frisk, 2020-2026
// Author: Ulf Frisk, pcileech@frizk.net
//
#include "modules.h"
LPCSTR szMSYSNET_README =
"Information about the sys net module \n" \
"==================================== \n" \
"The sys/net module tries to enumerate and list network connections in \n" \
"Windows 7 and later (x64 only). \n" \
"--- \n" \
"Documentation: https://github.com/ufrisk/MemProcFS/wiki/FS_SysInfo_Network \n";
// ----------------------------------------------------------------------------
// Net functionality below:
// Show information related to TCP/IP connectivity in the analyzed system.
// ----------------------------------------------------------------------------
#define MSYSNET_LINELENGTH 128ULL
#define MSYSNET_LINELENGTH_VERBOSE 278ULL
#define MSYSNET_LINEHEADER " # PID Proto State Src Dst Process"
#define MSYSNET_LINEHEADER_VERBOSE MSYSNET_LINEHEADER " Time Object Address Process Path"
VOID MSysNet_ReadLineCB(_In_ VMM_HANDLE H, _Inout_opt_ PVOID ctx, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVMM_MAP_NETENTRY pe, _Out_writes_(cbLineLength + 1) LPSTR szu8)
{
PVMM_PROCESS pObProcess = VmmProcessGet(H, pe->dwPID);
Util_usnprintf_ln(szu8, cbLineLength,
"%04x%7i %s %s",
ie,
pe->dwPID,
pe->uszText,
pObProcess ? pObProcess->pObPersistent->uszNameLong : ""
);
Ob_DECREF(pObProcess);
}
VOID MSysNet_ReadLineVerboseCB(_In_ VMM_HANDLE H, _Inout_opt_ PVOID ctx, _In_ DWORD cbLineLength, _In_ DWORD ie, _In_ PVMM_MAP_NETENTRY pe, _Out_writes_(cbLineLength + 1) LPSTR szu8)
{
CHAR szTime[24];
PVMM_PROCESS pObProcess = VmmProcessGet(H, pe->dwPID);
Util_FileTime2String(pe->ftTime, szTime);
Util_usnprintf_ln(szu8, cbLineLength,
"%04x%7i %s %-20s %s %016llx %s",
ie,
pe->dwPID,
pe->uszText,
pObProcess ? pObProcess->pObPersistent->uszNameLong : "",
szTime,
pe->vaObj,
pObProcess ? pObProcess->pObPersistent->uszPathKernel : ""
);
Ob_DECREF(pObProcess);
}
NTSTATUS MSysNet_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_NET pObNetMap;
if(!_stricmp(ctxP->uszPath, "readme.txt")) {
return Util_VfsReadFile_FromStrA(szMSYSNET_README, pb, cb, pcbRead, cbOffset);
}
if(VmmMap_GetNet(H, &pObNetMap)) {
if(!_stricmp(ctxP->uszPath, "netstat.txt")) {
nt = Util_VfsLineFixed_Read(
H, (UTIL_VFSLINEFIXED_PFN_CB)MSysNet_ReadLineCB, NULL, MSYSNET_LINELENGTH, MSYSNET_LINEHEADER,
pObNetMap->pMap, pObNetMap->cMap, sizeof(VMM_MAP_NETENTRY),
pb, cb, pcbRead, cbOffset
);
}
if(!_stricmp(ctxP->uszPath, "netstat-v.txt")) {
nt = Util_VfsLineFixed_Read(
H, (UTIL_VFSLINEFIXED_PFN_CB)MSysNet_ReadLineVerboseCB, NULL, MSYSNET_LINELENGTH_VERBOSE, MSYSNET_LINEHEADER_VERBOSE,
pObNetMap->pMap, pObNetMap->cMap, sizeof(VMM_MAP_NETENTRY),
pb, cb, pcbRead, cbOffset
);
}
Ob_DECREF(pObNetMap);
}
return nt;
}
BOOL MSysNet_List(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _Inout_ PHANDLE pFileList)
{
PVMMOB_MAP_NET pObNetMap;
if(ctxP->uszPath[0]) { return FALSE; }
VMMDLL_VfsList_AddFile(pFileList, "readme.txt", strlen(szMSYSNET_README), NULL);
if(VmmMap_GetNet(H, &pObNetMap)) {
VMMDLL_VfsList_AddFile(pFileList, "netstat.txt", UTIL_VFSLINEFIXED_LINECOUNT(H, pObNetMap->cMap) * MSYSNET_LINELENGTH, NULL);
VMMDLL_VfsList_AddFile(pFileList, "netstat-v.txt", UTIL_VFSLINEFIXED_LINECOUNT(H, pObNetMap->cMap) * MSYSNET_LINELENGTH_VERBOSE, NULL);
Ob_DECREF(pObNetMap);
}
return TRUE;
}
VOID MSysNet_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;
PVMM_MAP_NETENTRY pe;
PVMMOB_MAP_NET pObNetMap;
if(VmmMap_GetNet(H, &pObNetMap)) {
for(i = 0; i < pObNetMap->cMap; i++) {
pe = pObNetMap->pMap + i;
if(pe->ftTime && pe->uszText[0]) {
pfnAddEntry(H, hTimeline, pe->ftTime, FC_TIMELINE_ACTION_CREATE, pe->dwPID, 0, pe->vaObj, pe->uszText);
}
}
Ob_DECREF(pObNetMap);
}
}
VOID MSysNet_FcLogCSV(_In_ VMM_HANDLE H, _In_ PVMMDLL_PLUGIN_CONTEXT ctxP, _In_ VMMDLL_CSV_HANDLE hCSV)
{
static LPCSTR szSTATES[] = {
"CLOSED",
"LISTENING",
"SYN_SENT",
"SYN_RCVD",
"ESTABLISHED",
"FIN_WAIT_1",
"FIN_WAIT_2",
"CLOSE_WAIT",
"CLOSING",
"LAST_ACK",
"",
"",
"TIME_WAIT",
""
};
CHAR szTime[24];
DWORD iNetMap, dwIpVersion;
PVMM_MAP_NETENTRY pe;
PVMMOB_MAP_NET pObNetMap = NULL;
PVMM_PROCESS pObProcess = NULL;
if(ctxP->pProcess) { return; }
if(!VmmMap_GetNet(H, &pObNetMap)) { goto fail; }
FcFileAppend(H, "net.csv", "Proto,State,SrcAddr,SrcPort,DstAddr,DstPort,Time,Object,PID,Process,ProcessPath\n");
for(iNetMap = 0; iNetMap < pObNetMap->cMap; iNetMap++) {
Ob_DECREF_NULL(&pObProcess);
pe = pObNetMap->pMap + iNetMap;
pObProcess = VmmProcessGet(H, pe->dwPID);
Util_FileTime2String(pe->ftTime, szTime);
dwIpVersion = (pe->AF == AF_INET) ? 4 : (((pe->AF == 23 /* AF_INET6 */)) ? 6 : 0);
FcCsv_Reset(hCSV);
FcFileAppend(H, "net.csv", "%s%i,%s,%s,%i,%s,%i,%s,0x%llx,%i,%s,%s\n",
((pe->dwPoolTag == 'UdpA') ? "UDP" : "TCP"), dwIpVersion,
FcCsv_String(hCSV, (LPSTR)szSTATES[pe->dwState]),
pe->Src.uszText,
pe->Src.port,
pe->Dst.uszText,
pe->Dst.port,
FcCsv_String(hCSV, szTime),
pe->vaObj,
pe->dwPID,
FcCsv_String(hCSV, pObProcess ? pObProcess->pObPersistent->uszNameLong : ""),
FcCsv_String(hCSV, pObProcess ? pObProcess->pObPersistent->uszPathKernel : "")
);
}
fail:
Ob_DECREF(pObNetMap);
Ob_DECREF(pObProcess);
}
VOID MSysNet_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_NET pObNetMap = NULL;
PVMM_MAP_NETENTRY pe;
DWORD i;
PVMM_PROCESS pObProcess = NULL;
CHAR szTime[24], szu[MAX_PATH];
if(ctxP->pProcess || !(pd = LocalAlloc(LMEM_ZEROINIT, sizeof(VMMDLL_FORENSIC_JSONDATA)))) { return; }
pd->dwVersion = VMMDLL_FORENSIC_JSONDATA_VERSION;
pd->szjType = "net";
if(VmmMap_GetNet(H, &pObNetMap)) {
for(i = 0; i < pObNetMap->cMap; i++) {
pe = pObNetMap->pMap + i;
szu[0] = 0;
if((pObProcess = VmmProcessGet(H, pe->dwPID))) {
Util_FileTime2String(pe->ftTime, szTime);
snprintf(szu, _countof(szu), "proc:[%s] time:[%s] path:[%s]",
pObProcess ? pObProcess->pObPersistent->uszNameLong : "",
szTime,
pObProcess ? pObProcess->pObPersistent->uszPathKernel : "");
Ob_DECREF_NULL(&pObProcess);
}
pd->i = i;
pd->dwPID = pe->dwPID;
pd->vaObj = pe->vaObj;
pd->usz[0] = pe->uszText;
pd->usz[1] = szu;
pfnLogJSON(H, pd);
}
}
Ob_DECREF(pObNetMap);
LocalFree(pd);
}
VOID M_SysNet_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; }
strcpy_s(pRI->reg_info.uszPathName, 128, "\\sys\\net"); // module name
pRI->reg_info.fRootModule = TRUE; // module shows in root directory
pRI->reg_fn.pfnList = MSysNet_List; // List function supported
pRI->reg_fn.pfnRead = MSysNet_Read; // Read function supported
pRI->reg_fnfc.pfnTimeline = MSysNet_Timeline; // Timeline supported
pRI->reg_fnfc.pfnLogCSV = MSysNet_FcLogCSV; // CSV log function supported
pRI->reg_fnfc.pfnLogJSON = MSysNet_FcLogJSON; // JSON log function supported
memcpy(pRI->reg_info.sTimelineNameShort, "Net", 4);
strncpy_s(pRI->reg_info.uszTimelineFile, 32, "timeline_net", _TRUNCATE);
pRI->pfnPluginManager_Register(H, pRI);
}