Files
2026-04-29 17:10:47 +02:00

403 lines
14 KiB
C++

/*****************************************************************************/
/* WinMain.cpp Copyright (c) Ladislav Zezula 2003 */
/*---------------------------------------------------------------------------*/
/* A file that simulates access on a file */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 14.07.03 1.00 Lad The first version of WinMain.cpp */
/*****************************************************************************/
#include "FileTest.h"
#include "resource.h"
#pragma comment(lib, "Comctl32.lib")
//-----------------------------------------------------------------------------
// Global variables
TContextMenu g_ContextMenus[MAX_CONTEXT_MENUS];
TToolTip g_Tooltip;
DWORD g_dwWinVer;
DWORD g_dwWinBuild;
TCHAR g_szInitialDirectory[MAX_PATH];
DWORD g_dwMenuCount = 0;
//-----------------------------------------------------------------------------
// Local functions
static LPCTSTR IsCommandSwitch(LPCTSTR szArg, LPCTSTR szSwitch)
{
size_t nLength;
// It must be valid
if(szArg && szArg[0] && szSwitch && szSwitch[0])
{
// It has to start with '/' or '-'
if(szArg[0] == _T('/') || szArg[0] == _T('-'))
{
// Get length and the inner switch
nLength = _tcslen(szSwitch);
szArg++;
if(!_tcsnicmp(szArg, szSwitch, nLength))
{
return szArg + nLength;
}
}
}
return NULL;
}
static bool CheckForCommandSwitch(LPCTSTR szArg, LPCTSTR szSwitch, LPDWORD PtrValue, bool bIsSingleSwitch = false)
{
LPCTSTR szArgValue;
LPCTSTR szIntValue;
LPTSTR szEndValue;
int nRadix;
if((szArgValue = IsCommandSwitch(szArg, szSwitch)) != NULL)
{
// Pre-fill the value with zero
PtrValue[0] = 0;
// Variant #1: /Argument:IntValue
if(szArgValue[0] == _T(':') && bIsSingleSwitch == false)
{
szArgValue = szArgValue + 1;
szIntValue = SkipHexaPrefix(szArgValue);
nRadix = (szIntValue > szArgValue) ? 16 : 10;
PtrValue[0] = StrToInt(szIntValue, &szEndValue, nRadix);
return (szEndValue[0] == 0);
}
// Variant #2: /Argument
if(szArgValue[0] == 0 && bIsSingleSwitch)
{
PtrValue[0] = TRUE;
return true;
}
}
return false;
}
static void SetTokenObjectIntegrityLevel(DWORD dwIntegrityLevel)
{
SID_IDENTIFIER_AUTHORITY Sia = SECURITY_MANDATORY_LABEL_AUTHORITY;
SECURITY_DESCRIPTOR sd;
HANDLE hToken;
DWORD dwLength;
PACL pAcl;
PSID pSid;
// Do nothing on OSes where mandatory ACEs are not supported
if(pfnAddMandatoryAce == NULL)
return;
// Initialize blank security descriptor
if(!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION))
return;
// Allocate mandatory label SID
if(!AllocateAndInitializeSid(&Sia, 1, dwIntegrityLevel, 0, 0, 0, 0, 0, 0, 0, &pSid))
return;
// Open current token
if(!OpenThreadToken(GetCurrentThread(), WRITE_OWNER, TRUE, &hToken))
{
if(GetLastError() == ERROR_NO_TOKEN)
OpenProcessToken(GetCurrentProcess(), WRITE_OWNER, &hToken);
}
// If succeeded, set the integrity level
if(hToken != NULL)
{
// Create ACL
dwLength = sizeof(ACL) + sizeof(SYSTEM_MANDATORY_LABEL_ACE) - sizeof(DWORD) + GetLengthSid(pSid);
pAcl = (PACL)HeapAlloc(g_hHeap, 0, dwLength);
if(pAcl != NULL)
{
if(InitializeAcl(pAcl, dwLength, ACL_REVISION))
{
if(pfnAddMandatoryAce(pAcl, ACL_REVISION, 0, SYSTEM_MANDATORY_LABEL_NO_WRITE_UP, pSid))
{
NtSetSecurityObject(hToken, LABEL_SECURITY_INFORMATION, &sd);
}
}
HeapFree(g_hHeap, 0, pAcl);
}
}
FreeSid(pSid);
}
BOOL CALLBACK EnumMenusProc(HMODULE hModule, LPCTSTR lpszType, LPTSTR lpszName, LONG_PTR /* lParam */)
{
// Only take menus
if(lpszType == RT_MENU)
{
// Debug code check
assert(g_dwMenuCount < MAX_CONTEXT_MENUS);
// Check if the number of context menus is in range
if(g_dwMenuCount < MAX_CONTEXT_MENUS)
{
// Insert the menu entry
g_ContextMenus[g_dwMenuCount].szMenuName = lpszName;
g_ContextMenus[g_dwMenuCount].hMenu = LoadMenu(hModule, lpszName);
// Increment the menu count
g_dwMenuCount++;
}
}
// Keep enumerating
return TRUE;
}
static HANDLE InitialOpenFile(TFileTestData * pData)
{
OBJECT_ATTRIBUTES ObjAttr;
IO_STATUS_BLOCK IoStatus = {0};
UNICODE_STRING FileName;
HANDLE hFile = NULL;
if(pData->szFileName1 && pData->szFileName1[0])
{
if(IsNativeName(pData->szFileName1))
{
InitializeObjectAttributes(&ObjAttr, &FileName, OBJ_CASE_INSENSITIVE, NULL, NULL);
RtlInitUnicodeString(&FileName, pData->szFileName1);
NtCreateFile(&hFile,
pData->OpenFile.dwDesiredAccess,
&ObjAttr,
&IoStatus,
&pData->OpenFile.AllocationSize,
pData->OpenFile.dwFlagsAndAttributes,
pData->OpenFile.dwShareAccess,
pData->OpenFile.dwCreateDisposition2,
pData->OpenFile.dwCreateOptions,
pData->OpenFile.pvFileEa,
pData->OpenFile.cbFileEa);
}
else
{
hFile = CreateFile(pData->szFileName1,
pData->OpenFile.dwDesiredAccess,
pData->OpenFile.dwShareAccess,
NULL,
pData->OpenFile.dwCreateDisposition1,
pData->OpenFile.dwFlagsAndAttributes,
NULL);
}
}
return hFile;
}
//-----------------------------------------------------------------------------
// WinMain
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE, LPTSTR, int)
{
TFileTestData * pData;
DWORD bAsynchronousOpen = 0;
DWORD bOpenFile = 0;
DWORD bShowHelp = 0;
int nFileNameIndex = 0;
// Initialize the instance
InitInstance(hInstance);
InitCommonControls();
// Get the Windows version
g_dwWinVer = GetWindowsVersion();
// Allocate and fill our working structure with command line parameters
if((pData = new TFileTestData) != NULL)
{
// Initialize the TFileTestData structure
memset(pData, 0, sizeof(TFileTestData));
pData->MagicHeader = FILETEST_DATA_MAGIC;
pData->szDirName = pData->szBuffer1;
pData->szFileName1 = pData->szBuffer2;
pData->szFileName2 = pData->szBuffer3;
pData->szTemplate = pData->szBuffer4;
pData->szSectionName = pData->szBuffer5;
pData->RelaFile.szId = "RelativeFile";
pData->OpenFile.szId = "MainFile";
pData->pOP = &pData->OpenFile;
// Set default values for CreateFile and NtCreateFile
pData->OpenFile.dwOA_Attributes = OBJ_CASE_INSENSITIVE;
pData->OpenFile.dwCreateDisposition1 = OPEN_ALWAYS;
pData->OpenFile.dwCreateDisposition2 = FILE_OPEN_IF;
pData->OpenFile.dwDesiredAccess = GENERIC_READ;
pData->OpenFile.dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
pData->OpenFile.dwShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
pData->OpenFile.dwCreateOptions = 0;
pData->dwOplockLevel = OPLOCK_LEVEL_CACHE_READ | OPLOCK_LEVEL_CACHE_WRITE;
pData->dwCopyFileFlags = 0;
pData->dwMoveFileFlags = 0;
// Set default values for opening relative file by NtCreateFile
pData->RelaFile.dwOA_Attributes = OBJ_CASE_INSENSITIVE;
pData->RelaFile.dwCreateDisposition1 = OPEN_EXISTING;
pData->RelaFile.dwCreateDisposition2 = FILE_OPEN;
pData->RelaFile.dwDesiredAccess = FILE_READ_DATA;
pData->RelaFile.dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
pData->RelaFile.dwShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
// Set default values for NtCreateSection/NtOpenSection
pData->dwSectDesiredAccess = SECTION_ALL_ACCESS;
pData->dwSectPageProtection = PAGE_READONLY;
pData->dwSectAllocAttributes = SEC_COMMIT;
pData->dwSectWin32Protect = PAGE_READONLY;
// Set the default values for NtQuerySecurityObject
pData->SecurityInformation = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
pData->InitialPage = INVALID_PAGE_INDEX;
// Parse command line arguments
for(int i = 1; i < __argc; i++)
{
LPCTSTR szPrivilegeName;
if(CheckForCommandSwitch(__targv[i], _T("DesiredAccess"), &pData->OpenFile.dwDesiredAccess))
continue;
if(CheckForCommandSwitch(__targv[i], _T("ShareAccess"), &pData->OpenFile.dwShareAccess))
continue;
if(CheckForCommandSwitch(__targv[i], _T("CreateOptions"), &pData->OpenFile.dwCreateOptions))
continue;
if(CheckForCommandSwitch(__targv[i], _T("CopyFileFlags"), &pData->dwCopyFileFlags))
continue;
if(CheckForCommandSwitch(__targv[i], _T("MoveFileFlags"), &pData->dwMoveFileFlags))
continue;
if(CheckForCommandSwitch(__targv[i], _T("SecurityInformation"), &pData->SecurityInformation))
continue;
if(CheckForCommandSwitch(__targv[i], _T("InitialPage"), &pData->InitialPage))
continue;
if(CheckForCommandSwitch(__targv[i], _T("AsyncOpen"), &bAsynchronousOpen, true))
continue;
if(CheckForCommandSwitch(__targv[i], _T("OpenFile"), &bOpenFile, true))
continue;
if(CheckForCommandSwitch(__targv[i], _T("Help"), &bShowHelp, true))
continue;
if(CheckForCommandSwitch(__targv[i], _T("?"), &bShowHelp, true))
continue;
// Check for privileges to enable
if((szPrivilegeName = IsCommandSwitch(__targv[i], _T("EnablePrivilege"))) != NULL)
{
EnablePrivilege(szPrivilegeName + 1);
continue;
}
// We assume that the argument is a file name
switch(nFileNameIndex)
{
case 0: // The first file name argument
ExpandEnvironmentStrings(__targv[i], pData->szFileName1, MAX_NT_PATH);
nFileNameIndex++;
break;
case 1: // The second file name argument
ExpandEnvironmentStrings(__targv[i], pData->szFileName2, MAX_NT_PATH);
nFileNameIndex++;
break;
case 2: // The directory file name argument
ExpandEnvironmentStrings(__targv[i], pData->szDirName, MAX_NT_PATH);
nFileNameIndex++;
break;
}
}
// Set default file name
if(pData->szFileName1[0] == 0)
{
StringCchCopy(pData->szFileName1, MAX_NT_PATH, _T("C:\\TestFile.bin"));
pData->IsDefaultFileName1 = TRUE;
}
//
// DEVELOPMENT CODE: Build the NT status table from the NTSTATUS.h
//
// BuildNtStatusTableFromNTSTATUS_H();
// VerifyNtStatusTable();
//
// Resolve the dynamic loaded APIs
//
ResolveDynamicLoadedAPIs();
//
// On Vista or newer, set the required integrity level of our token object
// to lowest possible value. This will allow us to open our token even if the user
// lowers the integrity level.
//
SetTokenObjectIntegrityLevel(SECURITY_MANDATORY_UNTRUSTED_RID);
//
// Save the application initial directory
//
GetCurrentDirectory(_countof(g_szInitialDirectory), g_szInitialDirectory);
//
// Register the data editor window
//
RegisterDataEditor(hInstance);
//
// To make handles obtained by NtCreateFile usable for calling ReadFile and WriteFile,
// we have to set the FILE_SYNCHRONOUS_IO_NONALERT into CreateOptions
// and SYNCHRONIZE into DesiredAccess.
//
// Pre-load menus so they don't generate any FS requests when loaded
memset(g_ContextMenus, 0, sizeof(g_ContextMenus));
EnumResourceNames(g_hInst, RT_MENU, EnumMenusProc, 0);
// Modify for synchronous open, if required
if(bAsynchronousOpen == false)
{
pData->OpenFile.dwCreateOptions |= FILE_SYNCHRONOUS_IO_NONALERT;
pData->RelaFile.dwCreateOptions |= FILE_SYNCHRONOUS_IO_NONALERT;
pData->OpenFile.dwDesiredAccess |= SYNCHRONIZE;
pData->RelaFile.dwDesiredAccess |= SYNCHRONIZE;
}
#ifdef __TEST_MODE__
//DebugCode_TEST();
DebugCode_SecurityDescriptor(pData->szFileName1);
#endif
// Show the main dialog
if(bShowHelp == FALSE)
{
// Shall we open the file?
if(bOpenFile)
pData->hFile = InitialOpenFile(pData);
FileTestDialog(NULL, pData);
}
else
HelpCommandLineDialog(NULL);
// Free the data blobs
pData->NtInfoData.Free();
pData->RdWrData.Free();
pData->OutData.Free();
pData->InData.Free();
delete pData;
}
return 0;
}