2020-09-30 17:12:29 +02:00

625 lines
18 KiB
C

#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <stdio.h>
#include "gflags.h"
#define VALID_SYSTEM_REGISTRY_FLAGS FLG_VALID_BITS ^ FLG_STOP_ON_HUNG_GUI
#define VALID_KERNEL_MODE_FLAGS FLG_VALID_BITS ^ (FLG_DEBUG_INITIAL_COMMAND | \
FLG_KERNEL_STACK_TRACE_DB | \
FLG_MAINTAIN_OBJECT_TYPELIST | \
FLG_ENABLE_CSRDEBUG)
#define VALID_IMAGE_FILE_NAME_FLAGS FLG_USERMODE_VALID_BITS
LONG APIENTRY MainWndProc(HWND hwnd, UINT message, WPARAM wParam, LONG lParam);
BOOLEAN
EnableDebugPrivilege( VOID );
HWND hwndMain;
HKEY hKey;
DWORD InitialSetFlags;
DWORD LastSetFlags;
DWORD
GetSystemRegistryFlags( VOID )
{
DWORD cbKey;
DWORD GFlags;
DWORD type;
if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
"SYSTEM\\CurrentControlSet\\Control\\Session Manager",
0,
KEY_READ | KEY_WRITE,
&hKey
) != ERROR_SUCCESS
) {
MessageBox( hwndMain, "Open Error", "SYSTEM\\CurrentControlSet\\Control\\Session Manager", MB_OK );
ExitProcess( 0 );
}
cbKey = sizeof( GFlags );
if (RegQueryValueEx( hKey,
"GlobalFlag",
0,
&type,
(LPBYTE)&GFlags,
&cbKey
) != ERROR_SUCCESS ||
type != REG_DWORD
) {
MessageBox( hwndMain, "Value Error", "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\GlobalFlag", MB_OK );
RegCloseKey( hKey );
ExitProcess( 0 );
}
return GFlags;
}
BOOLEAN
SetSystemRegistryFlags(
DWORD GFlags
)
{
if (RegSetValueEx( hKey,
"GlobalFlag",
0,
REG_DWORD,
(LPBYTE)&GFlags,
sizeof( GFlags )
) != ERROR_SUCCESS
) {
MessageBox( hwndMain, "Value Error", "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\GlobalFlag", MB_OK );
RegCloseKey( hKey );
ExitProcess( 0 );
}
LastSetFlags = GFlags;
return TRUE;
}
DWORD
GetKernelModeFlags( VOID )
{
NTSTATUS Status;
SYSTEM_FLAGS_INFORMATION SystemInformation;
Status = NtQuerySystemInformation( SystemFlagsInformation,
&SystemInformation,
sizeof( SystemInformation ),
NULL
);
if (!NT_SUCCESS( Status )) {
MessageBox( hwndMain, "Value Error", "Kernel Mode Flags", MB_OK );
ExitProcess( 0 );
}
return SystemInformation.Flags;
}
BOOLEAN
SetKernelModeFlags(
DWORD GFlags
)
{
NTSTATUS Status;
SYSTEM_FLAGS_INFORMATION SystemInformation;
if (!EnableDebugPrivilege()) {
MessageBox( hwndMain, "Access Denied", "Unable to enable debug privilege", MB_OK );
ExitProcess( 0 );
}
SystemInformation.Flags = GFlags;
Status = NtSetSystemInformation( SystemFlagsInformation,
&SystemInformation,
sizeof( SystemInformation )
);
if (!NT_SUCCESS( Status )) {
MessageBox( hwndMain, "Value Error", "Kernel Mode Flags", MB_OK );
ExitProcess( 0 );
}
LastSetFlags = GFlags;
return TRUE;
}
DWORD
GetImageFileNameFlags(
PCHAR ImageFileName
)
{
NTSTATUS Status;
CHAR Buffer[ MAX_PATH ];
CHAR RegKey[ MAX_PATH ];
DWORD Length = MAX_PATH;
DWORD GFlags;
HKEY hKey;
sprintf( Buffer, "0x%x", GetKernelModeFlags() ); // default if query fails
if ( strlen( ImageFileName ) != 0 ) {
sprintf( RegKey,
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\%s",
ImageFileName
);
if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, RegKey, 0, KEY_READ, &hKey ) == ERROR_SUCCESS ) {
RegQueryValueEx( hKey, "GlobalFlag", NULL, NULL, Buffer, &Length );
RegCloseKey( hKey );
}
}
Status = RtlCharToInteger( Buffer, 0, &GFlags );
if (!NT_SUCCESS( Status )) {
MessageBox( hwndMain, "Value Error", ImageFileName, MB_OK );
ExitProcess( 0 );
}
return GFlags;
}
BOOLEAN
SetImageFileNameFlags(
PCHAR ImageFileName,
DWORD GFlags
)
{
CHAR Buffer[ MAX_PATH ];
CHAR RegKey[ MAX_PATH ];
HKEY hKey;
DWORD Result;
DWORD Length;
DWORD Disposition;
if ( strlen( ImageFileName ) != 0 ) {
Length = ( sprintf( Buffer, "0x%08x", GFlags ) + 1 ) * sizeof( CHAR );
sprintf( RegKey,
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\%s",
ImageFileName
);
Result = RegCreateKeyEx(
HKEY_LOCAL_MACHINE,
RegKey,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hKey,
&Disposition
);
if ( Result == ERROR_SUCCESS ) {
Result = RegSetValueEx(
hKey,
"GlobalFlag",
0,
REG_SZ,
Buffer,
Length
);
RegCloseKey( hKey );
}
if ( Result != ERROR_SUCCESS ) {
MessageBox( hwndMain, "Failed to set registry value", ImageFileName, MB_OK );
return FALSE;
}
LastSetFlags = GFlags;
return TRUE;
}
return FALSE;
}
int WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
INT nCmdShow)
{
MSG msg;
hwndMain = NULL;
CreateDialog( hInstance,
(LPSTR)DID_GFLAGS,
NULL,
MainWndProc
);
if (!hwndMain) {
MessageBox( hwndMain, "Main Error", "Cant create dialog", MB_OK );
ExitProcess( 0 );
}
while (GetMessage( &msg, 0, 0, 0 )) {
if (!IsDialogMessage( hwndMain, &msg )) {
DispatchMessage( &msg );
}
}
ExitProcess( 0 );
return 0;
}
VOID
SetCheckBoxesFromFlags(
DWORD GFlags,
DWORD ValidFlags
)
{
int iBit;
GFlags &= ValidFlags;
InitialSetFlags = GFlags;
LastSetFlags = 0;
for (iBit=0; iBit < 32; iBit++) {
CheckDlgButton( hwndMain,
ID_FLAG_1 + iBit,
(GFlags & (1 << iBit)) ? 1 : 0
);
ShowWindow( GetDlgItem( hwndMain, ID_FLAG_1 + iBit ),
(ValidFlags & (1 << iBit)) ? SW_SHOWNORMAL : SW_HIDE
);
}
}
DWORD
GetFlagsFromCheckBoxes( VOID )
{
DWORD GFlags;
int iBit;
GFlags = 0;
for (iBit=0; iBit < 32; iBit++) {
if (IsDlgButtonChecked( hwndMain, ID_FLAG_1 + iBit )) {
GFlags |= (1 << iBit);
}
}
return GFlags;
}
VOID
DoLaunch(
PCHAR CommandLine
)
{
STARTUPINFO StartupInfo;
PROCESS_INFORMATION ProcessInformation;
NTSTATUS Status;
PROCESS_BASIC_INFORMATION BasicInformation;
BOOLEAN ReadImageFileExecOptions;
DWORD BytesWritten;
DWORD GFlags;
memset( &StartupInfo, 0, sizeof( StartupInfo ) );
StartupInfo.cb = sizeof( StartupInfo );
if (CreateProcess( NULL,
CommandLine,
NULL,
NULL,
FALSE,
CREATE_SUSPENDED,
NULL,
NULL,
&StartupInfo,
&ProcessInformation
)
) {
Status = NtQueryInformationProcess( ProcessInformation.hProcess,
ProcessBasicInformation,
&BasicInformation,
sizeof( BasicInformation ),
NULL
);
if (NT_SUCCESS( Status )) {
ReadImageFileExecOptions = TRUE;
GFlags = GetFlagsFromCheckBoxes();
if (!WriteProcessMemory( ProcessInformation.hProcess,
&BasicInformation.PebBaseAddress->ReadImageFileExecOptions,
&ReadImageFileExecOptions,
sizeof( ReadImageFileExecOptions ),
&BytesWritten
) ||
!WriteProcessMemory( ProcessInformation.hProcess,
&BasicInformation.PebBaseAddress->NtGlobalFlag,
&GFlags,
sizeof( GFlags ),
&BytesWritten
)
) {
Status = STATUS_UNSUCCESSFUL;
}
}
if (!NT_SUCCESS( Status )) {
MessageBox( hwndMain,
"Launch Command Line",
"Unable to pass flags to process - terminating",
MB_OK
);
TerminateProcess( ProcessInformation.hProcess, 1 );
}
ResumeThread( ProcessInformation.hThread );
CloseHandle( ProcessInformation.hThread );
MsgWaitForMultipleObjects( 1,
&ProcessInformation.hProcess,
FALSE,
NMPWAIT_WAIT_FOREVER,
QS_ALLINPUT
);
CloseHandle( ProcessInformation.hProcess );
}
else {
MessageBox( hwndMain, "Launch Command Line", "Unable to create process", MB_OK );
}
return;
}
DWORD LastRadioButtonId;
LONG
APIENTRY
MainWndProc(
HWND hwnd,
UINT message,
WPARAM wParam,
LONG lParam
)
{
CHAR ImageFileName[ MAX_PATH ];
CHAR CommandLine[ MAX_PATH ];
switch (message) {
case WM_INITDIALOG:
hwndMain = hwnd;
LastRadioButtonId = ID_SYSTEM_REGISTRY;
CheckRadioButton( hwnd,
ID_SYSTEM_REGISTRY,
ID_IMAGE_FILE_OPTIONS,
LastRadioButtonId
);
SetCheckBoxesFromFlags( GetSystemRegistryFlags(), VALID_SYSTEM_REGISTRY_FLAGS );
return(TRUE);
case WM_COMMAND:
switch( LOWORD(wParam) ) {
case ID_LAUNCH:
GetDlgItemText( hwnd, ID_COMMAND_LINE, CommandLine, sizeof( CommandLine ) );
if (strlen( ImageFileName ) == 0) {
MessageBox( hwndMain, "Launch Command Line", "Must fill in command line first", MB_OK );
SetFocus( GetDlgItem( hwnd, ID_COMMAND_LINE ) );
break;
}
// fall through
case ID_APPLY:
if (IsDlgButtonChecked( hwnd, ID_SYSTEM_REGISTRY )) {
SetSystemRegistryFlags( GetFlagsFromCheckBoxes() );
}
else
if (IsDlgButtonChecked( hwnd, ID_KERNEL_MODE )) {
SetKernelModeFlags( GetFlagsFromCheckBoxes() );
}
else
if (IsDlgButtonChecked( hwnd, ID_IMAGE_FILE_OPTIONS )) {
GetDlgItemText( hwnd, ID_IMAGE_FILE_NAME, ImageFileName, sizeof( ImageFileName ) );
if (strlen( ImageFileName ) == 0) {
MessageBox( hwnd, "Missing Image File Name", "Must set image file name", MB_OK );
SetFocus( GetDlgItem( hwnd, ID_IMAGE_FILE_NAME ) );
break;
}
SetImageFileNameFlags( ImageFileName, GetFlagsFromCheckBoxes() );
}
if (LOWORD(wParam) == ID_LAUNCH) {
DoLaunch( CommandLine );
}
break;
case IDOK:
if (GetFlagsFromCheckBoxes() != InitialSetFlags) {
if (GetFlagsFromCheckBoxes() != LastSetFlags) {
if (MessageBox( hwndMain,
"Did you want to exit without applying these settings?",
"Warning",
MB_OKCANCEL
) == IDCANCEL
) {
break;
}
}
}
// fall through
case IDCANCEL:
PostQuitMessage(0);
DestroyWindow( hwnd );
break;
case ID_SYSTEM_REGISTRY:
if (GetFlagsFromCheckBoxes() != InitialSetFlags) {
if (MessageBox( hwndMain,
"Did you want to discard current changes??",
"Warning",
MB_OKCANCEL
) == IDCANCEL
) {
break;
}
}
LastRadioButtonId = ID_SYSTEM_REGISTRY;
SetCheckBoxesFromFlags( GetSystemRegistryFlags(), VALID_SYSTEM_REGISTRY_FLAGS );
break;
case ID_KERNEL_MODE:
if (GetFlagsFromCheckBoxes() != InitialSetFlags) {
if (MessageBox( hwndMain,
"Did you want to discard current changes??",
"Warning",
MB_OKCANCEL
) == IDCANCEL
) {
break;
}
}
LastRadioButtonId = ID_KERNEL_MODE;
SetCheckBoxesFromFlags( GetKernelModeFlags(), VALID_KERNEL_MODE_FLAGS );
break;
case ID_IMAGE_FILE_OPTIONS:
if (GetFlagsFromCheckBoxes() != InitialSetFlags) {
if (MessageBox( hwndMain,
"Did you want to discard current changes??",
"Warning",
MB_OKCANCEL
) == IDCANCEL
) {
break;
}
}
GetDlgItemText( hwnd, ID_IMAGE_FILE_NAME, ImageFileName, sizeof( ImageFileName ) );
if (strlen( ImageFileName ) == 0) {
MessageBox( hwndMain, "Image File Name Missing", "Must fill in image file name first", MB_OK );
CheckRadioButton( hwnd,
ID_SYSTEM_REGISTRY,
ID_IMAGE_FILE_OPTIONS,
LastRadioButtonId
);
SetCheckBoxesFromFlags( GetSystemRegistryFlags(), VALID_SYSTEM_REGISTRY_FLAGS );
SetFocus( GetDlgItem( hwnd, ID_IMAGE_FILE_NAME ) );
break;
}
else {
LastRadioButtonId = ID_IMAGE_FILE_NAME;
SetCheckBoxesFromFlags( GetImageFileNameFlags( ImageFileName ),
VALID_IMAGE_FILE_NAME_FLAGS
);
}
break;
default:
break;
}
break;
case WM_CLOSE:
PostQuitMessage(0);
DestroyWindow( hwnd );
break;
}
return 0;
}
BOOLEAN
EnableDebugPrivilege( VOID )
{
HANDLE Token;
PTOKEN_PRIVILEGES NewPrivileges;
BYTE OldPriv[ 1024 ];
PBYTE pbOldPriv;
ULONG cbNeeded;
BOOLEAN fRc;
LUID LuidPrivilege;
//
// Make sure we have access to adjust and to get the old token privileges
//
if (!OpenProcessToken( GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
&Token
)
) {
return FALSE;
}
cbNeeded = 0;
//
// Initialize the privilege adjustment structure
//
LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &LuidPrivilege );
NewPrivileges = (PTOKEN_PRIVILEGES)HeapAlloc( GetProcessHeap(), 0,
sizeof(TOKEN_PRIVILEGES) +
(1 - ANYSIZE_ARRAY) * sizeof(LUID_AND_ATTRIBUTES)
);
if (NewPrivileges == NULL) {
CloseHandle( Token );
return FALSE;
}
NewPrivileges->PrivilegeCount = 1;
NewPrivileges->Privileges[0].Luid = LuidPrivilege;
NewPrivileges->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
//
// Enable the privilege
//
pbOldPriv = OldPriv;
fRc = AdjustTokenPrivileges( Token,
FALSE,
NewPrivileges,
sizeof( OldPriv ),
(PTOKEN_PRIVILEGES)pbOldPriv,
&cbNeeded
);
if (!fRc) {
//
// If the stack was too small to hold the privileges
// then allocate off the heap
//
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
pbOldPriv = (PBYTE)HeapAlloc( GetProcessHeap(), 0, cbNeeded );
if (pbOldPriv == NULL) {
CloseHandle( Token );
return FALSE;
}
fRc = AdjustTokenPrivileges( Token,
FALSE,
NewPrivileges,
cbNeeded,
(PTOKEN_PRIVILEGES)pbOldPriv,
&cbNeeded
);
}
}
return fRc;
}