From e942bbcbea9b4a213edf757136489aa836983339 Mon Sep 17 00:00:00 2001 From: ufrisk Date: Mon, 16 Aug 2021 08:16:40 +0200 Subject: [PATCH] Version 4.11 --- files/agent-find-rwx.py | 38 +++++++- includes/leechcore.h | 34 ++++++- includes/lib64/leechcore.lib | Bin 5268 -> 5268 bytes includes/lib64/vmm.lib | Bin 21426 -> 21642 bytes includes/vmmdll.h | 30 +++++- pcileech/executor.c | 177 ++++++++++++++++++++++++++++++++++- pcileech/executor.h | 7 +- pcileech/help.c | 24 ++++- pcileech/pcileech.c | 6 +- pcileech/pcileech.h | 1 + pcileech/version.h | 4 +- readme.md | 11 ++- 12 files changed, 316 insertions(+), 16 deletions(-) diff --git a/files/agent-find-rwx.py b/files/agent-find-rwx.py index aa78e14..2d86623 100644 --- a/files/agent-find-rwx.py +++ b/files/agent-find-rwx.py @@ -1,6 +1,42 @@ +# Example file to demonstrate remote python functionality with the LeechAgent. +# +# Example: +# pcileech.exe -device -remote rpc://:host agent-execpy -in agent-find-rwx.py +# +# The python script will be executed in a child process to the LeechAgent in +# the user-context of the LeechAgent. If the agent is running as a service this +# is most likely SYSTEM. It's also possible to use this functionality to run +# Python scripts on the remote host without using the memory analysis functionality. +# +# Please check out agent installation instructions at: +# https://github.com/ufrisk/LeechCore/wiki/LeechAgent +# https://github.com/ufrisk/LeechCore/wiki/LeechAgent_Install +# + + +# +# Example to load LeechCore for Python connecting to the memory acqusition device +# specified in the PCILeech -device parameter. Please uncomment to activate. +# Guide at: https://github.com/ufrisk/LeechCore/wiki/LeechCore_API_Python +# +''' +import leechcorepyc +lc = leechcorepyc.LeechCore('existing') +print(lc) +''' + + +# +# Example to load MemProcFS for Python connecting to the memory acqusition device +# specified in the PCILeech -device parameter. +# For information about MemProcFS Python API please check out the wiki for API +# usage examples and a youtube demo. +# https://github.com/ufrisk/MemProcFS/wiki/API_Python +# +# import memprocfs vmm = memprocfs.Vmm() for process in vmm.process_list(): for entry in process.maps.pte(): if '-rwx' in entry['flags']: - print(str(process.pid) + ': ' + process.name + ': ' + str(entry)) \ No newline at end of file + print(str(process.pid) + ': ' + process.name + ': ' + str(entry)) diff --git a/includes/leechcore.h b/includes/leechcore.h index b1ef5cd..29ce7f7 100644 --- a/includes/leechcore.h +++ b/includes/leechcore.h @@ -14,7 +14,7 @@ // (c) Ulf Frisk, 2020-2021 // Author: Ulf Frisk, pcileech@frizk.net // -// Header Version: 2.6 +// Header Version: 2.7 // #ifndef __LEECHCORE_H__ @@ -396,7 +396,7 @@ EXPORTED_FUNCTION BOOL LcCommand( #define LC_OPT_FPGA_DELAY_WRITE 0x0300000700000000 // RW - uS #define LC_OPT_FPGA_DELAY_READ 0x0300000800000000 // RW - uS #define LC_OPT_FPGA_RETRY_ON_ERROR 0x0300000900000000 // RW -#define LC_OPT_FPGA_DEVICE_ID 0x0300008000000000 // R +#define LC_OPT_FPGA_DEVICE_ID 0x0300008000000000 // RW - bus:dev:fn (ex: 04:00.0 == 0x0400). #define LC_OPT_FPGA_FPGA_ID 0x0300008100000000 // R #define LC_OPT_FPGA_VERSION_MAJOR 0x0300008200000000 // R #define LC_OPT_FPGA_VERSION_MINOR 0x0300008300000000 // R @@ -433,6 +433,14 @@ EXPORTED_FUNCTION BOOL LcCommand( #define LC_CMD_AGENT_EXEC_PYTHON 0x8000000100000000 // RW - [lo-dword: optional timeout in ms] #define LC_CMD_AGENT_EXIT_PROCESS 0x8000000200000000 // - [lo-dword: process exit code] +#define LC_CMD_AGENT_VFS_LIST 0x8000000300000000 // RW +#define LC_CMD_AGENT_VFS_READ 0x8000000400000000 // RW +#define LC_CMD_AGENT_VFS_WRITE 0x8000000500000000 // RW +#define LC_CMD_AGENT_VFS_OPT_GET 0x8000000600000000 // RW +#define LC_CMD_AGENT_VFS_OPT_SET 0x8000000700000000 // RW + +#define LC_CMD_AGENT_VFS_REQ_VERSION 0xfeed0001 +#define LC_CMD_AGENT_VFS_RSP_VERSION 0xfeee0001 #define LC_STATISTICS_VERSION 0xe1a10002 #define LC_STATISTICS_ID_OPEN 0x00 @@ -445,6 +453,28 @@ EXPORTED_FUNCTION BOOL LcCommand( #define LC_STATISTICS_ID_COMMAND 0x07 #define LC_STATISTICS_ID_MAX 0x07 +typedef struct tdLC_CMD_AGENT_VFS_REQ { + DWORD dwVersion; + DWORD _FutureUse; + CHAR uszPathFile[2*MAX_PATH]; // file path to list/read/write + union { + QWORD qwOffset; // offset to read/write + QWORD fOption; // option to get/set (qword data in *pb) + }; + DWORD dwLength; // length to read + DWORD cb; + BYTE pb[0]; +} LC_CMD_AGENT_VFS_REQ, *PLC_CMD_AGENT_VFS_REQ; + +typedef struct tdLC_CMD_AGENT_VFS_RSP { + DWORD dwVersion; + DWORD dwStatus; // ntstatus of read/write + DWORD cbReadWrite; // number of bytes read/written + DWORD _FutureUse[2]; + DWORD cb; + BYTE pb[0]; +} LC_CMD_AGENT_VFS_RSP, *PLC_CMD_AGENT_VFS_RSP; + static LPCSTR LC_STATISTICS_NAME[] = { "LcOpen", "LcRead", diff --git a/includes/lib64/leechcore.lib b/includes/lib64/leechcore.lib index 72c29788ab2ce248fd00bc19c87528aaea715137..32a58ceaebbcc3e2d8bff71f96f4de3c1db617ed 100644 GIT binary patch delta 118 zcmbQDIYo2BH+Ie~N1xp0XJlaDm~6-;Jz0ul0*fp|MCs&p9MMb>rJK1qWf@uIiXI)D zti#m-lTn|1pNj)1JDHnPYBDo-EUWX}tjqT&>vG8h^-E8l&s_>rsf?s@b3BhJ2LQPa BBq9I+ delta 118 zcmbQDIYo2BH+D|OAkM4&j0_AMlMT6~CrfcmV3A?CT{3wcM>NyzlFi(lvWzSWQHxGb z*5T@a$*51h&&2_hoy^TCHJO<^mi6qD_rLB>*5#51>X)88pSu*MQW;6*=6D`c4gjW) BCRG3c diff --git a/includes/lib64/vmm.lib b/includes/lib64/vmm.lib index cab101063d6dbbda4dda6266cb564199610a3eaa..0be58a7e8f288981c90f946194f6ed861d3fe841 100644 GIT binary patch delta 2083 zcmb``ZD>iIP3ha%$8fz!1E=O>3P8(Kw%R4n40$~KswXmMK=+5hHVx6d03{PLXh+;h); z&N=sf^||igY26W5yv$aWm-xMt4B$LatOqRFKuHKFomJU9fWkVas+|NBwsWe|B#u)I zsr-FF!WBmHJy!)eZ^9u)3OM4*ADvPKU-ANl`Zd#x6n3h-CLrMmBejoe3K+@9MI;O} zQau-tu$7VOI9^dNsp{euCa7UT)6PilvzkUms<^LmhJb{Nj8w^oDymPaYEl42)fNp4 zsG`banpcce^GFr1?dDce4XagDa2peLGE#Y_hN~?n*9BFzl@BEQO3er(mAN%%8ObrD za`|{4+2>V`0py172OU%_IWz(p#k1Wr~1DK)^BDo#Mhn0rN!nCoVd!;DG1XD4Nr z^TBk%#SfSFt+WFp9WFt}F5;;171MJV!UguqXG_;VKvsE5NlBaE7rk+Iyg~@A{4`pQrNHndB}wsImpIJex#vIB{BKGgzqb50gZkQ!pUycb|MM+~4<*yMxA3rDa{avKiI^=q zBjuobm)K(|6kirw^=#^_nc~ml-{psO^S^w}GlsM`Aze1B*cP2Pax0}dv8Zz z^NyYB=lZcPD1Wmy`@ss1af@5N9@#c^d|K%>iw1v>+}w6`u7Ev{I2uS7wty_A{6T|t z^!nx1;&32?nQr-U&Y5Rsj%nqXP4b3kPcP@O*CuqqP4W}lrCZ8u?P7bd$GHEqqCb?L z7m{eoO%soUUis*?k6vXk=Mzn#Uis6)-A|RCUwjejU1WN^=Z9771z5cZFUu9qu+Qi} z`s+(28RR4*xn^-D?30(&@4cGOTuA&BNf+_83q(dFDDBVsen#AhWHMn8pG3k^Xia!V zggVUPMI>y;-tG$WJFVqvCD=zW$sQs zZ&^yJFs3AnuBgwrfA08qdCYeu@);uP4;Tl{FCHk{wVt`{<}5K}HV9Xz*LXX>YEsF^ P68W5kJPK?7;2{12BC5AV delta 1928 zcmb`{drVVT90%|(*fK6K@d2}SNTDDKg;Gj+ze*{z^!>mIE>l>x%*iB~A%#E`}P;o>ru_`*1|WQoybG0riv8NxEB#=o4hxjE+^0kZGuy>9<*$(nrnJLh-L zz2|q%x$XD|DQDhKIoOb}*EkB2pZ*L0CxOxlz;X&GzYSClY33Qp>QFWJ0+P+GvQ9Ej zl{%Gg97uY=NCA#ZI?G7@ZJL<`8#6$#ShJr|dZ-F*2PE&5s+;2^uTAAS4@lidRlXcf zNUbb9DV330I6mnJBQ;-8wI#ej8?|0nxmgorQxD#E}Ijp(MNbWHWSL~+HWmUKtkfI}+ zJB$?LnM+~5TT+BYN6Zm^9acrtIFMpjRPk0oYU5zZ$qADTjMTnU<$T0GdAyRiWvZHP zSs_xy!GKPf^m<|3oF@kJjnmEgU$YbT+P`1-J^&M?z$puGyBrv*1m?+M1$wyvw+)zN zTgTkE4|qUsp2At$<_Bh|I0)>ghqOHeOtFUIZk`O|c@J=u?Ht}W#C4=n!qx&Dp$nYA z+Xh@`(#7Mt)(-5gVIdT%<;_&z2pp&7IzE8!SqbAI8f^j=D2FB;KsxU^QO$|j4m1E4 z=^TqUR{?W&KA+ciG2W=>aUWoEktRBTEH^9W?gZ}A7_TkUWv;3@42(p9 zJG3pv9b;df++j*%?h13Qapt+8F(+W4om|i(MlW~aBzHOu3Nnz;L63CQp&l)0MH3p( zh-x@c1v`qd5hd7!a#WxU7Br&BR-VemXmUuQL7aremqPrS}XAqN{95mxphMh0|Ij)>-VS zZ0@$M7cW|V)BQB^>VoJm-}lb|r6TL`fU1h;RxFmS5^q<0`1rbo*QR${Kh6^sp|$$H zo0sMdqRpSnX+z5S!lhgMO~NJC1$HRI8O~Y$XQ4wR0)zUyVb86N;`M-8tPY0ttJ}BC znZ*5okw4CKQPSd5_U*YeU%=5_9GxqE491i_*4Rb)G>_;G?NEl!Jo}mKdBth=jPIE5 z8QJR=#_)g=j{bgC_I%<^_R5`q{!ql8UkpU@#LaxYSQ+st!(!?WnGG;InEB~z&o33S z7lcl{v1YyaITF-eo&EY3F&i<7foM4M8;|v-91!M!3eyHLAN47(eDuPXG8Yk+*vm@R zv9}(W*o%rpJXf5F#gx|TUwtR9$C4Ryyhj;5{mJJA%*2^_N$D$|nwJ~WBksosS1cL6 M5Z}j(#Ar{(Uy#j}0RR91 diff --git a/includes/vmmdll.h b/includes/vmmdll.h index 08d17a6..183f954 100644 --- a/includes/vmmdll.h +++ b/includes/vmmdll.h @@ -7,7 +7,7 @@ // (c) Ulf Frisk, 2018-2021 // Author: Ulf Frisk, pcileech@frizk.net // -// Header Version: 4.0 +// Header Version: 4.2 // #include "leechcore.h" @@ -306,6 +306,7 @@ typedef struct _SERVICE_STATUS { #define VMMDLL_VFS_FILELIST_EXINFO_VERSION 1 #define VMMDLL_VFS_FILELIST_VERSION 2 +#define VMMDLL_VFS_FILELISTBLOB_VERSION 0xf88f0001 typedef struct tdVMMDLL_VFS_FILELIST_EXINFO { DWORD dwVersion; @@ -331,8 +332,24 @@ typedef struct tdVMMDLL_VFS_FILELIST2 { HANDLE h; } VMMDLL_VFS_FILELIST2, *PVMMDLL_VFS_FILELIST2; +typedef struct tdVMMDLL_VFS_FILELISTBLOB_ENTRY { + ULONG64 ouszName; // byte offset to string from VMMDLL_VFS_FILELISTBLOB.uszMultiText + ULONG64 cbFileSize; // -1 == directory + VMMDLL_VFS_FILELIST_EXINFO ExInfo; // optional ExInfo +} VMMDLL_VFS_FILELISTBLOB_ENTRY, *PVMMDLL_VFS_FILELISTBLOB_ENTRY; + +typedef struct tdVMMDLL_VFS_FILELISTBLOB { + DWORD dwVersion; // VMMDLL_VFS_FILELISTBLOB_VERSION + DWORD cbStruct; + DWORD cFileEntry; + DWORD cbMultiText; + LPSTR uszMultiText; + DWORD _FutureUse[8]; + VMMDLL_VFS_FILELISTBLOB_ENTRY FileEntry[0]; +} VMMDLL_VFS_FILELISTBLOB, *PVMMDLL_VFS_FILELISTBLOB; + /* -* Helper functions for callbacks into the VMM_VFS_FILELIST structure. +* Helper functions for callbacks into the VMM_VFS_FILELIST2 structure. */ EXPORTED_FUNCTION VOID VMMDLL_VfsList_AddFile(_In_ HANDLE pFileList, _In_ LPSTR uszName, _In_ ULONG64 cb, _In_opt_ PVMMDLL_VFS_FILELIST_EXINFO pExInfo); @@ -355,6 +372,15 @@ EXPORTED_FUNCTION _Success_(return) BOOL VMMDLL_VfsListU(_In_ LPSTR uszPath, _Inout_ PVMMDLL_VFS_FILELIST2 pFileList); _Success_(return) BOOL VMMDLL_VfsListW(_In_ LPWSTR wszPath, _Inout_ PVMMDLL_VFS_FILELIST2 pFileList); +/* +* List a directory of files in MemProcFS and return a VMMDLL_VFS_FILELISTBLOB. +* CALLER FREE: VMMDLL_MemFree(return) +* -- uszPath +* -- return +*/ +EXPORTED_FUNCTION +_Success_(return != NULL) PVMMDLL_VFS_FILELISTBLOB VMMDLL_VfsListBlobU(_In_ LPSTR uszPath); + /* * Read select parts of a file in MemProcFS. * -- [uw]szFileName diff --git a/pcileech/executor.c b/pcileech/executor.c index 067d7aa..894d30a 100644 --- a/pcileech/executor.c +++ b/pcileech/executor.c @@ -12,6 +12,7 @@ #define EXEC_IO_CONSOLE_BUFFER_SIZE 0x800 #define EXEC_IO_DMAOFFSET_IS 0x80000 #define EXEC_IO_DMAOFFSET_OS 0x81000 + typedef struct tdEXEC_IO { QWORD magic; struct { @@ -390,7 +391,7 @@ VOID ActionExecShellcode() if(pFile) { fclose(pFile); } } -VOID ActionSvcExecPy() +VOID ActionAgentExecPy() { BOOL result; DWORD cbResult = 0; @@ -437,3 +438,177 @@ VOID ActionSvcExecPy() LcMemFree(pbResult); } +#ifdef _WIN32 + +DWORD ActionAgentForensic_OutFileDirectory(_Out_writes_z_(MAX_PATH) LPSTR szFilePrefix, _In_ LPSTR szUniqueTag) +{ + SYSTEMTIME st; + GetLocalTime(&st); + _snprintf_s( + szFilePrefix, + MAX_PATH, + _TRUNCATE, + "%s%sforensic-%i%02i%02i-%02i%02i%02i-%s", + ctxMain->cfg.szFileOut[0] ? ctxMain->cfg.szFileOut : "", + ctxMain->cfg.szFileOut[0] ? "\\" : "", + st.wYear, + st.wMonth, + st.wDay, + st.wHour, + st.wMinute, + st.wSecond, + szUniqueTag); + return (DWORD)strlen(szFilePrefix); +} + +VOID ActionAgentForensic_GetFile(_In_ LPSTR szRemoteFile, _In_ LPSTR szOutFile, _In_ QWORD qwSize) +{ + FILE *hFile = NULL; + LC_CMD_AGENT_VFS_REQ Req = { 0 }; + PLC_CMD_AGENT_VFS_RSP pRsp = NULL; + HANDLE hConsole; + CONSOLE_SCREEN_BUFFER_INFO consoleInfo; + Req.dwVersion = LC_CMD_AGENT_VFS_REQ_VERSION; + strncpy_s(Req.uszPathFile, _countof(Req.uszPathFile), szRemoteFile, _TRUNCATE); + if(fopen_s(&hFile, szOutFile, "wb")) { + printf("AGENT-ELASTIC: failed open local file %s\n", szOutFile); + goto fail; + } + printf(" Local File: %s\n Progress: 0%%", szOutFile); + hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + GetConsoleScreenBufferInfo(hConsole, &consoleInfo); + consoleInfo.dwCursorPosition.X -= 4; + while((Req.dwLength = min(0x01000000, (DWORD)(qwSize - Req.qwOffset)))) { + if(!LcCommand(ctxMain->hLC, LC_CMD_AGENT_VFS_READ, sizeof(LC_CMD_AGENT_VFS_REQ), (PBYTE)&Req, (PBYTE*)&pRsp, NULL) || !pRsp || !pRsp->cb) { + printf("\nAGENT-FORENSIC: Failed reading remote file.\n"); + goto fail; + } + if(pRsp->cb != fwrite(pRsp->pb, 1, pRsp->cb, hFile)) { + LocalFree(pRsp); + printf("\nAGENT-FORENSIC: failed write to local file %s\n", szOutFile); + break; + } + LocalFree(pRsp); + Req.qwOffset += Req.dwLength; + SetConsoleCursorPosition(hConsole, consoleInfo.dwCursorPosition); + printf("%3lli%%", ((Req.qwOffset * 100) / qwSize)); + } + printf("\n"); +fail: + if(hFile) { fclose(hFile); } +} + +/* +* Retrieve forensic mode JSON data from the remote system. This is achieved by +* starting MemProcFS as a child-process remotely and accessing its virtual file +* system. The JSON data retrieved is compatible with ElasticSearch. +*/ +VOID ActionAgentForensic() +{ + CHAR szPercent[4] = { 0 }, szRemoteFile[MAX_PATH] = { 0 }, szLocalFile[MAX_PATH] = { 0 }; + CHAR szTag[18] = { 0 }; + LPSTR szFile; + DWORD i, cPercent = 0, cbResult = 0, cchLocalFileDirectory; + PBYTE pbResult = NULL; + PLC_CMD_AGENT_VFS_REQ pReq = NULL; + PLC_CMD_AGENT_VFS_RSP pRsp = NULL; + PVMMDLL_VFS_FILELISTBLOB pVfsList; + HANDLE hConsole; + CONSOLE_SCREEN_BUFFER_INFO consoleInfo; + + // Initial setup + if(!(pReq = LocalAlloc(LMEM_ZEROINIT, sizeof(LC_CMD_AGENT_VFS_REQ) + 1))) { goto fail; } + pReq->dwVersion = LC_CMD_AGENT_VFS_REQ_VERSION; + strncpy_s(pReq->uszPathFile, _countof(pReq->uszPathFile), "\\forensic\\forensic_enable.txt", _TRUNCATE); + + // Enable/verify forensic mode '1' - in-memory database + pReq->cb = 1; + pReq->pb[0] = '1'; + if(!LcCommand(ctxMain->hLC, LC_CMD_AGENT_VFS_WRITE, sizeof(LC_CMD_AGENT_VFS_REQ) + 1, (PBYTE)pReq, NULL, NULL)) { + printf("AGENT-FORENSIC: Failed to connect to the remote system or enable memory analysis.\n"); + goto fail; + } + pReq->cb = 0; + pReq->dwLength = 3; + if(!LcCommand(ctxMain->hLC, LC_CMD_AGENT_VFS_READ, sizeof(LC_CMD_AGENT_VFS_REQ), (PBYTE)pReq, (PBYTE*)&pRsp, NULL) || !pRsp || !pRsp->cb || pRsp->pb[0] != '1') { + printf("AGENT-FORENSIC: Failed start remote forensic mode memory analysis.\n"); + goto fail; + } + LocalFree(pRsp); pRsp = NULL; + + // Get Unique Tag + strncpy_s(pReq->uszPathFile, _countof(pReq->uszPathFile), "\\sys\\unique-tag.txt", _TRUNCATE); + pReq->cb = 0; + pReq->dwLength = 17; + if(!LcCommand(ctxMain->hLC, LC_CMD_AGENT_VFS_READ, sizeof(LC_CMD_AGENT_VFS_REQ), (PBYTE)pReq, (PBYTE*)&pRsp, NULL) || !pRsp || !pRsp->cb || (pRsp->cb > 17)) { + printf("AGENT-FORENSIC: Failed retrieving unique tag.\n"); + goto fail; + } + memcpy(szTag, pRsp->pb, pRsp->cb); + LocalFree(pRsp); pRsp = NULL; + printf("AGENT-FORENSIC: Remote System Tag: %s\n", szTag); + + // Watch for progress until 100% + printf("AGENT-FORENSIC: Connected. Remote forensic memory analysis: 0%%"); + hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + GetConsoleScreenBufferInfo(hConsole, &consoleInfo); + consoleInfo.dwCursorPosition.X -= 4; + cPercent = 0; + strncpy_s(pReq->uszPathFile, _countof(pReq->uszPathFile), "\\forensic\\progress_percent.txt", _TRUNCATE); + pReq->cb = 0; + pReq->dwLength = 3; + while(cPercent != 100) { + Sleep(250); + if(!LcCommand(ctxMain->hLC, LC_CMD_AGENT_VFS_READ, sizeof(LC_CMD_AGENT_VFS_REQ), (PBYTE)pReq, (PBYTE*)&pRsp, NULL) || !pRsp) { + printf("\nAGENT-FORENSIC: Failed to retrieve progress percent ...\n"); + goto fail; + } + memcpy(szPercent, pRsp->pb, min(3, pRsp->cb)); + LocalFree(pRsp); pRsp = NULL; + cPercent = atoi(szPercent); + SetConsoleCursorPosition(hConsole, consoleInfo.dwCursorPosition); + printf("%3i%%", cPercent); + } + + // Retrieve /forensic/json directory info and print file list: + strncpy_s(pReq->uszPathFile, _countof(pReq->uszPathFile), "\\forensic\\json", _TRUNCATE); + pReq->dwLength = 0; + if(!LcCommand(ctxMain->hLC, LC_CMD_AGENT_VFS_LIST, sizeof(LC_CMD_AGENT_VFS_REQ), (PBYTE)pReq, (PBYTE*)&pRsp, NULL) || !pRsp) { + printf("AGENT-FORENSIC: Failed to retrieve file info.\n"); + goto fail; + } + pVfsList = (PVMMDLL_VFS_FILELISTBLOB)pRsp->pb; // sanity/security checks on remote deta done in leechcore + pVfsList->uszMultiText = pVfsList->uszMultiText + (QWORD)pVfsList; // fixup relative uszMultiText offset + if(pVfsList->cFileEntry > 16) { + printf("AGENT-FORENSIC: Too many files on remote system (%i).\n", pVfsList->cFileEntry); + goto fail; + } + cchLocalFileDirectory = ActionAgentForensic_OutFileDirectory(szLocalFile, szTag); + CreateDirectoryA(szLocalFile, NULL); + printf("\nRemote Files:\n"); + for(i = 0; i < pVfsList->cFileEntry; i++) { + if(pVfsList->FileEntry[i].cbFileSize != -1) { + szFile = pVfsList->uszMultiText + pVfsList->FileEntry[i].ouszName; + printf(" %s\t\t[%lli MB]\n", szFile, pVfsList->FileEntry[i].cbFileSize / (1024 * 1024)); + if(!strcmp(szFile, "general.json") || !strcmp(szFile, "registry.json") || !strcmp(szFile, "timeline.json")) { + _snprintf_s(szRemoteFile, _countof(szRemoteFile), _TRUNCATE, "\\forensic\\json\\%s", szFile); + _snprintf_s(szLocalFile + cchLocalFileDirectory, _countof(szLocalFile) - cchLocalFileDirectory, _TRUNCATE, "\\%s", szFile); + ActionAgentForensic_GetFile(szRemoteFile, szLocalFile, pVfsList->FileEntry[i].cbFileSize); + } + } + } + printf("Completed!\n\n"); +fail: + LocalFree(pReq); + LocalFree(pRsp); +} + +#endif /* _WIN32 */ +#ifdef LINUX + +VOID ActionAgentForensic() +{ + printf("Command 'agent-elastic' is only supported on Windows.\n"); +} + +#endif /* LINUX */ diff --git a/pcileech/executor.h b/pcileech/executor.h index 96789b4..a191075 100644 --- a/pcileech/executor.h +++ b/pcileech/executor.h @@ -57,6 +57,11 @@ VOID ActionExecShellcode(); /* * Try execute python code on a remote host in the context of the LeechSvc. */ -VOID ActionSvcExecPy(); +VOID ActionAgentExecPy(); + +/* +* Retrieve remote elasticsearch forensic information. +*/ +VOID ActionAgentForensic(); #endif /* __EXECUTOR_H__ */ diff --git a/pcileech/help.c b/pcileech/help.c index 641eddd..84d50b7 100644 --- a/pcileech/help.c +++ b/pcileech/help.c @@ -68,6 +68,7 @@ VOID Help_ShowGeneral() " pslist NATIVE \n" \ " psvirt2phys NATIVE [ 0, 1 ] \n" \ " agent-execpy NATIVE [ in, out ] (Remote LeechAgent) \n" \ + " agent-forensic NATIVE [ out ] (Remote LeechAgent) \n" \ " System specific commands and valid MODEs [ and options ]: \n" \ " mac_fvrecover NATIVE (USB3380) \n" \ " mac_fvrecover2 NATIVE (USB3380) \n" \ @@ -83,8 +84,8 @@ VOID Help_ShowGeneral() " LeechCore library at: https://github.com/ufrisk/LeechCore \n" \ " Affects all modes and commands. \n" \ " Common valid options: USB3380, FPGA, DumpIt, \n" \ - " -remote: Connect to a remote system LeechSvc to acquire remote memory. This \n" \ - " is a Windows-only feature. Specify remote host and remote user to \n" \ + " -remote: Connect to a remote system LeechAgent to acquire remote memory. \n" \ + " This is a Windows-only feature. Specify remote host + remote user to \n" \ " authenticate (or insecure if no authenciation). Kerberos-secure conn.\n" \ " Example: rpc://: \n" \ " -min : memory min address, valid range: 0x0 .. 0xffffffffffffffff \n" \ @@ -615,12 +616,12 @@ VOID Help_ShowDetailed() printf( " EXECUTE A PYTHON SCRIPT ON A REMOTE HOST RUNNING LeechAgent \n" \ " MODES : NATIVE \n" \ - " REQUIRE : Windows/Remote LeechSvc \n" \ + " REQUIRE : Windows/Remote LeechAgent \n" \ " OPTIONS : -in, -out \n" \ " Execute a Python script contained in the -in parameter on a remote host having\n" \ " the LeechAgent installed. The script will be executed in an embedded Python\n" \ " and the MemProcFS/LeechCore python APIs will be available and initialized. \n" \ - " Outout will be displayed on screen unless -out parameter is specified. \n" \ + " Output will be displayed on screen unless -out parameter is specified. \n" \ " EXAMPLE: \n" \ " 1) Execute the script 'myscript.py' on the remote host test1.contoso.com using\n" \ " physical memory acquired from WinPmem: \n" \ @@ -628,6 +629,21 @@ VOID Help_ShowDetailed() " -remote rpc://test1$@contoso.com:test1.contoso.com \n" \ ); break; + case AGENT_FORENSIC: + printf( + " RUN MemProcFS ON REMOTE HOST RUNNING LeechAgent AND RETRIEVE RESULT \n" \ + " MODES : NATIVE \n" \ + " REQUIRE : Windows/Remote LeechAgent \n" \ + " OPTIONS : -out \n" \ + " Start the MemProcFS memory analysis on the remote host. Results in the form of\n" \ + " ElasticSearch compatible JSON files are retrieved and saved locally. Result is\n" \ + " saved in working directory unless a _DIRECTORY_ is specified in -out parameter\n" \ + " EXAMPLE: \n" \ + " 1) Run memory analysis on remote host using WinPmem and save result in c:\\temp\n" \ + " pcileech.exe agent-forensic -out c:\temp -device pmem \n" \ + " -remote rpc://test1$@contoso.com:test1.contoso.com \n" \ + ); + break; case EXEC_KMD: _HelpShowExecCommand(); break; diff --git a/pcileech/pcileech.c b/pcileech/pcileech.c index 0546256..9e8503b 100644 --- a/pcileech/pcileech.c +++ b/pcileech/pcileech.c @@ -49,6 +49,7 @@ BOOL PCILeechConfigIntialize(_In_ DWORD argc, _In_ char* argv[]) {.tp = PSLIST,.sz = "pslist" }, {.tp = PSVIRT2PHYS,.sz = "psvirt2phys" }, {.tp = AGENT_EXEC_PY,.sz = "agent-execpy" }, + {.tp = AGENT_FORENSIC,.sz = "agent-forensic"}, }; DWORD j, i = 1; FILE *hFile; @@ -398,7 +399,10 @@ int main(_In_ int argc, _In_ char* argv[]) Action_UmdPsVirt2Phys(); break; case AGENT_EXEC_PY: - ActionSvcExecPy(); + ActionAgentExecPy(); + break; + case AGENT_FORENSIC: + ActionAgentForensic(); break; case KMDLOAD: if(ctxMain->cfg.qwKMD) { diff --git a/pcileech/pcileech.h b/pcileech/pcileech.h index 87510a9..e379602 100644 --- a/pcileech/pcileech.h +++ b/pcileech/pcileech.h @@ -58,6 +58,7 @@ typedef enum tdActionType { PSLIST, PSVIRT2PHYS, AGENT_EXEC_PY, + AGENT_FORENSIC, EXTERNAL_COMMAND_MODULE } ACTION_TYPE; diff --git a/pcileech/version.h b/pcileech/version.h index 989065a..8551f88 100644 --- a/pcileech/version.h +++ b/pcileech/version.h @@ -2,9 +2,9 @@ #define STRINGIZE(s) STRINGIZE2(s) #define VERSION_MAJOR 4 -#define VERSION_MINOR 10 +#define VERSION_MINOR 11 #define VERSION_REVISION 0 -#define VERSION_BUILD 24 +#define VERSION_BUILD 25 #define VER_FILE_DESCRIPTION_STR "The PCILeech Direct Memory Access Attack Toolkit" #define VER_FILE_VERSION VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, VERSION_BUILD diff --git a/readme.md b/readme.md index 0bd8bd6..d86e3f5 100644 --- a/readme.md +++ b/readme.md @@ -66,12 +66,13 @@ Please find a summary of the supported software based memory acquisition methods | [RAW physical memory dump](https://github.com/ufrisk/LeechCore/wiki/Device_File) | File | No | No | Yes | No | | [Full Microsoft Crash Dump](https://github.com/ufrisk/LeechCore/wiki/Device_File) | File | No | No | Yes | No | | [Full ELF Core Dump](https://github.com/ufrisk/LeechCore/wiki/Device_File) | File | No | No | Yes | No | +| [VMware](https://github.com/ufrisk/LeechCore/wiki/Device_VMWare) | Live Memory | Yes | Yes | No | No | | [VMware memory save file](https://github.com/ufrisk/LeechCore/wiki/Device_File) | File | No | No | Yes | No | | [TotalMeltdown](https://github.com/ufrisk/LeechCore/wiki/Device_Totalmeltdown) | CVE-2018-1038 | Yes | Yes | No | No | | [DumpIt /LIVEKD](https://github.com/ufrisk/LeechCore/wiki/Device_DumpIt) | Live Memory | Yes | No | No | No | | [WinPMEM](https://github.com/ufrisk/LeechCore/wiki/Device_WinPMEM) | Live Memory | Yes | No | No | No | | [LiveKd](https://github.com/ufrisk/LeechCore/wiki/Device_LiveKd) | Live Memory | Yes | No | No | No | -| [LiveCloudKd](https://github.com/ufrisk/LeechCore/wiki/Device_LiveCloudKd) | Live Memory | Yes | No | No | Yes | +| [LiveCloudKd](https://github.com/ufrisk/LeechCore/wiki/Device_LiveCloudKd) | Live Memory | Yes | Yes | No | Yes | | [Hyper-V Saved State](https://github.com/ufrisk/LeechCore/wiki/Device_HyperV_SavedState) | File | No | No | No | Yes | | [LeechAgent*](https://github.com/ufrisk/LeechCore/wiki/Device_Remote) | Remote | | | No | No | @@ -239,9 +240,15 @@ v4.1 * Signature updates. * Better support for recent x64 Linux kernels (Ubuntu 21.04). * Unmount of monted driver when CTRL+C pressed. - [v4.10](https://github.com/ufrisk/pcileech/releases/tag/v4.10) * Linux support for Windows 10 built-in signatures (dependency on MemProcFS v4.0). * Separate releases for Windows and Linux. * General cleanup. + + +[v4.11](https://github.com/ufrisk/pcileech/releases/tag/v4.11) +* Support for VMWare Workstation/Player live VM memory. +* Support for remote memory analysis with LeechAgent `agent-forensic` command. + * Runs MemProcFS forensic mode remotely. + * Retrieves ElasticSearch compatible JSON data.