479 lines
10 KiB
C
479 lines
10 KiB
C
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
settings.c
|
|
|
|
Abstract:
|
|
|
|
This module implements interfaces for enabling application
|
|
verifier flags persistently (registry).
|
|
|
|
Author:
|
|
|
|
Silviu Calinoiu (SilviuC) 17-Apr-2001
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
//
|
|
// IMPORTANT NOTE.
|
|
//
|
|
// This dll cannot contain non-ntdll dependencies. This way it allows
|
|
// verifier to be run system wide including for processes like smss and csrss.
|
|
//
|
|
// This explains why we load dynamically advapi32 dll and pick up the functions
|
|
// for registry manipulation. It is safe to do that for interfaces that set
|
|
// flags because they are called only in contexts where it is safe to load
|
|
// additional dlls.
|
|
//
|
|
|
|
#include "pch.h"
|
|
|
|
#include "verifier.h"
|
|
#include "settings.h"
|
|
|
|
//
|
|
// Handy functions exported by ntdll.dll
|
|
//
|
|
int __cdecl sscanf(const char *, const char *, ...);
|
|
int __cdecl swprintf(wchar_t *, const wchar_t *, ...);
|
|
|
|
//
|
|
// Signatures for registry functions
|
|
//
|
|
|
|
typedef LONG (APIENTRY * PFN_REG_CREATE_KEY) (HKEY, LPCWSTR, DWORD, LPWSTR, DWORD, REGSAM, LPSECURITY_ATTRIBUTES, PHKEY, LPDWORD);
|
|
typedef LONG (APIENTRY * PFN_REG_CLOSE_KEY)(HKEY);
|
|
typedef LONG (APIENTRY * PFN_REG_QUERY_VALUE) (HKEY, LPCWSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD);
|
|
typedef LONG (APIENTRY * PFN_REG_SET_VALUE) (HKEY, LPCWSTR, DWORD, DWORD, CONST BYTE *, DWORD);
|
|
typedef LONG (APIENTRY * PFN_REG_DELETE_VALUE) (HKEY, LPCWSTR);
|
|
|
|
//
|
|
// Dynamically detected registry functions
|
|
//
|
|
|
|
PFN_REG_CREATE_KEY FnRegCreateKey;
|
|
PFN_REG_CLOSE_KEY FnRegCloseKey;
|
|
PFN_REG_QUERY_VALUE FnRegQueryValue;
|
|
PFN_REG_SET_VALUE FnRegSetValue;
|
|
PFN_REG_DELETE_VALUE FnRegDeleteValue;
|
|
|
|
//
|
|
// Registry path to `image file execution options' key
|
|
//
|
|
|
|
#define EXECUTION_OPTIONS_KEY L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\"
|
|
|
|
//
|
|
// Internal functions
|
|
//
|
|
|
|
NTSTATUS
|
|
AVrfpGetRegistryInterfaces (
|
|
PVOID DllHandle
|
|
);
|
|
|
|
HKEY
|
|
AVrfpOpenImageKey (
|
|
PWSTR Name
|
|
);
|
|
|
|
VOID
|
|
AVrfpCloseImageKey (
|
|
HKEY Key
|
|
);
|
|
|
|
BOOL
|
|
AVrfpReadGlobalFlags (
|
|
HKEY Key,
|
|
PDWORD Value
|
|
);
|
|
|
|
BOOL
|
|
AVrfpWriteGlobalFlags (
|
|
HKEY Key,
|
|
DWORD Value
|
|
);
|
|
|
|
BOOL
|
|
AVrfpDeleteGlobalFlags (
|
|
HKEY Key
|
|
);
|
|
|
|
BOOL
|
|
AVrfpReadVerifierFlags (
|
|
HKEY Key,
|
|
PDWORD Value
|
|
);
|
|
|
|
BOOL
|
|
AVrfpWriteVerifierFlags (
|
|
HKEY Key,
|
|
DWORD Value
|
|
);
|
|
|
|
BOOL
|
|
AVrfpDeleteVerifierFlags (
|
|
HKEY Key
|
|
);
|
|
|
|
|
|
NTSTATUS
|
|
VerifierSetFlags (
|
|
PUNICODE_STRING ApplicationName,
|
|
ULONG VerifierFlags,
|
|
PVOID Details
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine enables persistently (through registry) application
|
|
verifier flags for a specified application.
|
|
|
|
Arguments:
|
|
|
|
ApplicationName - name of the application to be verifier. The path should
|
|
not be included. The extension should be included. Some examples of
|
|
correct names are: `services.exe', `logon.scr'. Incorrect examples are:
|
|
`c:\winnt\system32\notepad.exe' or just `notepad'. If we persist a setting
|
|
for `xxx.exe' then every time a process whose binary is xxx.exe is launched
|
|
application verifier will kick in no matter in what user context or from what
|
|
disk location this happens.
|
|
|
|
VerifierFlags - bit field with verifier flags to be enabled. The legal bits are
|
|
declared in sdk\inc\nturtl.h (and winnt.h) as constants names RTL_VRF_FLG_XXX.
|
|
For example RTL_VRF_FLG_FULL_PAGE_HEAP. If a zero value is used then all
|
|
registry values related to verifier will b e deleted from registry.
|
|
|
|
Details - Ignored right now. In the future this structure will support various
|
|
extensions of the API (e.g. page heap flags, per dll page heap settings, etc.).
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if all flags requested have been enabled. It can return
|
|
STATUS_NOT_IMPLEMENTED if one of the flags requested is not yet implemented
|
|
or we decided to block it internally due to a bug. It can also return
|
|
STATUS_INVALID_PARAMETER if the application name or other parameters
|
|
are ill-formed.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
UNICODE_STRING AdvapiName;
|
|
PVOID AdvapiHandle;
|
|
HKEY Key;
|
|
DWORD Flags;
|
|
|
|
if (ApplicationName == NULL || ApplicationName->Buffer == NULL) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Load advapi32.dll and get registry manipulation functions.
|
|
//
|
|
|
|
RtlInitUnicodeString (&AdvapiName, L"advapi32.dll");
|
|
Status = LdrLoadDll (NULL, NULL, &AdvapiName, &AdvapiHandle);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = AVrfpGetRegistryInterfaces (AdvapiHandle);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Open `image file execution options\xxx.exe' key. If the key does not
|
|
// exist it will be created.
|
|
//
|
|
|
|
Key = AVrfpOpenImageKey (ApplicationName->Buffer);
|
|
|
|
if (Key == NULL) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Create verifier settings.
|
|
//
|
|
|
|
if (VerifierFlags == 0) {
|
|
|
|
Flags = 0;
|
|
AVrfpReadGlobalFlags (Key, &Flags);
|
|
Flags &= ~FLG_APPLICATION_VERIFIER;
|
|
|
|
if (Flags == 0) {
|
|
AVrfpDeleteGlobalFlags (Key);
|
|
}
|
|
else {
|
|
AVrfpWriteGlobalFlags (Key, Flags);
|
|
}
|
|
|
|
AVrfpDeleteVerifierFlags (Key);
|
|
}
|
|
else {
|
|
|
|
Flags = 0;
|
|
AVrfpReadGlobalFlags (Key, &Flags);
|
|
Flags |= FLG_APPLICATION_VERIFIER;
|
|
AVrfpWriteGlobalFlags (Key, Flags);
|
|
|
|
Flags = VerifierFlags;
|
|
AVrfpWriteVerifierFlags (Key, Flags);
|
|
}
|
|
|
|
//
|
|
// Cleanup and return.
|
|
//
|
|
|
|
AVrfpCloseImageKey (Key);
|
|
|
|
Exit:
|
|
|
|
LdrUnloadDll (AdvapiHandle);
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
AVrfpGetRegistryInterfaces (
|
|
PVOID AdvapiHandle
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
ANSI_STRING FunctionName;
|
|
PVOID FunctionAddress;
|
|
|
|
RtlInitAnsiString (&FunctionName, "RegCreateKeyExW");
|
|
Status = LdrGetProcedureAddress (AdvapiHandle, &FunctionName, 0, &FunctionAddress);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
FnRegCreateKey = (PFN_REG_CREATE_KEY)FunctionAddress;
|
|
|
|
RtlInitAnsiString (&FunctionName, "RegCloseKey");
|
|
Status = LdrGetProcedureAddress (AdvapiHandle, &FunctionName, 0, &FunctionAddress);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
FnRegCloseKey = (PFN_REG_CLOSE_KEY)FunctionAddress;
|
|
|
|
RtlInitAnsiString (&FunctionName, "RegQueryValueExW");
|
|
Status = LdrGetProcedureAddress (AdvapiHandle, &FunctionName, 0, &FunctionAddress);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
FnRegQueryValue = (PFN_REG_QUERY_VALUE)FunctionAddress;
|
|
|
|
RtlInitAnsiString (&FunctionName, "RegSetValueExW");
|
|
Status = LdrGetProcedureAddress (AdvapiHandle, &FunctionName, 0, &FunctionAddress);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
FnRegSetValue = (PFN_REG_SET_VALUE)FunctionAddress;
|
|
|
|
RtlInitAnsiString (&FunctionName, "RegDeleteValueW");
|
|
Status = LdrGetProcedureAddress (AdvapiHandle, &FunctionName, 0, &FunctionAddress);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
FnRegDeleteValue = (PFN_REG_DELETE_VALUE)FunctionAddress;
|
|
|
|
return Status;
|
|
}
|
|
|
|
HKEY
|
|
AVrfpOpenImageKey (
|
|
PWSTR Name
|
|
)
|
|
{
|
|
HKEY Key;
|
|
LONG Result;
|
|
WCHAR Buffer [MAX_PATH];
|
|
|
|
wcscpy (Buffer, EXECUTION_OPTIONS_KEY);
|
|
wcscat (Buffer, Name);
|
|
|
|
Result = FnRegCreateKey (HKEY_LOCAL_MACHINE,
|
|
Buffer,
|
|
0,
|
|
0,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&Key,
|
|
NULL);
|
|
|
|
if (Result != ERROR_SUCCESS) {
|
|
return NULL;
|
|
}
|
|
else {
|
|
return Key;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
AVrfpCloseImageKey (
|
|
HKEY Key
|
|
)
|
|
{
|
|
FnRegCloseKey (Key);
|
|
}
|
|
|
|
BOOL
|
|
AVrfpReadGlobalFlags (
|
|
HKEY Key,
|
|
PDWORD Value
|
|
)
|
|
{
|
|
LONG Result;
|
|
DWORD Type;
|
|
BYTE Buffer[32];
|
|
BYTE Buffer2[32];
|
|
DWORD BytesRead;
|
|
DWORD FlagValue;
|
|
DWORD I;
|
|
|
|
BytesRead = sizeof Buffer;
|
|
|
|
Result = FnRegQueryValue (Key,
|
|
L"GlobalFlag",
|
|
0,
|
|
&Type,
|
|
(LPBYTE)Buffer,
|
|
&BytesRead);
|
|
|
|
if (Result != ERROR_SUCCESS || Type != REG_SZ) {
|
|
|
|
DbgPrint ("Result %u \n", Result);
|
|
return FALSE;
|
|
}
|
|
else {
|
|
|
|
for (I = 0; Buffer[2 * I] != L'\0'; I += 1) {
|
|
Buffer2[I] = Buffer[2 * I];
|
|
}
|
|
|
|
Buffer2[I] = 0;
|
|
FlagValue = 0;
|
|
|
|
sscanf (Buffer2, "%x", &FlagValue);
|
|
|
|
if (Value) {
|
|
*Value = FlagValue;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
AVrfpWriteGlobalFlags (
|
|
HKEY Key,
|
|
DWORD Value
|
|
)
|
|
{
|
|
LONG Result;
|
|
WCHAR Buffer[16];
|
|
DWORD Length;
|
|
|
|
swprintf (Buffer, L"0x%08X", Value);
|
|
Length = (wcslen(Buffer) + 1) * sizeof (WCHAR);
|
|
|
|
Result = FnRegSetValue (Key,
|
|
L"GlobalFlag",
|
|
0,
|
|
REG_SZ,
|
|
(LPBYTE)Buffer,
|
|
Length);
|
|
|
|
return (Result == ERROR_SUCCESS);
|
|
}
|
|
|
|
BOOL
|
|
AVrfpDeleteGlobalFlags (
|
|
HKEY Key
|
|
)
|
|
{
|
|
LONG Result;
|
|
|
|
Result = FnRegDeleteValue (Key, L"GlobalFlag");
|
|
return (Result == ERROR_SUCCESS);
|
|
}
|
|
|
|
BOOL
|
|
AVrfpReadVerifierFlags (
|
|
HKEY Key,
|
|
PDWORD Value
|
|
)
|
|
{
|
|
LONG Result;
|
|
DWORD Type;
|
|
DWORD BytesRead;
|
|
|
|
BytesRead = sizeof *Value;
|
|
|
|
Result = FnRegQueryValue (Key,
|
|
L"VerifierValue",
|
|
0,
|
|
&Type,
|
|
(LPBYTE)Value,
|
|
&BytesRead);
|
|
|
|
return (Result == ERROR_SUCCESS && Type != REG_DWORD);
|
|
}
|
|
|
|
BOOL
|
|
AVrfpWriteVerifierFlags (
|
|
HKEY Key,
|
|
DWORD Value
|
|
)
|
|
{
|
|
LONG Result;
|
|
|
|
Result = FnRegSetValue (Key,
|
|
L"VerifierFlags",
|
|
0,
|
|
REG_DWORD,
|
|
(LPBYTE)(&Value),
|
|
sizeof Value);
|
|
|
|
return (Result == ERROR_SUCCESS);
|
|
}
|
|
|
|
BOOL
|
|
AVrfpDeleteVerifierFlags (
|
|
HKEY Key
|
|
)
|
|
{
|
|
LONG Result;
|
|
|
|
Result = FnRegDeleteValue (Key, L"VerifierFlags");
|
|
return (Result == ERROR_SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
|
|
|