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 ca1b9d535..300961714 100644 Binary files a/trunk/KProcessHacker/i386/kprocesshacker.sys and b/trunk/KProcessHacker/i386/kprocesshacker.sys differ diff --git a/trunk/KProcessHacker/include/hook.h b/trunk/KProcessHacker/include/hook.h new file mode 100644 index 000000000..072acc3a5 --- /dev/null +++ b/trunk/KProcessHacker/include/hook.h @@ -0,0 +1,60 @@ +/* + * 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 . + */ + +#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