From 91d061b663fd3f8687e1cb93ffd02cbf2fc3dd44 Mon Sep 17 00:00:00 2001 From: wj32 Date: Sun, 17 May 2009 02:59:06 +0000 Subject: [PATCH] added experimental feature: protect processes git-svn-id: svn://svn.code.sf.net/p/processhacker/code@1287 21ef857c-d57f-4fe0-8362-d861dc6d29cd --- trunk/CHANGELOG.txt | 1 + trunk/KProcessHacker/hook.c | 177 ++++++++ trunk/KProcessHacker/i386/kprocesshacker.sys | Bin 17920 -> 19968 bytes trunk/KProcessHacker/include/hook.h | 60 +++ trunk/KProcessHacker/include/kprocesshacker.h | 6 + trunk/KProcessHacker/include/protect.h | 77 ++++ trunk/KProcessHacker/include/ps.h | 38 ++ trunk/KProcessHacker/include/version.h | 4 +- trunk/KProcessHacker/include/zw.h | 29 -- trunk/KProcessHacker/kprocesshacker.c | 189 ++++++++ trunk/KProcessHacker/protect.c | 337 ++++++++++++++ trunk/KProcessHacker/sources | 2 + trunk/KProcessHacker/version.c | 11 +- trunk/ProcessHacker.Native/KProcessHacker.cs | 45 +- trunk/ProcessHacker/Components/ModuleList.cs | 89 +++- .../Forms/HackerWindow.Designer.cs | 29 +- trunk/ProcessHacker/Forms/HackerWindow.cs | 10 +- .../Forms/OptionsWindow.Designer.cs | 52 ++- trunk/ProcessHacker/Forms/OptionsWindow.cs | 3 + .../Forms/ProcessWindow.Designer.cs | 48 +- trunk/ProcessHacker/Forms/ProcessWindow.resx | 416 +++++++++--------- .../Forms/ProtectProcessWindow.Designer.cs | 143 ++++++ .../Forms/ProtectProcessWindow.cs | 118 +++++ .../Forms/ProtectProcessWindow.resx | 120 +++++ trunk/ProcessHacker/ProcessHacker.csproj | 9 + .../Properties/Settings.Designer.cs | 12 + .../Properties/Settings.settings | 3 + trunk/ProcessHacker/app.config | 3 + 28 files changed, 1705 insertions(+), 326 deletions(-) create mode 100644 trunk/KProcessHacker/hook.c create mode 100644 trunk/KProcessHacker/include/hook.h create mode 100644 trunk/KProcessHacker/include/protect.h create mode 100644 trunk/KProcessHacker/protect.c create mode 100644 trunk/ProcessHacker/Forms/ProtectProcessWindow.Designer.cs create mode 100644 trunk/ProcessHacker/Forms/ProtectProcessWindow.cs create mode 100644 trunk/ProcessHacker/Forms/ProtectProcessWindow.resx diff --git a/trunk/CHANGELOG.txt b/trunk/CHANGELOG.txt index 1b0a2bef4..52b8a8c09 100644 --- a/trunk/CHANGELOG.txt +++ b/trunk/CHANGELOG.txt @@ -5,6 +5,7 @@ Process Hacker * KProcessHacker can now perform process memory reading/writing by itself and does not require MmCopyVirtualMemory * KProcessHacker can now bypass all handle-opening protections + * Experimental process protection feature * Ability to set handle flags such as protect-from-close and inherit * Better highlighting * Terminator test: TD1 (debugs a process and closes the debug object) diff --git a/trunk/KProcessHacker/hook.c b/trunk/KProcessHacker/hook.c new file mode 100644 index 000000000..93b440524 --- /dev/null +++ b/trunk/KProcessHacker/hook.c @@ -0,0 +1,177 @@ +/* + * Process Hacker Driver - + * hooks + * + * Copyright (C) 2009 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "include/hook.h" + +typedef struct _MAPPED_MDL +{ + PMDL Mdl; + PVOID Address; +} MAPPED_MDL, *PMAPPED_MDL; + +NTSTATUS KphpCreateMappedMdl( + PVOID Address, + ULONG Length, + PMAPPED_MDL MappedMdl + ); + +VOID KphpFreeMappedMdl( + PMAPPED_MDL MappedMdl + ); + +/* KphHook + * + * Hooks a kernel-mode function. + * WARNING: DO NOT HOOK A FUNCTION THAT IS CALLABLE ABOVE PASSIVE_LEVEL. + */ +NTSTATUS KphHook( + PKPH_HOOK Hook + ) +{ + NTSTATUS status = STATUS_SUCCESS; + KIRQL oldIrql; + MAPPED_MDL mappedMdl; + PCHAR function; + + status = KphpCreateMappedMdl( + Hook->Function, + 5, + &mappedMdl + ); + + if (!NT_SUCCESS(status)) + return status; + + function = (PCHAR)mappedMdl.Address; + /* Raise to APC_LEVEL to prevent drivers calling the function while we're patching it. */ + /* If they do, it's their problem because the function we're patching should only be + called at PASSIVE_LEVEL anyway (see hook.h for definition of KPH_HOOK). */ + KeRaiseIrql(APC_LEVEL, &oldIrql); + memcpy(Hook->Bytes, function, 5); + Hook->Hooked = TRUE; + /* jmp Target */ + *function = 0xe9; + *(PULONG_PTR)(function + 1) = (ULONG_PTR)Hook->Target - (ULONG_PTR)Hook->Function - 5; + /* Lower the IRQL back. */ + KeLowerIrql(oldIrql); + + KphpFreeMappedMdl(&mappedMdl); + + return status; +} + +/* KphUnhook + * + * Unhooks a kernel-mode function. + * WARNING: DO NOT UNHOOK A FUNCTION THAT IS CALLABLE ABOVE PASSIVE_LEVEL. + */ +NTSTATUS KphUnhook( + PKPH_HOOK Hook + ) +{ + NTSTATUS status = STATUS_SUCCESS; + KIRQL oldIrql; + MAPPED_MDL mappedMdl; + + if (!Hook->Hooked) + return STATUS_UNSUCCESSFUL; + + status = KphpCreateMappedMdl( + Hook->Function, + 5, + &mappedMdl + ); + + if (!NT_SUCCESS(status)) + return status; + + KeRaiseIrql(APC_LEVEL, &oldIrql); + memcpy(mappedMdl.Address, Hook->Bytes, 5); + Hook->Hooked = FALSE; + KeLowerIrql(oldIrql); + + KphpFreeMappedMdl(&mappedMdl); + + return status; +} + +/* KphpCreateMappedMdl + * + * Creates and maps a MDL. + */ +NTSTATUS KphpCreateMappedMdl( + PVOID Address, + ULONG Length, + PMAPPED_MDL MappedMdl + ) +{ + PMDL mdl; + + MappedMdl->Mdl = NULL; + MappedMdl->Address = NULL; + + mdl = IoAllocateMdl(Address, Length, FALSE, FALSE, NULL); + + if (mdl == NULL) + return STATUS_INSUFFICIENT_RESOURCES; + + MmBuildMdlForNonPagedPool(mdl); + mdl->MdlFlags |= MDL_MAPPED_TO_SYSTEM_VA; + MappedMdl->Address = MmMapLockedPagesSpecifyCache( + mdl, + KernelMode, + MmNonCached, + NULL, + FALSE, + HighPagePriority + ); + MappedMdl->Mdl = mdl; + + if (!MappedMdl->Address) + { + KphpFreeMappedMdl(MappedMdl); + return STATUS_INSUFFICIENT_RESOURCES; + } + + return STATUS_SUCCESS; +} + +/* KphpFreeMappedMdl + * + * Unmaps and frees a MDL. + */ +VOID KphpFreeMappedMdl( + PMAPPED_MDL MappedMdl + ) +{ + if (MappedMdl->Mdl != NULL) + { + if (MappedMdl->Address != NULL) + { + MmUnmapLockedPages(MappedMdl->Address, MappedMdl->Mdl); + MappedMdl->Address = NULL; + } + + IoFreeMdl(MappedMdl->Mdl); + MappedMdl->Mdl = NULL; + } +} diff --git a/trunk/KProcessHacker/i386/kprocesshacker.sys b/trunk/KProcessHacker/i386/kprocesshacker.sys index ca1b9d53552889edb64989d5613c27076649ca59..300961714662bec6ba1c33a44d0d461433249237 100644 GIT binary patch delta 10150 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. + */ + +#ifndef _HOOK_H +#define _HOOK_H + +#include "kph.h" + +#define KPH_DEFINE_HOOK_CALL(Name, Arguments, Hook) \ + __declspec(naked) Name(Arguments) \ + { \ + __asm lea eax, Hook \ + __asm mov eax, [eax+KPH_HOOK.Function] \ + __asm add eax, 5 \ + __asm push ebp \ + __asm mov ebp, esp \ + __asm jmp eax \ + } \ + +typedef struct _KPH_HOOK +{ + /* The address of the hooked function. + Should NOT be a function that is callable above PASSIVE_LEVEL. */ + PVOID Function; + /* The address of the new function. */ + PVOID Target; + /* Whether the function is hooked. */ + BOOLEAN Hooked; + /* The original first 5 bytes. */ + CHAR Bytes[5]; +} KPH_HOOK, *PKPH_HOOK; + +NTSTATUS KphHook( + PKPH_HOOK Hook + ); + +NTSTATUS KphUnhook( + PKPH_HOOK Hook + ); + +#endif diff --git a/trunk/KProcessHacker/include/kprocesshacker.h b/trunk/KProcessHacker/include/kprocesshacker.h index c5419bf58..851389ff3 100644 --- a/trunk/KProcessHacker/include/kprocesshacker.h +++ b/trunk/KProcessHacker/include/kprocesshacker.h @@ -70,11 +70,17 @@ #define KPH_GETFEATURES KPH_CTL_CODE(26) #define KPH_SETHANDLEGRANTEDACCESS KPH_CTL_CODE(27) #define KPH_ASSIGNIMPERSONATIONTOKEN KPH_CTL_CODE(28) +#define KPH_PROTECTADD KPH_CTL_CODE(29) +#define KPH_PROTECTREMOVE KPH_CTL_CODE(30) +#define KPH_PROTECTQUERY KPH_CTL_CODE(31) #define GET_BIT(integer, bit) (((integer) >> (bit)) & 0x1) #define SET_BIT(integer, bit) ((integer) |= 1 << (bit)) #define CLEAR_BIT(integer, bit) ((integer) &= ~(1 << (bit))) +#define KPH_TIMEOUT_TO_SEC ((LONGLONG) 1 * 10 * 1000 * 1000) +#define KPH_REL_TIMEOUT_IN_SEC(Time) (Time * -1 * KPH_TIMEOUT_TO_SEC) + NTSTATUS KphDispatchCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp); NTSTATUS KphDispatchClose(PDEVICE_OBJECT DeviceObject, PIRP Irp); NTSTATUS KphDispatchDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp); diff --git a/trunk/KProcessHacker/include/protect.h b/trunk/KProcessHacker/include/protect.h new file mode 100644 index 000000000..e180adacf --- /dev/null +++ b/trunk/KProcessHacker/include/protect.h @@ -0,0 +1,77 @@ +/* + * Process Hacker Driver - + * process protection + * + * Copyright (C) 2009 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#ifndef _PROTECT_H +#define _PROTECT_H + +#include "hook.h" + +#define OBOPENOBJECTBYPOINTER_ARGS \ + PVOID Object, \ + ULONG HandleAttributes, \ + PACCESS_STATE PassedAccessState, \ + ACCESS_MASK DesiredAccess, \ + POBJECT_TYPE ObjectType, \ + KPROCESSOR_MODE AccessMode, \ + PHANDLE Handle + +typedef struct _KPH_PROCESS_ENTRY +{ + LIST_ENTRY ListEntry; + PEPROCESS Process; + HANDLE Tag; + ACCESS_MASK ProcessAllowMask; + ACCESS_MASK ThreadAllowMask; +} KPH_PROCESS_ENTRY, *PKPH_PROCESS_ENTRY; + +NTSTATUS NTAPI KphNewObOpenObjectByPointer(OBOPENOBJECTBYPOINTER_ARGS); +NTSTATUS NTAPI KphOldObOpenObjectByPointer(OBOPENOBJECTBYPOINTER_ARGS); + +NTSTATUS KphProtectInit(); +NTSTATUS KphProtectDeinit(); + +PKPH_PROCESS_ENTRY KphProtectAddEntry( + PEPROCESS Process, + HANDLE Tag, + ACCESS_MASK ProcessAllowMask, + ACCESS_MASK ThreadAllowMask + ); + +BOOLEAN KphProtectCopyEntry( + PEPROCESS Process, + PKPH_PROCESS_ENTRY ProcessEntry + ); + +PKPH_PROCESS_ENTRY KphProtectFindEntry( + PEPROCESS Process, + HANDLE Tag + ); + +BOOLEAN KphProtectRemoveByProcess( + PEPROCESS Process + ); + +ULONG KphProtectRemoveByTag( + HANDLE Tag + ); + +#endif diff --git a/trunk/KProcessHacker/include/ps.h b/trunk/KProcessHacker/include/ps.h index 0280bead0..7d73b6e8a 100644 --- a/trunk/KProcessHacker/include/ps.h +++ b/trunk/KProcessHacker/include/ps.h @@ -29,6 +29,44 @@ #include "ob.h" #include "se.h" +#define PROCESS_TERMINATE (0x0001) +#define PROCESS_CREATE_THREAD (0x0002) +#define PROCESS_SET_SESSIONID (0x0004) +#define PROCESS_VM_OPERATION (0x0008) +#define PROCESS_VM_READ (0x0010) +#define PROCESS_VM_WRITE (0x0020) +#define PROCESS_DUP_HANDLE (0x0040) +#define PROCESS_CREATE_PROCESS (0x0080) +#define PROCESS_SET_QUOTA (0x0100) +#define PROCESS_SET_INFORMATION (0x0200) +#define PROCESS_QUERY_INFORMATION (0x0400) +#define PROCESS_SUSPEND_RESUME (0x0800) +#define PROCESS_QUERY_LIMITED_INFORMATION (0x1000) +#ifndef PROCESS_ALL_ACCESS +#define PROCESS_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xffff) +#endif + +#define THREAD_TERMINATE (0x0001) +#define THREAD_SUSPEND_RESUME (0x0002) +#define THREAD_ALERT (0x0004) +#define THREAD_GET_CONTEXT (0x0008) +#define THREAD_SET_CONTEXT (0x0010) +#define THREAD_SET_INFORMATION (0x0020) +#define THREAD_QUERY_INFORMATION (0x0040) +#define THREAD_SET_THREAD_TOKEN (0x0080) +#define THREAD_IMPERSONATE (0x0100) +#define THREAD_DIRECT_IMPERSONATION (0x0200) +#ifndef THREAD_ALL_ACCESS +#define THREAD_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3ff) +#endif + +#define JOB_OBJECT_ASSIGN_PROCESS (0x0001) +#define JOB_OBJECT_SET_ATTRIBUTES (0x0002) +#define JOB_OBJECT_QUERY (0x0004) +#define JOB_OBJECT_TERMINATE (0x0008) +#define JOB_OBJECT_SET_SECURITY_ATTRIBUTES (0x0010) +#define JOB_OBJECT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1f) + extern POBJECT_TYPE *PsJobType; /* FUNCTION DEFS */ diff --git a/trunk/KProcessHacker/include/version.h b/trunk/KProcessHacker/include/version.h index 6d4053a9f..01921dcb4 100644 --- a/trunk/KProcessHacker/include/version.h +++ b/trunk/KProcessHacker/include/version.h @@ -57,7 +57,7 @@ typedef struct _KV_SCANPROC NTSTATUS KvInit(); PVOID KvVerifyPrologue( - ULONG_PTR Offset + PVOID Address ); PVOID KvScanProc( @@ -85,6 +85,7 @@ EXT ACCESS_MASK ThreadAllAccess; /* Structures * Et: ETHREAD * Ep: EPROCESS + * Kt: KTHREAD * Ot: OBJECT_TYPE * Oti: OBJECT_TYPE_INITIALIZER, offset measured from an OBJECT_TYPE */ @@ -96,6 +97,7 @@ EXT ULONG OffEpObjectTable; EXT ULONG OffEpProtectedProcessOff; EXT ULONG OffEpProtectedProcessBit; EXT ULONG OffEpRundownProtect; +EXT ULONG OffKtProcess; EXT ULONG OffOhBody; EXT ULONG OffOtiGenericMapping; diff --git a/trunk/KProcessHacker/include/zw.h b/trunk/KProcessHacker/include/zw.h index 6937f5c5a..bd07f4ff3 100644 --- a/trunk/KProcessHacker/include/zw.h +++ b/trunk/KProcessHacker/include/zw.h @@ -25,35 +25,6 @@ #include "types.h" -#define PROCESS_TERMINATE (0x0001) -#define PROCESS_CREATE_THREAD (0x0002) -#define PROCESS_SET_SESSIONID (0x0004) -#define PROCESS_VM_OPERATION (0x0008) -#define PROCESS_VM_READ (0x0010) -#define PROCESS_VM_WRITE (0x0020) -#define PROCESS_DUP_HANDLE (0x0040) -#define PROCESS_CREATE_PROCESS (0x0080) -#define PROCESS_SET_QUOTA (0x0100) -#define PROCESS_SET_INFORMATION (0x0200) -#define PROCESS_QUERY_INFORMATION (0x0400) -#define PROCESS_SUSPEND_RESUME (0x0800) -#define PROCESS_QUERY_LIMITED_INFORMATION (0x1000) -#if (NTDDI_VERSION >= NTDDI_LONGHORN) -#define PROCESS_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | \ - 0xFFFF) -#else -#define PROCESS_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | \ - 0xFFF) -#endif - -#define JOB_OBJECT_ASSIGN_PROCESS (0x0001) -#define JOB_OBJECT_SET_ATTRIBUTES (0x0002) -#define JOB_OBJECT_QUERY (0x0004) -#define JOB_OBJECT_TERMINATE (0x0008) -#define JOB_OBJECT_SET_SECURITY_ATTRIBUTES (0x0010) -#define JOB_OBJECT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | \ - 0x1F) - typedef struct _SYSTEM_MODULE_INFORMATION { ULONG Reserved[2]; diff --git a/trunk/KProcessHacker/kprocesshacker.c b/trunk/KProcessHacker/kprocesshacker.c index 743bf9c20..ea32b1ad1 100644 --- a/trunk/KProcessHacker/kprocesshacker.c +++ b/trunk/KProcessHacker/kprocesshacker.c @@ -22,7 +22,9 @@ #include "include/kprocesshacker.h" #include "include/debug.h" + #include "include/kph.h" +#include "include/protect.h" #include "include/ps.h" #include "include/version.h" @@ -33,6 +35,8 @@ #pragma alloc_text(PAGE, KphUnsupported) #pragma pack(1) +static BOOLEAN ProtectionInitialized = FALSE; + VOID DriverUnload(PDRIVER_OBJECT DriverObject) { UNICODE_STRING dosDeviceName; @@ -41,6 +45,18 @@ VOID DriverUnload(PDRIVER_OBJECT DriverObject) IoDeleteSymbolicLink(&dosDeviceName); IoDeleteDevice(DriverObject->DeviceObject); + if (ProtectionInitialized) + { + LARGE_INTEGER waitLi; + + KphProtectDeinit(); + ProtectionInitialized = FALSE; + + /* Wait for a bit before unloading to prevent BSODs. */ + waitLi.QuadPart = KPH_REL_TIMEOUT_IN_SEC(5); + KeDelayExecutionThread(KernelMode, FALSE, &waitLi); + } + dprintf("Driver unloaded\n"); } @@ -119,11 +135,26 @@ NTSTATUS KphDispatchClose(PDEVICE_OBJECT DeviceObject, PIRP Irp) { NTSTATUS status = STATUS_SUCCESS; + if (ProtectionInitialized) + { + ULONG count = KphProtectRemoveByTag(PsGetCurrentProcessId()); + dprintf("Removed %d protection entries\n", count); + } + dprintf("Client (PID %d) disconnected\n", PsGetCurrentProcessId()); return status; } +VOID InitProtection() +{ + if (!ProtectionInitialized) + { + KphProtectInit(); + ProtectionInitialized = TRUE; + } +} + /* from YAPM */ NTSTATUS GetObjectName(PFILE_OBJECT FileObject, PVOID Buffer, ULONG BufferLength, PULONG ReturnLength) { @@ -239,6 +270,12 @@ PCHAR GetIoControlName(ULONG ControlCode) return "KphSetHandleGrantedAccess"; else if (ControlCode == KPH_ASSIGNIMPERSONATIONTOKEN) return "KphAssignImpersonationToken"; + else if (ControlCode == KPH_PROTECTADD) + return "Add Process Protection"; + else if (ControlCode == KPH_PROTECTREMOVE) + return "Remove Process Protection"; + else if (ControlCode == KPH_PROTECTQUERY) + return "Query Process Protection"; else return "Unknown"; } @@ -1239,6 +1276,158 @@ NTSTATUS KphDispatchDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp) } break; + /* Add Process Protection */ + case KPH_PROTECTADD: + { + struct + { + HANDLE ProcessHandle; + ACCESS_MASK ProcessAllowMask; + ACCESS_MASK ThreadAllowMask; + } *args = dataBuffer; + PEPROCESS processObject; + + if (inLength < sizeof(*args)) + { + status = STATUS_BUFFER_TOO_SMALL; + goto IoControlEnd; + } + + status = ObReferenceObjectByHandle( + args->ProcessHandle, + 0, + *PsProcessType, + KernelMode, + &processObject, + NULL + ); + ObDereferenceObject(processObject); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + InitProtection(); + + /* Don't protect the same process twice. */ + if (KphProtectFindEntry(processObject, NULL)) + { + status = STATUS_NOT_SUPPORTED; + goto IoControlEnd; + } + + if (!KphProtectAddEntry( + processObject, + PsGetCurrentProcessId(), + args->ProcessAllowMask, + args->ThreadAllowMask + )) + { + status = STATUS_UNSUCCESSFUL; + goto IoControlEnd; + } + } + break; + + /* Remove Process Protection */ + case KPH_PROTECTREMOVE: + { + struct + { + HANDLE ProcessHandle; + } *args = dataBuffer; + PEPROCESS processObject; + + if (inLength < sizeof(*args)) + { + status = STATUS_BUFFER_TOO_SMALL; + goto IoControlEnd; + } + + status = ObReferenceObjectByHandle( + args->ProcessHandle, + 0, + *PsProcessType, + KernelMode, + &processObject, + NULL + ); + ObDereferenceObject(processObject); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + InitProtection(); + + if (!KphProtectRemoveByProcess(processObject)) + { + status = STATUS_UNSUCCESSFUL; + goto IoControlEnd; + } + } + break; + + /* Query Process Protection */ + case KPH_PROTECTQUERY: + { + struct + { + HANDLE ProcessHandle; + PACCESS_MASK ProcessAllowMask; + PACCESS_MASK ThreadAllowMask; + } *args = dataBuffer; + PEPROCESS processObject; + KPH_PROCESS_ENTRY processEntry; + + if (inLength < sizeof(*args)) + { + status = STATUS_BUFFER_TOO_SMALL; + goto IoControlEnd; + } + + __try + { + ProbeForWrite(args->ProcessAllowMask, sizeof(ACCESS_MASK), 1); + ProbeForWrite(args->ThreadAllowMask, sizeof(ACCESS_MASK), 1); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + goto IoControlEnd; + } + + status = ObReferenceObjectByHandle( + args->ProcessHandle, + 0, + *PsProcessType, + KernelMode, + &processObject, + NULL + ); + ObDereferenceObject(processObject); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + InitProtection(); + + if (!KphProtectCopyEntry(processObject, &processEntry)) + { + status = STATUS_UNSUCCESSFUL; + goto IoControlEnd; + } + + __try + { + *(args->ProcessAllowMask) = processEntry.ProcessAllowMask; + *(args->ThreadAllowMask) = processEntry.ThreadAllowMask; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + } + } + break; + default: { dprintf("Unrecognized IOCTL code 0x%08x\n", controlCode); diff --git a/trunk/KProcessHacker/protect.c b/trunk/KProcessHacker/protect.c new file mode 100644 index 000000000..38080ed6e --- /dev/null +++ b/trunk/KProcessHacker/protect.c @@ -0,0 +1,337 @@ +/* + * Process Hacker Driver - + * process protection + * + * Copyright (C) 2009 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#include "include/protect.h" + +LIST_ENTRY ProtectedProcessListHead; +KSPIN_LOCK ProtectedProcessListLock; +NPAGED_LOOKASIDE_LIST ProtectedProcessLookasideList; + +KPH_HOOK ObOpenObjectByPointerHook = { 0 }; + +BOOLEAN KphpIsCurrentProcessProtected(); + +VOID KphpProtectRemoveEntry( + PKPH_PROCESS_ENTRY Entry + ); + +KPH_DEFINE_HOOK_CALL( + NTSTATUS NTAPI KphOldObOpenObjectByPointer, + OBOPENOBJECTBYPOINTER_ARGS, + ObOpenObjectByPointerHook + ); + +/* KphProtectInit + * + * Initializes process protection. + */ +NTSTATUS KphProtectInit() +{ + NTSTATUS status; + + /* Initialize list structures. */ + InitializeListHead(&ProtectedProcessListHead); + KeInitializeSpinLock(&ProtectedProcessListLock); + ExInitializeNPagedLookasideList( + &ProtectedProcessLookasideList, + NULL, + NULL, + 0, + sizeof(KPH_PROCESS_ENTRY), + KPH_TAG, + 0 + ); + + /* Hook various functions. */ + ObOpenObjectByPointerHook.Function = ObOpenObjectByPointer; + ObOpenObjectByPointerHook.Target = KphNewObOpenObjectByPointer; + if (!NT_SUCCESS(status = KphHook(&ObOpenObjectByPointerHook))) + return status; + + return STATUS_SUCCESS; +} + +/* KphProtectDeinit + * + * Removes process protection and frees associated structures. + */ +NTSTATUS KphProtectDeinit() +{ + KIRQL oldIrql; + + /* Unhook. */ + KphUnhook(&ObOpenObjectByPointerHook); + + KeAcquireSpinLock(&ProtectedProcessListLock, &oldIrql); + + /* Free and remove all process entries from the list. */ + while (!IsListEmpty(&ProtectedProcessListHead)) + { + PKPH_PROCESS_ENTRY entry = + CONTAINING_RECORD( + RemoveHeadList(&ProtectedProcessListHead), + KPH_PROCESS_ENTRY, + ListEntry + ); + + dprintf("KphProtectDeinit: removing entry 0x%08x\n", entry); + + ExFreeToNPagedLookasideList( + &ProtectedProcessLookasideList, + entry + ); + } + + KeReleaseSpinLock(&ProtectedProcessListLock, oldIrql); + + return STATUS_SUCCESS; +} + +/* KphNewObOpenObjectByPointer + * + * New ObOpenObjectByPointer function. + */ +NTSTATUS NTAPI KphNewObOpenObjectByPointer( + OBOPENOBJECTBYPOINTER_ARGS + ) +{ + if ( + AccessMode != KernelMode && /* let kernel-mode callers through */ + !KphpIsCurrentProcessProtected() /* let protected process callers through */ + ) + { + PEPROCESS processObject = (PEPROCESS)Object; + BOOLEAN isThread = ObjectType == *PsThreadType; + ACCESS_MASK access; + KPH_PROCESS_ENTRY processEntry; + + *Handle = NULL; + access = DesiredAccess; + + /* If we have an access state, get the desired access from it. */ + if (PassedAccessState != NULL) + access = PassedAccessState->OriginalDesiredAccess; + + /* If this is a thread, get its parent process. */ + if (isThread) + processObject = *(PEPROCESS *)KVOFF(Object, OffKtProcess); + + if (KphProtectCopyEntry(processObject, &processEntry)) + { + ACCESS_MASK mask = + isThread ? processEntry.ThreadAllowMask : processEntry.ProcessAllowMask; + + /* The process/thread is protected. Check if the requested access is allowed. */ + if ((access & mask) != access) + { + dprintf( + "%d: Access denied: 0x%08x (%s)\n", + PsGetCurrentProcessId(), + access, + isThread ? "Thread" : "Process" + ); + /* Access denied. */ + return STATUS_ACCESS_DENIED; + } + } + } + + return KphOldObOpenObjectByPointer( + Object, + HandleAttributes, + PassedAccessState, + DesiredAccess, + ObjectType, + AccessMode, + Handle + ); +} + +/* KphProtectAddEntry + * + * Protects the specified process. + */ +PKPH_PROCESS_ENTRY KphProtectAddEntry( + PEPROCESS Process, + HANDLE Tag, + ACCESS_MASK ProcessAllowMask, + ACCESS_MASK ThreadAllowMask + ) +{ + KIRQL oldIrql; + PKPH_PROCESS_ENTRY entry = + ExAllocateFromNPagedLookasideList(&ProtectedProcessLookasideList); + + if (entry == NULL) + return NULL; + + entry->Process = Process; + entry->Tag = Tag; + entry->ProcessAllowMask = ProcessAllowMask; + entry->ThreadAllowMask = ThreadAllowMask; + + KeAcquireSpinLock(&ProtectedProcessListLock, &oldIrql); + InsertHeadList(&ProtectedProcessListHead, &entry->ListEntry); + KeReleaseSpinLock(&ProtectedProcessListLock, oldIrql); + + return entry; +} + +/* KphProtectCopyEntry + * + * Copies process protection data for the specified process. + */ +BOOLEAN KphProtectCopyEntry( + PEPROCESS Process, + PKPH_PROCESS_ENTRY ProcessEntry + ) +{ + KIRQL oldIrql; + PLIST_ENTRY entry = ProtectedProcessListHead.Flink; + + KeAcquireSpinLock(&ProtectedProcessListLock, &oldIrql); + + while (entry != &ProtectedProcessListHead) + { + PKPH_PROCESS_ENTRY processEntry = + CONTAINING_RECORD(entry, KPH_PROCESS_ENTRY, ListEntry); + + if (processEntry->Process == Process) + { + memcpy(ProcessEntry, processEntry, sizeof(KPH_PROCESS_ENTRY)); + KeReleaseSpinLock(&ProtectedProcessListLock, oldIrql); + + return TRUE; + } + + entry = entry->Flink; + } + + KeReleaseSpinLock(&ProtectedProcessListLock, oldIrql); + + return FALSE; +} + +/* KphProtectFindEntry + * + * Finds process protection data. + */ +PKPH_PROCESS_ENTRY KphProtectFindEntry( + PEPROCESS Process, + HANDLE Tag + ) +{ + KIRQL oldIrql; + PLIST_ENTRY entry = ProtectedProcessListHead.Flink; + + KeAcquireSpinLock(&ProtectedProcessListLock, &oldIrql); + + while (entry != &ProtectedProcessListHead) + { + PKPH_PROCESS_ENTRY processEntry = + CONTAINING_RECORD(entry, KPH_PROCESS_ENTRY, ListEntry); + + if ( + (Process != NULL && processEntry->Process == Process) || + (Tag != NULL && processEntry->Tag == Tag) + ) + { + KeReleaseSpinLock(&ProtectedProcessListLock, oldIrql); + + return processEntry; + } + + entry = entry->Flink; + } + + KeReleaseSpinLock(&ProtectedProcessListLock, oldIrql); + + return NULL; +} + +/* KphProtectRemoveByProcess + * + * Removes protection from the specified process. + */ +BOOLEAN KphProtectRemoveByProcess( + PEPROCESS Process + ) +{ + PKPH_PROCESS_ENTRY entry = KphProtectFindEntry(Process, NULL); + + if (entry == NULL) + return FALSE; + + KphpProtectRemoveEntry(entry); + + return TRUE; +} + +/* KphProtectRemoveByTag + * + * Removes protection from all processes with the specified tag. + */ +ULONG KphProtectRemoveByTag( + HANDLE Tag + ) +{ + KIRQL oldIrql; + ULONG count = 0; + PKPH_PROCESS_ENTRY entry; + + /* Keep removing entries until we can't find any more. */ + while (entry = KphProtectFindEntry(NULL, Tag)) + { + KphpProtectRemoveEntry(entry); + count++; + } + + return count; +} + +/* KphpIsCurrentProcessProtected + * + * Determines whether the current process is protected. + */ +BOOLEAN KphpIsCurrentProcessProtected() +{ + return KphProtectFindEntry(PsGetCurrentProcess(), NULL) != NULL; +} + +/* KphpProtectRemoveEntry + * + * Removes and frees process protection data. + */ +VOID KphpProtectRemoveEntry( + PKPH_PROCESS_ENTRY Entry + ) +{ + KIRQL oldIrql; + + KeAcquireSpinLock(&ProtectedProcessListLock, &oldIrql); + RemoveEntryList(&Entry->ListEntry); + ExFreeToNPagedLookasideList( + &ProtectedProcessLookasideList, + Entry + ); + KeReleaseSpinLock(&ProtectedProcessListLock, oldIrql); +} diff --git a/trunk/KProcessHacker/sources b/trunk/KProcessHacker/sources index 6e6ab79dc..d46de85aa 100644 --- a/trunk/KProcessHacker/sources +++ b/trunk/KProcessHacker/sources @@ -9,6 +9,8 @@ SOURCES= \ kprocesshacker.c \ version.c \ kph.c \ + hook.c \ + protect.c \ mm.c \ ob.c \ ps.c \ diff --git a/trunk/KProcessHacker/version.c b/trunk/KProcessHacker/version.c index 073c73fa0..79d341e75 100644 --- a/trunk/KProcessHacker/version.c +++ b/trunk/KProcessHacker/version.c @@ -118,6 +118,7 @@ NTSTATUS KvInit() OffEpProtectedProcessOff = 0; OffEpProtectedProcessBit = 0; OffEpRundownProtect = 0x80; + OffKtProcess = 0x220; /* it's actually in the ETHREAD, but let's ignore that */ OffOtiGenericMapping = 0x60 + 0x8; OffOhBody = 0x18; @@ -182,6 +183,7 @@ NTSTATUS KvInit() OffEpProtectedProcessOff = 0x224; OffEpProtectedProcessBit = 0xb; OffEpRundownProtect = 0x98; + OffKtProcess = 0x144; OffOhBody = 0x18; INIT_SCAN( @@ -232,6 +234,7 @@ NTSTATUS KvInit() OffEpProtectedProcessOff = 0x25c; OffEpProtectedProcessBit = 0xb; OffEpRundownProtect = 0xb0; + OffKtProcess = 0x154; OffOtiGenericMapping = 0x28 + 0xc; OffOhBody = 0x18; @@ -266,13 +269,11 @@ NTSTATUS KvInit() } PVOID KvVerifyPrologue( - ULONG_PTR Offset + PVOID Address ) { - PVOID address = (PVOID)((ULONG_PTR)__NtClose + Offset); - - if (memcmp(address, StandardPrologue, 5) == 0) - return address; + if (memcmp(Address, StandardPrologue, 5) == 0) + return Address; else return NULL; } diff --git a/trunk/ProcessHacker.Native/KProcessHacker.cs b/trunk/ProcessHacker.Native/KProcessHacker.cs index 40b12569a..b6b910d3f 100644 --- a/trunk/ProcessHacker.Native/KProcessHacker.cs +++ b/trunk/ProcessHacker.Native/KProcessHacker.cs @@ -76,7 +76,10 @@ namespace ProcessHacker.Native KphTerminateThread, GetFeatures, KphSetHandleGrantedAccess, - KphAssignImpersonationToken + KphAssignImpersonationToken, + ProtectAdd, + ProtectRemove, + ProtectQuery } [Flags] @@ -113,9 +116,8 @@ namespace ProcessHacker.Native shandle.Delete(); } } - catch (Exception) - { - } + catch + { } try { @@ -546,6 +548,41 @@ namespace ProcessHacker.Native bytesWritten = returnLength; } + public void ProtectAdd(ProcessHandle processHandle, ProcessAccess ProcessAllowMask, ThreadAccess ThreadAllowMask) + { + byte* inData = stackalloc byte[12]; + + *(int*)inData = processHandle; + *(int*)(inData + 4) = (int)ProcessAllowMask; + *(int*)(inData + 8) = (int)ThreadAllowMask; + + _fileHandle.IoControl(CtlCode(Control.ProtectAdd), inData, 12, null, 0); + } + + public void ProtectQuery(ProcessHandle processHandle, out ProcessAccess ProcessAllowMask, out ThreadAccess ThreadAllowMask) + { + byte* inData = stackalloc byte[12]; + ProcessAccess processAllowMask; + ThreadAccess threadAllowMask; + + *(int*)inData = processHandle; + *(int*)(inData + 4) = (int)&processAllowMask; + *(int*)(inData + 8) = (int)&threadAllowMask; + + _fileHandle.IoControl(CtlCode(Control.ProtectQuery), inData, 12, null, 0); + + ProcessAllowMask = processAllowMask; + ThreadAllowMask = threadAllowMask; + } + + public void ProtectRemove(ProcessHandle processHandle) + { + int processHandleInt = processHandle; + + _fileHandle.IoControl(CtlCode(Control.ProtectRemove), + (byte*)&processHandleInt, 4, null, 0); + } + public byte[] Read(int address, int length) { byte[] buffer = new byte[length]; diff --git a/trunk/ProcessHacker/Components/ModuleList.cs b/trunk/ProcessHacker/Components/ModuleList.cs index 16dae8d37..32b51e042 100644 --- a/trunk/ProcessHacker/Components/ModuleList.cs +++ b/trunk/ProcessHacker/Components/ModuleList.cs @@ -29,6 +29,7 @@ using ProcessHacker.Native.Api; using ProcessHacker.Native.Objects; using ProcessHacker.Native.Security; using ProcessHacker.UI; +using Microsoft.Win32; namespace ProcessHacker.Components { @@ -409,41 +410,83 @@ namespace ProcessHacker.Components private void unloadMenuItem_Click(object sender, EventArgs e) { - if (MessageBox.Show("Are you sure you want to unload this library?", "Process Hacker", + if (MessageBox.Show("Are you sure you want to unload this " + + (_pid != 4 ? "library" : "driver") + "?", "Process Hacker", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button2) == DialogResult.No) return; - try + if (_pid == 4) { - IntPtr kernel32 = Win32.GetModuleHandle("kernel32.dll"); - IntPtr freeLibrary = Win32.GetProcAddress(kernel32, "FreeLibrary"); - - if (freeLibrary == IntPtr.Zero) - throw new Exception("Could not find the entry point of FreeLibrary in kernel32.dll!"); - - using (ProcessHandle phandle = new ProcessHandle(_pid, - Program.MinProcessQueryRights | Program.MinProcessReadMemoryRights | - Program.MinProcessWriteMemoryRights | ProcessAccess.CreateThread)) + try { - IntPtr baseAddress = ((ModuleItem)listModules.SelectedItems[0].Tag).BaseAddress; + string fileName = ((ModuleItem)listModules.SelectedItems[0].Tag).FileName; + RegistryKey servicesKey = + Registry.LocalMachine.OpenSubKey("SYSTEM\\CurrentControlSet\\Services", true); + string serviceName = Misc.MakeRandomString(8); + RegistryKey serviceKey = servicesKey.CreateSubKey(serviceName); - phandle.SetModuleReferenceCount(baseAddress, 1); + serviceKey.SetValue("ErrorControl", 1, RegistryValueKind.DWord); + serviceKey.SetValue("ImagePath", "\\??\\" + fileName, RegistryValueKind.ExpandString); + serviceKey.SetValue("Start", 1, RegistryValueKind.DWord); + serviceKey.SetValue("Type", 1, RegistryValueKind.DWord); + serviceKey.Close(); + servicesKey.Flush(); - var thread = phandle.CreateThread(freeLibrary, baseAddress, ThreadAccess.All); - - thread.Wait(1000); - - int exitCode = thread.GetExitCode(); - - if (exitCode == 0) + try { - throw new Exception("Error unloading the library."); + Windows.UnloadDriver(serviceName); + } + finally + { + servicesKey.DeleteSubKeyTree(serviceName); + servicesKey.Close(); } } + catch (System.Security.SecurityException ex) + { + MessageBox.Show("Could not unload the driver. Make sure Process Hacker " + + "is running with administrative privileges. Error:\n\n" + + ex.Message, "Process Hacker", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + catch (Exception ex) + { + MessageBox.Show(ex.Message, "Process Hacker", MessageBoxButtons.OK, MessageBoxIcon.Error); + } } - catch (Exception ex) + else { - MessageBox.Show(ex.Message, "Process Hacker", MessageBoxButtons.OK, MessageBoxIcon.Error); + try + { + IntPtr kernel32 = Win32.GetModuleHandle("kernel32.dll"); + IntPtr freeLibrary = Win32.GetProcAddress(kernel32, "FreeLibrary"); + + if (freeLibrary == IntPtr.Zero) + throw new Exception("Could not find the entry point of FreeLibrary in kernel32.dll!"); + + using (ProcessHandle phandle = new ProcessHandle(_pid, + Program.MinProcessQueryRights | Program.MinProcessReadMemoryRights | + Program.MinProcessWriteMemoryRights | ProcessAccess.CreateThread)) + { + IntPtr baseAddress = ((ModuleItem)listModules.SelectedItems[0].Tag).BaseAddress; + + phandle.SetModuleReferenceCount(baseAddress, 1); + + var thread = phandle.CreateThread(freeLibrary, baseAddress, ThreadAccess.All); + + thread.Wait(1000); + + int exitCode = thread.GetExitCode(); + + if (exitCode == 0) + { + throw new Exception("Error unloading the library."); + } + } + } + catch (Exception ex) + { + MessageBox.Show(ex.Message, "Process Hacker", MessageBoxButtons.OK, MessageBoxIcon.Error); + } } } } diff --git a/trunk/ProcessHacker/Forms/HackerWindow.Designer.cs b/trunk/ProcessHacker/Forms/HackerWindow.Designer.cs index 79cc3c551..7e7b84273 100644 --- a/trunk/ProcessHacker/Forms/HackerWindow.Designer.cs +++ b/trunk/ProcessHacker/Forms/HackerWindow.Designer.cs @@ -41,6 +41,7 @@ this.menuItem5 = new System.Windows.Forms.MenuItem(); this.affinityProcessMenuItem = new System.Windows.Forms.MenuItem(); this.injectDllProcessMenuItem = new System.Windows.Forms.MenuItem(); + this.protectionProcessMenuItem = new System.Windows.Forms.MenuItem(); this.setTokenProcessMenuItem = new System.Windows.Forms.MenuItem(); this.terminatorProcessMenuItem = new System.Windows.Forms.MenuItem(); this.priorityMenuItem = new System.Windows.Forms.MenuItem(); @@ -189,6 +190,7 @@ this.menuItem5, this.affinityProcessMenuItem, this.injectDllProcessMenuItem, + this.protectionProcessMenuItem, this.setTokenProcessMenuItem, this.terminatorProcessMenuItem, this.priorityMenuItem, @@ -264,22 +266,28 @@ this.injectDllProcessMenuItem.Text = "Inject DLL..."; this.injectDllProcessMenuItem.Click += new System.EventHandler(this.injectDllProcessMenuItem_Click); // + // protectionProcessMenuItem + // + this.protectionProcessMenuItem.Index = 10; + this.protectionProcessMenuItem.Text = "Protection..."; + this.protectionProcessMenuItem.Click += new System.EventHandler(this.protectionProcessMenuItem_Click); + // // setTokenProcessMenuItem // - this.setTokenProcessMenuItem.Index = 10; + this.setTokenProcessMenuItem.Index = 11; this.setTokenProcessMenuItem.Text = "Set Token..."; this.setTokenProcessMenuItem.Click += new System.EventHandler(this.setTokenProcessMenuItem_Click); // // terminatorProcessMenuItem // - this.terminatorProcessMenuItem.Index = 11; + this.terminatorProcessMenuItem.Index = 12; this.terminatorProcessMenuItem.Text = "Terminator..."; this.terminatorProcessMenuItem.Click += new System.EventHandler(this.terminatorProcessMenuItem_Click); // // priorityMenuItem // this.vistaMenu.SetImage(this.priorityMenuItem, global::ProcessHacker.Properties.Resources.control_equalizer_blue); - this.priorityMenuItem.Index = 12; + this.priorityMenuItem.Index = 13; this.priorityMenuItem.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { this.realTimeMenuItem, this.highMenuItem, @@ -333,7 +341,7 @@ // // runAsProcessMenuItem // - this.runAsProcessMenuItem.Index = 13; + this.runAsProcessMenuItem.Index = 14; this.runAsProcessMenuItem.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { this.launchAsUserProcessMenuItem, this.launchAsThisUserProcessMenuItem}); @@ -355,37 +363,37 @@ // this.propertiesProcessMenuItem.DefaultItem = true; this.vistaMenu.SetImage(this.propertiesProcessMenuItem, global::ProcessHacker.Properties.Resources.application_form_magnify); - this.propertiesProcessMenuItem.Index = 14; + this.propertiesProcessMenuItem.Index = 15; this.propertiesProcessMenuItem.Text = "&Properties..."; this.propertiesProcessMenuItem.Click += new System.EventHandler(this.propertiesProcessMenuItem_Click); // // menuItem7 // - this.menuItem7.Index = 15; + this.menuItem7.Index = 16; this.menuItem7.Text = "-"; // // searchProcessMenuItem // - this.searchProcessMenuItem.Index = 16; + this.searchProcessMenuItem.Index = 17; this.searchProcessMenuItem.Shortcut = System.Windows.Forms.Shortcut.CtrlM; this.searchProcessMenuItem.Text = "&Search Online..."; this.searchProcessMenuItem.Click += new System.EventHandler(this.searchProcessMenuItem_Click); // // reanalyzeProcessMenuItem // - this.reanalyzeProcessMenuItem.Index = 17; + this.reanalyzeProcessMenuItem.Index = 18; this.reanalyzeProcessMenuItem.Text = "Re-analyze"; this.reanalyzeProcessMenuItem.Click += new System.EventHandler(this.reanalyzeProcessMenuItem_Click); // // copyProcessMenuItem // this.vistaMenu.SetImage(this.copyProcessMenuItem, global::ProcessHacker.Properties.Resources.page_copy); - this.copyProcessMenuItem.Index = 18; + this.copyProcessMenuItem.Index = 19; this.copyProcessMenuItem.Text = "&Copy"; // // selectAllProcessMenuItem // - this.selectAllProcessMenuItem.Index = 19; + this.selectAllProcessMenuItem.Index = 20; this.selectAllProcessMenuItem.Shortcut = System.Windows.Forms.Shortcut.CtrlA; this.selectAllProcessMenuItem.Text = "Select &All"; this.selectAllProcessMenuItem.Click += new System.EventHandler(this.selectAllProcessMenuItem_Click); @@ -1343,6 +1351,7 @@ private System.Windows.Forms.MenuItem commitHistoryMenuItem; private System.Windows.Forms.MenuItem physMemHistoryMenuItem; private System.Windows.Forms.MenuItem closeNetworkMenuItem; + private System.Windows.Forms.MenuItem protectionProcessMenuItem; } } diff --git a/trunk/ProcessHacker/Forms/HackerWindow.cs b/trunk/ProcessHacker/Forms/HackerWindow.cs index 9100272de..25c5353d0 100644 --- a/trunk/ProcessHacker/Forms/HackerWindow.cs +++ b/trunk/ProcessHacker/Forms/HackerWindow.cs @@ -1163,6 +1163,11 @@ namespace ProcessHacker } } + private void protectionProcessMenuItem_Click(object sender, EventArgs e) + { + (new ProtectProcessWindow(processSelectedPID)).ShowDialog(); + } + private void setTokenProcessMenuItem_Click(object sender, EventArgs e) { ProcessPickerWindow picker = new ProcessPickerWindow(); @@ -2318,7 +2323,7 @@ namespace ProcessHacker treeProcesses.RefreshItems(); } - private void LoadFixMenuItems() + public void LoadFixMenuItems() { if (!System.IO.File.Exists(Application.StartupPath + "\\Assistant.exe")) { @@ -2332,6 +2337,9 @@ namespace ProcessHacker if (KProcessHacker.Instance == null || !OSVersion.HasSetAccessToken) setTokenProcessMenuItem.Visible = false; + if (KProcessHacker.Instance == null || !Properties.Settings.Default.EnableExperimentalFeatures) + protectionProcessMenuItem.Visible = false; + if (!OSVersion.HasUac) virtualizationProcessMenuItem.Visible = false; diff --git a/trunk/ProcessHacker/Forms/OptionsWindow.Designer.cs b/trunk/ProcessHacker/Forms/OptionsWindow.Designer.cs index 97017ff1b..909c273b5 100644 --- a/trunk/ProcessHacker/Forms/OptionsWindow.Designer.cs +++ b/trunk/ProcessHacker/Forms/OptionsWindow.Designer.cs @@ -50,6 +50,7 @@ this.label23 = new System.Windows.Forms.Label(); this.textIconMenuProcesses = new System.Windows.Forms.NumericUpDown(); this.tabAdvanced = new System.Windows.Forms.TabPage(); + this.checkHidePhConnections = new System.Windows.Forms.CheckBox(); this.textMaxSamples = new System.Windows.Forms.NumericUpDown(); this.label6 = new System.Windows.Forms.Label(); this.buttonChangeReplaceTaskManager = new System.Windows.Forms.Button(); @@ -95,7 +96,7 @@ this.toolTipProvider = new System.Windows.Forms.ToolTip(this.components); this.buttonCancel = new System.Windows.Forms.Button(); this.buttonApply = new System.Windows.Forms.Button(); - this.checkHidePhConnections = new System.Windows.Forms.CheckBox(); + this.checkEnableExperimentalFeatures = new System.Windows.Forms.CheckBox(); ((System.ComponentModel.ISupportInitialize)(this.textUpdateInterval)).BeginInit(); this.tabControl.SuspendLayout(); this.tabGeneral.SuspendLayout(); @@ -177,7 +178,7 @@ // this.checkWarnDangerous.AutoSize = true; this.checkWarnDangerous.FlatStyle = System.Windows.Forms.FlatStyle.System; - this.checkWarnDangerous.Location = new System.Drawing.Point(6, 78); + this.checkWarnDangerous.Location = new System.Drawing.Point(6, 102); this.checkWarnDangerous.Name = "checkWarnDangerous"; this.checkWarnDangerous.Size = new System.Drawing.Size(228, 18); this.checkWarnDangerous.TabIndex = 4; @@ -383,6 +384,7 @@ // // tabAdvanced // + this.tabAdvanced.Controls.Add(this.checkEnableExperimentalFeatures); this.tabAdvanced.Controls.Add(this.checkHidePhConnections); this.tabAdvanced.Controls.Add(this.textMaxSamples); this.tabAdvanced.Controls.Add(this.label6); @@ -400,6 +402,19 @@ this.tabAdvanced.Text = "Advanced"; this.tabAdvanced.UseVisualStyleBackColor = true; // + // checkHidePhConnections + // + this.checkHidePhConnections.AutoSize = true; + this.checkHidePhConnections.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.checkHidePhConnections.Location = new System.Drawing.Point(6, 150); + this.checkHidePhConnections.Name = "checkHidePhConnections"; + this.checkHidePhConnections.Size = new System.Drawing.Size(235, 18); + this.checkHidePhConnections.TabIndex = 21; + this.checkHidePhConnections.Text = "Hide Process Hacker network connections"; + this.toolTipProvider.SetToolTip(this.checkHidePhConnections, "Hides network connections made by Process Hacker. This may be useful when Process" + + " Hacker is resolving addresses."); + this.checkHidePhConnections.UseVisualStyleBackColor = true; + // // textMaxSamples // this.textMaxSamples.Increment = new decimal(new int[] { @@ -407,7 +422,7 @@ 0, 0, 0}); - this.textMaxSamples.Location = new System.Drawing.Point(118, 154); + this.textMaxSamples.Location = new System.Drawing.Point(118, 178); this.textMaxSamples.Maximum = new decimal(new int[] { 10000, 0, @@ -430,7 +445,7 @@ // label6 // this.label6.AutoSize = true; - this.label6.Location = new System.Drawing.Point(6, 156); + this.label6.Location = new System.Drawing.Point(6, 180); this.label6.Name = "label6"; this.label6.Size = new System.Drawing.Size(106, 13); this.label6.TabIndex = 19; @@ -440,7 +455,7 @@ // buttonChangeReplaceTaskManager // this.buttonChangeReplaceTaskManager.FlatStyle = System.Windows.Forms.FlatStyle.System; - this.buttonChangeReplaceTaskManager.Location = new System.Drawing.Point(257, 51); + this.buttonChangeReplaceTaskManager.Location = new System.Drawing.Point(257, 75); this.buttonChangeReplaceTaskManager.Name = "buttonChangeReplaceTaskManager"; this.buttonChangeReplaceTaskManager.Size = new System.Drawing.Size(89, 23); this.buttonChangeReplaceTaskManager.TabIndex = 18; @@ -452,7 +467,7 @@ // this.checkReplaceTaskManager.AutoSize = true; this.checkReplaceTaskManager.FlatStyle = System.Windows.Forms.FlatStyle.System; - this.checkReplaceTaskManager.Location = new System.Drawing.Point(6, 54); + this.checkReplaceTaskManager.Location = new System.Drawing.Point(6, 78); this.checkReplaceTaskManager.Name = "checkReplaceTaskManager"; this.checkReplaceTaskManager.Size = new System.Drawing.Size(245, 18); this.checkReplaceTaskManager.TabIndex = 17; @@ -477,7 +492,7 @@ // this.checkHideHandlesWithNoName.AutoSize = true; this.checkHideHandlesWithNoName.FlatStyle = System.Windows.Forms.FlatStyle.System; - this.checkHideHandlesWithNoName.Location = new System.Drawing.Point(6, 102); + this.checkHideHandlesWithNoName.Location = new System.Drawing.Point(6, 126); this.checkHideHandlesWithNoName.Name = "checkHideHandlesWithNoName"; this.checkHideHandlesWithNoName.Size = new System.Drawing.Size(160, 18); this.checkHideHandlesWithNoName.TabIndex = 13; @@ -489,7 +504,7 @@ // this.checkVerifySignatures.AutoSize = true; this.checkVerifySignatures.FlatStyle = System.Windows.Forms.FlatStyle.System; - this.checkVerifySignatures.Location = new System.Drawing.Point(6, 30); + this.checkVerifySignatures.Location = new System.Drawing.Point(6, 54); this.checkVerifySignatures.Name = "checkVerifySignatures"; this.checkVerifySignatures.Size = new System.Drawing.Size(254, 18); this.checkVerifySignatures.TabIndex = 4; @@ -932,18 +947,16 @@ this.buttonApply.UseVisualStyleBackColor = true; this.buttonApply.Click += new System.EventHandler(this.buttonApply_Click); // - // checkHidePhConnections + // checkEnableExperimentalFeatures // - this.checkHidePhConnections.AutoSize = true; - this.checkHidePhConnections.FlatStyle = System.Windows.Forms.FlatStyle.System; - this.checkHidePhConnections.Location = new System.Drawing.Point(6, 126); - this.checkHidePhConnections.Name = "checkHidePhConnections"; - this.checkHidePhConnections.Size = new System.Drawing.Size(235, 18); - this.checkHidePhConnections.TabIndex = 21; - this.checkHidePhConnections.Text = "Hide Process Hacker network connections"; - this.toolTipProvider.SetToolTip(this.checkHidePhConnections, "Hides network connections made by Process Hacker. This may be useful when Process" + - " Hacker is resolving addresses."); - this.checkHidePhConnections.UseVisualStyleBackColor = true; + this.checkEnableExperimentalFeatures.AutoSize = true; + this.checkEnableExperimentalFeatures.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.checkEnableExperimentalFeatures.Location = new System.Drawing.Point(6, 30); + this.checkEnableExperimentalFeatures.Name = "checkEnableExperimentalFeatures"; + this.checkEnableExperimentalFeatures.Size = new System.Drawing.Size(168, 18); + this.checkEnableExperimentalFeatures.TabIndex = 22; + this.checkEnableExperimentalFeatures.Text = "Enable experimental features"; + this.checkEnableExperimentalFeatures.UseVisualStyleBackColor = true; // // OptionsWindow // @@ -1054,5 +1067,6 @@ private System.Windows.Forms.CheckBox checkUndecorate; private System.Windows.Forms.Button buttonApply; private System.Windows.Forms.CheckBox checkHidePhConnections; + private System.Windows.Forms.CheckBox checkEnableExperimentalFeatures; } } \ No newline at end of file diff --git a/trunk/ProcessHacker/Forms/OptionsWindow.cs b/trunk/ProcessHacker/Forms/OptionsWindow.cs index 0932a538c..e54d78c18 100644 --- a/trunk/ProcessHacker/Forms/OptionsWindow.cs +++ b/trunk/ProcessHacker/Forms/OptionsWindow.cs @@ -235,6 +235,7 @@ namespace ProcessHacker checkVerifySignatures.Checked = Properties.Settings.Default.VerifySignatures; checkHideHandlesWithNoName.Checked = Properties.Settings.Default.HideHandlesWithNoName; checkEnableKPH.Checked = Properties.Settings.Default.EnableKPH; + checkEnableExperimentalFeatures.Checked = Properties.Settings.Default.EnableExperimentalFeatures; checkStartHidden.Checked = Properties.Settings.Default.StartHidden; checkHidePhConnections.Checked = Properties.Settings.Default.HideProcessHackerNetworkConnections; @@ -341,6 +342,7 @@ namespace ProcessHacker Properties.Settings.Default.HideHandlesWithNoName = checkHideHandlesWithNoName.Checked; Properties.Settings.Default.StartHidden = checkStartHidden.Checked; Properties.Settings.Default.EnableKPH = checkEnableKPH.Checked; + Properties.Settings.Default.EnableExperimentalFeatures = checkEnableExperimentalFeatures.Checked; Properties.Settings.Default.ImposterNames = textImposterNames.Text.ToLower(); Properties.Settings.Default.HideProcessHackerNetworkConnections = checkHidePhConnections.Checked; @@ -414,6 +416,7 @@ namespace ProcessHacker Program.ImposterNames.Add(s.Trim()); Program.HackerWindow.ApplyIconVisibilities(); + Program.HackerWindow.LoadFixMenuItems(); Program.ProcessProvider.Interval = Properties.Settings.Default.RefreshInterval; Program.HackerWindow.ServiceProvider.Interval = Properties.Settings.Default.RefreshInterval; Program.HackerWindow.NetworkProvider.Interval = Properties.Settings.Default.RefreshInterval; diff --git a/trunk/ProcessHacker/Forms/ProcessWindow.Designer.cs b/trunk/ProcessHacker/Forms/ProcessWindow.Designer.cs index d45b8b684..2dac8a2ac 100644 --- a/trunk/ProcessHacker/Forms/ProcessWindow.Designer.cs +++ b/trunk/ProcessHacker/Forms/ProcessWindow.Designer.cs @@ -563,7 +563,7 @@ this.tabStatistics.Location = new System.Drawing.Point(4, 42); this.tabStatistics.Name = "tabStatistics"; this.tabStatistics.Padding = new System.Windows.Forms.Padding(3); - this.tabStatistics.Size = new System.Drawing.Size(454, 383); + this.tabStatistics.Size = new System.Drawing.Size(481, 409); this.tabStatistics.TabIndex = 9; this.tabStatistics.Text = "Statistics"; this.tabStatistics.UseVisualStyleBackColor = true; @@ -575,7 +575,7 @@ this.tabPerformance.Location = new System.Drawing.Point(4, 42); this.tabPerformance.Name = "tabPerformance"; this.tabPerformance.Padding = new System.Windows.Forms.Padding(3); - this.tabPerformance.Size = new System.Drawing.Size(454, 383); + this.tabPerformance.Size = new System.Drawing.Size(481, 409); this.tabPerformance.TabIndex = 8; this.tabPerformance.Text = "Performance"; this.tabPerformance.UseVisualStyleBackColor = true; @@ -594,7 +594,7 @@ this.tablePerformance.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); this.tablePerformance.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); this.tablePerformance.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); - this.tablePerformance.Size = new System.Drawing.Size(448, 377); + this.tablePerformance.Size = new System.Drawing.Size(475, 403); this.tablePerformance.TabIndex = 1; // // groupCPUUsage @@ -603,7 +603,7 @@ this.groupCPUUsage.Dock = System.Windows.Forms.DockStyle.Fill; this.groupCPUUsage.Location = new System.Drawing.Point(3, 3); this.groupCPUUsage.Name = "groupCPUUsage"; - this.groupCPUUsage.Size = new System.Drawing.Size(442, 119); + this.groupCPUUsage.Size = new System.Drawing.Size(469, 128); this.groupCPUUsage.TabIndex = 0; this.groupCPUUsage.TabStop = false; this.groupCPUUsage.Text = "CPU Usage (Kernel, User)"; @@ -626,7 +626,7 @@ this.plotterCPUUsage.Name = "plotterCPUUsage"; this.plotterCPUUsage.OverlaySecondLine = false; this.plotterCPUUsage.ShowGrid = true; - this.plotterCPUUsage.Size = new System.Drawing.Size(436, 100); + this.plotterCPUUsage.Size = new System.Drawing.Size(463, 109); this.plotterCPUUsage.TabIndex = 0; this.plotterCPUUsage.TextBoxColor = System.Drawing.Color.FromArgb(((int)(((byte)(127)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(0))))); this.plotterCPUUsage.TextColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(255)))), ((int)(((byte)(0))))); @@ -640,9 +640,9 @@ // this.groupBox3.Controls.Add(this.plotterIO); this.groupBox3.Dock = System.Windows.Forms.DockStyle.Fill; - this.groupBox3.Location = new System.Drawing.Point(3, 253); + this.groupBox3.Location = new System.Drawing.Point(3, 271); this.groupBox3.Name = "groupBox3"; - this.groupBox3.Size = new System.Drawing.Size(442, 121); + this.groupBox3.Size = new System.Drawing.Size(469, 129); this.groupBox3.TabIndex = 0; this.groupBox3.TabStop = false; this.groupBox3.Text = "I/O (R+O, W)"; @@ -665,7 +665,7 @@ this.plotterIO.Name = "plotterIO"; this.plotterIO.OverlaySecondLine = true; this.plotterIO.ShowGrid = true; - this.plotterIO.Size = new System.Drawing.Size(436, 102); + this.plotterIO.Size = new System.Drawing.Size(463, 110); this.plotterIO.TabIndex = 0; this.plotterIO.TextBoxColor = System.Drawing.Color.FromArgb(((int)(((byte)(127)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(0))))); this.plotterIO.TextColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(255)))), ((int)(((byte)(0))))); @@ -679,9 +679,9 @@ // this.groupBox2.Controls.Add(this.plotterMemory); this.groupBox2.Dock = System.Windows.Forms.DockStyle.Fill; - this.groupBox2.Location = new System.Drawing.Point(3, 128); + this.groupBox2.Location = new System.Drawing.Point(3, 137); this.groupBox2.Name = "groupBox2"; - this.groupBox2.Size = new System.Drawing.Size(442, 119); + this.groupBox2.Size = new System.Drawing.Size(469, 128); this.groupBox2.TabIndex = 0; this.groupBox2.TabStop = false; this.groupBox2.Text = "Memory (Private Pages, Working Set)"; @@ -704,7 +704,7 @@ this.plotterMemory.Name = "plotterMemory"; this.plotterMemory.OverlaySecondLine = true; this.plotterMemory.ShowGrid = true; - this.plotterMemory.Size = new System.Drawing.Size(436, 100); + this.plotterMemory.Size = new System.Drawing.Size(463, 109); this.plotterMemory.TabIndex = 0; this.plotterMemory.TextBoxColor = System.Drawing.Color.FromArgb(((int)(((byte)(127)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(0))))); this.plotterMemory.TextColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(255)))), ((int)(((byte)(0))))); @@ -720,7 +720,7 @@ this.tabThreads.ImageKey = "hourglass"; this.tabThreads.Location = new System.Drawing.Point(4, 42); this.tabThreads.Name = "tabThreads"; - this.tabThreads.Size = new System.Drawing.Size(454, 383); + this.tabThreads.Size = new System.Drawing.Size(481, 409); this.tabThreads.TabIndex = 3; this.tabThreads.Text = "Threads"; this.tabThreads.UseVisualStyleBackColor = true; @@ -733,7 +733,7 @@ this.listThreads.Location = new System.Drawing.Point(0, 0); this.listThreads.Name = "listThreads"; this.listThreads.Provider = null; - this.listThreads.Size = new System.Drawing.Size(454, 383); + this.listThreads.Size = new System.Drawing.Size(481, 409); this.listThreads.TabIndex = 0; // // tabToken @@ -742,7 +742,7 @@ this.tabToken.Location = new System.Drawing.Point(4, 42); this.tabToken.Name = "tabToken"; this.tabToken.Padding = new System.Windows.Forms.Padding(3); - this.tabToken.Size = new System.Drawing.Size(454, 383); + this.tabToken.Size = new System.Drawing.Size(481, 409); this.tabToken.TabIndex = 1; this.tabToken.Text = "Token"; this.tabToken.UseVisualStyleBackColor = true; @@ -753,7 +753,7 @@ this.tabModules.ImageKey = "page_white_wrench"; this.tabModules.Location = new System.Drawing.Point(4, 42); this.tabModules.Name = "tabModules"; - this.tabModules.Size = new System.Drawing.Size(454, 383); + this.tabModules.Size = new System.Drawing.Size(481, 409); this.tabModules.TabIndex = 6; this.tabModules.Text = "Modules"; this.tabModules.UseVisualStyleBackColor = true; @@ -765,7 +765,7 @@ this.listModules.Location = new System.Drawing.Point(0, 0); this.listModules.Name = "listModules"; this.listModules.Provider = null; - this.listModules.Size = new System.Drawing.Size(454, 383); + this.listModules.Size = new System.Drawing.Size(481, 409); this.listModules.TabIndex = 0; // // tabMemory @@ -778,7 +778,7 @@ this.tabMemory.Location = new System.Drawing.Point(4, 42); this.tabMemory.Name = "tabMemory"; this.tabMemory.Padding = new System.Windows.Forms.Padding(3); - this.tabMemory.Size = new System.Drawing.Size(454, 383); + this.tabMemory.Size = new System.Drawing.Size(481, 409); this.tabMemory.TabIndex = 4; this.tabMemory.Text = "Memory"; this.tabMemory.UseVisualStyleBackColor = true; @@ -874,7 +874,7 @@ this.listMemory.Location = new System.Drawing.Point(6, 59); this.listMemory.Name = "listMemory"; this.listMemory.Provider = null; - this.listMemory.Size = new System.Drawing.Size(442, 318); + this.listMemory.Size = new System.Drawing.Size(469, 344); this.listMemory.TabIndex = 0; // // tabEnvironment @@ -884,7 +884,7 @@ this.tabEnvironment.Location = new System.Drawing.Point(4, 42); this.tabEnvironment.Name = "tabEnvironment"; this.tabEnvironment.Padding = new System.Windows.Forms.Padding(3); - this.tabEnvironment.Size = new System.Drawing.Size(454, 383); + this.tabEnvironment.Size = new System.Drawing.Size(481, 409); this.tabEnvironment.TabIndex = 10; this.tabEnvironment.Text = "Environment"; this.tabEnvironment.UseVisualStyleBackColor = true; @@ -900,7 +900,7 @@ this.listEnvironment.Location = new System.Drawing.Point(3, 3); this.listEnvironment.Name = "listEnvironment"; this.listEnvironment.ShowItemToolTips = true; - this.listEnvironment.Size = new System.Drawing.Size(448, 377); + this.listEnvironment.Size = new System.Drawing.Size(475, 403); this.listEnvironment.Sorting = System.Windows.Forms.SortOrder.Ascending; this.listEnvironment.TabIndex = 0; this.listEnvironment.UseCompatibleStateImageBehavior = false; @@ -924,7 +924,7 @@ this.tabHandles.Location = new System.Drawing.Point(4, 42); this.tabHandles.Name = "tabHandles"; this.tabHandles.Padding = new System.Windows.Forms.Padding(3); - this.tabHandles.Size = new System.Drawing.Size(454, 383); + this.tabHandles.Size = new System.Drawing.Size(481, 409); this.tabHandles.TabIndex = 5; this.tabHandles.Text = "Handles"; this.tabHandles.UseVisualStyleBackColor = true; @@ -950,7 +950,7 @@ this.listHandles.Location = new System.Drawing.Point(6, 30); this.listHandles.Name = "listHandles"; this.listHandles.Provider = null; - this.listHandles.Size = new System.Drawing.Size(442, 347); + this.listHandles.Size = new System.Drawing.Size(469, 373); this.listHandles.TabIndex = 0; // // tabJob @@ -958,7 +958,7 @@ this.tabJob.ImageKey = "wrench"; this.tabJob.Location = new System.Drawing.Point(4, 42); this.tabJob.Name = "tabJob"; - this.tabJob.Size = new System.Drawing.Size(454, 383); + this.tabJob.Size = new System.Drawing.Size(481, 409); this.tabJob.TabIndex = 11; this.tabJob.Text = "Job"; this.tabJob.UseVisualStyleBackColor = true; @@ -968,7 +968,7 @@ this.tabServices.ImageKey = "cog"; this.tabServices.Location = new System.Drawing.Point(4, 42); this.tabServices.Name = "tabServices"; - this.tabServices.Size = new System.Drawing.Size(454, 383); + this.tabServices.Size = new System.Drawing.Size(481, 409); this.tabServices.TabIndex = 7; this.tabServices.Text = "Services"; this.tabServices.UseVisualStyleBackColor = true; diff --git a/trunk/ProcessHacker/Forms/ProcessWindow.resx b/trunk/ProcessHacker/Forms/ProcessWindow.resx index 1992d4d49..c5131c83d 100644 --- a/trunk/ProcessHacker/Forms/ProcessWindow.resx +++ b/trunk/ProcessHacker/Forms/ProcessWindow.resx @@ -123,8 +123,8 @@ 577, 17 - - 577, 17 + + 338, 17 235, 17 @@ -133,223 +133,219 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj0yLjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 - ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAA2 + ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAAy MQAAAk1TRnQBSQFMAgEBCwEAAQwBAAEEAQABEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA AwABMAMAAQEBAAEgBgABMFYAAxUBHQMjATQDJAE2AyQBNgMkATYDJAE2AyQBNgMkATYDJAE2AyQBNgMk - ATYDJAE2AyMBMwMVAR0IAAJeAVoC1QGDAT8B/wHRAWsBOQH/A1QBr2wAAYcBAAGAAf8BgwEAASkB/wEq - AQABKAH/AScBAAEnAf8BJAEAASYB/wHGAgAB/wHGAgAB/wHEAgAB/wHAAgAB/wHAAgAB/wG/AgAB/wEn - AgAB/wElAgAB/wEiAgAB/wEgAgAB/wEeAgAB/wQAAyMBNAN0AfUDvAH9A/wB/wP8Af8D/AH/A/wB/wP8 - Af8D/AH/A/wB/wP8Af8DvAH9A3AB8wMjATMEAANcAcwB3wGkAYEB/wHqAcIBqwH/AeoBwAGoAf8B3AGZ - AV8B/wNUAa9qAAHzAf8BmQGbAf4B/wGWAZgB/gH/AZMBlQH+Af8BkQGTAf4B/wHJAgAB/wHgAZMBCAH/ - Ad8BjwEEAf8B3wGNAQAB/wHeAYoBAAH/AcACAAH/AaIByQGeAf8BnQHGAZkB/wGYAcMBlQH/AZQBwAGR - Af8BAAEYAQAB/wMAAQEDJAE2A88B/gP8Af8D/AH/A/wB/wP8Af8D/AH/A/wB/wP8Af8D/AH/A/wB/wP8 - Af8DvAH9AyQBNgQAAdsBlwFdAf8B7QHIAbMB/wHnAbgBmwH/AeYBtAGYAf8B6gHDAasB/wHeAZwBYQH/ - A1QBr2YAAfUB/wGeAaAB/gH/AQYBCQH+Af8BAQEEAf4B/wGVAZcB/gH/Ac0CAAH/AeEBlwEOAf8B2gGA - AQAB/wHZASgBAAH/Ad8BjwEDAf8BxgIAAf8BqAHNAaQB/wEiAbABHAH/ARsBqwEVAf8BmgHEAZYB/wEA - ASEBAAH/AwABAQMkATYD/AH/A/wB/wPdAf8D2wH/A9kB/wPXAf8D1QH/A9QB/wPUAf8D1AH/A/sB/wP8 - Af8DJAE2AwABAQHdAZ8BZwH/Ae0BzAG3Af8B6AG9AaMB/wHkAbEBkgH/AeYBtgGaAf8B6gHDAawB/wHe - AZwBYgH/AlQBUwGsYgAB9gH/AaIBpAH+Af8BDQERAf4B/wEIAQwB/gH/AZkBmwH+Af8BzwIAAf8B4wGc - ARcB/wHcAYYBAAH/AdsBgwEAAf8B4AGUAQkB/wHGAgAB/wGvAdEBqwH/AYABtwElAf8BJAGyAR4B/wGg + ATYDJAE2AyMBMwMVAR0IAAJeAVoC1QGDATwB/wHRAWgBNgH/A1QBr2wAAYcBAAGAAf8BgwEAASYB/wEn + AQABJQH/ASQBAAEkAf8BIQEAASMB/wHGAgAB/wHGAgAB/wHEAgAB/wHAAgAB/wHAAgAB/wG/AgAB/wEk + AgAB/wEiAgAB/wEfAgAB/wEdAgAB/wEbAgAB/wQAAyMBNANuAfUDuQH9A/wB/wP8Af8D/AH/A/wB/wP8 + Af8D/AH/A/wB/wP8Af8DuQH9A20B8wMjATMEAANcAcwB3wGkAYEB/wHqAcIBqwH/AeoBwAGoAf8B3AGZ + AVwB/wNUAa9qAAHzAf8BmQGbAf4B/wGWAZgB/gH/AZMBlQH+Af8BkQGTAf4B/wHJAgAB/wHgAZMBBQH/ + Ad8BjwEBAf8B3wGNAQAB/wHeAYoBAAH/AcACAAH/AaIByQGeAf8BnQHGAZkB/wGYAcMBlQH/AZQBwAGR + Af8BAAEVAQAB/wMAAQEDJAE2A8kB/gP8Af8D/AH/A/wB/wP8Af8D/AH/A/wB/wP8Af8D/AH/A/wB/wP8 + Af8DuQH9AyQBNgQAAdsBlwFaAf8B7QHIAbMB/wHnAbgBmwH/AeYBtAGYAf8B6gHDAasB/wHeAZwBXgH/ + A1QBr2YAAfUB/wGeAaAB/gH/AQMBBgH+Af8BAAEBAf4B/wGVAZcB/gH/Ac0CAAH/AeEBlwELAf8B2gGA + AQAB/wHZASUBAAH/Ad8BjwEAAf8BxgIAAf8BqAHNAaQB/wEfAbABGQH/ARgBqwESAf8BmgHEAZYB/wEA + AR4BAAH/AwABAQMkATYD/AH/A/wB/wPdAf8D2wH/A9kB/wPXAf8D1QH/A9QB/wPUAf8D1AH/A/sB/wP8 + Af8DJAE2AwABAQHdAZ8BZAH/Ae0BzAG3Af8B6AG9AaMB/wHkAbEBkgH/AeYBtgGaAf8B6gHDAawB/wHe + AZwBXwH/AlQBUwGsYgAB9gH/AaIBpAH+Af8BCgEOAf4B/wEFAQkB/gH/AZkBmwH+Af8BzwIAAf8B4wGc + ARQB/wHcAYYBAAH/AdsBgwEAAf8B4AGUAQYB/wHGAgAB/wGvAdEBqwH/AYABtwEiAf8BIQGyARsB/wGg AcgBnAH/AQABgAEAAf8DAAEBAyQBNgP8Af8D/AH/A/wB/wP8Af8D+wH/A/sB/wP6Af8D+gH/A/oB/wP6 Af8D+gH/A/wB/wMkATYDAAEBA0wBkgHmAbMBlAH/Ae4BzAG4Af8B6QG+AaUB/wHlAbMBlAH/AeYBtwGb - Af8B6gHEAa0B/wHeAZ4BZgH/AlQBUwGsXAACBgH4Af8BqAGqAf4B/wEWARoB/gH/ARABFAH+Af8BngGg - Af4B/wHRAQsBAAH/AeUBogEfAf8B3gGMAQAB/wHdAYkBAAH/AeIBmQERAf8ByQIAAf8BtQHVAbAB/wGK - Ab0BgwH/AYMBuAEoAf8BpwHNAaMB/wEAAYsBAAH/AwABAQMkATYD/AH/A/wB/wPWAf8D0wH/A88B/wPN + Af8B6gHEAa0B/wHeAZ4BYwH/AlQBUwGsXAACAwH4Af8BqAGqAf4B/wETARcB/gH/AQ0BEQH+Af8BngGg + Af4B/wHRAQgBAAH/AeUBogEcAf8B3gGMAQAB/wHdAYkBAAH/AeIBmQEOAf8ByQIAAf8BtQHVAbAB/wGK + Ab0BgwH/AYMBuAElAf8BpwHNAaMB/wEAAYsBAAH/AwABAQMkATYD/AH/A/wB/wPWAf8D0wH/A88B/wPN Af8DywH/A8gB/wPIAf8DxgH/A/gB/wP8Af8DJAE2AwABAQQAA0wBkgHmAbQBmAH/Ae4BzQG6Af8B6QG/ - AaUB/wHlAbQBlgH/AecBuQGdAf8B6wHGAa4B/wHeAZ8BZwH/A1MBqlgAAQ4BDwH6Af8BrAGvAf4B/wEd - ASEB/gH/ARgBHAH+Af8BogGkAf4B/wHWARQBAAH/AecBpwEmAf8B4AGSAQcB/wHfAY8BAQH/AeQBngEZ + AaUB/wHlAbQBlgH/AecBuQGdAf8B6wHGAa4B/wHeAZ8BZAH/A1MBqlgAAQsBDAH6Af8BrAGvAf4B/wEa + AR4B/gH/ARUBGQH+Af8BogGkAf4B/wHWAREBAAH/AecBpwEjAf8B4AGSAQQB/wHfAY8BAAH/AeQBngEW Af8BzQIAAf8BugHZAbUB/wG3AdYBsQH/AbMB0wGuAf8BrgHRAakB/wEAAZYBAAH/AwABAQMkATYD/AH/ A/wB/wP8Af8D/AH/A/wB/wP8Af8D/AH/A/sB/wP5Af8D+QH/A/gB/wP8Af8DJAE2AwABAQgAA0wBkgHm - AbcBmQH/Ae4BzgG7Af8B6QHAAacB/wHoAb0BowH/AewByAGzAf8B3wGkAYEB/wNcAclYAAEVARcB/AH/ - AbABswH+Af8BJAEpAf4B/wEgASQB/gH/AagBqgH+Af8B2AEfAQAB/wHoAa0BgwH/AeIBmAEQAf8B4QGV - AQsB/wHlAaMBIQH/Ac8BAgEAAf8BCwG8ARcB/wEHAbYBEgH/AQIBsAEMAf8BAAGoAQcB/wEAAaEBAAH/ - AwABAQMkATYD/AH/A/wB/wPOAf8DygH/A8YB/wPDAf8DwAH/A70B/wO8Af8DugH/A/YB/wP8Af8DJAE2 - AwABAQwAA0wBkgHmAbcBnAH/Ae8BzwG8Af8B7gHOAboB/wHiAa4BjAH/AdIBmwFpAf8DbQH3AxkBI1QA - ARsBHgH9Af8BtAG3Af4B/wGBAYUB/gH/AScBgQH+Af8BrAGvAf4B/wHZASYBAAH/AeoBsgGKAf8B5AGf - ARkB/wHjAZwBFQH/AecBqAEoAf8B0QENAQAB/xcAAQEDJAE2A/wB/wP8Af8D/AH/A/wB/wP8Af8D/AH/ - A/sB/wP4Af8D9gH/A/MB/wPyAf8D/AH/AyQBNgMAAQEQAANMAZIB5wG5AZwB/wHmAbYBmAH/AdgBqQGM - Af8D0gH/A7UB/wN/Af4DYgH7A18B+wNgAdYDQAFwRAABHwEjAf4B/wG4AbsB/gH/AbYBuQH+Af8BswG2 - Af4B/wGwAbMB/gH/Ad8BhAEAAf8B7AG3AZIB/wHmAaUBIwH/AeYBogEeAf8B6QGtAYUB/wHWARYBAAH/ - FwABAQMkATYD/AH/A/wB/wPHAf8DwgH/A74B/wO4Af8DtAH/A7EB/wOuAf8DrAH/A+0B/wP8Af8DJAE2 - AwABARQAA0wBkgNcAc8DgAH7A8cB/wPMAf8DxwH/A8YB/wPDAf8DwAH/A2QB9QNAAXBAAAEfASMB/gH/ - AR8BIwH+Af8BHQEhAf4B/wEZARwB/QH/ARUBFwH8Af8B4QGNAQAB/wHtAbsBmQH/AekBrAGBAf8B5wGo - AScB/wHqAbMBjQH/AdgBHwEAAf8XAAEBAyQBNgP8Af8D+wH/A/wB/wP8Af8D+wH/A/gB/wP1Af8D8QH/ - A+wB/wPqAf8D5gH/A/wB/wMkATYDAAEBHAADLgFIA38B/gPUAf8DyAH/A7wB/wO6Af8DwgH/A8QB/wNg - AdZUAAHiAZIBBwH/Ae4BwQGgAf8B6gGxAYkB/wHpAa4BhQH/Ae0BtwGUAf8B2wEnAQAB/xcAAQEDJAE2 - A/wB/wP5Af8DwAH/A7oB/wO0Af8DrwH/A6oB/wOlAf8D/AH/A/wB/wP8Af8D/AH/AyQBNgMAAQEgAAN1 - AfwD3QH/A8UB/wNYAcEDWwHDA6wB/wPXAf8DYgH7VAAB5gGbARIB/wHwAcUBpgH/AewBtgGRAf8B6wGz - AYwB/wHuAbwBmwH/Ad8BhQEAAf8XAAEBAyQBNgP8Af8D9wH/A/kB/wP3Af8D9wH/A/MB/wPwAf8D6gH/ - A/wB/wP2Af8D9AH/A00BkQMXASAkAAOFAfsD5AH/A88B/wNZAcIEAAOOAf8DjAH/A2oB+1QAAegBoAEb - Af8B8gHIAawB/wHwAcYBqAH/AfABxQGmAf8B7wHCAaIB/wHhAY4BAAH/GAADJAE2A7wB/QP0Af8D9QH/ - A/UB/wP1Af8D8QH/A+8B/wPpAf8D/AH/A+cB/wNNAZEDFwEgAwEBAiQAA2AB1gPiAf8D5wH/A7kB/wOT - Af9gAAHqAaYBIgH/AegBpAEfAf8B6AGgARkB/wHmAZ0BFgH/AeQBmQEQAf8B4gGVAQkB/xgAAyMBMwNm - AfADvAH9A/wB/wP8Af8D/AH/A/wB/wP8Af8D/AH/A/gB/wNNAZEDFwEgAwEBAigAA0ABcANrAfUD5AH/ - A+4B/wOWAf+QAAMUARwDIwEzAyQBNgMkATYDJAE2AyQBNgMkATYDJAE2AyQBNgMkATYDFwEgAwEBAjAA - A0ABcANgAdYDhwH7A4YB+2QAAwoBDQEiAiEBMQMgAS8DBQEHGAADEQEXAasCAAH/AWIBWQFIAfYDKQE/ - NAADBgEIAUACPwFuA1YBswFeAlgB3QFSAl0B9AFAAYQBpgH9AgABswH/AgABqAH/AkABnAH9AlIBXQH0 - AVoCWAHdA1YBswFAAj8BbgMGAQhQAAMYASEDUAGdAV0CVAHwA6EB/wOrAf8DpwH/A5UB/wFkAlwB5wNK - AYoDEAEWDAABugIAAf8BwAGJAQAB/wG/AYkBAAH/Aa8CAAH/AyoBQTAAAVsCWQHEAYcBtwHgAf8BlQHG - AeYB/wGbAc0B6QH/AZwBzQHpAf8BmQHHAecB/wGVAcEB5AH/AY4BuAHgAf8BiQGwAd0B/wGBAacB1wH/ - AQABmwHPAf8BAAGMAcIB/wIAAa4B/wFbAlkBxBAAAwkBDAJGAUcBgQJZAVwByQIAAegB/wMfAS0oAAMv - AUoBZQJdAfQDzgH/A+0B/wP0Af8D9QH/A/QB/wPvAf8D4gH/A7oB/wFkAlwB5wMkATUIAAHDAYgBAAH/ - Ac8BogEAAf8BzQGiAYEB/wHAAYwBAAH/AbACAAH/AU4CTQGVAzEBTgMmATkDFgEeAwMBBBwAAVsCWQHE - AZgBuQHUAf8BxQHHAcQB/wHsAdgBxwH/AfYB6wHjAf8B+gH1AfEB/wHzAecB3gH/Ad8BvwGmAf8B0AGk - AYEB/wHLAZoBAAH/AcgBlwEAAf8BowGTAYwB/wIAAZwB/wFbAlkBxAwAAy0BRQJaAWAB3gIAAesB/wEF - AQYB5wH/AgAB6QH/Ax8BLQFdAlkB0gFcAlkByQFHAkYBgQMJAQwYAAFcAlUB6gPeAf8D8wH/A9sB/wPS - Af8D2wH/A9YB/wPAAf8DyQH/A+YB/wPEAf8BXAJVAeoIAANAAXEBzAGZAQAB/wHQAaMBgQH/Ac8BpAGD - Af8BygGeAQAB/wG8AYUBAAH/Aa8CAAH/AacCAAH/AZ4CAAH/AVsCWAHGAwcBCRgAAx0BKgHmAcMBpQH/ - Ae8B1gHAAf8B+wHyAeoB/wH+AfwB+gL/Af4B/QH/Af4B/QH8Af8B/AH2AfAB/wH4AegB2QH/AfYB4wHR - Af8B9gHiAc4B/wHmAcgBrQH/Ac4BoAEAAf8DHQEqCAADNAFUAgAB8wH/ARYBGAHuAf8BlAGZAesB/wGN - AZEB6QH/AgAB7AH/Ax8BLQFdAlkB0gHWAY4BAAH/AbgCAAH/AWACWgHeAy4BSBQAAVwCVQHqA/AB/wPe - Af8D1AH/A9IB/wPbAf8D1gH/A78B/wOwAf8DswH/A94B/wFcAlUB6gwAA0EBcgHOAZ0BAAH/AdUBrAGM - Af8BywGbAQAB/wHMAaABAAH/AcgBmwEAAf8BxQGVAQAB/wHAAY8BAAH/AawCAAH/A0IBdhwAAVgCVgG5 - Ae0B0wG7Af8B+gHwAeUB/wH9AfkB9QH/Af4B/AH6Af8B/gH9AfwB/wH9AfkB9AH/AfYB4wHPAf8B9wHl - AdMB/wH2AeMB0QH/Ad0BuQGaAf8BVwJWAbgIAAMQARUDXwHzAZUBmQHyAf8BpQGqAe4B/wEUAYEB5gH/ - AZcBmgHrAf8CAAHvAf8DHwEtAV0BWwFZAdIB2wGZAQkB/wHmAaQBGAH/AcsBgAEAAf8BpgIAAf8DNAFU - EAABXAJVAeoD8gH/A+IB/wPYAf8D1QH/A9wB/wPYAf8DwAH/A7MB/wO3Af8D4AH/AVwCVQHqEAABVgJV - AbEB0wGoAYYB/wHWAawBjgH/AckBmAEAAf8BxAGQAQAB/wG/AYoBAAH/AcIBjwEAAf8BvwGLAQAB/wFf - AV0BRgH7Ax0BKRwAAVUCUwGwA38B/gH3AeoB3gH/Af4B+gH3Af8B/gH8AfkB/wH9AfcB8gH/AfoB7QHi - Af8B6wHQAbcB/wJ/AX4B/gNUAa4MAAMNAREDTgGZAmIBagH5AYQBhQH0Af8BowGoAe8B/wGgAaUB7QH/ - AgAB8QH/Ax8BLQJdAVkB0gHeAaEBEgH/Ad4BiQEAAf8B5gGmARgB/wHQAYcBAAH/AV8CTAHzAxABFQwA - AVwCVQHqA/MB/wPnAf8D3QH/A9kB/wPgAf8D2wH/A8QB/wO4Af8DuwH/A+EB/wFcAlUB6hAAAzEBTgHU - AaMBAAH/AdwBtQGYAf8B0AGhAQAB/wHMAZoBAAH/Ac8BpAGDAf8ByAGaAQAB/wEAAYwBAAH/AQABuAEA - Af8BXwFOATAB+wNUAa8DBwEJGAADJwE6AWECWwHhAfMB4gHSAf8B/AH0Ae0B/wH7AfEB5wH/AekBzAG1 - Af8BYQJcAdwDJgE4EAADQgFzAzwBZgMUARsDSgGNAl0BXwHzARUBFwHzAf8CAAH0Af8DHwEtAl0BWQHS - AeEBqAGBAf8B4AGSAQAB/wHZARIBAAH/AecBqAGEAf8BvgEJAQAB/wNIAYQMAAFcAlUB6gP0Af8D6gH/ - A+EB/wPdAf8D4wH/A94B/wPJAf8DvQH/A78B/wPiAf8BXAJVAeoQAAMmATkB2wGrAYkB/wHhAb0BogH/ - AdYBqgGHAf8B2QGzAZQB/wHOAZ8BAAH/AV8CXQH7AQABvAEAAf8BkwIAAf8BsAIAAf8BpAIAAf8BYQJe - AdoDAwEEHAADWQHHAfQB4wHQAf8B8wHfAc0B/wFbAlkBwxgAAVkBXAFZAc8BkAG/AZMB/wFVAVwBVQHq - A0EBcgMVAR0DRAF7A10B7QMfAS0CXQFZAdIB5AGwAYsB/wHjAZwBBgH/Ad0BhQEAAf8B4gGWAQAB/wHa - AZcBBgH/AVwCWQHPDAABXAJVAeoD9QH/A+4B/wPmAf8D4gH/A+YB/wPhAf8DzQH/A8IB/wPCAf8D4wH/ - AVwCVQHqEAADFgEeAeABsQGPAf8B5gHEAasB/wHiAb8BpAH/AdgBrQGOAf8DTQH6A0MBdwMrAfwBuwGE - AQAB/wHAAY8BAAH/AbwBigEAAf8BnAIAAf8DFgEeHAABWwJZAcMB9AHhAc4B/wHzAd8BzAH/AVkCVwHC - GAABWgJdAfABygHoAcgB/wGvAdkBqwH/AZIBvwGUAf8DXQHtAUUBRgFFAX4DDwEUAxIBGAJdAVkB0gHn - AbcBkwH/AecBpgEQAf8B4AGQAQAB/wHeAY4BAAH/AeYBrQGIAf8BXwFUAUwB8wwAAVwCVQHqA/YB/wPr - Af8D3gH/A9YB/wPVAf8D0QH/A8MB/wO8Af8DwAH/A+UB/wFcAlUB6hAAAwMBBAFhAl4B2gHkAbsBnwH/ - AeQBuwGfAf8DKwH8AQABwQEAAf8DKwH8AccBlgEAAf8BywGeAQAB/wG8AYUBAAH/AcMBkgEAAf8BpgIA - Af8DJgE5FAADJgE4AV4CWAHdAfMB3QHJAf8B+gHuAeIB/wH5AesB3gH/Ae0B0AG2Af8BXwJaAdsDJgE4 - EAABYAJqAfkBtgHgAbEB/wEUAcwBCAH/AZIB0gGJAf8BrQHZAakB/wGJAbgBiwH/A1ABnQM1AVYCYgFJ - AfYB7wHIAakB/wHmAaYBDAH/AeIBmwEAAf8B4gGYAQAB/wHnAbMBjwH/AV0BXAFOAfAMAAFcAlUB6gP3 - Af8D5wH/A+8B/wP2Af8D+wH/A/oB/wPwAf8D3gH/A8MB/wPmAf8BXAJVAeoUAAMHAQkDVAGvAWoCZgH5 - AQABxQGCAf8BtQGwAYEB/wHYAbABkgH/AdcBrgGPAf8ByQGXAQAB/wHDAY8BAAH/AcgBmwEAAf8BsQIA - Af8DMQFOEAADVAGvA38B/gH5AewB4AH/Af0B+AH0Af8B+wHwAeYB/wH4AecB1wH/AfkB6wHeAf8B8gHa - AcUB/wN/Af4DVAGuDAADXAHPAboB3wG4Af8BEwHMAQYB/wEAAcYBAAH/AQsByAEAAf8BqAHaAaMB/wEB - AagBBgH/AygBPANbAcMB5gG1AY4B/wHwAcwBrAH/AeUBpgEKAf8B6QGxAYQB/wHjAa8BiAH/AlwBWQHP - DAABXAJVAeoD+AH/A/4Z/wP7Af8D6gH/AVwCVQHqHAADGwEmAagBpgGEAf0B4gG+AaMB/wHfAbcBmgH/ - AdUBqAGGAf8B0AGhAQAB/wHLAZoBAAH/Ac4BogGBAf8BvwGLAQAB/wFOAk0BlQwAAVcCVgG4AfkB4wHN - Af8B+wHzAewB/wH+AfoB9wH/Af4B+wH4Af8B/AH1Ae0B/wH3AeYB1QH/AfYB4QHMAf8B+QHsAd8B/wH5 - AesB3QH/AesBzgG0Af8BVwJWAbgIAANIAYQBswHaAbUB/wGiAdgBmgH/AQYBygEAAf8BAAHGAQAB/wGA - AcwBDgH/AaMBzgGjAf8BWQFcAVkBzwMiATIBLgIrAfwB8gHRAbIB/wHrAbkBjQH/AfAByQGqAf8B2AGc - AQkB/wNIAYQMAAFZAlcBvwPhAf8D/hn/A/sB/wPPAf8BUgJRAaEgAANCAXYB5AG6AZ0B/wHmAcQBqwH/ - AeIBvgGkAf8B3gG5AZwB/wHZAbIBkwH/AdEBowEAAf8B0QGmAYUB/wG7AgAB/wMpAT8EAAMdASoBwAHF - Ac0B/wGaAbcB3AH/AQABpgHVAf8BAAGVAcoB/wEAAYcBvgH/AgABswH/AgABqAH/AgABnwH/AgABmAH/ - AgABmgH/AQABgwGnAf8BiAGUAZoB/wMdASoEAAMNARIDXwHzAb4B4QG+Af8BlAHUAYkB/wEHAcoBAAH/ - AQcByQEAAf8BngHWAZcB/wGTAcEBlgH/Az0BaQNOAZYB5wG0AY4B/wHzAdMBtQH/AekBuwGYAf8CXwFM - AfMDDQESDAADHQEqAVwCWAHRA9AB/wPoAf8D8wH/A/0B/wP8Af8D7QH/A+AB/wPCAf8BWwJZAcMDFAEb - IAADBwEJAVsCWAHGAeMBtAGTAf8B3wGxAY4B/wHaAasBiQH/AdoBrQGMAf8B3AG1AZgB/wHXAa8BkAH/ - AcwBmwEAAf8DTQH6BAABXAJYAdEBhwG3AeAB/wGVAcYB5gH/AZsBzQHpAf8BnAHNAekB/wGZAccB5wH/ - AZUBwQHkAf8BjgG4AeAB/wGJAbAB3QH/AYEBpwHXAf8BAAGbAc8B/wEAAYwBwgH/AgABrgH/AVwCWAHR - CAADMgFRAaAB1QGoAf8BugHgAbsB/wGnAdoBoAH/ARYBzgEJAf8BGAHNAQwB/wGwAdkBrQH/A10B7QMZ - ASMDXQHtAesBwgGeAf8B3QGiAQwB/wMyAVEUAAMFAQcBNQI0AVUDVAGuAWACWwHWAV8CXQH7AWoCZgH5 - AVwCWgHNA1IBqQMtAUYDAgEDKAADAwEEAxYBHgMmATkDMQROAZQB2AGnAYIB/wHXAawBiwH/AdMBpwGE - Af8BYgFcAUkB9gQAAVsCWQHEAYcBtwHgAf8BlQHGAeYB/wGdAc8B6gH/AaEB0wHsAf8BoAHRAesB/wGb - AcoB6AH/AZYBwgHlAf8BjwG6AeIB/wGHAbEB3QH/AQABowHUAf8BAAGQAcQB/wIAAa4B/wFbAlkBxAwA - AykBPwNgAd4BtAHcAbcB/wG8AeABugH/AbkB4QG1Af8BzgHqAcsB/wGkAc4BpgH/AU0CTgGWAz0BaQNg - Ad4DKQE/fAADKQE+AV8CXQH7AWICXAH2Ay4BSAQAAwYBCAFAAj8BbgNWAbMBXgJYAd0BZQJdAfQBQAGd - AaYB/QEAAZkB0QH/AQABkAHIAf8BQAGEAaYB/QFSAl0B9AFaAlgB3QNWAbMBQAI/AW4DBgEIEAADCQEM - A0YBfgNbAcYDKwH8AysB/ANbAcYDRQF9AwIBAwMHAQoRAAGdAdkB/wEAAZkB2AH/AQABlAHXAf8BAAGQ - AdYB/wEAAYwB1QH/AQABiAHUAf8BAAGEAdMB/wEAAYEB0gH/AgAB0QH/AgAB0QH/AgAB0AH/AgABzwH/ - AgABzwH/AgABzgH/YAADOwFjAVkCVwG/AVgCVwG/AzsBYyAAAxUBHQMjATQDJAE2AyQBNgMkATYDJAE2 - AyQBNgMkATYDJAE2AyQBNgMkATYDJAE2AyMBMwMVAR0BAAGjAdoB/wG8AesB+gH/AbwB6wH8Af8BvwHu - Af4B/wHGAfQC/wHOAfgC/wHTAfoC/wHQAfgC/wHHAfIC/wG6AekB/AH/AbMB5AH5Af8BsAHiAfgB/wGw - AeIB+AH/AgABzwH/VAADHQEpAwoBDgMBAQIBXAJVAeoDvQH/A7IB/wFcAlUB6gMBAQIDCgEOAx0BKRQA - AyMBNANZAfUBqAKmAf0D/AH/A/wB/wP8Af8D/AH/A/wB/wP8Af8D/AH/A/wB/wGoAqYB/QFfAl0B8wMj - ATMBAAGoAdsB/wG/AewB+wH/AQABzwH1Af8BAAGwAewB/wMAAf8CAAGJAf8BAAGJAb4B/wEAAZoByAH/ - AQABrgHnAf8BAAGlAeYB/wEAAZoB4QH/AQABuAHuAf8BsQHjAfgB/wIAAdAB/wgAA1IBqQHDAY4BAAH/ - AcABiwEAAf8BvgGIAQAB/wG7AYUBAAH/AbkBgwEAAf8BtAIAAf8BsgIAAf8BsQIAAf8BrgIAAf8BrQIA - Af8BqwIAAf8BqQIAAf8BqQIAAf8DUgGpDAABUAJPAZsDQAH9AWQCXAHnAxIBGQFkAlwB5wPLAf8DxwH/ - AWMCXAHnAxIBGQNcAecDQAH9AVACTwGbCAADNwFbAV0BVAFOAfABYgFcAUgB9gHlAbcBmgH/AfsC+gH/ - A/wB/wP8Af8D/AH/A/wB/wP8Af8D/AH/A/wB/wP8Af8D/AH/AagCpgH9AyQBNgEAAa0B3AH/AcEB7gH7 - Af8BAAHTAfcB/wEAAdsB/AH/AgABhQH/AZQBxwH5Af8BkQHJAfkB/wEAAYUByQH/AgABrgH/AQABvQHs - Af8BAAG+Ae8B/wEAAboB7gH/AbMB4wH5Af8CAAHRAf8IAAHIAZIBADX/AakCAAH/CAADRAF7A7wB/wPe - Af8DpgH/AWUCXQH0A38B/gPEAf8DwgH/AW4CbQH+AWUCXQH0A6YB/wPSAf8DgQH/A0QBewQAAWICWAHv - AeYBuAGcAf8B6QG/AaUB/wHcAZsBAAH/AeUBuAGdAf8D/AH/A/wB/wP8Af8D+wH/A/sB/wP7Af8D+wH/ - A/sB/wP7Af8D/AH/AyQBNgEAAbIB3QH/AcMB7wH7Af8BAAHWAfgB/wEAAbYB7AH/AQABiQGqAf8B4AHy - Av8BAAGaAdgB/wIAAb4B/wEAAZgBxQH/AQABhgHFAf8BAAGbAd4B/wEAAb4B7wH/AbQB5QH5Af8CAAHS - Af8IAAHKAZQBAAv/Af4D/wH9Af8C/gH9Af8C/gH8Af8C/gH8Af8C/gH8Af8C/gH8Af8C/gH6Af8C/gH6 - Af8C/AH5Bf8BqgIAAf8IAANFAX0DfwH+A9UB/wPFAf8DywH/A9EB/wPJAf8DxwH/A8wB/wPFAf8DvQH/ - A8sB/wFvAm4B/gNFAX0EAAFtAmcB9wHrAcQBrQH/AewByAGyAf8B6gHBAakB/wHeAZ4BAAH/AecBuwGh - Af8D/AH/A/sB/wP7Af8D+gH/A/oB/wP6Af8D+gH/A/oB/wP8Af8DJAE2AQABtwHeAf8BxgHwAfwB/wEA - AdkB+AH/AQAB4gH9Af8BAAG3AdkB/wEAAbYB1QH/AZABtwHRAf8BAAHJAeQB/wEAAd8B9QH/AQAB0AHt - Af8BAAGYAdwB/wEAAboB7QH/AbYB5wH5Af8BAAGDAdMB/wgAAcwBlwEAB/8B/AP/Af0B/wL+AfwB/wL+ - AfwB/wL+AfsB/wL9AfoB/wL9AfoB/wL9AfoB/wL9AfoB/wL8AfcB/wL7AfYF/wGsAgAB/wwAA0gBhQPF - Af8DwQH/A8UB/wPHAf8DqgH/A6cB/wPBAf8DvgH/A7UB/wOqAf8DSAGFCAADQgF1AWoCZgH5AewBxwGw - Af8B7QHKAbUB/wHrAcMBqwH/Ad4BoQEAAf8B5wG6AZ8B/wP7Af8D+wH/A/sB/wP6Af8D+gH/A/gB/wP4 - Af8D/AH/AyQBNgEAAbsB3wH/AccB8QH8Af8BAAHcAfkB/wEAAbsB7QH/AQABvQHvAf8BAAHGAecB/wEA - AbgB1gH/AcIB9gH9Af8BAAHfAfcB/wEAAeIB+AH/AQAB0wHwAf8BAAGXAdwB/wGoAdwB9QH/AQABiAHU - Af8IAAHRAZwBAAX/Av4B/AH/Av4B/AH/Av4B/AH/Av0B+wH/Av0B+wH/Av0B+gH/Av0B+AH/AvsB+QH/ - AfsB+gH3Af8B+wH6AfYB/wH7AfgB9AX/AbACAAH/BAABXAJaAc0BXwJYAeMBYQJWAe4DzwH/A8YB/wPM - Af8BWwJYAcYDLAFEAywBRAFbAlgBxgPBAf8DvAH/A7kB/wFhAlYB7gFbAlgB4wNaAc0EAANDAXgDfwH+ - Ae0ByAGzAf8B7QHNAbgB/wHpAb4BowH/AdYBjgEAAf8D/AH/A/wB/wP8Af8D+wH/A/kB/wP5Af8D+AH/ - A/wB/wMkATYBAAG/AeAB/wHIAfMB/AH/AQAB3wH5Af8BiQHmAf0B/wGVAecC/wGaAeUC/wEAAcoB5wH/ - AQABywHnAf8BxwH3Af0B/wEAAdwB9QH/AQAB4QH3Af8BAAHUAfEB/wEAAZkB3gH/AQABjQHWAf8IAAHU - AZ4BAAX/Av4B/AH/Av0B+wH/Av0B/AH/Av0B+wH/Av0B+QH/AvwB+AH/AfsB+QH3Af8B+wH5AfUB/wH7 - AfgB9AH/AfsB9wHyAf8B+wH1AfIF/wGyAgAB/wQAAagCpgH9A+IB/wPSAf8DxgH/A80B/wOxAf8DLAFE - CAADLAFEA6gB/wPCAf8DtwH/A8AB/wPSAf8DQAH9BwABAQNMAZIB4AGpAYgB/wHrAccBsAH/Ad0BoQEA - Af8BvAGlAZUB/wOsAf8D0AH/A9QB/wPvAf8D+QH/A/YB/wP2Af8D/AH/AyQBNgEAAcIB4QH/AckB8wH8 - Af8BywHzAf0B/wHUAfYB/gH/AdcB9gL/AdgB9AL/AeAB+AL/AakB4wH1Af8BAAHTAe4B/wHHAfcB/QH/ - AQAB3AH1Af8BAAHiAfcB/wEAAdYB8gH/AQABmAHeAf8DIQEwBAAB1QGgAQAF/wL9AfwB/wL9AfsB/wL9 - AfoB/wL8AfkB/wH8AfsB9wH/AfsB+QH1Af8B+wH4AfQB/wH7AfcB8wH/AfsB9QHyAf8B+gHzAe8B/wH4 - AfIB7AX/AbUCAAH/BAABqAKmAf0D6QH/A9YB/wPJAf8DzgH/A6UB/wMsAUQIAAMsAUQDrAH/A8QB/wO6 - Af8DxgH/A90B/wNAAf0HAAEBAyQBNgHwAdYBxgH/Ad4BrQGQAf8BxAGvAaMB/wPVAf8DuwH/A6YB/wOg - Af8DkAH/A8kB/wPzAf8D8gH/A/wB/wMkATYBAAHDAeEB/wGIAaABqAH/A5EB/wOOAf8BAAG5AdwB/wEA - AbgB3wH/AQABtQHeAf8BAAGxAd0B/wEAAbAB3gH/AQAB1AHuAf8BxAH2Af0B/wEAAd0B9gH/AQABygHt - Af8BAAGjAdcB/wFgAlkB7AMbASYB2AGiAQAF/wL9AfoB/wL8AfoB/wH8AfsB+QH/AfsB+gH2Af8B+wH4 - AfUB/wH7AfcB9AH/AfsB9gHxAf8B+AH0Ae4B/wH3AfIB6wH/AfcB8AHqAf8B9gHsAegF/wG3AYEBAAH/ - BAABXAJaAc0BXwJYAeMBYQJWAe4D2AH/A80B/wO8Af8BWwJYAcYDLAFEAywBRAFbAlgBxgPDAf8DwgH/ - A80B/wFhAlYB7gFfAlgB4wFcAloBzQcAAQEDJAE2A/wB/wP7Af8DrAH/A8sB/wPSAf8DyQH/A9IB/wPG - Af8DjwH/A+8B/wPtAf8D/AH/AyQBNgQAAVsCWQHDA8YB/wOUAf8DBgEIEAADNwFaAQAB0wHrAf8BsgHj - AfkB/wGLAcAB5wH/Aa4B0wH2Af8BxAHgAfwB/wNnAfcB2QGjAQAF/wH8AfsB+QH/AfwB+wH4Af8B+wH5 - AfcB/wH7AfcB9AH/AfoB9wHyAf8B+QH1AfAB/wH3AfMB7QH/AfYB7wHqAf8B9QHrAecB/wHzAeoB5AH/ - AfIB5wHeBf8BugGFAQAB/wwAA0gBhQPUAf8DzAH/A8kB/wO6Af8DnAH/A6EB/wPCAf8DxgH/A8EB/wO3 - Af8DSAGFDwABAQMkATYD/AH/A/sB/wPbAf8DsgH/A9YB/wOgAf8DkgH/A8AB/wOKAf8D6gH/A+YB/wP8 - Af8DJAE2BAADVAGuA8QB/wOhAf8DHQEpEAADHQEpAQABmQGpAf8BAAG+AecB/wG0AdIB8AH/AeUB8wL/ - AawB0gHvAf8BXwJXAegB2wGkAQA1/wG9AYcBAAH/CAADRQF9A38B/gPcAf8D1AH/A9kB/wPbAf8D1gH/ - A9QB/wPZAf8D0gH/A8sB/wPIAf8BegJ5Af4DRQF9CwABAQMkATYD/AH/A/kB/wPaAf8DtQH/A+YB/wOa - Af8DsAH/A68B/wO9Af8D/AH/A/wB/wP8Af8DJAE2BAADQgF1A7oB/wO/Af8BXgJYAd0DFgEfAwQBBQME - AQUDFgEfAWUCXgHlA6gB/wEAAaQBswH/AQABpQHYAf8BhQGxAdsB/wEAAZ0B0AH/AzgBXgHcAacBAAH/ - AdwBpwEAAf8B3AGnAQAB/wHcAacBAAH/AdwBpwEAAf8B3AGnAQAB/wHcAacBAAH/AdwBpwEAAf8B3AGn - AQAB/wHcAacBAAH/AdwBpwEAAf8B3AGnAQAB/wHcAacBAAH/AdwBpwEAAf8BwAGLAQAB/wgAA0QBewPc - Af8D7QH/A9sB/wFlAl0B9AN/Af4D1gH/A9QB/wN/Af4BZQJdAfQDywH/A+cB/wO3Af8DRAF7CwABAQMk - ATYD/AH/A/cB/wPvAf8DpgH/A+EB/wPSAf8DtAH/A+oB/wP8Af8D9gH/A/QB/wFNAkwBkQMXASAEAAMJ - AQwBXwJaAdsDxAH/A74B/wOhAf8DlgH/A5MB/wOXAf8DrgH/A64B/wFfAloB2wMHAQkMAAGoAaYBgwH9 - AegBuQGSAf8B6AG5AZIB/wHoAbkBkgH/AegBuQGSAf8B6AG5AZIB/wHoAbkBkgH/AegBuQGSAf8B6AG5 - AZIB/wHoAbkBkgH/AegBuQGSAf8B6AG5AZIB/wHoAbkBkgH/AegBuQGSAf8BqAGOAUAB/QwAAVACTwGb - AagCpgH9AWQCXAHnAxIBGQFkAlwB5wPeAf8D3QH/AWQCXAHnAxIBGQFkAlwB5wGnAqUB/QFQAk8BmxAA - AyQBNgGoAqYB/QP0Af8D9QH/A9QB/wOlAf8DnQH/A74B/wPpAf8D/AH/A+cB/wFNAkwBkQMXASADAQEC - CAADIQEwAWACWgHeA7wB/wPKAf8DzAH/A8oB/wPCAf8DrQH/AWACWgHeAyEBMBAAAz4BawFlAl0B9AHc - AacBAAH/AdwBpgEAAf8B2gGkAQAB/wHYAaIBAAH/AdUBoAEAAf8B1AGeAQAB/wHSAZ0BAAH/Ac8BmgEA - Af8BzgGZAQAB/wHLAZYBAAH/AckBlAEAAf8BZQJdAfQDPgFrEAADHQEpAwoBDgMBAQIBXAJVAeoD5QH/ - A+QB/wFcAlUB6gMBAQIDCgEOAx0BKRQAAyMBMwFdAlQB8AGoAqYB/QP8Af8D/AH/A/wB/wP8Af8D/AH/ - A/wB/wP4Af8BTQJMAZEDFwEgAwEBAhAAAwkBDAFHAkYBgQFXAlUBugFcAlkBzAFcAlkBzAFXAlUBugFH - AkYBgQMJAQxsAAM7AWMBWQJXAb8BWQJXAb8DOwFjIAADFAEcAyMBMwMkATYDJAE2AyQBNgMkATYDJAE2 - AyQBNgMkATYDJAE2AxcBIAMBAQIIAAFCAU0BPgcAAT4DAAEoAwABQAMAATADAAEBAQABAQUAAYABARYA - A/8BAAL/AYABAQGHAf8EAAGAAQEBAwH/BQACAQH/BwAB/wcAAX8GAAGAAT8GAAHAAT8GAAHgAR8DAAEf - AgAB8AEBAwABHwIAAfgEAAEfAgAB/gMAAfgBHwIAAf8DAAH4AR8BAAEBAf8BCAIAAfgBHwGAAQEB/wEH - AgAB+AEfAYABAwH/AQcCAAL/AYABBwH/AYcCAAH8AT8BDwH/AYABAQL/AeACBwH/AYABAQHgAf8BwAED - AQABPwGAAQEBwAEPAcABAwEAAR8BgAEBAYABBwHAAQMBgAEfAcABAwEAAQMBwAEDAcABDwHgAQcBAAEB - AcABAwHAAQMB8AEPAQABAQHAAQMBwAEBAfwBPwEAAQEBwAEDAcABAQH8AT8BAAEBAcABAwHAAQEB8AEP - AQABAQHAAQMB4AEBAeABBwEAAQEBwAEDAfgBAQHAAQMBAAEBAcABAwH8AQABgAEBAQABAQHAAQMB/AEA - AYABAQGAAQMB4AEHAf4BAAGAAQEBwAEHA/8B8AGAAQEB4AEPAQABAwL/AfwBPwHAAgABAwL/AeABBwHA - AgABAwEAAQEBwAEDAwABAwEAAQEBgAEBAwABAwEAAQEBgAEBAwABAwEAAQEBwAEDAwABAwEAAQECAAGA - AgABAwEAAgECgAIAAQEBAAIBAoAEAAEBAgABgAEAAYcBgAEAAQEBwAEDAYABAAGHAYABAAEBAYABAQGA - AQABgAIAAQEBgAEBAYABAAGAAQcBAAEBAcABAwHAAQABwAEPAQABAQHgAQcBwAEBAeABHwL/AfwBPwHA - AQML + AbcBmQH/Ae4BzgG7Af8B6QHAAacB/wHoAb0BowH/AewByAGzAf8B3wGkAYEB/wNcAclYAAESARQB/AH/ + AbABswH+Af8BIQEmAf4B/wEdASEB/gH/AagBqgH+Af8B2AEcAQAB/wHoAa0BgwH/AeIBmAENAf8B4QGV + AQgB/wHlAaMBHgH/Ac8CAAH/AQgBvAEUAf8BBAG2AQ8B/wEAAbABCQH/AQABqAEEAf8BAAGhAQAB/wMA + AQEDJAE2A/wB/wP8Af8DzgH/A8oB/wPGAf8DwwH/A8AB/wO9Af8DvAH/A7oB/wP2Af8D/AH/AyQBNgMA + AQEMAANMAZIB5gG3AZwB/wHvAc8BvAH/Ae4BzgG6Af8B4gGuAYwB/wHSAZsBZgH/A20B9wMZASNUAAEY + ARsB/QH/AbQBtwH+Af8BgQGFAf4B/wEkAYEB/gH/AawBrwH+Af8B2QEjAQAB/wHqAbIBigH/AeQBnwEW + Af8B4wGcARIB/wHnAagBJQH/AdEBCgEAAf8XAAEBAyQBNgP8Af8D/AH/A/wB/wP8Af8D/AH/A/wB/wP7 + Af8D+AH/A/YB/wPzAf8D8gH/A/wB/wMkATYDAAEBEAADTAGSAecBuQGcAf8B5gG2AZgB/wHYAakBjAH/ + A9IB/wO1Af8DfwH+A18B+wNfAfsDYAHWA0ABcEQAARwBIAH+Af8BuAG7Af4B/wG2AbkB/gH/AbMBtgH+ + Af8BsAGzAf4B/wHfAYQBAAH/AewBtwGSAf8B5gGlASAB/wHmAaIBGwH/AekBrQGFAf8B1gETAQAB/xcA + AQEDJAE2A/wB/wP8Af8DxwH/A8IB/wO+Af8DuAH/A7QB/wOxAf8DrgH/A6wB/wPtAf8D/AH/AyQBNgMA + AQEUAANMAZIDXAHPA3kB+wPHAf8DzAH/A8cB/wPGAf8DwwH/A8AB/wNeAfUDQAFwQAABHAEgAf4B/wEc + ASAB/gH/ARoBHgH+Af8BFgEZAf0B/wESARQB/AH/AeEBjQEAAf8B7QG7AZkB/wHpAawBgQH/AecBqAEk + Af8B6gGzAY0B/wHYARwBAAH/FwABAQMkATYD/AH/A/sB/wP8Af8D/AH/A/sB/wP4Af8D9QH/A/EB/wPs + Af8D6gH/A+YB/wP8Af8DJAE2AwABARwAAy4BSAN/Af4D1AH/A8gB/wO8Af8DugH/A8IB/wPEAf8DYAHW + VAAB4gGSAQQB/wHuAcEBoAH/AeoBsQGJAf8B6QGuAYUB/wHtAbcBlAH/AdsBJAEAAf8XAAEBAyQBNgP8 + Af8D+QH/A8AB/wO6Af8DtAH/A68B/wOqAf8DpQH/A/wB/wP8Af8D/AH/A/wB/wMkATYDAAEBIAADcgH8 + A90B/wPFAf8DWAHBA1sBwwOsAf8D1wH/A18B+1QAAeYBmwEPAf8B8AHFAaYB/wHsAbYBkQH/AesBswGM + Af8B7gG8AZsB/wHfAYUBAAH/FwABAQMkATYD/AH/A/cB/wP5Af8D9wH/A/cB/wPzAf8D8AH/A+oB/wP8 + Af8D9gH/A/QB/wNNAZEDFwEgJAADggH7A+QB/wPPAf8DWQHCBAADjgH/A4wB/wNiAftUAAHoAaABGAH/ + AfIByAGsAf8B8AHGAagB/wHwAcUBpgH/Ae8BwgGiAf8B4QGOAQAB/xgAAyQBNgO5Af0D9AH/A/UB/wP1 + Af8D9QH/A/EB/wPvAf8D6QH/A/wB/wPnAf8DTQGRAxcBIAMBAQIkAANgAdYD4gH/A+cB/wO5Af8DkwH/ + YAAB6gGmAR8B/wHoAaQBHAH/AegBoAEWAf8B5gGdARMB/wHkAZkBDQH/AeIBlQEGAf8YAAMjATMDYQHw + A7kB/QP8Af8D/AH/A/wB/wP8Af8D/AH/A/wB/wP4Af8DTQGRAxcBIAMBAQIoAANAAXADaAH1A+QB/wPu + Af8DlgH/kAADFAEcAyMBMwMkATYDJAE2AyQBNgMkATYDJAE2AyQBNgMkATYDJAE2AxcBIAMBAQIwAANA + AXADYAHWA4QB+wODAftkAAMKAQ0BIgIhATEDIAEvAwUBBxgAAxEBFwGrAgAB/wFiAVkBSAH2AykBPzQA + AwYBCAFAAj8BbgNWAbMBXgJYAd0BUgJdAfQBQAGEAaYB/QIAAbMB/wIAAagB/wJAAZwB/QJSAV0B9AFa + AlgB3QNWAbMBQAI/AW4DBgEIUAADGAEhA1ABnQFdAlQB8AOhAf8DqwH/A6cB/wOVAf8BZAJcAecDSgGK + AxABFgwAAboCAAH/AcABiQEAAf8BvwGJAQAB/wGvAgAB/wMqAUEwAAFbAlkBxAGHAbcB4AH/AZUBxgHm + Af8BmwHNAekB/wGcAc0B6QH/AZkBxwHnAf8BlQHBAeQB/wGOAbgB4AH/AYkBsAHdAf8BgQGnAdcB/wEA + AZsBzwH/AQABjAHCAf8CAAGuAf8BWwJZAcQQAAMJAQwCRgFHAYECWQFcAckCAAHoAf8DHwEtKAADLwFK + AWUCXQH0A84B/wPtAf8D9AH/A/UB/wP0Af8D7wH/A+IB/wO6Af8BZAJcAecDJAE1CAABwwGIAQAB/wHP + AaIBAAH/Ac0BogGBAf8BwAGMAQAB/wGwAgAB/wFOAk0BlQMxAU4DJgE5AxYBHgMDAQQcAAFbAlkBxAGY + AbkB1AH/AcUBxwHEAf8B7AHYAccB/wH2AesB4wH/AfoB9QHxAf8B8wHnAd4B/wHfAb8BpgH/AdABpAGB + Af8BywGaAQAB/wHIAZcBAAH/AaMBkwGMAf8CAAGcAf8BWwJZAcQMAAMtAUUCWgFgAd4CAAHrAf8BAgED + AecB/wIAAekB/wMfAS0BXQJZAdIBXAJZAckBRwJGAYEDCQEMGAABXAJVAeoD3gH/A/MB/wPbAf8D0gH/ + A9sB/wPWAf8DwAH/A8kB/wPmAf8DxAH/AVwCVQHqCAADQAFxAcwBmQEAAf8B0AGjAYEB/wHPAaQBgwH/ + AcoBngEAAf8BvAGFAQAB/wGvAgAB/wGnAgAB/wGeAgAB/wFbAlgBxgMHAQkYAAMdASoB5gHDAaUB/wHv + AdYBwAH/AfsB8gHqAf8B/gH8AfoC/wH+Af0B/wH+Af0B/AH/AfwB9gHwAf8B+AHoAdkB/wH2AeMB0QH/ + AfYB4gHOAf8B5gHIAa0B/wHOAaABAAH/Ax0BKggAAzQBVAIAAfMB/wETARUB7gH/AZQBmQHrAf8BjQGR + AekB/wIAAewB/wMfAS0BXQJZAdIB1gGOAQAB/wG4AgAB/wFgAloB3gMuAUgUAAFcAlUB6gPwAf8D3gH/ + A9QB/wPSAf8D2wH/A9YB/wO/Af8DsAH/A7MB/wPeAf8BXAJVAeoMAANBAXIBzgGdAQAB/wHVAawBjAH/ + AcsBmwEAAf8BzAGgAQAB/wHIAZsBAAH/AcUBlQEAAf8BwAGPAQAB/wGsAgAB/wNCAXYcAAFYAlYBuQHt + AdMBuwH/AfoB8AHlAf8B/QH5AfUB/wH+AfwB+gH/Af4B/QH8Af8B/QH5AfQB/wH2AeMBzwH/AfcB5QHT + Af8B9gHjAdEB/wHdAbkBmgH/AVcCVgG4CAADEAEVA18B8wGVAZkB8gH/AaUBqgHuAf8BEQGBAeYB/wGX + AZoB6wH/AgAB7wH/Ax8BLQFdAVsBWQHSAdsBmQEGAf8B5gGkARUB/wHLAYABAAH/AaYCAAH/AzQBVBAA + AVwCVQHqA/IB/wPiAf8D2AH/A9UB/wPcAf8D2AH/A8AB/wOzAf8DtwH/A+AB/wFcAlUB6hAAAVYCVQGx + AdMBqAGGAf8B1gGsAY4B/wHJAZgBAAH/AcQBkAEAAf8BvwGKAQAB/wHCAY8BAAH/Ab8BiwEAAf8BXwFd + AUYB+wMdASkcAAFVAlMBsAN/Af4B9wHqAd4B/wH+AfoB9wH/Af4B/AH5Af8B/QH3AfIB/wH6Ae0B4gH/ + AesB0AG3Af8CfwF+Af4DVAGuDAADDQERA04BmQJiAWoB+QGEAYUB9AH/AaMBqAHvAf8BoAGlAe0B/wIA + AfEB/wMfAS0CXQFZAdIB3gGhAQ8B/wHeAYkBAAH/AeYBpgEVAf8B0AGHAQAB/wFfAkwB8wMQARUMAAFc + AlUB6gPzAf8D5wH/A90B/wPZAf8D4AH/A9sB/wPEAf8DuAH/A7sB/wPhAf8BXAJVAeoQAAMxAU4B1AGj + AQAB/wHcAbUBmAH/AdABoQEAAf8BzAGaAQAB/wHPAaQBgwH/AcgBmgEAAf8BAAGMAQAB/wEAAbgBAAH/ + AV8BTgEwAfsDVAGvAwcBCRgAAycBOgFhAlsB4QHzAeIB0gH/AfwB9AHtAf8B+wHxAecB/wHpAcwBtQH/ + AWECXAHcAyYBOBAAA0IBcwM8AWYDFAEbA0oBjQJdAV8B8wESARQB8wH/AgAB9AH/Ax8BLQJdAVkB0gHh + AagBgQH/AeABkgEAAf8B2QEPAQAB/wHnAagBhAH/Ab4BBgEAAf8DSAGEDAABXAJVAeoD9AH/A+oB/wPh + Af8D3QH/A+MB/wPeAf8DyQH/A70B/wO/Af8D4gH/AVwCVQHqEAADJgE5AdsBqwGJAf8B4QG9AaIB/wHW + AaoBhwH/AdkBswGUAf8BzgGfAQAB/wFfAl0B+wEAAbwBAAH/AZMCAAH/AbACAAH/AaQCAAH/AWECXgHa + AwMBBBwAA1kBxwH0AeMB0AH/AfMB3wHNAf8BWwJZAcMYAAFZAVwBWQHPAZABvwGTAf8BVQFcAVUB6gNB + AXIDFQEdA0QBewNdAe0DHwEtAl0BWQHSAeQBsAGLAf8B4wGcAQMB/wHdAYUBAAH/AeIBlgEAAf8B2gGX + AQMB/wFcAlkBzwwAAVwCVQHqA/UB/wPuAf8D5gH/A+IB/wPmAf8D4QH/A80B/wPCAf8DwgH/A+MB/wFc + AlUB6hAAAxYBHgHgAbEBjwH/AeYBxAGrAf8B4gG/AaQB/wHYAa0BjgH/A00B+gNDAXcDKwH8AbsBhAEA + Af8BwAGPAQAB/wG8AYoBAAH/AZwCAAH/AxYBHhwAAVsCWQHDAfQB4QHOAf8B8wHfAcwB/wFZAlcBwhgA + AVoCXQHwAcoB6AHIAf8BrwHZAasB/wGSAb8BlAH/A10B7QFFAUYBRQF+Aw8BFAMSARgCXQFZAdIB5wG3 + AZMB/wHnAaYBDQH/AeABkAEAAf8B3gGOAQAB/wHmAa0BiAH/AV8BVAFMAfMMAAFcAlUB6gP2Af8D6wH/ + A94B/wPWAf8D1QH/A9EB/wPDAf8DvAH/A8AB/wPlAf8BXAJVAeoQAAMDAQQBYQJeAdoB5AG7AZ8B/wHk + AbsBnwH/AysB/AEAAcEBAAH/AysB/AHHAZYBAAH/AcsBngEAAf8BvAGFAQAB/wHDAZIBAAH/AaYCAAH/ + AyYBORQAAyYBOAFeAlgB3QHzAd0ByQH/AfoB7gHiAf8B+QHrAd4B/wHtAdABtgH/AV8CWgHbAyYBOBAA + AWACagH5AbYB4AGxAf8BEQHMAQUB/wGSAdIBiQH/Aa0B2QGpAf8BiQG4AYsB/wNQAZ0DNQFWAmIBSQH2 + Ae8ByAGpAf8B5gGmAQkB/wHiAZsBAAH/AeIBmAEAAf8B5wGzAY8B/wFdAVwBTgHwDAABXAJVAeoD9wH/ + A+cB/wPvAf8D9gH/A/sB/wP6Af8D8AH/A94B/wPDAf8D5gH/AVwCVQHqFAADBwEJA1QBrwFqAmYB+QEA + AcUBggH/AbUBsAGBAf8B2AGwAZIB/wHXAa4BjwH/AckBlwEAAf8BwwGPAQAB/wHIAZsBAAH/AbECAAH/ + AzEBThAAA1QBrwN/Af4B+QHsAeAB/wH9AfgB9AH/AfsB8AHmAf8B+AHnAdcB/wH5AesB3gH/AfIB2gHF + Af8DfwH+A1QBrgwAA1wBzwG6Ad8BuAH/ARABzAEDAf8BAAHGAQAB/wEIAcgBAAH/AagB2gGjAf8BAAGo + AQMB/wMoATwDWwHDAeYBtQGOAf8B8AHMAawB/wHlAaYBBwH/AekBsQGEAf8B4wGvAYgB/wJcAVkBzwwA + AVwCVQHqA/gB/wP+Gf8D+wH/A+oB/wFcAlUB6hwAAxsBJgGoAaYBhAH9AeIBvgGjAf8B3wG3AZoB/wHV + AagBhgH/AdABoQEAAf8BywGaAQAB/wHOAaIBgQH/Ab8BiwEAAf8BTgJNAZUMAAFXAlYBuAH5AeMBzQH/ + AfsB8wHsAf8B/gH6AfcB/wH+AfsB+AH/AfwB9QHtAf8B9wHmAdUB/wH2AeEBzAH/AfkB7AHfAf8B+QHr + Ad0B/wHrAc4BtAH/AVcCVgG4CAADSAGEAbMB2gG1Af8BogHYAZoB/wEDAcoBAAH/AQABxgEAAf8BgAHM + AQsB/wGjAc4BowH/AVkBXAFZAc8DIgEyAysB/AHyAdEBsgH/AesBuQGNAf8B8AHJAaoB/wHYAZwBBgH/ + A0gBhAwAAVkCVwG/A+EB/wP+Gf8D+wH/A88B/wFSAlEBoSAAA0IBdgHkAboBnQH/AeYBxAGrAf8B4gG+ + AaQB/wHeAbkBnAH/AdkBsgGTAf8B0QGjAQAB/wHRAaYBhQH/AbsCAAH/AykBPwQAAx0BKgHAAcUBzQH/ + AZoBtwHcAf8BAAGmAdUB/wEAAZUBygH/AQABhwG+Af8CAAGzAf8CAAGoAf8CAAGfAf8CAAGYAf8CAAGa + Af8BAAGDAacB/wGIAZQBmgH/Ax0BKgQAAw0BEgNfAfMBvgHhAb4B/wGUAdQBiQH/AQQBygEAAf8BBAHJ + AQAB/wGeAdYBlwH/AZMBwQGWAf8DPQFpA04BlgHnAbQBjgH/AfMB0wG1Af8B6QG7AZgB/wJfAUwB8wMN + ARIMAAMdASoBXAJYAdED0AH/A+gB/wPzAf8D/QH/A/wB/wPtAf8D4AH/A8IB/wFbAlkBwwMUARsgAAMH + AQkBWwJYAcYB4wG0AZMB/wHfAbEBjgH/AdoBqwGJAf8B2gGtAYwB/wHcAbUBmAH/AdcBrwGQAf8BzAGb + AQAB/wNNAfoEAAFcAlgB0QGHAbcB4AH/AZUBxgHmAf8BmwHNAekB/wGcAc0B6QH/AZkBxwHnAf8BlQHB + AeQB/wGOAbgB4AH/AYkBsAHdAf8BgQGnAdcB/wEAAZsBzwH/AQABjAHCAf8CAAGuAf8BXAJYAdEIAAMy + AVEBoAHVAagB/wG6AeABuwH/AacB2gGgAf8BEwHOAQYB/wEVAc0BCQH/AbAB2QGtAf8DXQHtAxkBIwNd + Ae0B6wHCAZ4B/wHdAaIBCQH/AzIBURQAAwUBBwE1AjQBVQNUAa4BYAJbAdYBXwJdAfsBagJmAfkBXAJa + Ac0DUgGpAy0BRgMCAQMoAAMDAQQDFgEeAyYBOQMxBE4BlAHYAacBggH/AdcBrAGLAf8B0wGnAYQB/wFi + AVwBSQH2BAABWwJZAcQBhwG3AeAB/wGVAcYB5gH/AZ0BzwHqAf8BoQHTAewB/wGgAdEB6wH/AZsBygHo + Af8BlgHCAeUB/wGPAboB4gH/AYcBsQHdAf8BAAGjAdQB/wEAAZABxAH/AgABrgH/AVsCWQHEDAADKQE/ + A2AB3gG0AdwBtwH/AbwB4AG6Af8BuQHhAbUB/wHOAeoBywH/AaQBzgGmAf8BTQJOAZYDPQFpA2AB3gMp + AT98AAMpAT4BXwJdAfsBYgJcAfYDLgFIBAADBgEIAUACPwFuA1YBswFeAlgB3QFlAl0B9AFAAZ0BpgH9 + AQABmQHRAf8BAAGQAcgB/wFAAYQBpgH9AVICXQH0AVoCWAHdA1YBswFAAj8BbgMGAQgQAAMJAQwDRgF+ + A1sBxgMrAfwDKwH8A1sBxgNFAX0DAgEDAwcBChEAAZ0B2QH/AQABmQHYAf8BAAGUAdcB/wEAAZAB1gH/ + AQABjAHVAf8BAAGIAdQB/wEAAYQB0wH/AQABgQHSAf8CAAHRAf8CAAHRAf8CAAHQAf8CAAHPAf8CAAHP + Af8CAAHOAf9gAAM7AWMBWQJXAb8BWAJXAb8DOwFjIAADFQEdAyMBNAMkATYDJAE2AyQBNgMkATYDJAE2 + AyQBNgMkATYDJAE2AyQBNgMkATYDIwEzAxUBHQEAAaMB2gH/AbwB6wH6Af8BvAHrAfwB/wG/Ae4B/gH/ + AcYB9AL/Ac4B+AL/AdMB+gL/AdAB+AL/AccB8gL/AboB6QH8Af8BswHkAfkB/wGwAeIB+AH/AbAB4gH4 + Af8CAAHPAf9UAAMdASkDCgEOAwEBAgFcAlUB6gO9Af8DsgH/AVwCVQHqAwEBAgMKAQ4DHQEpFAADIwE0 + A1kB9QGoAqYB/QP8Af8D/AH/A/wB/wP8Af8D/AH/A/wB/wP8Af8D/AH/AagCpgH9AV8CXQHzAyMBMwEA + AagB2wH/Ab8B7AH7Af8BAAHPAfUB/wEAAbAB7AH/AwAB/wIAAYkB/wEAAYkBvgH/AQABmgHIAf8BAAGu + AecB/wEAAaUB5gH/AQABmgHhAf8BAAG4Ae4B/wGxAeMB+AH/AgAB0AH/CAADUgGpAcMBjgEAAf8BwAGL + AQAB/wG+AYgBAAH/AbsBhQEAAf8BuQGDAQAB/wG0AgAB/wGyAgAB/wGxAgAB/wGuAgAB/wGtAgAB/wGr + AgAB/wGpAgAB/wGpAgAB/wNSAakMAAFQAk8BmwNAAf0BZAJcAecDEgEZAWQCXAHnA8sB/wPHAf8BYwJc + AecDEgEZA1wB5wNAAf0BUAJPAZsIAAM3AVsBXQFUAU4B8AFiAVwBSAH2AeUBtwGaAf8B+wL6Af8D/AH/ + A/wB/wP8Af8D/AH/A/wB/wP8Af8D/AH/A/wB/wP8Af8BqAKmAf0DJAE2AQABrQHcAf8BwQHuAfsB/wEA + AdMB9wH/AQAB2wH8Af8CAAGFAf8BlAHHAfkB/wGRAckB+QH/AQABhQHJAf8CAAGuAf8BAAG9AewB/wEA + Ab4B7wH/AQABugHuAf8BswHjAfkB/wIAAdEB/wgAAcgBkgEANf8BqQIAAf8IAANEAXsDvAH/A94B/wOm + Af8BZQJdAfQDfwH+A8QB/wPCAf8BbgJtAf4BZQJdAfQDpgH/A9IB/wOBAf8DRAF7BAABYgJYAe8B5gG4 + AZwB/wHpAb8BpQH/AdwBmwEAAf8B5QG4AZ0B/wP8Af8D/AH/A/wB/wP7Af8D+wH/A/sB/wP7Af8D+wH/ + A/sB/wP8Af8DJAE2AQABsgHdAf8BwwHvAfsB/wEAAdYB+AH/AQABtgHsAf8BAAGJAaoB/wHgAfIC/wEA + AZoB2AH/AgABvgH/AQABmAHFAf8BAAGGAcUB/wEAAZsB3gH/AQABvgHvAf8BtAHlAfkB/wIAAdIB/wgA + AcoBlAEAC/8B/gP/Af0B/wL+Af0B/wL+AfwB/wL+AfwB/wL+AfwB/wL+AfwB/wL+AfoB/wL+AfoB/wL8 + AfkF/wGqAgAB/wgAA0UBfQN/Af4D1QH/A8UB/wPLAf8D0QH/A8kB/wPHAf8DzAH/A8UB/wO9Af8DywH/ + AW8CbgH+A0UBfQQAAW0CZwH3AesBxAGtAf8B7AHIAbIB/wHqAcEBqQH/Ad4BngEAAf8B5wG7AaEB/wP8 + Af8D+wH/A/sB/wP6Af8D+gH/A/oB/wP6Af8D+gH/A/wB/wMkATYBAAG3Ad4B/wHGAfAB/AH/AQAB2QH4 + Af8BAAHiAf0B/wEAAbcB2QH/AQABtgHVAf8BkAG3AdEB/wEAAckB5AH/AQAB3wH1Af8BAAHQAe0B/wEA + AZgB3AH/AQABugHtAf8BtgHnAfkB/wEAAYMB0wH/CAABzAGXAQAH/wH8A/8B/QH/Av4B/AH/Av4B/AH/ + Av4B+wH/Av0B+gH/Av0B+gH/Av0B+gH/Av0B+gH/AvwB9wH/AvsB9gX/AawCAAH/DAADSAGFA8UB/wPB + Af8DxQH/A8cB/wOqAf8DpwH/A8EB/wO+Af8DtQH/A6oB/wNIAYUIAANCAXUBagJmAfkB7AHHAbAB/wHt + AcoBtQH/AesBwwGrAf8B3gGhAQAB/wHnAboBnwH/A/sB/wP7Af8D+wH/A/oB/wP6Af8D+AH/A/gB/wP8 + Af8DJAE2AQABuwHfAf8BxwHxAfwB/wEAAdwB+QH/AQABuwHtAf8BAAG9Ae8B/wEAAcYB5wH/AQABuAHW + Af8BwgH2Af0B/wEAAd8B9wH/AQAB4gH4Af8BAAHTAfAB/wEAAZcB3AH/AagB3AH1Af8BAAGIAdQB/wgA + AdEBnAEABf8C/gH8Af8C/gH8Af8C/gH8Af8C/QH7Af8C/QH7Af8C/QH6Af8C/QH4Af8C+wH5Af8B+wH6 + AfcB/wH7AfoB9gH/AfsB+AH0Bf8BsAIAAf8EAAFcAloBzQFfAlgB4wFhAlYB7gPPAf8DxgH/A8wB/wFb + AlgBxgMsAUQDLAFEAVsCWAHGA8EB/wO8Af8DuQH/AWECVgHuAVsCWAHjA1oBzQQAA0MBeAN/Af4B7QHI + AbMB/wHtAc0BuAH/AekBvgGjAf8B1gGOAQAB/wP8Af8D/AH/A/wB/wP7Af8D+QH/A/kB/wP4Af8D/AH/ + AyQBNgEAAb8B4AH/AcgB8wH8Af8BAAHfAfkB/wGJAeYB/QH/AZUB5wL/AZoB5QL/AQABygHnAf8BAAHL + AecB/wHHAfcB/QH/AQAB3AH1Af8BAAHhAfcB/wEAAdQB8QH/AQABmQHeAf8BAAGNAdYB/wgAAdQBngEA + Bf8C/gH8Af8C/QH7Af8C/QH8Af8C/QH7Af8C/QH5Af8C/AH4Af8B+wH5AfcB/wH7AfkB9QH/AfsB+AH0 + Af8B+wH3AfIB/wH7AfUB8gX/AbICAAH/BAABqAKmAf0D4gH/A9IB/wPGAf8DzQH/A7EB/wMsAUQIAAMs + AUQDqAH/A8IB/wO3Af8DwAH/A9IB/wNAAf0HAAEBA0wBkgHgAakBiAH/AesBxwGwAf8B3QGhAQAB/wG8 + AaUBlQH/A6wB/wPQAf8D1AH/A+8B/wP5Af8D9gH/A/YB/wP8Af8DJAE2AQABwgHhAf8ByQHzAfwB/wHL + AfMB/QH/AdQB9gH+Af8B1wH2Av8B2AH0Av8B4AH4Av8BqQHjAfUB/wEAAdMB7gH/AccB9wH9Af8BAAHc + AfUB/wEAAeIB9wH/AQAB1gHyAf8BAAGYAd4B/wMhATAEAAHVAaABAAX/Av0B/AH/Av0B+wH/Av0B+gH/ + AvwB+QH/AfwB+wH3Af8B+wH5AfUB/wH7AfgB9AH/AfsB9wHzAf8B+wH1AfIB/wH6AfMB7wH/AfgB8gHs + Bf8BtQIAAf8EAAGoAqYB/QPpAf8D1gH/A8kB/wPOAf8DpQH/AywBRAgAAywBRAOsAf8DxAH/A7oB/wPG + Af8D3QH/A0AB/QcAAQEDJAE2AfAB1gHGAf8B3gGtAZAB/wHEAa8BowH/A9UB/wO7Af8DpgH/A6AB/wOQ + Af8DyQH/A/MB/wPyAf8D/AH/AyQBNgEAAcMB4QH/AYgBoAGoAf8DkQH/A44B/wEAAbkB3AH/AQABuAHf + Af8BAAG1Ad4B/wEAAbEB3QH/AQABsAHeAf8BAAHUAe4B/wHEAfYB/QH/AQAB3QH2Af8BAAHKAe0B/wEA + AaMB1wH/AWACWQHsAxsBJgHYAaIBAAX/Av0B+gH/AvwB+gH/AfwB+wH5Af8B+wH6AfYB/wH7AfgB9QH/ + AfsB9wH0Af8B+wH2AfEB/wH4AfQB7gH/AfcB8gHrAf8B9wHwAeoB/wH2AewB6AX/AbcBgQEAAf8EAAFc + AloBzQFfAlgB4wFhAlYB7gPYAf8DzQH/A7wB/wFbAlgBxgMsAUQDLAFEAVsCWAHGA8MB/wPCAf8DzQH/ + AWECVgHuAV8CWAHjAVwCWgHNBwABAQMkATYD/AH/A/sB/wOsAf8DywH/A9IB/wPJAf8D0gH/A8YB/wOP + Af8D7wH/A+0B/wP8Af8DJAE2BAABWwJZAcMDxgH/A5QB/wMGAQgQAAM3AVoBAAHTAesB/wGyAeMB+QH/ + AYsBwAHnAf8BrgHTAfYB/wHEAeAB/AH/A2cB9wHZAaMBAAX/AfwB+wH5Af8B/AH7AfgB/wH7AfkB9wH/ + AfsB9wH0Af8B+gH3AfIB/wH5AfUB8AH/AfcB8wHtAf8B9gHvAeoB/wH1AesB5wH/AfMB6gHkAf8B8gHn + Ad4F/wG6AYUBAAH/DAADSAGFA9QB/wPMAf8DyQH/A7oB/wOcAf8DoQH/A8IB/wPGAf8DwQH/A7cB/wNI + AYUPAAEBAyQBNgP8Af8D+wH/A9sB/wOyAf8D1gH/A6AB/wOSAf8DwAH/A4oB/wPqAf8D5gH/A/wB/wMk + ATYEAANUAa4DxAH/A6EB/wMdASkQAAMdASkBAAGZAakB/wEAAb4B5wH/AbQB0gHwAf8B5QHzAv8BrAHS + Ae8B/wFfAlcB6AHbAaQBADX/Ab0BhwEAAf8IAANFAX0DfwH+A9wB/wPUAf8D2QH/A9sB/wPWAf8D1AH/ + A9kB/wPSAf8DywH/A8gB/wF6AnkB/gNFAX0LAAEBAyQBNgP8Af8D+QH/A9oB/wO1Af8D5gH/A5oB/wOw + Af8DrwH/A70B/wP8Af8D/AH/A/wB/wMkATYEAANCAXUDugH/A78B/wFeAlgB3QMWAR8DBAEFAwQBBQMW + AR8BZQJeAeUDqAH/AQABpAGzAf8BAAGlAdgB/wGFAbEB2wH/AQABnQHQAf8DOAFeAdwBpwEAAf8B3AGn + AQAB/wHcAacBAAH/AdwBpwEAAf8B3AGnAQAB/wHcAacBAAH/AdwBpwEAAf8B3AGnAQAB/wHcAacBAAH/ + AdwBpwEAAf8B3AGnAQAB/wHcAacBAAH/AdwBpwEAAf8B3AGnAQAB/wHAAYsBAAH/CAADRAF7A9wB/wPt + Af8D2wH/AWUCXQH0A38B/gPWAf8D1AH/A38B/gFlAl0B9APLAf8D5wH/A7cB/wNEAXsLAAEBAyQBNgP8 + Af8D9wH/A+8B/wOmAf8D4QH/A9IB/wO0Af8D6gH/A/wB/wP2Af8D9AH/AU0CTAGRAxcBIAQAAwkBDAFf + AloB2wPEAf8DvgH/A6EB/wOWAf8DkwH/A5cB/wOuAf8DrgH/AV8CWgHbAwcBCQwAAagBpgGDAf0B6AG5 + AZIB/wHoAbkBkgH/AegBuQGSAf8B6AG5AZIB/wHoAbkBkgH/AegBuQGSAf8B6AG5AZIB/wHoAbkBkgH/ + AegBuQGSAf8B6AG5AZIB/wHoAbkBkgH/AegBuQGSAf8B6AG5AZIB/wGoAY4BQAH9DAABUAJPAZsBqAKm + Af0BZAJcAecDEgEZAWQCXAHnA94B/wPdAf8BZAJcAecDEgEZAWQCXAHnAacCpQH9AVACTwGbEAADJAE2 + AagCpgH9A/QB/wP1Af8D1AH/A6UB/wOdAf8DvgH/A+kB/wP8Af8D5wH/AU0CTAGRAxcBIAMBAQIIAAMh + ATABYAJaAd4DvAH/A8oB/wPMAf8DygH/A8IB/wOtAf8BYAJaAd4DIQEwEAADPgFrAWUCXQH0AdwBpwEA + Af8B3AGmAQAB/wHaAaQBAAH/AdgBogEAAf8B1QGgAQAB/wHUAZ4BAAH/AdIBnQEAAf8BzwGaAQAB/wHO + AZkBAAH/AcsBlgEAAf8ByQGUAQAB/wFlAl0B9AM+AWsQAAMdASkDCgEOAwEBAgFcAlUB6gPlAf8D5AH/ + AVwCVQHqAwEBAgMKAQ4DHQEpFAADIwEzAV0CVAHwAagCpgH9A/wB/wP8Af8D/AH/A/wB/wP8Af8D/AH/ + A/gB/wFNAkwBkQMXASADAQECEAADCQEMAUcCRgGBAVcCVQG6AVwCWQHMAVwCWQHMAVcCVQG6AUcCRgGB + AwkBDGwAAzsBYwFZAlcBvwFZAlcBvwM7AWMgAAMUARwDIwEzAyQBNgMkATYDJAE2AyQBNgMkATYDJAE2 + AyQBNgMkATYDFwEgAwEBAggAAUIBTQE+BwABPgMAASgDAAFAAwABMAMAAQEBAAEBBQABgAEBFgAD/wEA + Av8BgAEBAYcB/wQAAYABAQEDAf8FAAIBAf8HAAH/BwABfwYAAYABPwYAAcABPwYAAeABHwMAAR8CAAHw + AQEDAAEfAgAB+AQAAR8CAAH+AwAB+AEfAgAB/wMAAfgBHwEAAQEB/wEIAgAB+AEfAYABAQH/AQcCAAH4 + AR8BgAEDAf8BBwIAAv8BgAEHAf8BhwIAAfwBPwEPAf8BgAEBAv8B4AIHAf8BgAEBAeAB/wHAAQMBAAE/ + AYABAQHAAQ8BwAEDAQABHwGAAQEBgAEHAcABAwGAAR8BwAEDAQABAwHAAQMBwAEPAeABBwEAAQEBwAED + AcABAwHwAQ8BAAEBAcABAwHAAQEB/AE/AQABAQHAAQMBwAEBAfwBPwEAAQEBwAEDAcABAQHwAQ8BAAEB + AcABAwHgAQEB4AEHAQABAQHAAQMB+AEBAcABAwEAAQEBwAEDAfwBAAGAAQEBAAEBAcABAwH8AQABgAEB + AYABAwHgAQcB/gEAAYABAQHAAQcD/wHwAYABAQHgAQ8BAAEDAv8B/AE/AcACAAEDAv8B4AEHAcACAAED + AQABAQHAAQMDAAEDAQABAQGAAQEDAAEDAQABAQGAAQEDAAEDAQABAQHAAQMDAAEDAQABAQIAAYACAAED + AQACAQKAAgABAQEAAgECgAQAAQECAAGAAQABhwGAAQABAQHAAQMBgAEAAYcBgAEAAQEBgAEBAYABAAGA + AgABAQGAAQEBgAEAAYABBwEAAQEBwAEDAcABAAHAAQ8BAAEBAeABBwHAAQEB4AEfAv8B/AE/AcABAws= - - 338, 17 - 457, 17 diff --git a/trunk/ProcessHacker/Forms/ProtectProcessWindow.Designer.cs b/trunk/ProcessHacker/Forms/ProtectProcessWindow.Designer.cs new file mode 100644 index 000000000..7625f84ad --- /dev/null +++ b/trunk/ProcessHacker/Forms/ProtectProcessWindow.Designer.cs @@ -0,0 +1,143 @@ +namespace ProcessHacker +{ + partial class ProtectProcessWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.checkProtect = new System.Windows.Forms.CheckBox(); + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.listProcessAccess = new System.Windows.Forms.CheckedListBox(); + this.listThreadAccess = new System.Windows.Forms.CheckedListBox(); + this.buttonCancel = new System.Windows.Forms.Button(); + this.buttonOK = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // checkProtect + // + this.checkProtect.AutoSize = true; + this.checkProtect.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.checkProtect.Location = new System.Drawing.Point(12, 12); + this.checkProtect.Name = "checkProtect"; + this.checkProtect.Size = new System.Drawing.Size(125, 18); + this.checkProtect.TabIndex = 0; + this.checkProtect.Text = "Protect this process"; + this.checkProtect.UseVisualStyleBackColor = true; + this.checkProtect.CheckedChanged += new System.EventHandler(this.checkProtect_CheckedChanged); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 42); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(124, 13); + this.label1.TabIndex = 1; + this.label1.Text = "Allowed process access:"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(12, 155); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(117, 13); + this.label2.TabIndex = 2; + this.label2.Text = "Allowed thread access:"; + // + // listProcessAccess + // + this.listProcessAccess.FormattingEnabled = true; + this.listProcessAccess.Location = new System.Drawing.Point(12, 58); + this.listProcessAccess.Name = "listProcessAccess"; + this.listProcessAccess.Size = new System.Drawing.Size(474, 94); + this.listProcessAccess.TabIndex = 3; + // + // listThreadAccess + // + this.listThreadAccess.FormattingEnabled = true; + this.listThreadAccess.Location = new System.Drawing.Point(12, 171); + this.listThreadAccess.Name = "listThreadAccess"; + this.listThreadAccess.Size = new System.Drawing.Size(474, 94); + this.listThreadAccess.TabIndex = 3; + // + // buttonCancel + // + this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonCancel.Location = new System.Drawing.Point(411, 271); + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.Size = new System.Drawing.Size(75, 23); + this.buttonCancel.TabIndex = 4; + this.buttonCancel.Text = "Cancel"; + this.buttonCancel.UseVisualStyleBackColor = true; + this.buttonCancel.Click += new System.EventHandler(this.buttonCancel_Click); + // + // buttonOK + // + this.buttonOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonOK.Location = new System.Drawing.Point(330, 271); + this.buttonOK.Name = "buttonOK"; + this.buttonOK.Size = new System.Drawing.Size(75, 23); + this.buttonOK.TabIndex = 4; + this.buttonOK.Text = "OK"; + this.buttonOK.UseVisualStyleBackColor = true; + this.buttonOK.Click += new System.EventHandler(this.buttonOK_Click); + // + // ProtectProcessWindow + // + this.AcceptButton = this.buttonOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(498, 306); + this.Controls.Add(this.buttonOK); + this.Controls.Add(this.buttonCancel); + this.Controls.Add(this.listThreadAccess); + this.Controls.Add(this.listProcessAccess); + this.Controls.Add(this.label2); + this.Controls.Add(this.label1); + this.Controls.Add(this.checkProtect); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "ProtectProcessWindow"; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Protect Process"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.CheckBox checkProtect; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.CheckedListBox listProcessAccess; + private System.Windows.Forms.CheckedListBox listThreadAccess; + private System.Windows.Forms.Button buttonCancel; + private System.Windows.Forms.Button buttonOK; + } +} \ No newline at end of file diff --git a/trunk/ProcessHacker/Forms/ProtectProcessWindow.cs b/trunk/ProcessHacker/Forms/ProtectProcessWindow.cs new file mode 100644 index 000000000..755dd84a7 --- /dev/null +++ b/trunk/ProcessHacker/Forms/ProtectProcessWindow.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Text; +using System.Windows.Forms; +using ProcessHacker.Native; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker +{ + public partial class ProtectProcessWindow : Form + { + private int _pid; + private bool _isProtected; + + public ProtectProcessWindow(int pid) + { + InitializeComponent(); + + _pid = pid; + + ProcessAccess processAccess; + ThreadAccess threadAccess; + + if (ProtectQuery(_pid, out processAccess, out threadAccess)) + checkProtect.Checked = _isProtected = true; + + foreach (string value in Enum.GetNames(typeof(ProcessAccess))) + { + if (value == "All") + continue; + + listProcessAccess.Items.Add(value, + (processAccess & (ProcessAccess)Enum.Parse(typeof(ProcessAccess), value)) != 0); + } + + foreach (string value in Enum.GetNames(typeof(ThreadAccess))) + { + if (value == "All") + continue; + + listThreadAccess.Items.Add(value, + (threadAccess & (ThreadAccess)Enum.Parse(typeof(ThreadAccess), value)) != 0); + } + + checkProtect_CheckedChanged(null, null); + } + + private bool ProtectQuery(int pid, out ProcessAccess processAccess, out ThreadAccess threadAccess) + { + try + { + using (var phandle = new ProcessHandle(pid, Program.MinProcessQueryRights)) + KProcessHacker.Instance.ProtectQuery(phandle, out processAccess, out threadAccess); + + return true; + } + catch + { + processAccess = 0; + threadAccess = 0; + + return false; + } + } + + private void buttonCancel_Click(object sender, EventArgs e) + { + this.Close(); + } + + private void buttonOK_Click(object sender, EventArgs e) + { + // remove protection + if (_isProtected) + { + try + { + using (var phandle = new ProcessHandle(_pid, Program.MinProcessQueryRights)) + KProcessHacker.Instance.ProtectRemove(phandle); + } + catch + { } + } + + // re-add protection (with new masks) + if (checkProtect.Checked) + { + ProcessAccess processAccess = 0; + ThreadAccess threadAccess = 0; + + foreach (string value in listProcessAccess.CheckedItems) + processAccess |= (ProcessAccess)Enum.Parse(typeof(ProcessAccess), value); + foreach (string value in listThreadAccess.CheckedItems) + threadAccess |= (ThreadAccess)Enum.Parse(typeof(ThreadAccess), value); + + try + { + using (var phandle = new ProcessHandle(_pid, Program.MinProcessQueryRights)) + KProcessHacker.Instance.ProtectAdd(phandle, processAccess, threadAccess); + } + catch + { } + } + + this.Close(); + } + + private void checkProtect_CheckedChanged(object sender, EventArgs e) + { + listProcessAccess.Enabled = checkProtect.Checked; + listThreadAccess.Enabled = checkProtect.Checked; + } + } +} diff --git a/trunk/ProcessHacker/Forms/ProtectProcessWindow.resx b/trunk/ProcessHacker/Forms/ProtectProcessWindow.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/trunk/ProcessHacker/Forms/ProtectProcessWindow.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/trunk/ProcessHacker/ProcessHacker.csproj b/trunk/ProcessHacker/ProcessHacker.csproj index f77eecf86..f2a06542e 100644 --- a/trunk/ProcessHacker/ProcessHacker.csproj +++ b/trunk/ProcessHacker/ProcessHacker.csproj @@ -230,6 +230,9 @@ ProcessWindow.cs Designer + + ProtectProcessWindow.cs + StructWindow.cs @@ -330,6 +333,12 @@ ProcessStatistics.cs + + Form + + + ProtectProcessWindow.cs + diff --git a/trunk/ProcessHacker/Properties/Settings.Designer.cs b/trunk/ProcessHacker/Properties/Settings.Designer.cs index 099e372b6..7448c2cf9 100644 --- a/trunk/ProcessHacker/Properties/Settings.Designer.cs +++ b/trunk/ProcessHacker/Properties/Settings.Designer.cs @@ -1452,5 +1452,17 @@ namespace ProcessHacker.Properties { this["HideProcessHackerNetworkConnections"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool EnableExperimentalFeatures { + get { + return ((bool)(this["EnableExperimentalFeatures"])); + } + set { + this["EnableExperimentalFeatures"] = value; + } + } } } diff --git a/trunk/ProcessHacker/Properties/Settings.settings b/trunk/ProcessHacker/Properties/Settings.settings index acbfd414f..d420789c8 100644 --- a/trunk/ProcessHacker/Properties/Settings.settings +++ b/trunk/ProcessHacker/Properties/Settings.settings @@ -359,5 +359,8 @@ True + + False + \ No newline at end of file diff --git a/trunk/ProcessHacker/app.config b/trunk/ProcessHacker/app.config index cd60bb70a..03329be84 100644 --- a/trunk/ProcessHacker/app.config +++ b/trunk/ProcessHacker/app.config @@ -364,6 +364,9 @@ True + + False + \ No newline at end of file