Files
MemProcFS/memprocfs/memprocfs_dokan.c
2026-09-14 23:19:49 +02:00

591 lines
25 KiB
C

// memprocfs_dokan.c : implementation of core functionality for MemProcFS
// This is just a thin loader for the virtual memory manager dll which contains the logic.
//
// (c) Ulf Frisk, 2018-2026
// Author: Ulf Frisk, [email protected]
//
#ifdef _WIN32
#include <Windows.h>
#include <stdio.h>
#include <vmmdll.h>
#include "charutil.h"
#include "vfslist.h"
#include "vmmloader.h"
#include "version.h"
#pragma warning( push )
#pragma warning( disable : 4005 )
#include <dokan.h>
#pragma warning( pop )
#define dbg_wprintf_init(format, ...) {}
#define dbg_wprintf(format, ...) {}
#define dbg_GetTickCount64() 0
#define VER_OSARCH "Windows"
typedef struct tdVMMVFS_CONFIG {
FILETIME ftDefaultTime;
BOOL fInitialized;
} VMMVFS_CONFIG, *PVMMVFS_CONFIG;
PVMMVFS_CONFIG ctxVfs;
VMM_HANDLE g_hVMM;
CHAR g_VfsMountPoint = 'M';
BOOL g_IsLinux = FALSE;
//-------------------------------------------------------------------------------
// DOKAN CALLBACK FUNCTIONS BELOW:
//-------------------------------------------------------------------------------
NTSTATUS
VfsDokanCallback_CreateFile_ExistingDisposition(_In_ ULONG CreateDisposition)
{
// Dokan passes the native NtCreateFile FILE_* disposition values here,
// not the similarly numbered Win32 CreateFile CREATE_*/OPEN_* values.
switch(CreateDisposition) {
case FILE_OPEN:
case FILE_OVERWRITE:
return STATUS_SUCCESS;
case FILE_SUPERSEDE:
case FILE_CREATE:
case FILE_OPEN_IF:
case FILE_OVERWRITE_IF:
return STATUS_OBJECT_NAME_COLLISION;
default:
return STATUS_INVALID_PARAMETER;
}
}
NTSTATUS
VfsDokanCallback_CreateFile_Impl(_In_ LPSTR uszFullPath, PDOKAN_IO_SECURITY_CONTEXT SecurityContext, ACCESS_MASK DesiredAccess, ULONG FileAttributes, ULONG ShareAccess, ULONG CreateDisposition, ULONG CreateOptions, PDOKAN_FILE_INFO DokanFileInfo)
{
VFS_ENTRY VfsEntry;
CHAR uszPath[MAX_PATH];
LPSTR uszFile;
BOOL fIsDirectoryExisting = FALSE;
UNREFERENCED_PARAMETER(SecurityContext);
UNREFERENCED_PARAMETER(FileAttributes);
if(!ctxVfs || !ctxVfs->fInitialized) { return STATUS_FILE_INVALID; }
// root directory
if(!strcmp(uszFullPath, "\\")) {
DokanFileInfo->IsDirectory = TRUE;
if(CreateOptions & FILE_NON_DIRECTORY_FILE) { return STATUS_FILE_IS_A_DIRECTORY; }
if((CreateDisposition == FILE_SUPERSEDE) || (CreateDisposition == FILE_OVERWRITE) || (CreateDisposition == FILE_OVERWRITE_IF)) { return STATUS_FILE_IS_A_DIRECTORY; }
return VfsDokanCallback_CreateFile_ExistingDisposition(CreateDisposition);
}
// other files
uszFile = CharUtil_PathSplitLastEx(uszFullPath, uszPath, sizeof(uszPath));
if(!VfsList_GetSingle(uszPath[0] ? uszPath : "\\", uszFile, &VfsEntry, &fIsDirectoryExisting)) {
return fIsDirectoryExisting ? STATUS_OBJECT_NAME_NOT_FOUND : STATUS_OBJECT_PATH_NOT_FOUND;
}
DokanFileInfo->Nocache = TRUE;
DokanFileInfo->IsDirectory = VfsEntry.fDirectory;
if(VfsEntry.fDirectory) {
if(CreateOptions & FILE_NON_DIRECTORY_FILE) { return STATUS_FILE_IS_A_DIRECTORY; }
if((CreateDisposition == FILE_SUPERSEDE) || (CreateDisposition == FILE_OVERWRITE) || (CreateDisposition == FILE_OVERWRITE_IF)) { return STATUS_FILE_IS_A_DIRECTORY; }
} else if(CreateOptions & FILE_DIRECTORY_FILE) {
return STATUS_NOT_A_DIRECTORY;
}
return VfsDokanCallback_CreateFile_ExistingDisposition(CreateDisposition);
}
NTSTATUS DOKAN_CALLBACK
VfsDokanCallback_CreateFile(LPCWSTR FileName, PDOKAN_IO_SECURITY_CONTEXT SecurityContext, ACCESS_MASK DesiredAccess, ULONG FileAttributes, ULONG ShareAccess, ULONG CreateDisposition, ULONG CreateOptions, PDOKAN_FILE_INFO DokanFileInfo)
{
UINT64 tmStart = dbg_GetTickCount64();
NTSTATUS nt;
LPSTR uszFullPath;
BYTE pbBuffer[3 * MAX_PATH];
if(!CharUtil_WtoU((LPWSTR)FileName, -1, pbBuffer, sizeof(pbBuffer), &uszFullPath, NULL, 0)) { return STATUS_OBJECT_NAME_NOT_FOUND; }
if(!ctxVfs || !ctxVfs->fInitialized) { return STATUS_FILE_INVALID; }
nt = VfsDokanCallback_CreateFile_Impl(uszFullPath, SecurityContext, DesiredAccess, FileAttributes, ShareAccess, CreateDisposition, CreateOptions, DokanFileInfo);
dbg_wprintf(L"DEBUG::%08x %8x VfsCallback_CreateFile:\t\t 0x%08x %s [ %08x %08x %08x %08x ]\n", (DWORD)(dbg_GetTickCount64() - tmStart), nt, FileName, FileAttributes, ShareAccess, CreateDisposition, CreateOptions);
return nt;
}
NTSTATUS DOKAN_CALLBACK
VfsDokanCallback_GetFileInformation_Impl(_In_ LPSTR uszFullPath, _Inout_ LPBY_HANDLE_FILE_INFORMATION hfi, _In_ PDOKAN_FILE_INFO DokanFileInfo)
{
UINT64 tmStart = dbg_GetTickCount64();
VFS_ENTRY VfsEntry;
CHAR uszPath[MAX_PATH];
LPSTR uszFile;
BOOL fIsDirectoryExisting = FALSE;
if(!ctxVfs || !ctxVfs->fInitialized) { return STATUS_FILE_INVALID; }
dbg_wprintf_init(L"DEBUG::%08x -------- VfsCallback_GetFileInformation:\t 0x%08x %s\n", 0, wcsFileName);
// matches: root directory
if(!strcmp(uszFullPath, "\\")) {
hfi->ftCreationTime = ctxVfs->ftDefaultTime;
hfi->ftLastWriteTime = ctxVfs->ftDefaultTime;
hfi->ftLastAccessTime = ctxVfs->ftDefaultTime;
hfi->nFileSizeHigh = 0;
hfi->nFileSizeLow = 0;
hfi->dwFileAttributes = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
dbg_wprintf(L"DEBUG::%08x %8x VfsCallback_GetFileInformation:\t 0x%08x %S\n", (DWORD)(dbg_GetTickCount64() - tmStart), STATUS_SUCCESS, uszFullPath);
return STATUS_SUCCESS;
}
uszFile = CharUtil_PathSplitLastEx(uszFullPath, uszPath, sizeof(uszPath));
if(!VfsList_GetSingle((uszPath[0] ? uszPath : "\\"), uszFile, &VfsEntry, &fIsDirectoryExisting)) {
dbg_wprintf(L"DEBUG::%08x %8x VfsCallback_GetFileInformation:\t 0x%08x %S\n", (DWORD)(dbg_GetTickCount64() - tmStart), STATUS_FILE_NOT_AVAILABLE, uszFullPath);
return STATUS_FILE_NOT_AVAILABLE;
}
hfi->dwFileAttributes = VfsEntry.dwFileAttributes;
hfi->ftCreationTime = VfsEntry.ftCreationTime;
hfi->ftLastAccessTime = VfsEntry.ftLastAccessTime;
hfi->ftLastWriteTime = VfsEntry.ftLastWriteTime;
hfi->nFileSizeHigh = (DWORD)(VfsEntry.cbFileSize >> 32);
hfi->nFileSizeLow = (DWORD)(VfsEntry.cbFileSize);
hfi->nFileIndexHigh = CharUtil_Hash32U(uszFullPath, TRUE);
hfi->nFileIndexLow = CharUtil_Hash32U(VfsEntry.uszName, TRUE);
dbg_wprintf(L"DEBUG::%08x %8x VfsCallback_GetFileInformation:\t 0x%08x %S\t [ %08x %08x%08x %016llx %016llx %016llx ]\n",
(DWORD)(dbg_GetTickCount64() - tmStart),
STATUS_SUCCESS,
uszFullPath,
hfi->dwFileAttributes,
hfi->nFileSizeHigh, hfi->nFileSizeLow,
*(PQWORD)&hfi->ftCreationTime,
*(PQWORD)&hfi->ftLastAccessTime,
*(PQWORD)&hfi->ftLastWriteTime
);
return STATUS_SUCCESS;
}
NTSTATUS DOKAN_CALLBACK
VfsDokanCallback_GetFileInformation(_In_ LPCWSTR wcsFileName, _Inout_ LPBY_HANDLE_FILE_INFORMATION hfi, _In_ PDOKAN_FILE_INFO DokanFileInfo)
{
LPSTR uszFullPath;
BYTE pbBuffer[3 * MAX_PATH];
if(!CharUtil_WtoU((LPWSTR)wcsFileName, -1, pbBuffer, sizeof(pbBuffer), &uszFullPath, NULL, 0)) { return STATUS_FILE_INVALID; }
return VfsDokanCallback_GetFileInformation_Impl(uszFullPath, hfi, DokanFileInfo);
}
NTSTATUS DOKAN_CALLBACK
VfsDokanCallback_FindFiles(LPCWSTR wcsFileName, PFillFindData FillFindData, PDOKAN_FILE_INFO DokanFileInfo)
{
UINT64 tmStart = dbg_GetTickCount64();
if(!ctxVfs || !ctxVfs->fInitialized) { return STATUS_FILE_INVALID; }
dbg_wprintf_init(L"DEBUG::%08x -------- VfsCallback_FindFiles:\t\t\t 0x%08x %s\n", 0, wcsFileName);
VfsList_ListDirectoryW((LPWSTR)wcsFileName, DokanFileInfo, (PFN_VFSLISTW_CALLBACK)FillFindData);
dbg_wprintf(L"DEBUG::%08x %8x VfsCallback_FindFiles:\t\t\t 0x%08x %s\n", (DWORD)(dbg_GetTickCount64() - tmStart), STATUS_SUCCESS, wcsFileName);
return STATUS_SUCCESS;
}
NTSTATUS DOKAN_CALLBACK
VfsDokanCallback_ReadFile(LPCWSTR wcsFileName, LPVOID Buffer, DWORD BufferLength, LPDWORD ReadLength, LONGLONG Offset, PDOKAN_FILE_INFO DokanFileInfo)
{
UINT64 tmStart = dbg_GetTickCount64();
NTSTATUS nt;
if(!ctxVfs || !ctxVfs->fInitialized) { return STATUS_FILE_INVALID; }
dbg_wprintf_init(L"DEBUG::%08x -------- VfsCallback_ReadFile:\t\t\t 0x%08x %s\n", 0, wcsFileName);
nt = VMMDLL_VfsReadW(g_hVMM, (LPWSTR)wcsFileName, Buffer, BufferLength, ReadLength, Offset);
dbg_wprintf(L"DEBUG::%08x %8x VfsCallback_ReadFile:\t\t\t 0x%08x %s\t [ %016llx %08x %08x ]\n", (DWORD)(dbg_GetTickCount64() - tmStart), nt, wcsFileName, Offset, BufferLength, *ReadLength);
return nt;
}
NTSTATUS DOKAN_CALLBACK
VfsDokanCallback_WriteFile(LPCWSTR wcsFileName, LPCVOID Buffer, DWORD NumberOfBytesToWrite, LPDWORD NumberOfBytesWritten, LONGLONG Offset, PDOKAN_FILE_INFO DokanFileInfo)
{
UINT64 tmStart = dbg_GetTickCount64();
NTSTATUS nt;
if(!ctxVfs || !ctxVfs->fInitialized) { return STATUS_FILE_INVALID; }
dbg_wprintf_init(L"DEBUG::%08x -------- VfsCallback_WriteFile:\t\t\t 0x%08x %s\n", 0, wcsFileName);
nt = VMMDLL_VfsWriteW(g_hVMM, (LPWSTR)wcsFileName, (PBYTE)Buffer, NumberOfBytesToWrite, NumberOfBytesWritten, Offset);
dbg_wprintf(L"DEBUG::%08x %8x VfsCallback_WriteFile:\t\t\t 0x%08x %s\t [ %016llx %08x %08x ]\n", (DWORD)(dbg_GetTickCount64() - tmStart), nt, wcsFileName, Offset, NumberOfBytesToWrite, *NumberOfBytesWritten);
return nt;
}
NTSTATUS DOKAN_CALLBACK
VfsDokanCallback_SetFileSize(LPCWSTR wcsFileName, LONGLONG ByteOffset, PDOKAN_FILE_INFO DokanFileInfo)
{
if(!ctxVfs || !ctxVfs->fInitialized) { return STATUS_FILE_INVALID; }
if(ByteOffset < 0) { return STATUS_INVALID_PARAMETER; }
// MemProcFS files have a fixed virtual size. Acknowledge advisory allocation
// and end-of-file changes and let writes update the virtual file by path.
return STATUS_SUCCESS;
}
NTSTATUS DOKAN_CALLBACK
VfsDokanCallback_SetFileAttributes(LPCWSTR wcsFileName, DWORD FileAttributes, PDOKAN_FILE_INFO DokanFileInfo)
{
if(!ctxVfs || !ctxVfs->fInitialized) { return STATUS_FILE_INVALID; }
// File attributes are synthesized by MemProcFS and cannot be persisted.
return STATUS_SUCCESS;
}
NTSTATUS DOKAN_CALLBACK
VfsDokanCallback_SetFileTime(LPCWSTR wcsFileName, CONST FILETIME *CreationTime, CONST FILETIME *LastAccessTime, CONST FILETIME *LastWriteTime, PDOKAN_FILE_INFO DokanFileInfo)
{
if(!ctxVfs || !ctxVfs->fInitialized) { return STATUS_FILE_INVALID; }
// File timestamps are synthesized by MemProcFS and cannot be persisted.
return STATUS_SUCCESS;
}
//-------------------------------------------------------------------------------
// VFS INITIALIZATION FUNCTIONALITY BELOW:
//-------------------------------------------------------------------------------
VOID VfsDokan_Close(_In_ CHAR chMountPoint)
{
HMODULE hModuleDokan = NULL;
WCHAR wchMountPoint = chMountPoint;
BOOL(WINAPI * pfnDokanUnmount)(WCHAR DriveLetter);
if(ctxVfs && ctxVfs->fInitialized) {
ctxVfs->fInitialized = FALSE;
if(wchMountPoint) {
hModuleDokan = LoadLibraryExA("dokan2.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
if(!hModuleDokan) {
hModuleDokan = LoadLibraryExA("dokan2.dll", NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32);
}
if(hModuleDokan) {
pfnDokanUnmount = (BOOL(WINAPI *)(WCHAR))GetProcAddress(hModuleDokan, "DokanUnmount");
if(pfnDokanUnmount) {
pfnDokanUnmount(wchMountPoint);
}
FreeLibrary(hModuleDokan);
}
}
}
LocalFree(ctxVfs);
ctxVfs = NULL;
}
#ifdef VMM_PROFILE_FULL
#include "ex/memprocfs_ex.h"
#else /* VMM_PROFILE_FULL */
#define MEMPROCFS_IS_OPENSOURCE 1
#define MEMPROCFS_SPLASH \
"============================== MemProcFS ==============================\n" \
" - Author: Ulf Frisk - [email protected] \n" \
" - Info: https://github.com/ufrisk/MemProcFS \n" \
" - Discord: https://pcileech.com/discord \n" \
" - License: GNU Affero General Public License v3.0 \n" \
" - Licensed To: %s\n" \
" --------------------------------------------------------------------- \n"
#endif /* VMM_PROFILE_FULL */
VOID VfsDokan_InitializeAndMount_DisplayInfo(LPWSTR wszMountPoint)
{
ULONG64 qwVersionVmmMajor = 0, qwVersionVmmMinor = 0, qwVersionVmmRevision = 0;
ULONG64 qwVersionWinMajor = 0, qwVersionWinMinor = 0, qwVersionWinBuild = 0;
ULONG64 qwUniqueSystemId = 0, iMemoryModel;
DWORD cbRead = 0;
CHAR szLinuxBanner[96] = { 0 }, szTag[32] = { 0 };
LPSTR szLinuxRelease = NULL;
LPSTR uszLicensedTo = NULL;
BOOL fGPL;
// get vmm.dll versions
VMMDLL_ConfigGet(g_hVMM, VMMDLL_OPT_CONFIG_VMM_VERSION_MAJOR, &qwVersionVmmMajor);
VMMDLL_ConfigGet(g_hVMM, VMMDLL_OPT_CONFIG_VMM_VERSION_MINOR, &qwVersionVmmMinor);
VMMDLL_ConfigGet(g_hVMM, VMMDLL_OPT_CONFIG_VMM_VERSION_REVISION, &qwVersionVmmRevision);
// get operating system versions
VMMDLL_ConfigGet(g_hVMM, VMMDLL_OPT_CORE_MEMORYMODEL, &iMemoryModel);
VMMDLL_ConfigGet(g_hVMM, VMMDLL_OPT_WIN_VERSION_MAJOR, &qwVersionWinMajor);
VMMDLL_ConfigGet(g_hVMM, VMMDLL_OPT_WIN_VERSION_MINOR, &qwVersionWinMinor);
VMMDLL_ConfigGet(g_hVMM, VMMDLL_OPT_WIN_VERSION_BUILD, &qwVersionWinBuild);
VMMDLL_ConfigGet(g_hVMM, VMMDLL_OPT_WIN_SYSTEM_UNIQUE_ID, &qwUniqueSystemId);
if(g_IsLinux) {
VMMDLL_VfsReadU(g_hVMM, "\\sys\\unique-tag.txt", (PBYTE)szTag, sizeof(szTag) - 1, &cbRead, 0);
} else {
snprintf(szTag, sizeof(szTag), "%i_%x", (DWORD)qwVersionWinBuild, (DWORD)qwUniqueSystemId);
}
uszLicensedTo = VMMDLL_LicensedTo();
if(!uszLicensedTo) {
printf("[CRITICAL] A valid license could not be found. Terminating.\n");
exit(1);
return;
}
fGPL = strstr(uszLicensedTo, "General Public License") != NULL;
if((MEMPROCFS_IS_OPENSOURCE && !fGPL) || (!MEMPROCFS_IS_OPENSOURCE && fGPL)) {
printf("[CRITICAL] License mis-match. Terminating.\n");
exit(1);
return;
}
printf("\n"MEMPROCFS_SPLASH \
" - Version: %i.%i.%i (%s)\n" \
" - Mount Point: %S \n" \
" - Tag: %s \n",
uszLicensedTo,
(DWORD)qwVersionVmmMajor, (DWORD)qwVersionVmmMinor, (DWORD)qwVersionVmmRevision, VER_OSARCH,
wszMountPoint, szTag);
if(qwVersionWinMajor && (iMemoryModel < (sizeof(VMMDLL_MEMORYMODEL_TOSTRING) / sizeof(LPSTR)))) {
printf(" - Operating System: Windows %i.%i.%i (%s)\n",
(DWORD)qwVersionWinMajor, (DWORD)qwVersionWinMinor, (DWORD)qwVersionWinBuild, VMMDLL_MEMORYMODEL_TOSTRING[iMemoryModel]);
} else if(g_IsLinux) {
VMMDLL_VfsReadU(g_hVMM, "\\sys\\version.txt", (PBYTE)szLinuxBanner, sizeof(szLinuxBanner) - 1, &cbRead, 0);
if(!strncmp(szLinuxBanner, "Linux version ", 14)) {
szLinuxRelease = szLinuxBanner + 14;
szLinuxRelease[strcspn(szLinuxRelease, " ")] = 0;
}
printf(" - Operating System: Linux x64 %s\n", szLinuxRelease);
} else {
printf(" - Operating System: Unknown\n");
}
printf("==========================================================================\n\n");
VMMDLL_MemFree(uszLicensedTo);
}
VOID VfsDokan_InitializeAndMount(_In_ CHAR chMountPoint)
{
int status;
HMODULE hModuleDokan = NULL;
PDOKAN_OPTIONS pDokanOptions = NULL;
PDOKAN_OPERATIONS pDokanOperations = NULL;
WCHAR wszMountPoint[] = { 'M', ':', '\\', 0 };
WCHAR wszUnc[] = { '\\', 'M', 'e', 'm', 'P', 'r', 'o', 'c', 'F', 'S', '\\', 'M', 0};
SYSTEMTIME SystemTimeNow;
VOID(WINAPI *pfnDokanInit)();
int(WINAPI *pfnDokanMain)(PDOKAN_OPTIONS, PDOKAN_OPERATIONS);
VOID(WINAPI *pfnDokanShutdown)();
// allocate
hModuleDokan = LoadLibraryExA("dokan2.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
if(!hModuleDokan) {
hModuleDokan = LoadLibraryExA("dokan2.dll", NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32);
}
if(!hModuleDokan) {
printf("MOUNT: Failed. The required DOKANY file system library is not installed. \n");
printf("Please download from : https://github.com/dokan-dev/dokany/releases/latest\n");
goto fail;
}
pfnDokanInit = (VOID(WINAPI*)())GetProcAddress(hModuleDokan, "DokanInit");
pfnDokanMain = (int(WINAPI*)(PDOKAN_OPTIONS, PDOKAN_OPERATIONS))GetProcAddress(hModuleDokan, "DokanMain");
pfnDokanShutdown = (VOID(WINAPI*)())GetProcAddress(hModuleDokan, "DokanShutdown");
if(!pfnDokanMain || !pfnDokanInit || !pfnDokanShutdown) {
printf("MOUNT: Failed. The required DOKANY file system library is not installed. \n");
printf("Please download from : https://github.com/dokan-dev/dokany/releases/latest\n");
goto fail;
}
pDokanOptions = (PDOKAN_OPTIONS)LocalAlloc(LMEM_ZEROINIT, sizeof(DOKAN_OPTIONS));
pDokanOperations = (PDOKAN_OPERATIONS)LocalAlloc(LMEM_ZEROINIT, sizeof(DOKAN_OPERATIONS));
if(!pDokanOptions || !pDokanOperations) {
printf("MOUNT: Failed (out of memory).\n");
goto fail;
}
// allocate empty vfs context
ctxVfs = (PVMMVFS_CONFIG)LocalAlloc(LMEM_ZEROINIT, sizeof(VMMVFS_CONFIG));
if(!ctxVfs) { goto fail; }
// set vfs context
GetSystemTime(&SystemTimeNow);
SystemTimeToFileTime(&SystemTimeNow, &ctxVfs->ftDefaultTime);
ctxVfs->fInitialized = TRUE;
// set options
pDokanOptions->Version = DOKAN_VERSION;
pDokanOptions->Options |= DOKAN_OPTION_NETWORK;
wszUnc[11] = chMountPoint;
pDokanOptions->UNCName = wszUnc;
wszMountPoint[0] = chMountPoint;
pDokanOptions->MountPoint = wszMountPoint;
pDokanOptions->Timeout = 60000;
// set callbacks
pDokanOperations->ZwCreateFile = VfsDokanCallback_CreateFile;
pDokanOperations->GetFileInformation = VfsDokanCallback_GetFileInformation;
pDokanOperations->FindFiles = VfsDokanCallback_FindFiles;
pDokanOperations->ReadFile = VfsDokanCallback_ReadFile;
pDokanOperations->WriteFile = VfsDokanCallback_WriteFile;
pDokanOperations->SetFileAttributes = VfsDokanCallback_SetFileAttributes;
pDokanOperations->SetFileTime = VfsDokanCallback_SetFileTime;
pDokanOperations->SetEndOfFile = VfsDokanCallback_SetFileSize;
pDokanOperations->SetAllocationSize = VfsDokanCallback_SetFileSize;
// print system information to console
VfsDokan_InitializeAndMount_DisplayInfo(wszMountPoint);
// mount file system
pfnDokanInit();
status = pfnDokanMain(pDokanOptions, pDokanOperations);
while(ctxVfs && ctxVfs->fInitialized && (status == DOKAN_SUCCESS)) {
printf("MOUNT: ReMounting as drive %S\n", pDokanOptions->MountPoint);
status = pfnDokanMain(pDokanOptions, pDokanOperations);
}
pfnDokanShutdown();
if(status == -5) {
printf("MOUNT: Failed: drive busy/already mounted.\n");
} else if(status) {
printf("MOUNT: Failed. Status Code: %i\n", status);
}
fail:
if(hModuleDokan) { FreeLibrary(hModuleDokan); }
LocalFree(pDokanOptions);
LocalFree(pDokanOperations);
VfsDokan_Close(0);
}
//-----------------------------------------------------------------------------
// GENERAL INITIALIZATION FUNCTIONALITY BELOW:
//-----------------------------------------------------------------------------
_Success_(return) BOOL MemProcFS_VfsListU(_In_ LPSTR uszPath, _Inout_ PVMMDLL_VFS_FILELIST2 pFileList)
{
return VMMDLL_VfsListU(g_hVMM, uszPath, pFileList);
}
/*
* Retrieve the mount point from the command line arguments.
* If no '-mount' command line argument is given the default mount point will be M:
* _EXCEPT_ if '-pythonexec' is also given in which case '\0' will be returned.
* -- argc
* -- argv
* -- pfMountSpecified
* -- pfPythonExec
* -- return = the mount point as a drive letter.
*/
CHAR GetMountPoint(_In_ DWORD argc, _In_ wchar_t* argv[], _Out_ PBOOL pfMountSpecified, _Out_ PBOOL pfPythonExec)
{
CHAR chMountPoint = 'M';
DWORD i = 1;
*pfPythonExec = FALSE;
*pfMountSpecified = FALSE;
for(i = 0; i < argc - 1; i++) {
if(0 == _wcsicmp(argv[i], L"-mount")) {
chMountPoint = (CHAR)argv[i + 1][0];
*pfMountSpecified = TRUE;
}
if(0 == _wcsicmp(argv[i], L"-pythonexec")) {
*pfPythonExec = TRUE;
}
}
if(chMountPoint >= 'a' && chMountPoint <= 'z') {
chMountPoint = chMountPoint - 'a' + 'A';
}
return chMountPoint;
}
/*
*
*/
VOID MemProcFS_SetLinuxMode(_In_ DWORD argc, _In_ wchar_t* argv[])
{
DWORD i;
for(i = 1; i < argc; i++) {
if(0 == _wcsicmp(argv[i], L"-linux")) {
g_IsLinux = TRUE;
return;
}
}
}
/*
* Call the VMMDLL_Close() function in a separate newly create thread.
* This will allow the main thread to exit even if the VMMDLL_Close()
* function should happen to get stuck.
* -- pv
*/
DWORD WINAPI MemProcFsCtrlHandler_TryShutdownThread(PVOID pv)
{
__try {
VfsDokan_Close(g_VfsMountPoint);
VfsList_Close();
} __except(EXCEPTION_EXECUTE_HANDLER) { ; }
__try {
VMMDLL_CloseAll();
} __except(EXCEPTION_EXECUTE_HANDLER) { ; }
return 1;
}
/*
* SetConsoleCtrlHandler for the MemProcFS - clean up whenever CTRL+C is pressed.
* If this is not here MemProcFS might not exit otherwise if there are lingering
* threads most notably in the Python plugin functionality.
* -- fdwCtrlType
* -- return
*/
BOOL WINAPI MemProcFsCtrlHandler(DWORD fdwCtrlType)
{
HANDLE hThread;
if (fdwCtrlType == CTRL_C_EVENT) {
printf("CTRL+C detected - shutting down ...\n");
hThread = CreateThread(NULL, 0, MemProcFsCtrlHandler_TryShutdownThread, NULL, 0, NULL);
if(hThread) { WaitForSingleObject(hThread, INFINITE); }
TerminateProcess(GetCurrentProcess(), 1);
Sleep(1000);
ExitProcess(1);
return TRUE;
}
if(fdwCtrlType == CTRL_BREAK_EVENT) {
printf("CTRL+BREAK detected - refresh/debug initiated ...\n");
VMMDLL_ConfigSet(g_hVMM, VMMDLL_OPT_CONFIG_DEBUG, 1);
printf("CTRL+BREAK finished ...\n");
return TRUE;
}
return FALSE;
}
/*
* Main entry point of MemProcFS. The main function will load and initialize
* VMM.DLL then initialize the VMM.DLL plugin manager and then hand over control
* to vfs.c!VfsInitializeAndMount which will start the virtual file system and
* mount it at the correct mount point.
* All 'interesting' functionality will take part in VMM.DLL - the memprocfs
* executable should be considered as a thin wrapper around VMM.DLL.
* -- argc
* -- argv
* -- return
*/
int wmain(_In_ int argc, _In_ wchar_t* argv[])
{
// MAIN FUNCTION PROPER BELOW:
int i;
BOOL result, fMountSpecified, fPythonExec;
LPSTR *szArgs = NULL;
LC_CMD_AGENT_VFS_REQ Req = { 0 };
g_VfsMountPoint = GetMountPoint(argc, argv, &fMountSpecified, &fPythonExec);
if(g_VfsMountPoint < 'A' || g_VfsMountPoint > 'Z') {
if(!fPythonExec || fMountSpecified) {
printf("MemProcFS: Invalid -mount specified (only A-Z allowed).\n");
return 1;
}
}
LoadLibraryExA("leechcore.dll", NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32);
if(!(szArgs = LocalAlloc(LMEM_ZEROINIT, (argc + 1ULL) * sizeof(LPSTR)))) {
printf("MemProcFS: Out of memory!\n");
return 1;
}
SetConsoleCtrlHandler(MemProcFsCtrlHandler, TRUE);
szArgs[0] = "-printf";
for(i = 1; i < argc; i++) {
if(!CharUtil_WtoU(argv[i], (DWORD)-1, NULL, 0, &szArgs[i], NULL, CHARUTIL_FLAG_ALLOC)) {
printf("MemProcFS: Invalid argument!\n");
return 1;
}
if(!_stricmp(szArgs[i], "-linux")) {
g_IsLinux = TRUE;
}
}
if(argc > 2) {
CharUtil_UtoU("-userinteract", (DWORD)-1, NULL, 0, &szArgs[argc++], NULL, CHARUTIL_FLAG_ALLOC);
}
if(g_IsLinux && !VmmlxLoader_Initialize()) {
printf("MemProcFS: Error: Unable to load required vmmlx.dll\n");
return 1;
}
g_hVMM = VMMDLL_Initialize(argc, szArgs);
if(!g_hVMM) {
// any error message will already be shown by the InitializeReserved function.
return 1;
}
if(fPythonExec && !fMountSpecified) {
VMMDLL_CloseAll();
return 0;
}
VMMDLL_ConfigSet(g_hVMM, VMMDLL_OPT_CONFIG_STATISTICS_FUNCTIONCALL, 1);
result = VMMDLL_InitializePlugins(g_hVMM);
if(!result) {
printf("MemProcFS: Error file system plugins in %s!\n", (g_IsLinux ? "vmmlx.dll" : "vmm.dll"));
return 1;
}
SetConsoleCtrlHandler(MemProcFsCtrlHandler, TRUE);
VfsList_Initialize(MemProcFS_VfsListU, 500, 128, FALSE);
VfsDokan_InitializeAndMount(g_VfsMountPoint);
CreateThread(NULL, 0, MemProcFsCtrlHandler_TryShutdownThread, NULL, 0, NULL);
Sleep(250);
TerminateProcess(GetCurrentProcess(), 1);
Sleep(500);
ExitProcess(1);
return 0;
}
#endif /* _WIN32 */