go my file uploader
This commit is contained in:
139
KProcessHacker/KProcessHacker.vcxproj
Normal file
139
KProcessHacker/KProcessHacker.vcxproj
Normal file
@@ -0,0 +1,139 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Win8 Debug|Win32">
|
||||
<Configuration>Win8 Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Win8 Release|Win32">
|
||||
<Configuration>Win8 Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Win8 Debug|x64">
|
||||
<Configuration>Win8 Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Win8 Release|x64">
|
||||
<Configuration>Win8 Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}</ProjectGuid>
|
||||
<TemplateGuid>{dd38f7fc-d7bd-488b-9242-7d8754cde80d}</TemplateGuid>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
|
||||
<Configuration>Win8 Debug</Configuration>
|
||||
<Platform Condition="'$(Platform)' == ''">Win32</Platform>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<RootNamespace>KProcessHacker</RootNamespace>
|
||||
<VCTargetsPath Condition="'$(VCTargetsPath11)' != '' and '$(VisualStudioVersion)' == '11.0'">$(VCTargetsPath11)</VCTargetsPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="PropertySheets">
|
||||
<PlatformToolset>WindowsKernelModeDriver8.0</PlatformToolset>
|
||||
<ConfigurationType>Driver</ConfigurationType>
|
||||
<DriverType>WDM</DriverType>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'" Label="Configuration">
|
||||
<TargetVersion>Windows8</TargetVersion>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'" Label="Configuration">
|
||||
<TargetVersion>Windows8</TargetVersion>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'" Label="Configuration">
|
||||
<TargetVersion>Windows8</TargetVersion>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'" Label="Configuration">
|
||||
<TargetVersion>Windows8</TargetVersion>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'">
|
||||
<OutDir>$(ProjectDir)bin\$(Configuration) $(PlatformArchitecture)\</OutDir>
|
||||
<IntDir>$(ProjectDir)obj\$(Configuration) $(PlatformArchitecture)\</IntDir>
|
||||
<TargetName>kprocesshacker</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'">
|
||||
<OutDir>$(ProjectDir)bin\$(Configuration) $(PlatformArchitecture)\</OutDir>
|
||||
<IntDir>$(ProjectDir)obj\$(Configuration) $(PlatformArchitecture)\</IntDir>
|
||||
<TargetName>kprocesshacker</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'">
|
||||
<OutDir>$(ProjectDir)bin\$(Configuration) $(PlatformArchitecture)\</OutDir>
|
||||
<IntDir>$(ProjectDir)obj\$(Configuration) $(PlatformArchitecture)\</IntDir>
|
||||
<TargetName>kprocesshacker</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'">
|
||||
<OutDir>$(ProjectDir)bin\$(Configuration) $(PlatformArchitecture)\</OutDir>
|
||||
<IntDir>$(ProjectDir)obj\$(Configuration) $(PlatformArchitecture)\</IntDir>
|
||||
<TargetName>kprocesshacker</TargetName>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>../phnt/include;../phlib/include;include;$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>KPH_CONFIG_CLEAN;_X86_=1;i386=1;STD_CALL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>../phnt/include;../phlib/include;include;$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>KPH_CONFIG_CLEAN;_X86_=1;i386=1;STD_CALL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>../phnt/include;../phlib/include;include;$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>KPH_CONFIG_CLEAN;_WIN64;_AMD64_;AMD64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>../phnt/include;../phlib/include;include;$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>KPH_CONFIG_CLEAN;_WIN64;_AMD64_;AMD64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<FilesToPackage Include="$(TargetPath)" />
|
||||
<FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="devctrl.c" />
|
||||
<ClCompile Include="dyndata.c" />
|
||||
<ClCompile Include="dynimp.c" />
|
||||
<ClCompile Include="main.c" />
|
||||
<ClCompile Include="object.c" />
|
||||
<ClCompile Include="process.c" />
|
||||
<ClCompile Include="qrydrv.c" />
|
||||
<ClCompile Include="thread.c" />
|
||||
<ClCompile Include="vm.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="resource.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\dyndata.h" />
|
||||
<ClInclude Include="include\kph.h" />
|
||||
<ClInclude Include="include\ntfill.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
66
KProcessHacker/KProcessHacker.vcxproj.filters
Normal file
66
KProcessHacker/KProcessHacker.vcxproj.filters
Normal file
@@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Driver Files">
|
||||
<UniqueIdentifier>{8E41214B-6785-4CFE-B992-037D68949A14}</UniqueIdentifier>
|
||||
<Extensions>inf;inv;inx;mof;mc;</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="devctrl.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="dyndata.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="dynimp.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="main.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="object.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="process.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="qrydrv.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="thread.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="vm.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="resource.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\dyndata.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\kph.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\ntfill.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
BIN
KProcessHacker/bin-signed/amd64/kprocesshacker.sys
Normal file
BIN
KProcessHacker/bin-signed/amd64/kprocesshacker.sys
Normal file
Binary file not shown.
BIN
KProcessHacker/bin-signed/i386/kprocesshacker.sys
Normal file
BIN
KProcessHacker/bin-signed/i386/kprocesshacker.sys
Normal file
Binary file not shown.
1
KProcessHacker/clean/makefile
Normal file
1
KProcessHacker/clean/makefile
Normal file
@@ -0,0 +1 @@
|
||||
!INCLUDE $(NTMAKEENV)\makefile.def
|
||||
7
KProcessHacker/clean/sources
Normal file
7
KProcessHacker/clean/sources
Normal file
@@ -0,0 +1,7 @@
|
||||
!IF 0
|
||||
|
||||
This builds a clean version of KProcessHacker suitable for driver signing.
|
||||
|
||||
!ENDIF
|
||||
|
||||
!include ..\sources.inc
|
||||
566
KProcessHacker/devctrl.c
Normal file
566
KProcessHacker/devctrl.c
Normal file
@@ -0,0 +1,566 @@
|
||||
/*
|
||||
* KProcessHacker
|
||||
*
|
||||
* Copyright (C) 2010-2016 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <kph.h>
|
||||
|
||||
NTSTATUS KphDispatchDeviceControl(
|
||||
__in PDEVICE_OBJECT DeviceObject,
|
||||
__in PIRP Irp
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
PIO_STACK_LOCATION stackLocation;
|
||||
PFILE_OBJECT fileObject;
|
||||
PKPH_CLIENT client;
|
||||
PVOID originalInput;
|
||||
ULONG inputLength;
|
||||
ULONG ioControlCode;
|
||||
KPROCESSOR_MODE accessMode;
|
||||
UCHAR capturedInput[16 * sizeof(ULONG_PTR)];
|
||||
PVOID capturedInputPointer;
|
||||
|
||||
#define VERIFY_INPUT_LENGTH \
|
||||
do { \
|
||||
/* Ensure at compile time that our local buffer fits this particular call. */ \
|
||||
C_ASSERT(sizeof(*input) <= sizeof(capturedInput)); \
|
||||
\
|
||||
if (inputLength != sizeof(*input)) \
|
||||
{ \
|
||||
status = STATUS_INFO_LENGTH_MISMATCH; \
|
||||
goto ControlEnd; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
stackLocation = IoGetCurrentIrpStackLocation(Irp);
|
||||
fileObject = stackLocation->FileObject;
|
||||
client = fileObject->FsContext;
|
||||
|
||||
originalInput = stackLocation->Parameters.DeviceIoControl.Type3InputBuffer;
|
||||
inputLength = stackLocation->Parameters.DeviceIoControl.InputBufferLength;
|
||||
ioControlCode = stackLocation->Parameters.DeviceIoControl.IoControlCode;
|
||||
accessMode = Irp->RequestorMode;
|
||||
|
||||
// Make sure we have a client object.
|
||||
if (!client)
|
||||
{
|
||||
status = STATUS_INTERNAL_ERROR;
|
||||
goto ControlEnd;
|
||||
}
|
||||
|
||||
// Enforce signature requirement if necessary.
|
||||
if ((ioControlCode != KPH_GETFEATURES && ioControlCode != KPH_VERIFYCLIENT) &&
|
||||
(KphParameters.SecurityLevel == KphSecuritySignatureCheck ||
|
||||
KphParameters.SecurityLevel == KphSecuritySignatureAndPrivilegeCheck) &&
|
||||
!client->VerificationSucceeded)
|
||||
{
|
||||
status = STATUS_ACCESS_DENIED;
|
||||
goto ControlEnd;
|
||||
}
|
||||
|
||||
// Make sure we actually have input if the input length is non-zero.
|
||||
if (inputLength != 0 && !originalInput)
|
||||
{
|
||||
status = STATUS_INVALID_BUFFER_SIZE;
|
||||
goto ControlEnd;
|
||||
}
|
||||
|
||||
// Make sure the caller isn't giving us a huge buffer. If they are, it can't be correct because
|
||||
// we have a compile-time check that makes sure our buffer can store the arguments for all the
|
||||
// calls.
|
||||
if (inputLength > sizeof(capturedInput))
|
||||
{
|
||||
status = STATUS_INVALID_BUFFER_SIZE;
|
||||
goto ControlEnd;
|
||||
}
|
||||
|
||||
// Probe and capture the input buffer.
|
||||
if (accessMode != KernelMode)
|
||||
{
|
||||
__try
|
||||
{
|
||||
ProbeForRead(originalInput, inputLength, sizeof(UCHAR));
|
||||
memcpy(capturedInput, originalInput, inputLength);
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
status = GetExceptionCode();
|
||||
goto ControlEnd;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(capturedInput, originalInput, inputLength);
|
||||
}
|
||||
|
||||
capturedInputPointer = capturedInput; // avoid casting below
|
||||
|
||||
switch (ioControlCode)
|
||||
{
|
||||
case KPH_GETFEATURES:
|
||||
{
|
||||
struct
|
||||
{
|
||||
PULONG Features;
|
||||
} *input = capturedInputPointer;
|
||||
|
||||
VERIFY_INPUT_LENGTH;
|
||||
|
||||
status = KpiGetFeatures(
|
||||
input->Features,
|
||||
accessMode
|
||||
);
|
||||
}
|
||||
break;
|
||||
case KPH_VERIFYCLIENT:
|
||||
{
|
||||
struct
|
||||
{
|
||||
PVOID CodeAddress;
|
||||
PVOID Signature;
|
||||
ULONG SignatureSize;
|
||||
} *input = capturedInputPointer;
|
||||
|
||||
VERIFY_INPUT_LENGTH;
|
||||
|
||||
if (accessMode == UserMode)
|
||||
{
|
||||
status = KpiVerifyClient(
|
||||
input->CodeAddress,
|
||||
input->Signature,
|
||||
input->SignatureSize,
|
||||
client
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case KPH_RETRIEVEKEY:
|
||||
{
|
||||
struct
|
||||
{
|
||||
KPH_KEY_LEVEL KeyLevel;
|
||||
} *input = capturedInputPointer;
|
||||
|
||||
VERIFY_INPUT_LENGTH;
|
||||
|
||||
if (accessMode == UserMode)
|
||||
{
|
||||
status = KphRetrieveKeyViaApc(
|
||||
client,
|
||||
input->KeyLevel,
|
||||
Irp
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case KPH_OPENPROCESS:
|
||||
{
|
||||
struct
|
||||
{
|
||||
PHANDLE ProcessHandle;
|
||||
ACCESS_MASK DesiredAccess;
|
||||
PCLIENT_ID ClientId;
|
||||
KPH_KEY Key;
|
||||
} *input = capturedInputPointer;
|
||||
|
||||
VERIFY_INPUT_LENGTH;
|
||||
|
||||
status = KpiOpenProcess(
|
||||
input->ProcessHandle,
|
||||
input->DesiredAccess,
|
||||
input->ClientId,
|
||||
input->Key,
|
||||
client,
|
||||
accessMode
|
||||
);
|
||||
}
|
||||
break;
|
||||
case KPH_OPENPROCESSTOKEN:
|
||||
{
|
||||
struct
|
||||
{
|
||||
HANDLE ProcessHandle;
|
||||
ACCESS_MASK DesiredAccess;
|
||||
PHANDLE TokenHandle;
|
||||
KPH_KEY Key;
|
||||
} *input = capturedInputPointer;
|
||||
|
||||
VERIFY_INPUT_LENGTH;
|
||||
|
||||
status = KpiOpenProcessToken(
|
||||
input->ProcessHandle,
|
||||
input->DesiredAccess,
|
||||
input->TokenHandle,
|
||||
input->Key,
|
||||
client,
|
||||
accessMode
|
||||
);
|
||||
}
|
||||
break;
|
||||
case KPH_OPENPROCESSJOB:
|
||||
{
|
||||
struct
|
||||
{
|
||||
HANDLE ProcessHandle;
|
||||
ACCESS_MASK DesiredAccess;
|
||||
PHANDLE JobHandle;
|
||||
} *input = capturedInputPointer;
|
||||
|
||||
VERIFY_INPUT_LENGTH;
|
||||
|
||||
status = KpiOpenProcessJob(
|
||||
input->ProcessHandle,
|
||||
input->DesiredAccess,
|
||||
input->JobHandle,
|
||||
accessMode
|
||||
);
|
||||
}
|
||||
break;
|
||||
case KPH_TERMINATEPROCESS:
|
||||
{
|
||||
struct
|
||||
{
|
||||
HANDLE ProcessHandle;
|
||||
NTSTATUS ExitStatus;
|
||||
KPH_KEY Key;
|
||||
} *input = capturedInputPointer;
|
||||
|
||||
VERIFY_INPUT_LENGTH;
|
||||
|
||||
status = KpiTerminateProcess(
|
||||
input->ProcessHandle,
|
||||
input->ExitStatus,
|
||||
input->Key,
|
||||
client,
|
||||
accessMode
|
||||
);
|
||||
}
|
||||
break;
|
||||
case KPH_READVIRTUALMEMORYUNSAFE:
|
||||
{
|
||||
struct
|
||||
{
|
||||
HANDLE ProcessHandle;
|
||||
PVOID BaseAddress;
|
||||
PVOID Buffer;
|
||||
SIZE_T BufferSize;
|
||||
PSIZE_T NumberOfBytesRead;
|
||||
KPH_KEY Key;
|
||||
} *input = capturedInputPointer;
|
||||
|
||||
VERIFY_INPUT_LENGTH;
|
||||
|
||||
status = KpiReadVirtualMemoryUnsafe(
|
||||
input->ProcessHandle,
|
||||
input->BaseAddress,
|
||||
input->Buffer,
|
||||
input->BufferSize,
|
||||
input->NumberOfBytesRead,
|
||||
input->Key,
|
||||
client,
|
||||
accessMode
|
||||
);
|
||||
}
|
||||
break;
|
||||
case KPH_QUERYINFORMATIONPROCESS:
|
||||
{
|
||||
struct
|
||||
{
|
||||
HANDLE ProcessHandle;
|
||||
KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass;
|
||||
PVOID ProcessInformation;
|
||||
ULONG ProcessInformationLength;
|
||||
PULONG ReturnLength;
|
||||
} *input = capturedInputPointer;
|
||||
|
||||
VERIFY_INPUT_LENGTH;
|
||||
|
||||
status = KpiQueryInformationProcess(
|
||||
input->ProcessHandle,
|
||||
input->ProcessInformationClass,
|
||||
input->ProcessInformation,
|
||||
input->ProcessInformationLength,
|
||||
input->ReturnLength,
|
||||
accessMode
|
||||
);
|
||||
}
|
||||
break;
|
||||
case KPH_SETINFORMATIONPROCESS:
|
||||
{
|
||||
struct
|
||||
{
|
||||
HANDLE ProcessHandle;
|
||||
KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass;
|
||||
PVOID ProcessInformation;
|
||||
ULONG ProcessInformationLength;
|
||||
} *input = capturedInputPointer;
|
||||
|
||||
VERIFY_INPUT_LENGTH;
|
||||
|
||||
status = KpiSetInformationProcess(
|
||||
input->ProcessHandle,
|
||||
input->ProcessInformationClass,
|
||||
input->ProcessInformation,
|
||||
input->ProcessInformationLength,
|
||||
accessMode
|
||||
);
|
||||
}
|
||||
break;
|
||||
case KPH_OPENTHREAD:
|
||||
{
|
||||
struct
|
||||
{
|
||||
PHANDLE ThreadHandle;
|
||||
ACCESS_MASK DesiredAccess;
|
||||
PCLIENT_ID ClientId;
|
||||
KPH_KEY Key;
|
||||
} *input = capturedInputPointer;
|
||||
|
||||
VERIFY_INPUT_LENGTH;
|
||||
|
||||
status = KpiOpenThread(
|
||||
input->ThreadHandle,
|
||||
input->DesiredAccess,
|
||||
input->ClientId,
|
||||
input->Key,
|
||||
client,
|
||||
accessMode
|
||||
);
|
||||
}
|
||||
break;
|
||||
case KPH_OPENTHREADPROCESS:
|
||||
{
|
||||
struct
|
||||
{
|
||||
HANDLE ThreadHandle;
|
||||
ACCESS_MASK DesiredAccess;
|
||||
PHANDLE ProcessHandle;
|
||||
} *input = capturedInputPointer;
|
||||
|
||||
VERIFY_INPUT_LENGTH;
|
||||
|
||||
status = KpiOpenThreadProcess(
|
||||
input->ThreadHandle,
|
||||
input->DesiredAccess,
|
||||
input->ProcessHandle,
|
||||
accessMode
|
||||
);
|
||||
}
|
||||
break;
|
||||
case KPH_CAPTURESTACKBACKTRACETHREAD:
|
||||
{
|
||||
struct
|
||||
{
|
||||
HANDLE ThreadHandle;
|
||||
ULONG FramesToSkip;
|
||||
ULONG FramesToCapture;
|
||||
PVOID *BackTrace;
|
||||
PULONG CapturedFrames;
|
||||
PULONG BackTraceHash;
|
||||
} *input = capturedInputPointer;
|
||||
|
||||
VERIFY_INPUT_LENGTH;
|
||||
|
||||
status = KpiCaptureStackBackTraceThread(
|
||||
input->ThreadHandle,
|
||||
input->FramesToSkip,
|
||||
input->FramesToCapture,
|
||||
input->BackTrace,
|
||||
input->CapturedFrames,
|
||||
input->BackTraceHash,
|
||||
accessMode
|
||||
);
|
||||
}
|
||||
break;
|
||||
case KPH_QUERYINFORMATIONTHREAD:
|
||||
{
|
||||
struct
|
||||
{
|
||||
HANDLE ThreadHandle;
|
||||
KPH_THREAD_INFORMATION_CLASS ThreadInformationClass;
|
||||
PVOID ThreadInformation;
|
||||
ULONG ThreadInformationLength;
|
||||
PULONG ReturnLength;
|
||||
} *input = capturedInputPointer;
|
||||
|
||||
VERIFY_INPUT_LENGTH;
|
||||
|
||||
status = KpiQueryInformationThread(
|
||||
input->ThreadHandle,
|
||||
input->ThreadInformationClass,
|
||||
input->ThreadInformation,
|
||||
input->ThreadInformationLength,
|
||||
input->ReturnLength,
|
||||
accessMode
|
||||
);
|
||||
}
|
||||
break;
|
||||
case KPH_SETINFORMATIONTHREAD:
|
||||
{
|
||||
struct
|
||||
{
|
||||
HANDLE ThreadHandle;
|
||||
KPH_THREAD_INFORMATION_CLASS ThreadInformationClass;
|
||||
PVOID ThreadInformation;
|
||||
ULONG ThreadInformationLength;
|
||||
} *input = capturedInputPointer;
|
||||
|
||||
VERIFY_INPUT_LENGTH;
|
||||
|
||||
status = KpiSetInformationThread(
|
||||
input->ThreadHandle,
|
||||
input->ThreadInformationClass,
|
||||
input->ThreadInformation,
|
||||
input->ThreadInformationLength,
|
||||
accessMode
|
||||
);
|
||||
}
|
||||
break;
|
||||
case KPH_ENUMERATEPROCESSHANDLES:
|
||||
{
|
||||
struct
|
||||
{
|
||||
HANDLE ProcessHandle;
|
||||
PVOID Buffer;
|
||||
ULONG BufferLength;
|
||||
PULONG ReturnLength;
|
||||
} *input = capturedInputPointer;
|
||||
|
||||
VERIFY_INPUT_LENGTH;
|
||||
|
||||
status = KpiEnumerateProcessHandles(
|
||||
input->ProcessHandle,
|
||||
input->Buffer,
|
||||
input->BufferLength,
|
||||
input->ReturnLength,
|
||||
accessMode
|
||||
);
|
||||
}
|
||||
break;
|
||||
case KPH_QUERYINFORMATIONOBJECT:
|
||||
{
|
||||
struct
|
||||
{
|
||||
HANDLE ProcessHandle;
|
||||
HANDLE Handle;
|
||||
KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass;
|
||||
PVOID ObjectInformation;
|
||||
ULONG ObjectInformationLength;
|
||||
PULONG ReturnLength;
|
||||
} *input = capturedInputPointer;
|
||||
|
||||
VERIFY_INPUT_LENGTH;
|
||||
|
||||
status = KpiQueryInformationObject(
|
||||
input->ProcessHandle,
|
||||
input->Handle,
|
||||
input->ObjectInformationClass,
|
||||
input->ObjectInformation,
|
||||
input->ObjectInformationLength,
|
||||
input->ReturnLength,
|
||||
accessMode
|
||||
);
|
||||
}
|
||||
break;
|
||||
case KPH_SETINFORMATIONOBJECT:
|
||||
{
|
||||
struct
|
||||
{
|
||||
HANDLE ProcessHandle;
|
||||
HANDLE Handle;
|
||||
KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass;
|
||||
PVOID ObjectInformation;
|
||||
ULONG ObjectInformationLength;
|
||||
} *input = capturedInputPointer;
|
||||
|
||||
VERIFY_INPUT_LENGTH;
|
||||
|
||||
status = KpiSetInformationObject(
|
||||
input->ProcessHandle,
|
||||
input->Handle,
|
||||
input->ObjectInformationClass,
|
||||
input->ObjectInformation,
|
||||
input->ObjectInformationLength,
|
||||
accessMode
|
||||
);
|
||||
}
|
||||
break;
|
||||
case KPH_OPENDRIVER:
|
||||
{
|
||||
struct
|
||||
{
|
||||
PHANDLE DriverHandle;
|
||||
ACCESS_MASK DesiredAccess;
|
||||
POBJECT_ATTRIBUTES ObjectAttributes;
|
||||
} *input = capturedInputPointer;
|
||||
|
||||
VERIFY_INPUT_LENGTH;
|
||||
|
||||
status = KpiOpenDriver(
|
||||
input->DriverHandle,
|
||||
input->DesiredAccess,
|
||||
input->ObjectAttributes,
|
||||
accessMode
|
||||
);
|
||||
}
|
||||
break;
|
||||
case KPH_QUERYINFORMATIONDRIVER:
|
||||
{
|
||||
struct
|
||||
{
|
||||
HANDLE DriverHandle;
|
||||
DRIVER_INFORMATION_CLASS DriverInformationClass;
|
||||
PVOID DriverInformation;
|
||||
ULONG DriverInformationLength;
|
||||
PULONG ReturnLength;
|
||||
} *input = capturedInputPointer;
|
||||
|
||||
VERIFY_INPUT_LENGTH;
|
||||
|
||||
status = KpiQueryInformationDriver(
|
||||
input->DriverHandle,
|
||||
input->DriverInformationClass,
|
||||
input->DriverInformation,
|
||||
input->DriverInformationLength,
|
||||
input->ReturnLength,
|
||||
accessMode
|
||||
);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
break;
|
||||
}
|
||||
|
||||
ControlEnd:
|
||||
Irp->IoStatus.Status = status;
|
||||
Irp->IoStatus.Information = 0;
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
|
||||
return status;
|
||||
}
|
||||
1
KProcessHacker/dirs
Normal file
1
KProcessHacker/dirs
Normal file
@@ -0,0 +1 @@
|
||||
DIRS=clean
|
||||
167
KProcessHacker/dyndata.c
Normal file
167
KProcessHacker/dyndata.c
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* KProcessHacker
|
||||
*
|
||||
* Copyright (C) 2010-2016 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <kph.h>
|
||||
#define _DYNDATA_PRIVATE
|
||||
#include <dyndata.h>
|
||||
|
||||
#define C_2sTo4(x) ((unsigned int)(signed short)(x))
|
||||
|
||||
NTSTATUS KphpLoadDynamicConfiguration(
|
||||
__in PVOID Buffer,
|
||||
__in ULONG Length
|
||||
);
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, KphDynamicDataInitialization)
|
||||
#pragma alloc_text(PAGE, KphReadDynamicDataParameters)
|
||||
#pragma alloc_text(PAGE, KphpLoadDynamicConfiguration)
|
||||
#endif
|
||||
|
||||
NTSTATUS KphDynamicDataInitialization(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
// Get Windows version information.
|
||||
|
||||
KphDynOsVersionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
|
||||
status = RtlGetVersion((PRTL_OSVERSIONINFOW)&KphDynOsVersionInfo);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS KphReadDynamicDataParameters(
|
||||
__in_opt HANDLE KeyHandle
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
UNICODE_STRING valueName;
|
||||
PKEY_VALUE_PARTIAL_INFORMATION info;
|
||||
ULONG resultLength;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
if (!KeyHandle)
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
|
||||
RtlInitUnicodeString(&valueName, L"DynamicConfiguration");
|
||||
|
||||
status = ZwQueryValueKey(
|
||||
KeyHandle,
|
||||
&valueName,
|
||||
KeyValuePartialInformation,
|
||||
NULL,
|
||||
0,
|
||||
&resultLength
|
||||
);
|
||||
|
||||
if (status != STATUS_BUFFER_OVERFLOW && status != STATUS_BUFFER_TOO_SMALL)
|
||||
{
|
||||
// Unexpected status; fail now.
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
info = ExAllocatePoolWithTag(PagedPool, resultLength, 'ThpK');
|
||||
|
||||
if (!info)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
status = ZwQueryValueKey(
|
||||
KeyHandle,
|
||||
&valueName,
|
||||
KeyValuePartialInformation,
|
||||
info,
|
||||
resultLength,
|
||||
&resultLength
|
||||
);
|
||||
|
||||
if (NT_SUCCESS(status))
|
||||
{
|
||||
if (info->Type == REG_BINARY)
|
||||
status = KphpLoadDynamicConfiguration(info->Data, info->DataLength);
|
||||
else
|
||||
status = STATUS_OBJECT_TYPE_MISMATCH;
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
dprintf("Unable to load dynamic configuration: 0x%x\n", status);
|
||||
}
|
||||
|
||||
ExFreePoolWithTag(info, 'ThpK');
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS KphpLoadDynamicConfiguration(
|
||||
__in PVOID Buffer,
|
||||
__in ULONG Length
|
||||
)
|
||||
{
|
||||
PKPH_DYN_CONFIGURATION config;
|
||||
ULONG i;
|
||||
PKPH_DYN_PACKAGE package;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
config = Buffer;
|
||||
|
||||
if (Length < FIELD_OFFSET(KPH_DYN_CONFIGURATION, Packages))
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
if (config->Version != KPH_DYN_CONFIGURATION_VERSION)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
if (config->NumberOfPackages > KPH_DYN_MAXIMUM_PACKAGES)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
if (Length < FIELD_OFFSET(KPH_DYN_CONFIGURATION, Packages) + config->NumberOfPackages * sizeof(KPH_DYN_PACKAGE))
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
dprintf("Loading dynamic configuration with %u package(s)\n", config->NumberOfPackages);
|
||||
|
||||
for (i = 0; i < config->NumberOfPackages; i++)
|
||||
{
|
||||
package = &config->Packages[i];
|
||||
|
||||
if (package->MajorVersion == KphDynOsVersionInfo.dwMajorVersion &&
|
||||
package->MinorVersion == KphDynOsVersionInfo.dwMinorVersion &&
|
||||
(package->ServicePackMajor == (USHORT)-1 || package->ServicePackMajor == KphDynOsVersionInfo.wServicePackMajor) &&
|
||||
(package->BuildNumber == (USHORT)-1 || package->BuildNumber == KphDynOsVersionInfo.dwBuildNumber))
|
||||
{
|
||||
dprintf("Found matching package at index %u for Windows %u.%u\n", i, package->MajorVersion, package->MinorVersion);
|
||||
|
||||
KphDynNtVersion = package->ResultingNtVersion;
|
||||
|
||||
KphDynEgeGuid = C_2sTo4(package->StructData.EgeGuid);
|
||||
KphDynEpObjectTable = C_2sTo4(package->StructData.EpObjectTable);
|
||||
KphDynEreGuidEntry = C_2sTo4(package->StructData.EreGuidEntry);
|
||||
KphDynHtHandleContentionEvent = C_2sTo4(package->StructData.HtHandleContentionEvent);
|
||||
KphDynOtName = C_2sTo4(package->StructData.OtName);
|
||||
KphDynOtIndex = C_2sTo4(package->StructData.OtIndex);
|
||||
KphDynObDecodeShift = C_2sTo4(package->StructData.ObDecodeShift);
|
||||
KphDynObAttributesShift = C_2sTo4(package->StructData.ObAttributesShift);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return STATUS_NOT_FOUND;
|
||||
}
|
||||
60
KProcessHacker/dynimp.c
Normal file
60
KProcessHacker/dynimp.c
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* KProcessHacker
|
||||
*
|
||||
* Copyright (C) 2010-2016 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <kph.h>
|
||||
#include <dyndata.h>
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, KphGetSystemRoutineAddress)
|
||||
#pragma alloc_text(PAGE, KphDynamicImport)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Dynamically imports routines.
|
||||
*/
|
||||
VOID KphDynamicImport(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
PAGED_CODE();
|
||||
NOTHING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the address of a function exported by NTOS or HAL.
|
||||
*
|
||||
* \param SystemRoutineName The name of the function.
|
||||
*
|
||||
* \return The address of the function, or NULL if the function could
|
||||
* not be found.
|
||||
*/
|
||||
PVOID KphGetSystemRoutineAddress(
|
||||
__in PWSTR SystemRoutineName
|
||||
)
|
||||
{
|
||||
UNICODE_STRING systemRoutineName;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
RtlInitUnicodeString(&systemRoutineName, SystemRoutineName);
|
||||
|
||||
return MmGetSystemRoutineAddress(&systemRoutineName);
|
||||
}
|
||||
47
KProcessHacker/include/dyndata.h
Normal file
47
KProcessHacker/include/dyndata.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#ifndef DYNDATA_H
|
||||
#define DYNDATA_H
|
||||
|
||||
#ifdef EXT
|
||||
#undef EXT
|
||||
#endif
|
||||
|
||||
#ifdef _DYNDATA_PRIVATE
|
||||
#define EXT
|
||||
#define OFFDEFAULT = -1
|
||||
#else
|
||||
#define EXT extern
|
||||
#define OFFDEFAULT
|
||||
#endif
|
||||
|
||||
EXT ULONG KphDynNtVersion;
|
||||
EXT RTL_OSVERSIONINFOEXW KphDynOsVersionInfo;
|
||||
|
||||
// Structures
|
||||
// Ege: ETW_GUID_ENTRY
|
||||
// Ep: EPROCESS
|
||||
// Ere: ETW_REG_ENTRY
|
||||
// Et: ETHREAD
|
||||
// Ht: HANDLE_TABLE
|
||||
// Oh: OBJECT_HEADER
|
||||
// Ot: OBJECT_TYPE
|
||||
// Oti: OBJECT_TYPE_INITIALIZER, offset measured from an OBJECT_TYPE
|
||||
// ObDecodeShift: shift value in ObpDecodeObject
|
||||
// ObAttributesShift: shift value in ObpGetHandleAttributes
|
||||
EXT ULONG KphDynEgeGuid OFFDEFAULT;
|
||||
EXT ULONG KphDynEpObjectTable OFFDEFAULT;
|
||||
EXT ULONG KphDynEreGuidEntry OFFDEFAULT;
|
||||
EXT ULONG KphDynHtHandleContentionEvent OFFDEFAULT;
|
||||
EXT ULONG KphDynOtName OFFDEFAULT;
|
||||
EXT ULONG KphDynOtIndex OFFDEFAULT;
|
||||
EXT ULONG KphDynObDecodeShift OFFDEFAULT;
|
||||
EXT ULONG KphDynObAttributesShift OFFDEFAULT;
|
||||
|
||||
NTSTATUS KphDynamicDataInitialization(
|
||||
VOID
|
||||
);
|
||||
|
||||
NTSTATUS KphReadDynamicDataParameters(
|
||||
__in_opt HANDLE KeyHandle
|
||||
);
|
||||
|
||||
#endif
|
||||
365
KProcessHacker/include/kph.h
Normal file
365
KProcessHacker/include/kph.h
Normal file
@@ -0,0 +1,365 @@
|
||||
#ifndef KPH_H
|
||||
#define KPH_H
|
||||
|
||||
#include <ntifs.h>
|
||||
#define PHNT_MODE PHNT_MODE_KERNEL
|
||||
#include <phnt.h>
|
||||
#include <ntfill.h>
|
||||
#include <bcrypt.h>
|
||||
#include <kphapi.h>
|
||||
|
||||
// Debugging
|
||||
|
||||
#ifdef DBG
|
||||
#define dprintf(Format, ...) DbgPrint("KProcessHacker: " Format, __VA_ARGS__)
|
||||
#else
|
||||
#define dprintf
|
||||
#endif
|
||||
|
||||
typedef struct _KPH_CLIENT
|
||||
{
|
||||
struct
|
||||
{
|
||||
ULONG VerificationPerformed : 1;
|
||||
ULONG VerificationSucceeded : 1;
|
||||
ULONG KeysGenerated : 1;
|
||||
ULONG SpareBits : 29;
|
||||
};
|
||||
FAST_MUTEX StateMutex;
|
||||
NTSTATUS VerificationStatus;
|
||||
PVOID VerifiedProcess; // EPROCESS (for equality checking only - do not access contents)
|
||||
HANDLE VerifiedProcessId;
|
||||
PVOID VerifiedRangeBase;
|
||||
SIZE_T VerifiedRangeSize;
|
||||
// Level 1 and 2 secret keys
|
||||
FAST_MUTEX KeyBackoffMutex;
|
||||
KPH_KEY L1Key;
|
||||
KPH_KEY L2Key;
|
||||
} KPH_CLIENT, *PKPH_CLIENT;
|
||||
|
||||
typedef struct _KPH_PARAMETERS
|
||||
{
|
||||
KPH_SECURITY_LEVEL SecurityLevel;
|
||||
} KPH_PARAMETERS, *PKPH_PARAMETERS;
|
||||
|
||||
// main
|
||||
|
||||
extern ULONG KphFeatures;
|
||||
extern KPH_PARAMETERS KphParameters;
|
||||
|
||||
NTSTATUS KpiGetFeatures(
|
||||
__out PULONG Features,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
);
|
||||
|
||||
// devctrl
|
||||
|
||||
__drv_dispatchType(IRP_MJ_DEVICE_CONTROL) DRIVER_DISPATCH KphDispatchDeviceControl;
|
||||
|
||||
NTSTATUS KphDispatchDeviceControl(
|
||||
__in PDEVICE_OBJECT DeviceObject,
|
||||
__in PIRP Irp
|
||||
);
|
||||
|
||||
// dynimp
|
||||
|
||||
VOID KphDynamicImport(
|
||||
VOID
|
||||
);
|
||||
|
||||
PVOID KphGetSystemRoutineAddress(
|
||||
__in PWSTR SystemRoutineName
|
||||
);
|
||||
|
||||
// object
|
||||
|
||||
PHANDLE_TABLE KphReferenceProcessHandleTable(
|
||||
__in PEPROCESS Process
|
||||
);
|
||||
|
||||
VOID KphDereferenceProcessHandleTable(
|
||||
__in PEPROCESS Process
|
||||
);
|
||||
|
||||
VOID KphUnlockHandleTableEntry(
|
||||
__in PHANDLE_TABLE HandleTable,
|
||||
__in PHANDLE_TABLE_ENTRY HandleTableEntry
|
||||
);
|
||||
|
||||
NTSTATUS KpiEnumerateProcessHandles(
|
||||
__in HANDLE ProcessHandle,
|
||||
__out_bcount(BufferLength) PVOID Buffer,
|
||||
__in_opt ULONG BufferLength,
|
||||
__out_opt PULONG ReturnLength,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
);
|
||||
|
||||
NTSTATUS KphQueryNameObject(
|
||||
__in PVOID Object,
|
||||
__out_bcount(BufferLength) POBJECT_NAME_INFORMATION Buffer,
|
||||
__in ULONG BufferLength,
|
||||
__out PULONG ReturnLength
|
||||
);
|
||||
|
||||
NTSTATUS KphQueryNameFileObject(
|
||||
__in PFILE_OBJECT FileObject,
|
||||
__out_bcount(BufferLength) POBJECT_NAME_INFORMATION Buffer,
|
||||
__in ULONG BufferLength,
|
||||
__out PULONG ReturnLength
|
||||
);
|
||||
|
||||
NTSTATUS KpiQueryInformationObject(
|
||||
__in HANDLE ProcessHandle,
|
||||
__in HANDLE Handle,
|
||||
__in KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass,
|
||||
__out_bcount(ObjectInformationLength) PVOID ObjectInformation,
|
||||
__in ULONG ObjectInformationLength,
|
||||
__out_opt PULONG ReturnLength,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
);
|
||||
|
||||
NTSTATUS KpiSetInformationObject(
|
||||
__in HANDLE ProcessHandle,
|
||||
__in HANDLE Handle,
|
||||
__in KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass,
|
||||
__in_bcount(ObjectInformationLength) PVOID ObjectInformation,
|
||||
__in ULONG ObjectInformationLength,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
);
|
||||
|
||||
NTSTATUS KphOpenNamedObject(
|
||||
__out PHANDLE ObjectHandle,
|
||||
__in ACCESS_MASK DesiredAccess,
|
||||
__in POBJECT_ATTRIBUTES ObjectAttributes,
|
||||
__in POBJECT_TYPE ObjectType,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
);
|
||||
|
||||
// process
|
||||
|
||||
NTSTATUS KpiOpenProcess(
|
||||
__out PHANDLE ProcessHandle,
|
||||
__in ACCESS_MASK DesiredAccess,
|
||||
__in PCLIENT_ID ClientId,
|
||||
__in_opt KPH_KEY Key,
|
||||
__in PKPH_CLIENT Client,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
);
|
||||
|
||||
NTSTATUS KpiOpenProcessToken(
|
||||
__in HANDLE ProcessHandle,
|
||||
__in ACCESS_MASK DesiredAccess,
|
||||
__out PHANDLE TokenHandle,
|
||||
__in_opt KPH_KEY Key,
|
||||
__in PKPH_CLIENT Client,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
);
|
||||
|
||||
NTSTATUS KpiOpenProcessJob(
|
||||
__in HANDLE ProcessHandle,
|
||||
__in ACCESS_MASK DesiredAccess,
|
||||
__out PHANDLE JobHandle,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
);
|
||||
|
||||
NTSTATUS KpiTerminateProcess(
|
||||
__in HANDLE ProcessHandle,
|
||||
__in NTSTATUS ExitStatus,
|
||||
__in_opt KPH_KEY Key,
|
||||
__in PKPH_CLIENT Client,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
);
|
||||
|
||||
NTSTATUS KpiQueryInformationProcess(
|
||||
__in HANDLE ProcessHandle,
|
||||
__in KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass,
|
||||
__out_bcount(ProcessInformationLength) PVOID ProcessInformation,
|
||||
__in ULONG ProcessInformationLength,
|
||||
__out_opt PULONG ReturnLength,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
);
|
||||
|
||||
NTSTATUS KpiSetInformationProcess(
|
||||
__in HANDLE ProcessHandle,
|
||||
__in KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass,
|
||||
__in_bcount(ProcessInformationLength) PVOID ProcessInformation,
|
||||
__in ULONG ProcessInformationLength,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
);
|
||||
|
||||
// qrydrv
|
||||
|
||||
NTSTATUS KpiOpenDriver(
|
||||
__out PHANDLE DriverHandle,
|
||||
__in ACCESS_MASK DesiredAccess,
|
||||
__in POBJECT_ATTRIBUTES ObjectAttributes,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
);
|
||||
|
||||
NTSTATUS KpiQueryInformationDriver(
|
||||
__in HANDLE DriverHandle,
|
||||
__in DRIVER_INFORMATION_CLASS DriverInformationClass,
|
||||
__out_bcount(DriverInformationLength) PVOID DriverInformation,
|
||||
__in ULONG DriverInformationLength,
|
||||
__out_opt PULONG ReturnLength,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
);
|
||||
|
||||
// thread
|
||||
|
||||
NTSTATUS KpiOpenThread(
|
||||
__out PHANDLE ThreadHandle,
|
||||
__in ACCESS_MASK DesiredAccess,
|
||||
__in PCLIENT_ID ClientId,
|
||||
__in_opt KPH_KEY Key,
|
||||
__in PKPH_CLIENT Client,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
);
|
||||
|
||||
NTSTATUS KpiOpenThreadProcess(
|
||||
__in HANDLE ThreadHandle,
|
||||
__in ACCESS_MASK DesiredAccess,
|
||||
__out PHANDLE ProcessHandle,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
);
|
||||
|
||||
ULONG KphCaptureStackBackTrace(
|
||||
__in ULONG FramesToSkip,
|
||||
__in ULONG FramesToCapture,
|
||||
__in_opt ULONG Flags,
|
||||
__out_ecount(FramesToCapture) PVOID *BackTrace,
|
||||
__out_opt PULONG BackTraceHash
|
||||
);
|
||||
|
||||
NTSTATUS KphCaptureStackBackTraceThread(
|
||||
__in PETHREAD Thread,
|
||||
__in ULONG FramesToSkip,
|
||||
__in ULONG FramesToCapture,
|
||||
__out_ecount(FramesToCapture) PVOID *BackTrace,
|
||||
__out_opt PULONG CapturedFrames,
|
||||
__out_opt PULONG BackTraceHash,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
);
|
||||
|
||||
NTSTATUS KpiCaptureStackBackTraceThread(
|
||||
__in HANDLE ThreadHandle,
|
||||
__in ULONG FramesToSkip,
|
||||
__in ULONG FramesToCapture,
|
||||
__out_ecount(FramesToCapture) PVOID *BackTrace,
|
||||
__out_opt PULONG CapturedFrames,
|
||||
__out_opt PULONG BackTraceHash,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
);
|
||||
|
||||
NTSTATUS KpiQueryInformationThread(
|
||||
__in HANDLE ThreadHandle,
|
||||
__in KPH_THREAD_INFORMATION_CLASS ThreadInformationClass,
|
||||
__out_bcount(ProcessInformationLength) PVOID ThreadInformation,
|
||||
__in ULONG ThreadInformationLength,
|
||||
__out_opt PULONG ReturnLength,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
);
|
||||
|
||||
NTSTATUS KpiSetInformationThread(
|
||||
__in HANDLE ThreadHandle,
|
||||
__in KPH_THREAD_INFORMATION_CLASS ThreadInformationClass,
|
||||
__in_bcount(ThreadInformationLength) PVOID ThreadInformation,
|
||||
__in ULONG ThreadInformationLength,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
);
|
||||
|
||||
// util
|
||||
|
||||
VOID KphFreeCapturedUnicodeString(
|
||||
__in PUNICODE_STRING CapturedUnicodeString
|
||||
);
|
||||
|
||||
NTSTATUS KphCaptureUnicodeString(
|
||||
__in PUNICODE_STRING UnicodeString,
|
||||
__out PUNICODE_STRING CapturedUnicodeString
|
||||
);
|
||||
|
||||
NTSTATUS KphEnumerateSystemModules(
|
||||
__out PRTL_PROCESS_MODULES *Modules
|
||||
);
|
||||
|
||||
NTSTATUS KphValidateAddressForSystemModules(
|
||||
__in PVOID Address,
|
||||
__in SIZE_T Length
|
||||
);
|
||||
|
||||
NTSTATUS KphGetProcessMappedFileName(
|
||||
__in HANDLE ProcessHandle,
|
||||
__in PVOID BaseAddress,
|
||||
__out PUNICODE_STRING *FileName
|
||||
);
|
||||
|
||||
// verify
|
||||
|
||||
NTSTATUS KphHashFile(
|
||||
__in PUNICODE_STRING FileName,
|
||||
__out PVOID *Hash,
|
||||
__out PULONG HashSize
|
||||
);
|
||||
|
||||
NTSTATUS KphVerifyFile(
|
||||
__in PUNICODE_STRING FileName,
|
||||
__in_bcount(SignatureSize) PUCHAR Signature,
|
||||
__in ULONG SignatureSize
|
||||
);
|
||||
|
||||
VOID KphVerifyClient(
|
||||
__inout PKPH_CLIENT Client,
|
||||
__in PVOID CodeAddress,
|
||||
__in_bcount(SignatureSize) PUCHAR Signature,
|
||||
__in ULONG SignatureSize
|
||||
);
|
||||
|
||||
NTSTATUS KpiVerifyClient(
|
||||
__in PVOID CodeAddress,
|
||||
__in_bcount(SignatureSize) PUCHAR Signature,
|
||||
__in ULONG SignatureSize,
|
||||
__in PKPH_CLIENT Client
|
||||
);
|
||||
|
||||
VOID KphGenerateKeysClient(
|
||||
__inout PKPH_CLIENT Client
|
||||
);
|
||||
|
||||
NTSTATUS KphRetrieveKeyViaApc(
|
||||
__inout PKPH_CLIENT Client,
|
||||
__in KPH_KEY_LEVEL KeyLevel,
|
||||
__inout PIRP Irp
|
||||
);
|
||||
|
||||
NTSTATUS KphValidateKey(
|
||||
__in KPH_KEY_LEVEL RequiredKeyLevel,
|
||||
__in_opt KPH_KEY Key,
|
||||
__in PKPH_CLIENT Client,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
);
|
||||
|
||||
// vm
|
||||
|
||||
NTSTATUS KphCopyVirtualMemory(
|
||||
__in PEPROCESS FromProcess,
|
||||
__in PVOID FromAddress,
|
||||
__in PEPROCESS ToProcess,
|
||||
__in PVOID ToAddress,
|
||||
__in SIZE_T BufferLength,
|
||||
__in KPROCESSOR_MODE AccessMode,
|
||||
__out PSIZE_T ReturnLength
|
||||
);
|
||||
|
||||
NTSTATUS KpiReadVirtualMemoryUnsafe(
|
||||
__in_opt HANDLE ProcessHandle,
|
||||
__in PVOID BaseAddress,
|
||||
__out_bcount(BufferSize) PVOID Buffer,
|
||||
__in SIZE_T BufferSize,
|
||||
__out_opt PSIZE_T NumberOfBytesRead,
|
||||
__in_opt KPH_KEY Key,
|
||||
__in PKPH_CLIENT Client,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
);
|
||||
|
||||
#endif
|
||||
351
KProcessHacker/include/ntfill.h
Normal file
351
KProcessHacker/include/ntfill.h
Normal file
@@ -0,0 +1,351 @@
|
||||
#ifndef NTFILL_H
|
||||
#define NTFILL_H
|
||||
|
||||
extern ULONG KphDynNtVersion;
|
||||
extern ULONG KphDynObDecodeShift;
|
||||
extern ULONG KphDynObAttributesShift;
|
||||
|
||||
// EX
|
||||
|
||||
typedef struct _EX_PUSH_LOCK_WAIT_BLOCK *PEX_PUSH_LOCK_WAIT_BLOCK;
|
||||
|
||||
NTKERNELAPI
|
||||
VOID
|
||||
FASTCALL
|
||||
ExfUnblockPushLock(
|
||||
__inout PEX_PUSH_LOCK PushLock,
|
||||
__inout_opt PEX_PUSH_LOCK_WAIT_BLOCK WaitBlock
|
||||
);
|
||||
|
||||
typedef struct _HANDLE_TABLE_ENTRY
|
||||
{
|
||||
union
|
||||
{
|
||||
PVOID Object;
|
||||
ULONG ObAttributes;
|
||||
ULONG_PTR Value;
|
||||
};
|
||||
union
|
||||
{
|
||||
ACCESS_MASK GrantedAccess;
|
||||
LONG NextFreeTableEntry;
|
||||
};
|
||||
} HANDLE_TABLE_ENTRY, *PHANDLE_TABLE_ENTRY;
|
||||
|
||||
typedef struct _HANDLE_TABLE HANDLE_TABLE, *PHANDLE_TABLE;
|
||||
|
||||
typedef BOOLEAN (NTAPI *PEX_ENUM_HANDLE_CALLBACK_61)(
|
||||
__inout PHANDLE_TABLE_ENTRY HandleTableEntry,
|
||||
__in HANDLE Handle,
|
||||
__in PVOID Context
|
||||
);
|
||||
|
||||
// since WIN8
|
||||
typedef BOOLEAN (NTAPI *PEX_ENUM_HANDLE_CALLBACK)(
|
||||
__in PHANDLE_TABLE HandleTable,
|
||||
__inout PHANDLE_TABLE_ENTRY HandleTableEntry,
|
||||
__in HANDLE Handle,
|
||||
__in PVOID Context
|
||||
);
|
||||
|
||||
NTKERNELAPI
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
ExEnumHandleTable(
|
||||
__in PHANDLE_TABLE HandleTable,
|
||||
__in PEX_ENUM_HANDLE_CALLBACK EnumHandleProcedure,
|
||||
__inout PVOID Context,
|
||||
__out_opt PHANDLE Handle
|
||||
);
|
||||
|
||||
NTSYSCALLAPI
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
ZwQuerySystemInformation(
|
||||
__in SYSTEM_INFORMATION_CLASS SystemInformationClass,
|
||||
__out_bcount_opt(SystemInformationLength) PVOID SystemInformation,
|
||||
__in ULONG SystemInformationLength,
|
||||
__out_opt PULONG ReturnLength
|
||||
);
|
||||
|
||||
// IO
|
||||
|
||||
extern POBJECT_TYPE *IoDriverObjectType;
|
||||
|
||||
// KE
|
||||
|
||||
typedef enum _KAPC_ENVIRONMENT
|
||||
{
|
||||
OriginalApcEnvironment,
|
||||
AttachedApcEnvironment,
|
||||
CurrentApcEnvironment,
|
||||
InsertApcEnvironment
|
||||
} KAPC_ENVIRONMENT, *PKAPC_ENVIRONMENT;
|
||||
|
||||
typedef VOID (NTAPI *PKNORMAL_ROUTINE)(
|
||||
__in PVOID NormalContext,
|
||||
__in PVOID SystemArgument1,
|
||||
__in PVOID SystemArgument2
|
||||
);
|
||||
|
||||
typedef VOID KKERNEL_ROUTINE(
|
||||
__in PRKAPC Apc,
|
||||
__inout PKNORMAL_ROUTINE *NormalRoutine,
|
||||
__inout PVOID *NormalContext,
|
||||
__inout PVOID *SystemArgument1,
|
||||
__inout PVOID *SystemArgument2
|
||||
);
|
||||
|
||||
typedef KKERNEL_ROUTINE (NTAPI *PKKERNEL_ROUTINE);
|
||||
|
||||
typedef VOID (NTAPI *PKRUNDOWN_ROUTINE)(
|
||||
__in PRKAPC Apc
|
||||
);
|
||||
|
||||
NTKERNELAPI
|
||||
VOID
|
||||
NTAPI
|
||||
KeInitializeApc(
|
||||
__out PRKAPC Apc,
|
||||
__in PRKTHREAD Thread,
|
||||
__in KAPC_ENVIRONMENT Environment,
|
||||
__in PKKERNEL_ROUTINE KernelRoutine,
|
||||
__in_opt PKRUNDOWN_ROUTINE RundownRoutine,
|
||||
__in_opt PKNORMAL_ROUTINE NormalRoutine,
|
||||
__in_opt KPROCESSOR_MODE ProcessorMode,
|
||||
__in_opt PVOID NormalContext
|
||||
);
|
||||
|
||||
NTKERNELAPI
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
KeInsertQueueApc(
|
||||
__inout PRKAPC Apc,
|
||||
__in_opt PVOID SystemArgument1,
|
||||
__in_opt PVOID SystemArgument2,
|
||||
__in KPRIORITY Increment
|
||||
);
|
||||
|
||||
// MM
|
||||
|
||||
NTSYSCALLAPI
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
ZwQueryVirtualMemory(
|
||||
__in HANDLE ProcessHandle,
|
||||
__in PVOID BaseAddress,
|
||||
__in MEMORY_INFORMATION_CLASS MemoryInformationClass,
|
||||
__out_bcount(MemoryInformationLength) PVOID MemoryInformation,
|
||||
__in SIZE_T MemoryInformationLength,
|
||||
__out_opt PSIZE_T ReturnLength
|
||||
);
|
||||
|
||||
// OB
|
||||
|
||||
// These definitions are no longer correct, but they produce correct results.
|
||||
|
||||
#define OBJ_PROTECT_CLOSE 0x00000001
|
||||
#define OBJ_HANDLE_ATTRIBUTES (OBJ_PROTECT_CLOSE | OBJ_INHERIT | OBJ_AUDIT_OBJECT_CLOSE)
|
||||
|
||||
// This attribute is now stored in the GrantedAccess field.
|
||||
#define ObpAccessProtectCloseBit 0x2000000
|
||||
|
||||
#define ObpDecodeGrantedAccess(Access) \
|
||||
((Access) & ~ObpAccessProtectCloseBit)
|
||||
|
||||
FORCEINLINE PVOID ObpDecodeObject(PVOID Object)
|
||||
{
|
||||
#ifdef _M_X64
|
||||
if (KphDynNtVersion >= PHNT_WIN8)
|
||||
{
|
||||
if (KphDynObDecodeShift != -1)
|
||||
return (PVOID)(((LONG_PTR)Object >> KphDynObDecodeShift) & ~(ULONG_PTR)0xf);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (PVOID)((ULONG_PTR)Object & ~OBJ_HANDLE_ATTRIBUTES);
|
||||
}
|
||||
#else
|
||||
return (PVOID)((ULONG_PTR)Object & ~OBJ_HANDLE_ATTRIBUTES);
|
||||
#endif
|
||||
}
|
||||
|
||||
FORCEINLINE ULONG ObpGetHandleAttributes(PHANDLE_TABLE_ENTRY HandleTableEntry)
|
||||
{
|
||||
#ifdef _M_X64
|
||||
if (KphDynNtVersion >= PHNT_WIN8)
|
||||
{
|
||||
if (KphDynObAttributesShift != -1)
|
||||
return (ULONG)(HandleTableEntry->Value >> KphDynObAttributesShift) & 0x3;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (HandleTableEntry->ObAttributes & (OBJ_INHERIT | OBJ_AUDIT_OBJECT_CLOSE)) |
|
||||
((HandleTableEntry->GrantedAccess & ObpAccessProtectCloseBit) ? OBJ_PROTECT_CLOSE : 0);
|
||||
}
|
||||
#else
|
||||
return (HandleTableEntry->ObAttributes & (OBJ_INHERIT | OBJ_AUDIT_OBJECT_CLOSE)) |
|
||||
((HandleTableEntry->GrantedAccess & ObpAccessProtectCloseBit) ? OBJ_PROTECT_CLOSE : 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
typedef struct _OBJECT_CREATE_INFORMATION OBJECT_CREATE_INFORMATION, *POBJECT_CREATE_INFORMATION;
|
||||
|
||||
// This is incorrect as of Windows 8.1, but the size of the structure is still correct.
|
||||
typedef struct _OBJECT_HEADER
|
||||
{
|
||||
LONG PointerCount;
|
||||
union
|
||||
{
|
||||
LONG HandleCount;
|
||||
PVOID NextToFree;
|
||||
};
|
||||
POBJECT_TYPE Type;
|
||||
UCHAR NameInfoOffset;
|
||||
UCHAR HandleInfoOffset;
|
||||
UCHAR QuotaInfoOffset;
|
||||
UCHAR Flags;
|
||||
union
|
||||
{
|
||||
POBJECT_CREATE_INFORMATION ObjectCreateInfo;
|
||||
PVOID QuotaBlockCharged;
|
||||
};
|
||||
PVOID SecurityDescriptor;
|
||||
QUAD Body;
|
||||
} OBJECT_HEADER, *POBJECT_HEADER;
|
||||
|
||||
#define OBJECT_TO_OBJECT_HEADER(Object) CONTAINING_RECORD((Object), OBJECT_HEADER, Body)
|
||||
|
||||
NTKERNELAPI
|
||||
POBJECT_TYPE
|
||||
NTAPI
|
||||
ObGetObjectType(
|
||||
__in PVOID Object
|
||||
);
|
||||
|
||||
NTKERNELAPI
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
ObOpenObjectByName(
|
||||
__in POBJECT_ATTRIBUTES ObjectAttributes,
|
||||
__in POBJECT_TYPE ObjectType,
|
||||
__in KPROCESSOR_MODE PreviousMode,
|
||||
__in_opt PACCESS_STATE AccessState,
|
||||
__in_opt ACCESS_MASK DesiredAccess,
|
||||
__in PVOID ParseContext,
|
||||
__out PHANDLE Handle
|
||||
);
|
||||
|
||||
NTKERNELAPI
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
ObSetHandleAttributes(
|
||||
__in HANDLE Handle,
|
||||
__in POBJECT_HANDLE_FLAG_INFORMATION HandleFlags,
|
||||
__in KPROCESSOR_MODE PreviousMode
|
||||
);
|
||||
|
||||
NTKERNELAPI
|
||||
NTSTATUS
|
||||
ObCloseHandle(
|
||||
__in HANDLE Handle,
|
||||
__in KPROCESSOR_MODE PreviousMode
|
||||
);
|
||||
|
||||
// PS
|
||||
|
||||
NTSYSCALLAPI
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
ZwQueryInformationProcess(
|
||||
__in HANDLE ProcessHandle,
|
||||
__in PROCESSINFOCLASS ProcessInformationClass,
|
||||
__out_bcount(ProcessInformationLength) PVOID ProcessInformation,
|
||||
__in ULONG ProcessInformationLength,
|
||||
__out_opt PULONG ReturnLength
|
||||
);
|
||||
|
||||
NTSYSCALLAPI
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
ZwSetInformationProcess(
|
||||
__in HANDLE ProcessHandle,
|
||||
__in PROCESSINFOCLASS ProcessInformationClass,
|
||||
__in_bcount(ProcessInformationLength) PVOID ProcessInformation,
|
||||
__in ULONG ProcessInformationLength
|
||||
);
|
||||
|
||||
NTSYSCALLAPI
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
ZwQueryInformationThread(
|
||||
__in HANDLE ThreadHandle,
|
||||
__in THREADINFOCLASS ThreadInformationClass,
|
||||
__out_bcount(ThreadInformationLength) PVOID ThreadInformation,
|
||||
__in ULONG ThreadInformationLength,
|
||||
__out_opt PULONG ReturnLength
|
||||
);
|
||||
|
||||
NTKERNELAPI
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
PsLookupProcessThreadByCid(
|
||||
__in PCLIENT_ID ClientId,
|
||||
__out_opt PEPROCESS *Process,
|
||||
__out PETHREAD *Thread
|
||||
);
|
||||
|
||||
NTKERNELAPI
|
||||
PVOID
|
||||
NTAPI
|
||||
PsGetThreadWin32Thread(
|
||||
__in PETHREAD Thread
|
||||
);
|
||||
|
||||
typedef struct _EJOB *PEJOB;
|
||||
|
||||
extern POBJECT_TYPE *PsJobType;
|
||||
|
||||
NTKERNELAPI
|
||||
PEJOB
|
||||
NTAPI
|
||||
PsGetProcessJob(
|
||||
__in PEPROCESS Process
|
||||
);
|
||||
|
||||
NTKERNELAPI
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
PsAcquireProcessExitSynchronization(
|
||||
__in PEPROCESS Process
|
||||
);
|
||||
|
||||
NTKERNELAPI
|
||||
VOID
|
||||
NTAPI
|
||||
PsReleaseProcessExitSynchronization(
|
||||
__in PEPROCESS Process
|
||||
);
|
||||
|
||||
// RTL
|
||||
|
||||
// Sensible limit that may or may not correspond to the actual Windows value.
|
||||
#define MAX_STACK_DEPTH 256
|
||||
|
||||
#define RTL_WALK_USER_MODE_STACK 0x00000001
|
||||
#define RTL_WALK_VALID_FLAGS 0x00000001
|
||||
|
||||
NTSYSAPI
|
||||
ULONG
|
||||
NTAPI
|
||||
RtlWalkFrameChain(
|
||||
__out PVOID *Callers,
|
||||
__in ULONG Count,
|
||||
__in ULONG Flags
|
||||
);
|
||||
|
||||
#endif
|
||||
356
KProcessHacker/main.c
Normal file
356
KProcessHacker/main.c
Normal file
@@ -0,0 +1,356 @@
|
||||
/*
|
||||
* KProcessHacker
|
||||
*
|
||||
* Copyright (C) 2010-2016 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <kph.h>
|
||||
#include <dyndata.h>
|
||||
|
||||
DRIVER_INITIALIZE DriverEntry;
|
||||
DRIVER_UNLOAD DriverUnload;
|
||||
__drv_dispatchType(IRP_MJ_CREATE) DRIVER_DISPATCH KphDispatchCreate;
|
||||
__drv_dispatchType(IRP_MJ_CLOSE) DRIVER_DISPATCH KphDispatchClose;
|
||||
|
||||
ULONG KphpReadIntegerParameter(
|
||||
__in_opt HANDLE KeyHandle,
|
||||
__in PUNICODE_STRING ValueName,
|
||||
__in ULONG DefaultValue
|
||||
);
|
||||
|
||||
NTSTATUS KphpReadDriverParameters(
|
||||
__in PUNICODE_STRING RegistryPath
|
||||
);
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, DriverEntry)
|
||||
#pragma alloc_text(PAGE, DriverUnload)
|
||||
#pragma alloc_text(PAGE, KphpReadIntegerParameter)
|
||||
#pragma alloc_text(PAGE, KphpReadDriverParameters)
|
||||
#pragma alloc_text(PAGE, KpiGetFeatures)
|
||||
#endif
|
||||
|
||||
PDRIVER_OBJECT KphDriverObject;
|
||||
PDEVICE_OBJECT KphDeviceObject;
|
||||
ULONG KphFeatures;
|
||||
KPH_PARAMETERS KphParameters;
|
||||
|
||||
NTSTATUS DriverEntry(
|
||||
__in PDRIVER_OBJECT DriverObject,
|
||||
__in PUNICODE_STRING RegistryPath
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
UNICODE_STRING deviceName;
|
||||
PDEVICE_OBJECT deviceObject;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
KphDriverObject = DriverObject;
|
||||
|
||||
if (!NT_SUCCESS(status = KphDynamicDataInitialization()))
|
||||
return status;
|
||||
|
||||
KphDynamicImport();
|
||||
|
||||
if (!NT_SUCCESS(status = KphpReadDriverParameters(RegistryPath)))
|
||||
return status;
|
||||
|
||||
// Create the device.
|
||||
|
||||
RtlInitUnicodeString(&deviceName, KPH_DEVICE_NAME);
|
||||
|
||||
status = IoCreateDevice(
|
||||
DriverObject,
|
||||
0,
|
||||
&deviceName,
|
||||
FILE_DEVICE_UNKNOWN,
|
||||
FILE_DEVICE_SECURE_OPEN,
|
||||
FALSE,
|
||||
&deviceObject
|
||||
);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
return status;
|
||||
|
||||
KphDeviceObject = deviceObject;
|
||||
|
||||
// Set up I/O.
|
||||
|
||||
DriverObject->MajorFunction[IRP_MJ_CREATE] = KphDispatchCreate;
|
||||
DriverObject->MajorFunction[IRP_MJ_CLOSE] = KphDispatchClose;
|
||||
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KphDispatchDeviceControl;
|
||||
DriverObject->DriverUnload = DriverUnload;
|
||||
|
||||
deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
|
||||
|
||||
dprintf("Driver loaded\n");
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
VOID DriverUnload(
|
||||
__in PDRIVER_OBJECT DriverObject
|
||||
)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
IoDeleteDevice(KphDeviceObject);
|
||||
|
||||
dprintf("Driver unloaded\n");
|
||||
}
|
||||
|
||||
NTSTATUS KphDispatchCreate(
|
||||
__in PDEVICE_OBJECT DeviceObject,
|
||||
__in PIRP Irp
|
||||
)
|
||||
{
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
PIO_STACK_LOCATION stackLocation;
|
||||
PFILE_OBJECT fileObject;
|
||||
PIO_SECURITY_CONTEXT securityContext;
|
||||
PKPH_CLIENT client;
|
||||
|
||||
stackLocation = IoGetCurrentIrpStackLocation(Irp);
|
||||
fileObject = stackLocation->FileObject;
|
||||
securityContext = stackLocation->Parameters.Create.SecurityContext;
|
||||
|
||||
dprintf("Client (PID %Iu) is connecting\n", PsGetCurrentProcessId());
|
||||
|
||||
if (KphParameters.SecurityLevel == KphSecurityPrivilegeCheck ||
|
||||
KphParameters.SecurityLevel == KphSecuritySignatureAndPrivilegeCheck)
|
||||
{
|
||||
UCHAR requiredPrivilegesBuffer[FIELD_OFFSET(PRIVILEGE_SET, Privilege) + sizeof(LUID_AND_ATTRIBUTES)];
|
||||
PPRIVILEGE_SET requiredPrivileges;
|
||||
|
||||
// Check for SeDebugPrivilege.
|
||||
|
||||
requiredPrivileges = (PPRIVILEGE_SET)requiredPrivilegesBuffer;
|
||||
requiredPrivileges->PrivilegeCount = 1;
|
||||
requiredPrivileges->Control = PRIVILEGE_SET_ALL_NECESSARY;
|
||||
requiredPrivileges->Privilege[0].Luid.LowPart = SE_DEBUG_PRIVILEGE;
|
||||
requiredPrivileges->Privilege[0].Luid.HighPart = 0;
|
||||
requiredPrivileges->Privilege[0].Attributes = 0;
|
||||
|
||||
if (!SePrivilegeCheck(
|
||||
requiredPrivileges,
|
||||
&securityContext->AccessState->SubjectSecurityContext,
|
||||
Irp->RequestorMode
|
||||
))
|
||||
{
|
||||
status = STATUS_PRIVILEGE_NOT_HELD;
|
||||
dprintf("Client (PID %Iu) was rejected\n", PsGetCurrentProcessId());
|
||||
}
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(status))
|
||||
{
|
||||
client = ExAllocatePoolWithTag(PagedPool, sizeof(KPH_CLIENT), 'ChpK');
|
||||
|
||||
if (client)
|
||||
{
|
||||
memset(client, 0, sizeof(KPH_CLIENT));
|
||||
|
||||
ExInitializeFastMutex(&client->StateMutex);
|
||||
ExInitializeFastMutex(&client->KeyBackoffMutex);
|
||||
|
||||
fileObject->FsContext = client;
|
||||
}
|
||||
else
|
||||
{
|
||||
dprintf("Unable to allocate memory for client (PID %Iu)\n", PsGetCurrentProcessId());
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
}
|
||||
|
||||
Irp->IoStatus.Status = status;
|
||||
Irp->IoStatus.Information = 0;
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS KphDispatchClose(
|
||||
__in PDEVICE_OBJECT DeviceObject,
|
||||
__in PIRP Irp
|
||||
)
|
||||
{
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
PIO_STACK_LOCATION stackLocation;
|
||||
PFILE_OBJECT fileObject;
|
||||
PKPH_CLIENT client;
|
||||
|
||||
stackLocation = IoGetCurrentIrpStackLocation(Irp);
|
||||
fileObject = stackLocation->FileObject;
|
||||
client = fileObject->FsContext;
|
||||
|
||||
if (client)
|
||||
{
|
||||
ExFreePoolWithTag(client, 'ChpK');
|
||||
}
|
||||
|
||||
Irp->IoStatus.Status = status;
|
||||
Irp->IoStatus.Information = 0;
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an integer (REG_DWORD) parameter from the registry.
|
||||
*
|
||||
* \param KeyHandle A handle to the Parameters key. If NULL, the function
|
||||
* fails immediately and returns \a DefaultValue.
|
||||
* \param ValueName The name of the parameter.
|
||||
* \param DefaultValue The value that is returned if the function fails
|
||||
* to retrieve the parameter from the registry.
|
||||
*
|
||||
* \return The parameter value, or \a DefaultValue if the function failed.
|
||||
*/
|
||||
ULONG KphpReadIntegerParameter(
|
||||
__in_opt HANDLE KeyHandle,
|
||||
__in PUNICODE_STRING ValueName,
|
||||
__in ULONG DefaultValue
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
UCHAR buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + sizeof(ULONG)];
|
||||
PKEY_VALUE_PARTIAL_INFORMATION info;
|
||||
ULONG resultLength;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
if (!KeyHandle)
|
||||
return DefaultValue;
|
||||
|
||||
info = (PKEY_VALUE_PARTIAL_INFORMATION)buffer;
|
||||
|
||||
status = ZwQueryValueKey(
|
||||
KeyHandle,
|
||||
ValueName,
|
||||
KeyValuePartialInformation,
|
||||
info,
|
||||
sizeof(buffer),
|
||||
&resultLength
|
||||
);
|
||||
|
||||
if (info->Type != REG_DWORD)
|
||||
status = STATUS_OBJECT_TYPE_MISMATCH;
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
dprintf("Unable to query parameter %.*S: 0x%x\n", ValueName->Length / sizeof(WCHAR), ValueName->Buffer, status);
|
||||
return DefaultValue;
|
||||
}
|
||||
|
||||
return *(PULONG)info->Data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the driver parameters.
|
||||
*
|
||||
* \param RegistryPath The registry path of the driver.
|
||||
*/
|
||||
NTSTATUS KphpReadDriverParameters(
|
||||
__in PUNICODE_STRING RegistryPath
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
HANDLE parametersKeyHandle;
|
||||
UNICODE_STRING parametersString;
|
||||
UNICODE_STRING parametersKeyName;
|
||||
OBJECT_ATTRIBUTES objectAttributes;
|
||||
UNICODE_STRING valueName;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
// Open the Parameters key.
|
||||
|
||||
RtlInitUnicodeString(¶metersString, L"\\Parameters");
|
||||
|
||||
parametersKeyName.Length = RegistryPath->Length + parametersString.Length;
|
||||
parametersKeyName.MaximumLength = parametersKeyName.Length;
|
||||
parametersKeyName.Buffer = ExAllocatePoolWithTag(PagedPool, parametersKeyName.MaximumLength, 'ThpK');
|
||||
|
||||
if (!parametersKeyName.Buffer)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
memcpy(parametersKeyName.Buffer, RegistryPath->Buffer, RegistryPath->Length);
|
||||
memcpy(¶metersKeyName.Buffer[RegistryPath->Length / sizeof(WCHAR)], parametersString.Buffer, parametersString.Length);
|
||||
|
||||
InitializeObjectAttributes(
|
||||
&objectAttributes,
|
||||
¶metersKeyName,
|
||||
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
status = ZwOpenKey(
|
||||
¶metersKeyHandle,
|
||||
KEY_READ,
|
||||
&objectAttributes
|
||||
);
|
||||
ExFreePoolWithTag(parametersKeyName.Buffer, 'ThpK');
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
dprintf("Unable to open Parameters key: 0x%x\n", status);
|
||||
status = STATUS_SUCCESS;
|
||||
parametersKeyHandle = NULL;
|
||||
// Continue so we can set up defaults.
|
||||
}
|
||||
|
||||
// Read in the parameters.
|
||||
|
||||
RtlInitUnicodeString(&valueName, L"SecurityLevel");
|
||||
KphParameters.SecurityLevel = KphpReadIntegerParameter(parametersKeyHandle, &valueName, KphSecurityPrivilegeCheck);
|
||||
|
||||
KphReadDynamicDataParameters(parametersKeyHandle);
|
||||
|
||||
if (parametersKeyHandle)
|
||||
ZwClose(parametersKeyHandle);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS KpiGetFeatures(
|
||||
__out PULONG Features,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
if (AccessMode != KernelMode)
|
||||
{
|
||||
__try
|
||||
{
|
||||
ProbeForWrite(Features, sizeof(ULONG), sizeof(ULONG));
|
||||
*Features = KphFeatures;
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
return GetExceptionCode();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*Features = KphFeatures;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
1295
KProcessHacker/object.c
Normal file
1295
KProcessHacker/object.c
Normal file
File diff suppressed because it is too large
Load Diff
570
KProcessHacker/process.c
Normal file
570
KProcessHacker/process.c
Normal file
@@ -0,0 +1,570 @@
|
||||
/*
|
||||
* KProcessHacker
|
||||
*
|
||||
* Copyright (C) 2010-2016 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <kph.h>
|
||||
#include <dyndata.h>
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, KpiOpenProcess)
|
||||
#pragma alloc_text(PAGE, KpiOpenProcessToken)
|
||||
#pragma alloc_text(PAGE, KpiOpenProcessJob)
|
||||
#pragma alloc_text(PAGE, KpiTerminateProcess)
|
||||
#pragma alloc_text(PAGE, KpiQueryInformationProcess)
|
||||
#pragma alloc_text(PAGE, KpiSetInformationProcess)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Opens a process.
|
||||
*
|
||||
* \param ProcessHandle A variable which receives the process handle.
|
||||
* \param DesiredAccess The desired access to the process.
|
||||
* \param ClientId The identifier of a process or thread. If \a UniqueThread is present, the process
|
||||
* of the identified thread will be opened. If \a UniqueProcess is present, the identified process
|
||||
* will be opened.
|
||||
* \param Key An access key.
|
||||
* \li If a L2 key is provided, no access checks are performed.
|
||||
* \li If a L1 key is provided, only read access is permitted but no additional access checks are
|
||||
* performed.
|
||||
* \li If no valid key is provided, the function fails.
|
||||
* \param Client The client that initiated the request.
|
||||
* \param AccessMode The mode in which to perform access checks.
|
||||
*/
|
||||
NTSTATUS KpiOpenProcess(
|
||||
__out PHANDLE ProcessHandle,
|
||||
__in ACCESS_MASK DesiredAccess,
|
||||
__in PCLIENT_ID ClientId,
|
||||
__in_opt KPH_KEY Key,
|
||||
__in PKPH_CLIENT Client,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
CLIENT_ID clientId;
|
||||
PEPROCESS process;
|
||||
PETHREAD thread;
|
||||
KPH_KEY_LEVEL requiredKeyLevel;
|
||||
HANDLE processHandle;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
if (AccessMode != KernelMode)
|
||||
{
|
||||
__try
|
||||
{
|
||||
ProbeForWrite(ProcessHandle, sizeof(HANDLE), sizeof(HANDLE));
|
||||
ProbeForRead(ClientId, sizeof(CLIENT_ID), sizeof(ULONG));
|
||||
clientId = *ClientId;
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
return GetExceptionCode();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
clientId = *ClientId;
|
||||
}
|
||||
|
||||
// Use the thread ID if it was specified.
|
||||
if (clientId.UniqueThread)
|
||||
{
|
||||
status = PsLookupProcessThreadByCid(&clientId, &process, &thread);
|
||||
|
||||
if (NT_SUCCESS(status))
|
||||
{
|
||||
// We don't actually need the thread.
|
||||
ObDereferenceObject(thread);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = PsLookupProcessByProcessId(clientId.UniqueProcess, &process);
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
return status;
|
||||
|
||||
requiredKeyLevel = KphKeyLevel1;
|
||||
|
||||
if ((DesiredAccess & KPH_PROCESS_READ_ACCESS) != DesiredAccess)
|
||||
requiredKeyLevel = KphKeyLevel2;
|
||||
|
||||
if (NT_SUCCESS(status = KphValidateKey(requiredKeyLevel, Key, Client, AccessMode)))
|
||||
{
|
||||
// Always open in KernelMode to skip ordinary access checks.
|
||||
status = ObOpenObjectByPointer(
|
||||
process,
|
||||
0,
|
||||
NULL,
|
||||
DesiredAccess,
|
||||
*PsProcessType,
|
||||
KernelMode,
|
||||
&processHandle
|
||||
);
|
||||
}
|
||||
|
||||
ObDereferenceObject(process);
|
||||
|
||||
if (NT_SUCCESS(status))
|
||||
{
|
||||
if (AccessMode != KernelMode)
|
||||
{
|
||||
__try
|
||||
{
|
||||
*ProcessHandle = processHandle;
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
status = GetExceptionCode();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*ProcessHandle = processHandle;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the token of a process.
|
||||
*
|
||||
* \param ProcessHandle A handle to a process.
|
||||
* \param DesiredAccess The desired access to the token.
|
||||
* \param TokenHandle A variable which receives the token handle.
|
||||
* \param Key An access key.
|
||||
* \li If a L2 key is provided, no access checks are performed.
|
||||
* \li If a L1 key is provided, only read access is permitted but no additional access checks are
|
||||
* performed.
|
||||
* \li If no valid key is provided, the function fails.
|
||||
* \param Client The client that initiated the request.
|
||||
* \param AccessMode The mode in which to perform access checks.
|
||||
*/
|
||||
NTSTATUS KpiOpenProcessToken(
|
||||
__in HANDLE ProcessHandle,
|
||||
__in ACCESS_MASK DesiredAccess,
|
||||
__out PHANDLE TokenHandle,
|
||||
__in_opt KPH_KEY Key,
|
||||
__in PKPH_CLIENT Client,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
PEPROCESS process;
|
||||
PACCESS_TOKEN primaryToken;
|
||||
KPH_KEY_LEVEL requiredKeyLevel;
|
||||
HANDLE tokenHandle;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
if (AccessMode != KernelMode)
|
||||
{
|
||||
__try
|
||||
{
|
||||
ProbeForWrite(TokenHandle, sizeof(HANDLE), sizeof(HANDLE));
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
return GetExceptionCode();
|
||||
}
|
||||
}
|
||||
|
||||
status = ObReferenceObjectByHandle(
|
||||
ProcessHandle,
|
||||
0,
|
||||
*PsProcessType,
|
||||
AccessMode,
|
||||
&process,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
return status;
|
||||
|
||||
if (primaryToken = PsReferencePrimaryToken(process))
|
||||
{
|
||||
requiredKeyLevel = KphKeyLevel1;
|
||||
|
||||
if ((DesiredAccess & KPH_TOKEN_READ_ACCESS) != DesiredAccess)
|
||||
requiredKeyLevel = KphKeyLevel2;
|
||||
|
||||
if (NT_SUCCESS(status = KphValidateKey(requiredKeyLevel, Key, Client, AccessMode)))
|
||||
{
|
||||
status = ObOpenObjectByPointer(
|
||||
primaryToken,
|
||||
0,
|
||||
NULL,
|
||||
DesiredAccess,
|
||||
*SeTokenObjectType,
|
||||
KernelMode,
|
||||
&tokenHandle
|
||||
);
|
||||
}
|
||||
|
||||
PsDereferencePrimaryToken(primaryToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = STATUS_NO_TOKEN;
|
||||
}
|
||||
|
||||
ObDereferenceObject(process);
|
||||
|
||||
if (NT_SUCCESS(status))
|
||||
{
|
||||
if (AccessMode != KernelMode)
|
||||
{
|
||||
__try
|
||||
{
|
||||
*TokenHandle = tokenHandle;
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
status = GetExceptionCode();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*TokenHandle = tokenHandle;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the job object of a process.
|
||||
*
|
||||
* \param ProcessHandle A handle to a process.
|
||||
* \param DesiredAccess The desired access to the job.
|
||||
* \param JobHandle A variable which receives the job object handle.
|
||||
* \param AccessMode The mode in which to perform access checks.
|
||||
*/
|
||||
NTSTATUS KpiOpenProcessJob(
|
||||
__in HANDLE ProcessHandle,
|
||||
__in ACCESS_MASK DesiredAccess,
|
||||
__out PHANDLE JobHandle,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
PEPROCESS process;
|
||||
PEJOB job;
|
||||
HANDLE jobHandle = NULL;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
if (AccessMode != KernelMode)
|
||||
{
|
||||
__try
|
||||
{
|
||||
ProbeForWrite(JobHandle, sizeof(HANDLE), sizeof(HANDLE));
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
return GetExceptionCode();
|
||||
}
|
||||
}
|
||||
|
||||
status = ObReferenceObjectByHandle(
|
||||
ProcessHandle,
|
||||
0,
|
||||
*PsProcessType,
|
||||
AccessMode,
|
||||
&process,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
return status;
|
||||
|
||||
job = PsGetProcessJob(process);
|
||||
|
||||
if (job)
|
||||
{
|
||||
status = ObOpenObjectByPointer(
|
||||
job,
|
||||
0,
|
||||
NULL,
|
||||
DesiredAccess,
|
||||
*PsJobType,
|
||||
AccessMode,
|
||||
&jobHandle
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = STATUS_NOT_FOUND;
|
||||
}
|
||||
|
||||
ObDereferenceObject(process);
|
||||
|
||||
if (NT_SUCCESS(status))
|
||||
{
|
||||
if (AccessMode != KernelMode)
|
||||
{
|
||||
__try
|
||||
{
|
||||
*JobHandle = jobHandle;
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
status = GetExceptionCode();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*JobHandle = jobHandle;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminates a process.
|
||||
*
|
||||
* \param ProcessHandle A handle to a process.
|
||||
* \param ExitStatus A status value which indicates why the process is being terminated.
|
||||
* \param Key An access key.
|
||||
* \li If a L2 key is provided, no access checks are performed.
|
||||
* \li If no valid L2 key is provided, the function fails.
|
||||
* \param Client The client that initiated the request.
|
||||
* \param AccessMode The mode in which to perform access checks.
|
||||
*/
|
||||
NTSTATUS KpiTerminateProcess(
|
||||
__in HANDLE ProcessHandle,
|
||||
__in NTSTATUS ExitStatus,
|
||||
__in_opt KPH_KEY Key,
|
||||
__in PKPH_CLIENT Client,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
PEPROCESS process;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
if (!NT_SUCCESS(status = KphValidateKey(KphKeyLevel2, Key, Client, AccessMode)))
|
||||
return status;
|
||||
|
||||
status = ObReferenceObjectByHandle(
|
||||
ProcessHandle,
|
||||
0,
|
||||
*PsProcessType,
|
||||
AccessMode,
|
||||
&process,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
return status;
|
||||
|
||||
if (process != PsGetCurrentProcess())
|
||||
{
|
||||
HANDLE newProcessHandle;
|
||||
|
||||
// Re-open the process to get a kernel handle.
|
||||
if (NT_SUCCESS(status = ObOpenObjectByPointer(
|
||||
process,
|
||||
OBJ_KERNEL_HANDLE,
|
||||
NULL,
|
||||
PROCESS_TERMINATE,
|
||||
*PsProcessType,
|
||||
KernelMode,
|
||||
&newProcessHandle
|
||||
)))
|
||||
{
|
||||
status = ZwTerminateProcess(newProcessHandle, ExitStatus);
|
||||
ZwClose(newProcessHandle);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = STATUS_CANT_TERMINATE_SELF;
|
||||
}
|
||||
|
||||
ObDereferenceObject(process);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries process information.
|
||||
*
|
||||
* \param ProcessHandle A handle to a process.
|
||||
* \param ProcessInformationClass The type of information to query.
|
||||
* \param ProcessInformation The buffer in which the information will be stored.
|
||||
* \param ProcessInformationLength The number of bytes available in \a ProcessInformation.
|
||||
* \param ReturnLength A variable which receives the number of bytes required to be available in
|
||||
* \a ProcessInformation.
|
||||
* \param AccessMode The mode in which to perform access checks.
|
||||
*/
|
||||
NTSTATUS KpiQueryInformationProcess(
|
||||
__in HANDLE ProcessHandle,
|
||||
__in KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass,
|
||||
__out_bcount(ProcessInformationLength) PVOID ProcessInformation,
|
||||
__in ULONG ProcessInformationLength,
|
||||
__out_opt PULONG ReturnLength,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
PEPROCESS process;
|
||||
ULONG returnLength;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
if (AccessMode != KernelMode)
|
||||
{
|
||||
ULONG alignment;
|
||||
|
||||
switch (ProcessInformationClass)
|
||||
{
|
||||
default:
|
||||
alignment = sizeof(ULONG);
|
||||
break;
|
||||
}
|
||||
|
||||
__try
|
||||
{
|
||||
ProbeForWrite(ProcessInformation, ProcessInformationLength, alignment);
|
||||
|
||||
if (ReturnLength)
|
||||
ProbeForWrite(ReturnLength, sizeof(ULONG), sizeof(ULONG));
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
return GetExceptionCode();
|
||||
}
|
||||
}
|
||||
|
||||
status = ObReferenceObjectByHandle(
|
||||
ProcessHandle,
|
||||
PROCESS_QUERY_INFORMATION,
|
||||
*PsProcessType,
|
||||
AccessMode,
|
||||
&process,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
return status;
|
||||
|
||||
switch (ProcessInformationClass)
|
||||
{
|
||||
default:
|
||||
status = STATUS_INVALID_INFO_CLASS;
|
||||
returnLength = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
ObDereferenceObject(process);
|
||||
|
||||
if (ReturnLength)
|
||||
{
|
||||
if (AccessMode != KernelMode)
|
||||
{
|
||||
__try
|
||||
{
|
||||
*ReturnLength = returnLength;
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
NOTHING;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*ReturnLength = returnLength;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets process information.
|
||||
*
|
||||
* \param ProcessHandle A handle to a process.
|
||||
* \param ProcessInformationClass The type of information to set.
|
||||
* \param ProcessInformation A buffer which contains the information to set.
|
||||
* \param ProcessInformationLength The number of bytes present in \a ProcessInformation.
|
||||
* \param AccessMode The mode in which to perform access checks.
|
||||
*/
|
||||
NTSTATUS KpiSetInformationProcess(
|
||||
__in HANDLE ProcessHandle,
|
||||
__in KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass,
|
||||
__in_bcount(ProcessInformationLength) PVOID ProcessInformation,
|
||||
__in ULONG ProcessInformationLength,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
PEPROCESS process;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
if (AccessMode != KernelMode)
|
||||
{
|
||||
ULONG alignment;
|
||||
|
||||
switch (ProcessInformationClass)
|
||||
{
|
||||
default:
|
||||
alignment = sizeof(ULONG);
|
||||
break;
|
||||
}
|
||||
|
||||
__try
|
||||
{
|
||||
ProbeForRead(ProcessInformation, ProcessInformationLength, alignment);
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
return GetExceptionCode();
|
||||
}
|
||||
}
|
||||
|
||||
status = ObReferenceObjectByHandle(
|
||||
ProcessHandle,
|
||||
PROCESS_SET_INFORMATION,
|
||||
*PsProcessType,
|
||||
AccessMode,
|
||||
&process,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
return status;
|
||||
|
||||
switch (ProcessInformationClass)
|
||||
{
|
||||
default:
|
||||
status = STATUS_INVALID_INFO_CLASS;
|
||||
break;
|
||||
}
|
||||
|
||||
ObDereferenceObject(process);
|
||||
|
||||
return status;
|
||||
}
|
||||
238
KProcessHacker/qrydrv.c
Normal file
238
KProcessHacker/qrydrv.c
Normal file
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
* KProcessHacker
|
||||
*
|
||||
* Copyright (C) 2010-2016 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <kph.h>
|
||||
|
||||
VOID KphpCopyInfoUnicodeString(
|
||||
__out PVOID Information,
|
||||
__in_opt PUNICODE_STRING UnicodeString
|
||||
);
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, KpiOpenDriver)
|
||||
#pragma alloc_text(PAGE, KpiQueryInformationDriver)
|
||||
#pragma alloc_text(PAGE, KphpCopyInfoUnicodeString)
|
||||
#endif
|
||||
|
||||
NTSTATUS KpiOpenDriver(
|
||||
__out PHANDLE DriverHandle,
|
||||
__in ACCESS_MASK DesiredAccess,
|
||||
__in POBJECT_ATTRIBUTES ObjectAttributes,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
return KphOpenNamedObject(
|
||||
DriverHandle,
|
||||
DesiredAccess,
|
||||
ObjectAttributes,
|
||||
*IoDriverObjectType,
|
||||
AccessMode
|
||||
);
|
||||
}
|
||||
|
||||
NTSTATUS KpiQueryInformationDriver(
|
||||
__in HANDLE DriverHandle,
|
||||
__in DRIVER_INFORMATION_CLASS DriverInformationClass,
|
||||
__out_bcount(DriverInformationLength) PVOID DriverInformation,
|
||||
__in ULONG DriverInformationLength,
|
||||
__out_opt PULONG ReturnLength,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
)
|
||||
{
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
PDRIVER_OBJECT driverObject;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
if (AccessMode != KernelMode)
|
||||
{
|
||||
__try
|
||||
{
|
||||
ProbeForWrite(DriverInformation, DriverInformationLength, 1);
|
||||
|
||||
if (ReturnLength)
|
||||
ProbeForWrite(ReturnLength, sizeof(ULONG), 1);
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
return GetExceptionCode();
|
||||
}
|
||||
}
|
||||
|
||||
status = ObReferenceObjectByHandle(
|
||||
DriverHandle,
|
||||
0,
|
||||
*IoDriverObjectType,
|
||||
AccessMode,
|
||||
&driverObject,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
return status;
|
||||
|
||||
__try
|
||||
{
|
||||
switch (DriverInformationClass)
|
||||
{
|
||||
// Basic information such as flags, driver base and driver size.
|
||||
case DriverBasicInformation:
|
||||
{
|
||||
if (DriverInformationLength == sizeof(DRIVER_BASIC_INFORMATION))
|
||||
{
|
||||
PDRIVER_BASIC_INFORMATION basicInfo;
|
||||
|
||||
basicInfo = (PDRIVER_BASIC_INFORMATION)DriverInformation;
|
||||
basicInfo->Flags = driverObject->Flags;
|
||||
basicInfo->DriverStart = driverObject->DriverStart;
|
||||
basicInfo->DriverSize = driverObject->DriverSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = STATUS_INFO_LENGTH_MISMATCH;
|
||||
}
|
||||
|
||||
if (ReturnLength)
|
||||
*ReturnLength = sizeof(DRIVER_BASIC_INFORMATION);
|
||||
}
|
||||
break;
|
||||
|
||||
// The name of the driver - e.g. \Driver\Null.
|
||||
case DriverNameInformation:
|
||||
{
|
||||
if (DriverInformation)
|
||||
{
|
||||
/* Check buffer length. */
|
||||
if (sizeof(UNICODE_STRING) + driverObject->DriverName.Length <=
|
||||
DriverInformationLength)
|
||||
{
|
||||
KphpCopyInfoUnicodeString(
|
||||
DriverInformation,
|
||||
&driverObject->DriverName
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = STATUS_BUFFER_TOO_SMALL;
|
||||
}
|
||||
}
|
||||
|
||||
if (ReturnLength)
|
||||
*ReturnLength = sizeof(UNICODE_STRING) + driverObject->DriverName.Length;
|
||||
}
|
||||
break;
|
||||
|
||||
// The name of the driver's service key - e.g. \REGISTRY\...
|
||||
case DriverServiceKeyNameInformation:
|
||||
{
|
||||
if (driverObject->DriverExtension)
|
||||
{
|
||||
if (DriverInformation)
|
||||
{
|
||||
if (sizeof(UNICODE_STRING) +
|
||||
driverObject->DriverExtension->ServiceKeyName.Length <=
|
||||
DriverInformationLength)
|
||||
{
|
||||
KphpCopyInfoUnicodeString(
|
||||
DriverInformation,
|
||||
&driverObject->DriverExtension->ServiceKeyName
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = STATUS_BUFFER_TOO_SMALL;
|
||||
}
|
||||
}
|
||||
|
||||
if (ReturnLength)
|
||||
{
|
||||
*ReturnLength = sizeof(UNICODE_STRING) +
|
||||
driverObject->DriverExtension->ServiceKeyName.Length;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (DriverInformation)
|
||||
{
|
||||
if (sizeof(UNICODE_STRING) <= DriverInformationLength)
|
||||
{
|
||||
// Zero the information buffer.
|
||||
KphpCopyInfoUnicodeString(
|
||||
DriverInformation,
|
||||
NULL
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = STATUS_BUFFER_TOO_SMALL;
|
||||
}
|
||||
}
|
||||
|
||||
if (ReturnLength)
|
||||
*ReturnLength = sizeof(UNICODE_STRING);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
status = STATUS_INVALID_INFO_CLASS;
|
||||
}
|
||||
}
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
status = GetExceptionCode();
|
||||
}
|
||||
|
||||
ObDereferenceObject(driverObject);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
VOID KphpCopyInfoUnicodeString(
|
||||
__out PVOID Information,
|
||||
__in_opt PUNICODE_STRING UnicodeString
|
||||
)
|
||||
{
|
||||
PUNICODE_STRING targetUnicodeString = Information;
|
||||
PWCHAR targetBuffer;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
if (UnicodeString)
|
||||
{
|
||||
targetBuffer = (PWCHAR)((PCHAR)Information + sizeof(UNICODE_STRING));
|
||||
|
||||
targetUnicodeString->Length = UnicodeString->Length;
|
||||
targetUnicodeString->MaximumLength = UnicodeString->Length;
|
||||
targetUnicodeString->Buffer = targetBuffer;
|
||||
memcpy(targetBuffer, UnicodeString->Buffer, UnicodeString->Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
targetUnicodeString->Length = 0;
|
||||
targetUnicodeString->MaximumLength = 0;
|
||||
targetUnicodeString->Buffer = NULL;
|
||||
}
|
||||
}
|
||||
53
KProcessHacker/resource.rc
Normal file
53
KProcessHacker/resource.rc
Normal file
@@ -0,0 +1,53 @@
|
||||
#include <windows.h>
|
||||
|
||||
#define VER_COMMA 3,0,0,0
|
||||
#define VER_STR "3.0\0"
|
||||
|
||||
#define VER_FILEVERSION VER_COMMA
|
||||
#define VER_FILEVERSION_STR VER_STR
|
||||
#define VER_PRODUCTVERSION VER_COMMA
|
||||
#define VER_PRODUCTVERSION_STR VER_STR
|
||||
|
||||
#ifndef DEBUG
|
||||
#define VER_DEBUG 0
|
||||
#else
|
||||
#define VER_DEBUG VS_FF_DEBUG
|
||||
#endif
|
||||
|
||||
#define VER_PRIVATEBUILD 0
|
||||
#define VER_PRERELEASE 0
|
||||
|
||||
#define VER_COMPANYNAME_STR "wj32\0"
|
||||
#define VER_FILEDESCRIPTION_STR "KProcessHacker\0"
|
||||
#define VER_LEGALCOPYRIGHT_STR "Licensed under the GNU GPL, v3.\0"
|
||||
#define VER_ORIGINALFILENAME_STR "kprocesshacker.sys\0"
|
||||
#define VER_PRODUCTNAME_STR "KProcessHacker\0"
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION VER_FILEVERSION
|
||||
PRODUCTVERSION VER_PRODUCTVERSION
|
||||
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
|
||||
FILEFLAGS (VER_PRIVATEBUILD | VER_PRERELEASE | VER_DEBUG)
|
||||
FILEOS VOS__WINDOWS32
|
||||
FILETYPE VFT_DRV
|
||||
FILESUBTYPE VFT2_DRV_SYSTEM
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904E4"
|
||||
BEGIN
|
||||
VALUE "CompanyName", VER_COMPANYNAME_STR
|
||||
VALUE "FileDescription", VER_FILEDESCRIPTION_STR
|
||||
VALUE "FileVersion", VER_FILEVERSION_STR
|
||||
VALUE "LegalCopyright", VER_LEGALCOPYRIGHT_STR
|
||||
VALUE "OriginalFilename", VER_ORIGINALFILENAME_STR
|
||||
VALUE "ProductName", VER_PRODUCTNAME_STR
|
||||
VALUE "ProductVersion", VER_PRODUCTVERSION_STR
|
||||
END
|
||||
END
|
||||
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1252
|
||||
END
|
||||
END
|
||||
7
KProcessHacker/sign.cmd
Normal file
7
KProcessHacker/sign.cmd
Normal file
@@ -0,0 +1,7 @@
|
||||
@echo off
|
||||
set PHBASE=..
|
||||
set SIGN_TIMESTAMP=1
|
||||
copy bin\i386\kprocesshacker.sys bin-signed\i386\kprocesshacker.sys
|
||||
copy bin\amd64\kprocesshacker.sys bin-signed\amd64\kprocesshacker.sys
|
||||
call ..\build\internal\sign.cmd bin-signed\i386\kprocesshacker.sys kmcs
|
||||
call ..\build\internal\sign.cmd bin-signed\amd64\kprocesshacker.sys kmcs
|
||||
28
KProcessHacker/sources.inc
Normal file
28
KProcessHacker/sources.inc
Normal file
@@ -0,0 +1,28 @@
|
||||
TARGETTYPE=DRIVER
|
||||
|
||||
!IF !DEFINED(TARGETNAME)
|
||||
TARGETNAME=kprocesshacker
|
||||
!ENDIF
|
||||
|
||||
!IF !DEFINED(TARGETPATH)
|
||||
TARGETPATH=..\bin
|
||||
!ENDIF
|
||||
|
||||
TARGETLIBS=$(TARGETLIBS) $(DDK_LIB_PATH)\ksecdd.lib
|
||||
|
||||
INCLUDES=$(DDK_INC_PATH);..\include;..\..\phnt\include;..\..\phlib\include
|
||||
LIBS=%BUILD%\lib
|
||||
|
||||
SOURCES= \
|
||||
..\main.c \
|
||||
..\devctrl.c \
|
||||
..\dyndata.c \
|
||||
..\dynimp.c \
|
||||
..\object.c \
|
||||
..\process.c \
|
||||
..\qrydrv.c \
|
||||
..\thread.c \
|
||||
..\util.c \
|
||||
..\verify.c \
|
||||
..\vm.c \
|
||||
..\resource.rc
|
||||
714
KProcessHacker/thread.c
Normal file
714
KProcessHacker/thread.c
Normal file
@@ -0,0 +1,714 @@
|
||||
/*
|
||||
* KProcessHacker
|
||||
*
|
||||
* Copyright (C) 2010-2016 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <kph.h>
|
||||
#include <dyndata.h>
|
||||
|
||||
typedef struct _CAPTURE_BACKTRACE_THREAD_CONTEXT
|
||||
{
|
||||
BOOLEAN Local;
|
||||
KAPC Apc;
|
||||
KEVENT CompletedEvent;
|
||||
ULONG FramesToSkip;
|
||||
ULONG FramesToCapture;
|
||||
PVOID *BackTrace;
|
||||
ULONG CapturedFrames;
|
||||
ULONG BackTraceHash;
|
||||
} CAPTURE_BACKTRACE_THREAD_CONTEXT, *PCAPTURE_BACKTRACE_THREAD_CONTEXT;
|
||||
|
||||
KKERNEL_ROUTINE KphpCaptureStackBackTraceThreadSpecialApc;
|
||||
|
||||
VOID KphpCaptureStackBackTraceThreadSpecialApc(
|
||||
__in PRKAPC Apc,
|
||||
__inout PKNORMAL_ROUTINE *NormalRoutine,
|
||||
__inout PVOID *NormalContext,
|
||||
__inout PVOID *SystemArgument1,
|
||||
__inout PVOID *SystemArgument2
|
||||
);
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, KpiOpenThread)
|
||||
#pragma alloc_text(PAGE, KpiOpenThreadProcess)
|
||||
#pragma alloc_text(PAGE, KphCaptureStackBackTraceThread)
|
||||
#pragma alloc_text(PAGE, KphpCaptureStackBackTraceThreadSpecialApc)
|
||||
#pragma alloc_text(PAGE, KpiCaptureStackBackTraceThread)
|
||||
#pragma alloc_text(PAGE, KpiQueryInformationThread)
|
||||
#pragma alloc_text(PAGE, KpiSetInformationThread)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Opens a thread.
|
||||
*
|
||||
* \param ThreadHandle A variable which receives the thread handle.
|
||||
* \param DesiredAccess The desired access to the thread.
|
||||
* \param ClientId The identifier of a thread. \a UniqueThread must be present. If \a UniqueProcess
|
||||
* is present, the process of the referenced thread will be checked against this identifier.
|
||||
* \param Key An access key.
|
||||
* \li If a L2 key is provided, no access checks are performed.
|
||||
* \li If a L1 key is provided, only read access is permitted but no additional access checks are
|
||||
* performed.
|
||||
* \li If no valid key is provided, the function fails.
|
||||
* \param Client The client that initiated the request.
|
||||
* \param AccessMode The mode in which to perform access checks.
|
||||
*/
|
||||
NTSTATUS KpiOpenThread(
|
||||
__out PHANDLE ThreadHandle,
|
||||
__in ACCESS_MASK DesiredAccess,
|
||||
__in PCLIENT_ID ClientId,
|
||||
__in_opt KPH_KEY Key,
|
||||
__in PKPH_CLIENT Client,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
CLIENT_ID clientId;
|
||||
PETHREAD thread;
|
||||
KPH_KEY_LEVEL requiredKeyLevel;
|
||||
HANDLE threadHandle;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
if (AccessMode != KernelMode)
|
||||
{
|
||||
__try
|
||||
{
|
||||
ProbeForWrite(ThreadHandle, sizeof(HANDLE), sizeof(HANDLE));
|
||||
ProbeForRead(ClientId, sizeof(CLIENT_ID), sizeof(ULONG));
|
||||
clientId = *ClientId;
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
return GetExceptionCode();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
clientId = *ClientId;
|
||||
}
|
||||
|
||||
// Use the process ID if it was specified.
|
||||
if (clientId.UniqueProcess)
|
||||
{
|
||||
status = PsLookupProcessThreadByCid(&clientId, NULL, &thread);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = PsLookupThreadByThreadId(clientId.UniqueThread, &thread);
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
return status;
|
||||
|
||||
|
||||
requiredKeyLevel = KphKeyLevel1;
|
||||
|
||||
if ((DesiredAccess & KPH_THREAD_READ_ACCESS) != DesiredAccess)
|
||||
requiredKeyLevel = KphKeyLevel2;
|
||||
|
||||
if (NT_SUCCESS(status = KphValidateKey(requiredKeyLevel, Key, Client, AccessMode)))
|
||||
{
|
||||
// Always open in KernelMode to skip access checks.
|
||||
status = ObOpenObjectByPointer(
|
||||
thread,
|
||||
0,
|
||||
NULL,
|
||||
DesiredAccess,
|
||||
*PsThreadType,
|
||||
KernelMode,
|
||||
&threadHandle
|
||||
);
|
||||
}
|
||||
|
||||
ObDereferenceObject(thread);
|
||||
|
||||
if (NT_SUCCESS(status))
|
||||
{
|
||||
if (AccessMode != KernelMode)
|
||||
{
|
||||
__try
|
||||
{
|
||||
*ThreadHandle = threadHandle;
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
status = GetExceptionCode();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*ThreadHandle = threadHandle;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the process of a thread.
|
||||
*
|
||||
* \param ThreadHandle A handle to a thread.
|
||||
* \param DesiredAccess The desired access to the process.
|
||||
* \param ProcessHandle A variable which receives the process handle.
|
||||
* \param AccessMode The mode in which to perform access checks.
|
||||
*/
|
||||
NTSTATUS KpiOpenThreadProcess(
|
||||
__in HANDLE ThreadHandle,
|
||||
__in ACCESS_MASK DesiredAccess,
|
||||
__out PHANDLE ProcessHandle,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
PETHREAD thread;
|
||||
PEPROCESS process;
|
||||
HANDLE processHandle;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
if (AccessMode != KernelMode)
|
||||
{
|
||||
__try
|
||||
{
|
||||
ProbeForWrite(ProcessHandle, sizeof(HANDLE), sizeof(HANDLE));
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
return GetExceptionCode();
|
||||
}
|
||||
}
|
||||
|
||||
status = ObReferenceObjectByHandle(
|
||||
ThreadHandle,
|
||||
0,
|
||||
*PsThreadType,
|
||||
AccessMode,
|
||||
&thread,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
return status;
|
||||
|
||||
process = IoThreadToProcess(thread);
|
||||
|
||||
status = ObOpenObjectByPointer(
|
||||
process,
|
||||
0,
|
||||
NULL,
|
||||
DesiredAccess,
|
||||
*PsProcessType,
|
||||
AccessMode,
|
||||
&processHandle
|
||||
);
|
||||
|
||||
ObDereferenceObject(thread);
|
||||
|
||||
if (NT_SUCCESS(status))
|
||||
{
|
||||
if (AccessMode != KernelMode)
|
||||
{
|
||||
__try
|
||||
{
|
||||
*ProcessHandle = processHandle;
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
status = GetExceptionCode();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*ProcessHandle = processHandle;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Captures a stack trace of the current thread.
|
||||
*
|
||||
* \param FramesToSkip The number of frames to skip from the bottom of the stack.
|
||||
* \param FramesToCapture The number of frames to capture.
|
||||
* \param Flags A combination of the following:
|
||||
* \li \c RTL_WALK_USER_MODE_STACK The user-mode stack will be retrieved instead of the kernel-mode
|
||||
* stack.
|
||||
* \param BackTrace An array in which the stack trace will be stored.
|
||||
* \param BackTraceHash A variable which receives a hash of the stack trace.
|
||||
*
|
||||
* \return The number of frames captured.
|
||||
*/
|
||||
ULONG KphCaptureStackBackTrace(
|
||||
__in ULONG FramesToSkip,
|
||||
__in ULONG FramesToCapture,
|
||||
__in_opt ULONG Flags,
|
||||
__out_ecount(FramesToCapture) PVOID *BackTrace,
|
||||
__out_opt PULONG BackTraceHash
|
||||
)
|
||||
{
|
||||
PVOID backTrace[MAX_STACK_DEPTH];
|
||||
ULONG framesFound;
|
||||
ULONG hash;
|
||||
ULONG i;
|
||||
|
||||
// Skip the current frame (for this function).
|
||||
FramesToSkip++;
|
||||
|
||||
// Ensure that we won't overrun the buffer.
|
||||
if (FramesToCapture + FramesToSkip > MAX_STACK_DEPTH)
|
||||
return 0;
|
||||
// Validate the flags.
|
||||
if ((Flags & RTL_WALK_VALID_FLAGS) != Flags)
|
||||
return 0;
|
||||
|
||||
// Walk the stack.
|
||||
framesFound = RtlWalkFrameChain(
|
||||
backTrace,
|
||||
FramesToCapture + FramesToSkip,
|
||||
Flags
|
||||
);
|
||||
// Return nothing if we found fewer frames than we wanted to skip.
|
||||
if (framesFound <= FramesToSkip)
|
||||
return 0;
|
||||
|
||||
// Copy over the stack trace. At the same time we calculate the stack trace hash by summing the
|
||||
// addresses.
|
||||
for (i = 0, hash = 0; i < FramesToCapture; i++)
|
||||
{
|
||||
if (FramesToSkip + i >= framesFound)
|
||||
break;
|
||||
|
||||
BackTrace[i] = backTrace[FramesToSkip + i];
|
||||
hash += PtrToUlong(BackTrace[i]);
|
||||
}
|
||||
|
||||
if (BackTraceHash)
|
||||
*BackTraceHash = hash;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Captures the stack trace of a thread.
|
||||
*
|
||||
* \param Thread The thread to capture the stack trace of.
|
||||
* \param FramesToSkip The number of frames to skip from the bottom of the stack.
|
||||
* \param FramesToCapture The number of frames to capture.
|
||||
* \param BackTrace An array in which the stack trace will be stored.
|
||||
* \param CapturedFrames A variable which receives the number of frames captured.
|
||||
* \param BackTraceHash A variable which receives a hash of the stack trace.
|
||||
* \param AccessMode The mode in which to perform access checks.
|
||||
*
|
||||
* \return The number of frames captured.
|
||||
*/
|
||||
NTSTATUS KphCaptureStackBackTraceThread(
|
||||
__in PETHREAD Thread,
|
||||
__in ULONG FramesToSkip,
|
||||
__in ULONG FramesToCapture,
|
||||
__out_ecount(FramesToCapture) PVOID *BackTrace,
|
||||
__out_opt PULONG CapturedFrames,
|
||||
__out_opt PULONG BackTraceHash,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
)
|
||||
{
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
CAPTURE_BACKTRACE_THREAD_CONTEXT context;
|
||||
ULONG backTraceSize;
|
||||
PVOID *backTrace;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
// Make sure the caller didn't request too many frames. This also restricts the amount of memory
|
||||
// we will try to allocate later.
|
||||
if (FramesToCapture > MAX_STACK_DEPTH)
|
||||
return STATUS_INVALID_PARAMETER_3;
|
||||
|
||||
backTraceSize = FramesToCapture * sizeof(PVOID);
|
||||
|
||||
if (AccessMode != KernelMode)
|
||||
{
|
||||
__try
|
||||
{
|
||||
ProbeForWrite(BackTrace, backTraceSize, sizeof(PVOID));
|
||||
|
||||
if (CapturedFrames)
|
||||
ProbeForWrite(CapturedFrames, sizeof(ULONG), sizeof(ULONG));
|
||||
if (BackTraceHash)
|
||||
ProbeForWrite(BackTraceHash, sizeof(ULONG), sizeof(ULONG));
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
return GetExceptionCode();
|
||||
}
|
||||
}
|
||||
|
||||
// If the caller doesn't want to capture anything, return immediately.
|
||||
if (backTraceSize == 0)
|
||||
{
|
||||
if (AccessMode != KernelMode)
|
||||
{
|
||||
__try
|
||||
{
|
||||
if (CapturedFrames)
|
||||
*CapturedFrames = 0;
|
||||
if (BackTraceHash)
|
||||
*BackTraceHash = 0;
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
status = GetExceptionCode();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (CapturedFrames)
|
||||
*CapturedFrames = 0;
|
||||
if (BackTraceHash)
|
||||
*BackTraceHash = 0;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// Allocate storage for the stack trace.
|
||||
backTrace = ExAllocatePoolWithTag(NonPagedPool, backTraceSize, 'bhpK');
|
||||
|
||||
if (!backTrace)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
// Initialize the context structure.
|
||||
context.FramesToSkip = FramesToSkip;
|
||||
context.FramesToCapture = FramesToCapture;
|
||||
context.BackTrace = backTrace;
|
||||
|
||||
// Check if we're trying to get a stack trace of the current thread.
|
||||
// If so, we don't need to insert an APC.
|
||||
if (Thread == PsGetCurrentThread())
|
||||
{
|
||||
PCAPTURE_BACKTRACE_THREAD_CONTEXT contextPtr = &context;
|
||||
PVOID dummy = NULL;
|
||||
KIRQL oldIrql;
|
||||
|
||||
// Raise the IRQL to APC_LEVEL to simulate an APC environment,
|
||||
// and call the APC routine directly.
|
||||
|
||||
context.Local = TRUE;
|
||||
KeRaiseIrql(APC_LEVEL, &oldIrql);
|
||||
KphpCaptureStackBackTraceThreadSpecialApc(
|
||||
&context.Apc,
|
||||
NULL,
|
||||
NULL,
|
||||
&contextPtr,
|
||||
&dummy
|
||||
);
|
||||
KeLowerIrql(oldIrql);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Local = FALSE;
|
||||
KeInitializeEvent(&context.CompletedEvent, NotificationEvent, FALSE);
|
||||
KeInitializeApc(
|
||||
&context.Apc,
|
||||
(PKTHREAD)Thread,
|
||||
OriginalApcEnvironment,
|
||||
KphpCaptureStackBackTraceThreadSpecialApc,
|
||||
NULL,
|
||||
NULL,
|
||||
KernelMode,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (KeInsertQueueApc(&context.Apc, &context, NULL, 2))
|
||||
{
|
||||
// Wait for the APC to complete.
|
||||
status = KeWaitForSingleObject(
|
||||
&context.CompletedEvent,
|
||||
Executive,
|
||||
KernelMode,
|
||||
FALSE,
|
||||
NULL
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(status))
|
||||
{
|
||||
ASSERT(context.CapturedFrames <= FramesToCapture);
|
||||
|
||||
if (AccessMode != KernelMode)
|
||||
{
|
||||
__try
|
||||
{
|
||||
memcpy(BackTrace, backTrace, context.CapturedFrames * sizeof(PVOID));
|
||||
|
||||
if (CapturedFrames)
|
||||
*CapturedFrames = context.CapturedFrames;
|
||||
if (BackTraceHash)
|
||||
*BackTraceHash = context.BackTraceHash;
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
status = GetExceptionCode();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(BackTrace, backTrace, context.CapturedFrames * sizeof(PVOID));
|
||||
|
||||
if (CapturedFrames)
|
||||
*CapturedFrames = context.CapturedFrames;
|
||||
if (BackTraceHash)
|
||||
*BackTraceHash = context.BackTraceHash;
|
||||
}
|
||||
}
|
||||
|
||||
ExFreePoolWithTag(backTrace, 'bhpK');
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
VOID KphpCaptureStackBackTraceThreadSpecialApc(
|
||||
__in PRKAPC Apc,
|
||||
__inout PKNORMAL_ROUTINE *NormalRoutine,
|
||||
__inout PVOID *NormalContext,
|
||||
__inout PVOID *SystemArgument1,
|
||||
__inout PVOID *SystemArgument2
|
||||
)
|
||||
{
|
||||
PCAPTURE_BACKTRACE_THREAD_CONTEXT context = *SystemArgument1;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
context->CapturedFrames = KphCaptureStackBackTrace(
|
||||
context->FramesToSkip,
|
||||
context->FramesToCapture,
|
||||
0,
|
||||
context->BackTrace,
|
||||
&context->BackTraceHash
|
||||
);
|
||||
|
||||
if (!context->Local)
|
||||
{
|
||||
// Notify the originating thread that we have completed.
|
||||
KeSetEvent(&context->CompletedEvent, 0, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Captures the stack trace of a thread.
|
||||
*
|
||||
* \param ThreadHandle A handle to the thread to capture the stack trace of.
|
||||
* \param FramesToSkip The number of frames to skip from the bottom of the stack.
|
||||
* \param FramesToCapture The number of frames to capture.
|
||||
* \param BackTrace An array in which the stack trace will be stored.
|
||||
* \param CapturedFrames A variable which receives the number of frames captured.
|
||||
* \param BackTraceHash A variable which receives a hash of the stack trace.
|
||||
* \param AccessMode The mode in which to perform access checks.
|
||||
*
|
||||
* \return The number of frames captured.
|
||||
*/
|
||||
NTSTATUS KpiCaptureStackBackTraceThread(
|
||||
__in HANDLE ThreadHandle,
|
||||
__in ULONG FramesToSkip,
|
||||
__in ULONG FramesToCapture,
|
||||
__out_ecount(FramesToCapture) PVOID *BackTrace,
|
||||
__out_opt PULONG CapturedFrames,
|
||||
__out_opt PULONG BackTraceHash,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
)
|
||||
{
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
PETHREAD thread;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
status = ObReferenceObjectByHandle(
|
||||
ThreadHandle,
|
||||
0,
|
||||
*PsThreadType,
|
||||
AccessMode,
|
||||
&thread,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
return status;
|
||||
|
||||
status = KphCaptureStackBackTraceThread(
|
||||
thread,
|
||||
FramesToSkip,
|
||||
FramesToCapture,
|
||||
BackTrace,
|
||||
CapturedFrames,
|
||||
BackTraceHash,
|
||||
AccessMode
|
||||
);
|
||||
ObDereferenceObject(thread);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries thread information.
|
||||
*
|
||||
* \param ThreadHandle A handle to a thread.
|
||||
* \param ThreadInformationClass The type of information to query.
|
||||
* \param ThreadInformation The buffer in which the information will be stored.
|
||||
* \param ThreadInformationLength The number of bytes available in \a ThreadInformation.
|
||||
* \param ReturnLength A variable which receives the number of bytes required to be available in
|
||||
* \a ThreadInformation.
|
||||
* \param AccessMode The mode in which to perform access checks.
|
||||
*/
|
||||
NTSTATUS KpiQueryInformationThread(
|
||||
__in HANDLE ThreadHandle,
|
||||
__in KPH_THREAD_INFORMATION_CLASS ThreadInformationClass,
|
||||
__out_bcount(ProcessInformationLength) PVOID ThreadInformation,
|
||||
__in ULONG ThreadInformationLength,
|
||||
__out_opt PULONG ReturnLength,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
PETHREAD thread;
|
||||
ULONG returnLength;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
if (AccessMode != KernelMode)
|
||||
{
|
||||
__try
|
||||
{
|
||||
ProbeForWrite(ThreadInformation, ThreadInformationLength, sizeof(ULONG));
|
||||
|
||||
if (ReturnLength)
|
||||
ProbeForWrite(ReturnLength, sizeof(ULONG), sizeof(ULONG));
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
return GetExceptionCode();
|
||||
}
|
||||
}
|
||||
|
||||
status = ObReferenceObjectByHandle(
|
||||
ThreadHandle,
|
||||
THREAD_QUERY_INFORMATION,
|
||||
*PsThreadType,
|
||||
AccessMode,
|
||||
&thread,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
return status;
|
||||
|
||||
switch (ThreadInformationClass)
|
||||
{
|
||||
default:
|
||||
status = STATUS_INVALID_INFO_CLASS;
|
||||
returnLength = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
ObDereferenceObject(thread);
|
||||
|
||||
if (ReturnLength)
|
||||
{
|
||||
if (AccessMode != KernelMode)
|
||||
{
|
||||
__try
|
||||
{
|
||||
*ReturnLength = returnLength;
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
NOTHING;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*ReturnLength = returnLength;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets thread information.
|
||||
*
|
||||
* \param ThreadHandle A handle to a thread.
|
||||
* \param ThreadInformationClass The type of information to set.
|
||||
* \param ThreadInformation A buffer which contains the information to set.
|
||||
* \param ThreadInformationLength The number of bytes present in \a ThreadInformation.
|
||||
* \param AccessMode The mode in which to perform access checks.
|
||||
*/
|
||||
NTSTATUS KpiSetInformationThread(
|
||||
__in HANDLE ThreadHandle,
|
||||
__in KPH_THREAD_INFORMATION_CLASS ThreadInformationClass,
|
||||
__in_bcount(ThreadInformationLength) PVOID ThreadInformation,
|
||||
__in ULONG ThreadInformationLength,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
PETHREAD thread;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
if (AccessMode != KernelMode)
|
||||
{
|
||||
__try
|
||||
{
|
||||
ProbeForRead(ThreadInformation, ThreadInformationLength, sizeof(ULONG));
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
return GetExceptionCode();
|
||||
}
|
||||
}
|
||||
|
||||
status = ObReferenceObjectByHandle(
|
||||
ThreadHandle,
|
||||
THREAD_SET_INFORMATION,
|
||||
*PsThreadType,
|
||||
AccessMode,
|
||||
&thread,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
return status;
|
||||
|
||||
switch (ThreadInformationClass)
|
||||
{
|
||||
default:
|
||||
status = STATUS_INVALID_INFO_CLASS;
|
||||
break;
|
||||
}
|
||||
|
||||
ObDereferenceObject(thread);
|
||||
|
||||
return status;
|
||||
}
|
||||
272
KProcessHacker/util.c
Normal file
272
KProcessHacker/util.c
Normal file
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* KProcessHacker
|
||||
*
|
||||
* Copyright (C) 2016 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <kph.h>
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, KphFreeCapturedUnicodeString)
|
||||
#pragma alloc_text(PAGE, KphCaptureUnicodeString)
|
||||
#pragma alloc_text(PAGE, KphEnumerateSystemModules)
|
||||
#pragma alloc_text(PAGE, KphValidateAddressForSystemModules)
|
||||
#pragma alloc_text(PAGE, KphGetProcessMappedFileName)
|
||||
#endif
|
||||
|
||||
VOID KphFreeCapturedUnicodeString(
|
||||
__in PUNICODE_STRING CapturedUnicodeString
|
||||
)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
if (CapturedUnicodeString->Buffer)
|
||||
ExFreePoolWithTag(CapturedUnicodeString->Buffer, 'UhpK');
|
||||
}
|
||||
|
||||
NTSTATUS KphCaptureUnicodeString(
|
||||
__in PUNICODE_STRING UnicodeString,
|
||||
__out PUNICODE_STRING CapturedUnicodeString
|
||||
)
|
||||
{
|
||||
UNICODE_STRING unicodeString;
|
||||
PWCHAR userBuffer;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
__try
|
||||
{
|
||||
ProbeForRead(UnicodeString, sizeof(UNICODE_STRING), sizeof(ULONG));
|
||||
unicodeString.Length = UnicodeString->Length;
|
||||
unicodeString.MaximumLength = unicodeString.Length;
|
||||
unicodeString.Buffer = NULL;
|
||||
|
||||
userBuffer = UnicodeString->Buffer;
|
||||
ProbeForRead(userBuffer, unicodeString.Length, sizeof(WCHAR));
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
return GetExceptionCode();
|
||||
}
|
||||
|
||||
if (unicodeString.Length & 1)
|
||||
{
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (unicodeString.Length != 0)
|
||||
{
|
||||
unicodeString.Buffer = ExAllocatePoolWithTag(
|
||||
PagedPool,
|
||||
unicodeString.Length,
|
||||
'UhpK'
|
||||
);
|
||||
|
||||
if (!unicodeString.Buffer)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
__try
|
||||
{
|
||||
memcpy(
|
||||
unicodeString.Buffer,
|
||||
userBuffer,
|
||||
unicodeString.Length
|
||||
);
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
KphFreeCapturedUnicodeString(&unicodeString);
|
||||
return GetExceptionCode();
|
||||
}
|
||||
}
|
||||
|
||||
*CapturedUnicodeString = unicodeString;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumerates the modules loaded by the kernel.
|
||||
*
|
||||
* \param Modules A variable which receives a pointer to a structure containing information about
|
||||
* the kernel modules. The structure must be freed with the tag 'ThpK'.
|
||||
*/
|
||||
NTSTATUS KphEnumerateSystemModules(
|
||||
__out PRTL_PROCESS_MODULES *Modules
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
PVOID buffer;
|
||||
ULONG bufferSize;
|
||||
ULONG attempts;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
bufferSize = 2048;
|
||||
attempts = 8;
|
||||
|
||||
do
|
||||
{
|
||||
buffer = ExAllocatePoolWithTag(PagedPool, bufferSize, 'ThpK');
|
||||
|
||||
if (!buffer)
|
||||
{
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
break;
|
||||
}
|
||||
|
||||
status = ZwQuerySystemInformation(
|
||||
SystemModuleInformation,
|
||||
buffer,
|
||||
bufferSize,
|
||||
&bufferSize
|
||||
);
|
||||
|
||||
if (NT_SUCCESS(status))
|
||||
{
|
||||
*Modules = buffer;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
ExFreePoolWithTag(buffer, 'ThpK');
|
||||
|
||||
if (status != STATUS_INFO_LENGTH_MISMATCH)
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while (--attempts);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an address range lies within a kernel module.
|
||||
*
|
||||
* \param Address The beginning of the address range.
|
||||
* \param Length The number of bytes in the address range.
|
||||
*/
|
||||
NTSTATUS KphValidateAddressForSystemModules(
|
||||
__in PVOID Address,
|
||||
__in SIZE_T Length
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
PRTL_PROCESS_MODULES modules;
|
||||
ULONG i;
|
||||
BOOLEAN valid;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
status = KphEnumerateSystemModules(&modules);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
return status;
|
||||
|
||||
valid = FALSE;
|
||||
|
||||
for (i = 0; i < modules->NumberOfModules; i++)
|
||||
{
|
||||
if (
|
||||
(ULONG_PTR)Address + Length >= (ULONG_PTR)Address &&
|
||||
(ULONG_PTR)Address >= (ULONG_PTR)modules->Modules[i].ImageBase &&
|
||||
(ULONG_PTR)Address + Length <= (ULONG_PTR)modules->Modules[i].ImageBase + modules->Modules[i].ImageSize
|
||||
)
|
||||
{
|
||||
dprintf("Validated address 0x%Ix in %s\n", Address, modules->Modules[i].FullPathName);
|
||||
valid = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ExFreePoolWithTag(modules, 'ThpK');
|
||||
|
||||
if (valid)
|
||||
status = STATUS_SUCCESS;
|
||||
else
|
||||
status = STATUS_ACCESS_VIOLATION;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the file name of a mapped section.
|
||||
*
|
||||
* \param ProcessHandle A handle to a process. The handle must have PROCESS_QUERY_INFORMATION
|
||||
* access.
|
||||
* \param BaseAddress The base address of the section view.
|
||||
* \param Modules A variable which receives a pointer to a string containing the file name of the
|
||||
* section. The structure must be freed with the tag 'ThpK'.
|
||||
*/
|
||||
NTSTATUS KphGetProcessMappedFileName(
|
||||
__in HANDLE ProcessHandle,
|
||||
__in PVOID BaseAddress,
|
||||
__out PUNICODE_STRING *FileName
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
PVOID buffer;
|
||||
SIZE_T bufferSize;
|
||||
SIZE_T returnLength;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
bufferSize = 0x100;
|
||||
buffer = ExAllocatePoolWithTag(PagedPool, bufferSize, 'ThpK');
|
||||
|
||||
if (!buffer)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
status = ZwQueryVirtualMemory(
|
||||
ProcessHandle,
|
||||
BaseAddress,
|
||||
MemoryMappedFilenameInformation,
|
||||
buffer,
|
||||
bufferSize,
|
||||
&returnLength
|
||||
);
|
||||
|
||||
if (status == STATUS_BUFFER_OVERFLOW)
|
||||
{
|
||||
ExFreePoolWithTag(buffer, 'ThpK');
|
||||
bufferSize = returnLength;
|
||||
buffer = ExAllocatePoolWithTag(PagedPool, bufferSize, 'ThpK');
|
||||
|
||||
if (!buffer)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
status = ZwQueryVirtualMemory(
|
||||
ProcessHandle,
|
||||
BaseAddress,
|
||||
MemoryMappedFilenameInformation,
|
||||
buffer,
|
||||
bufferSize,
|
||||
&returnLength
|
||||
);
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
ExFreePoolWithTag(buffer, 'ThpK');
|
||||
return status;
|
||||
}
|
||||
|
||||
*FileName = buffer;
|
||||
|
||||
return status;
|
||||
}
|
||||
496
KProcessHacker/verify.c
Normal file
496
KProcessHacker/verify.c
Normal file
@@ -0,0 +1,496 @@
|
||||
/*
|
||||
* KProcessHacker
|
||||
*
|
||||
* Copyright (C) 2016 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <kph.h>
|
||||
|
||||
#define FILE_BUFFER_SIZE (2 * PAGE_SIZE)
|
||||
#define FILE_MAX_SIZE (32 * 1024 * 1024) // 32 MB
|
||||
|
||||
VOID KphpBackoffKey(
|
||||
__in PKPH_CLIENT Client
|
||||
);
|
||||
|
||||
static UCHAR KphpTrustedPublicKey[] =
|
||||
{
|
||||
0x45, 0x43, 0x53, 0x31, 0x20, 0x00, 0x00, 0x00, 0x5f, 0xe8, 0xab, 0xac, 0x01, 0xad, 0x6b, 0x48,
|
||||
0xfd, 0x84, 0x7f, 0x43, 0x70, 0xb6, 0x57, 0xb0, 0x76, 0xe3, 0x10, 0x07, 0x19, 0xbd, 0x0e, 0xd4,
|
||||
0x10, 0x5c, 0x1f, 0xfc, 0x40, 0x91, 0xb6, 0xed, 0x94, 0x37, 0x76, 0xb7, 0x86, 0x88, 0xf7, 0x34,
|
||||
0x12, 0x91, 0xf6, 0x65, 0x23, 0x58, 0xc9, 0xeb, 0x2f, 0xcb, 0x96, 0x13, 0x8f, 0xca, 0x57, 0x7a,
|
||||
0xd0, 0x7a, 0xbf, 0x22, 0xde, 0xd2, 0x15, 0xfc
|
||||
};
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, KphHashFile)
|
||||
#pragma alloc_text(PAGE, KphVerifyFile)
|
||||
#pragma alloc_text(PAGE, KphVerifyClient)
|
||||
#pragma alloc_text(PAGE, KpiVerifyClient)
|
||||
#pragma alloc_text(PAGE, KphGenerateKeysClient)
|
||||
#pragma alloc_text(PAGE, KphRetrieveKeyViaApc)
|
||||
#pragma alloc_text(PAGE, KphValidateKey)
|
||||
#pragma alloc_text(PAGE, KphpBackoffKey)
|
||||
#endif
|
||||
|
||||
NTSTATUS KphHashFile(
|
||||
__in PUNICODE_STRING FileName,
|
||||
__out PVOID *Hash,
|
||||
__out PULONG HashSize
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
BCRYPT_ALG_HANDLE hashAlgHandle = NULL;
|
||||
ULONG querySize;
|
||||
ULONG hashObjectSize;
|
||||
ULONG hashSize;
|
||||
PVOID hashObject = NULL;
|
||||
PVOID hash = NULL;
|
||||
BCRYPT_HASH_HANDLE hashHandle = NULL;
|
||||
OBJECT_ATTRIBUTES objectAttributes;
|
||||
IO_STATUS_BLOCK iosb;
|
||||
HANDLE fileHandle = NULL;
|
||||
FILE_STANDARD_INFORMATION standardInfo;
|
||||
ULONG remainingBytes;
|
||||
ULONG bytesToRead;
|
||||
PVOID buffer = NULL;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
// Open the hash algorithm and allocate memory for the hash object.
|
||||
|
||||
if (!NT_SUCCESS(status = BCryptOpenAlgorithmProvider(&hashAlgHandle, KPH_HASH_ALGORITHM, NULL, 0)))
|
||||
goto CleanupExit;
|
||||
if (!NT_SUCCESS(status = BCryptGetProperty(hashAlgHandle, BCRYPT_OBJECT_LENGTH,
|
||||
(PUCHAR)&hashObjectSize, sizeof(ULONG), &querySize, 0)))
|
||||
{
|
||||
goto CleanupExit;
|
||||
}
|
||||
if (!NT_SUCCESS(status = BCryptGetProperty(hashAlgHandle, BCRYPT_HASH_LENGTH, (PUCHAR)&hashSize,
|
||||
sizeof(ULONG), &querySize, 0)))
|
||||
{
|
||||
goto CleanupExit;
|
||||
}
|
||||
|
||||
if (!(hashObject = ExAllocatePoolWithTag(PagedPool, hashObjectSize, 'vhpK')))
|
||||
{
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto CleanupExit;
|
||||
}
|
||||
if (!(hash = ExAllocatePoolWithTag(PagedPool, hashSize, 'vhpK')))
|
||||
{
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto CleanupExit;
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(status = BCryptCreateHash(hashAlgHandle, &hashHandle, hashObject, hashObjectSize,
|
||||
NULL, 0, 0)))
|
||||
{
|
||||
goto CleanupExit;
|
||||
}
|
||||
|
||||
// Open the file and compute the hash.
|
||||
|
||||
InitializeObjectAttributes(&objectAttributes, FileName, OBJ_KERNEL_HANDLE, NULL, NULL);
|
||||
|
||||
if (!NT_SUCCESS(status = ZwCreateFile(&fileHandle, FILE_GENERIC_READ, &objectAttributes,
|
||||
&iosb, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN,
|
||||
FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0)))
|
||||
{
|
||||
goto CleanupExit;
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(status = ZwQueryInformationFile(fileHandle, &iosb, &standardInfo,
|
||||
sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation)))
|
||||
{
|
||||
goto CleanupExit;
|
||||
}
|
||||
|
||||
if (standardInfo.EndOfFile.QuadPart <= 0)
|
||||
{
|
||||
status = STATUS_UNSUCCESSFUL;
|
||||
goto CleanupExit;
|
||||
}
|
||||
if (standardInfo.EndOfFile.QuadPart > FILE_MAX_SIZE)
|
||||
{
|
||||
status = STATUS_FILE_TOO_LARGE;
|
||||
goto CleanupExit;
|
||||
}
|
||||
|
||||
if (!(buffer = ExAllocatePoolWithTag(PagedPool, FILE_BUFFER_SIZE, 'vhpK')))
|
||||
{
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto CleanupExit;
|
||||
}
|
||||
|
||||
remainingBytes = (ULONG)standardInfo.EndOfFile.QuadPart;
|
||||
|
||||
while (remainingBytes != 0)
|
||||
{
|
||||
bytesToRead = FILE_BUFFER_SIZE;
|
||||
if (bytesToRead > remainingBytes)
|
||||
bytesToRead = remainingBytes;
|
||||
|
||||
if (!NT_SUCCESS(status = ZwReadFile(fileHandle, NULL, NULL, NULL, &iosb, buffer, bytesToRead,
|
||||
NULL, NULL)))
|
||||
{
|
||||
goto CleanupExit;
|
||||
}
|
||||
if ((ULONG)iosb.Information != bytesToRead)
|
||||
{
|
||||
status = STATUS_INTERNAL_ERROR;
|
||||
goto CleanupExit;
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(status = BCryptHashData(hashHandle, buffer, bytesToRead, 0)))
|
||||
goto CleanupExit;
|
||||
|
||||
remainingBytes -= bytesToRead;
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(status = BCryptFinishHash(hashHandle, hash, hashSize, 0)))
|
||||
goto CleanupExit;
|
||||
|
||||
if (NT_SUCCESS(status))
|
||||
{
|
||||
*Hash = hash;
|
||||
*HashSize = hashSize;
|
||||
|
||||
hash = NULL; // Don't free this in the cleanup section
|
||||
}
|
||||
|
||||
CleanupExit:
|
||||
if (buffer)
|
||||
ExFreePoolWithTag(buffer, 'vhpK');
|
||||
if (fileHandle)
|
||||
ZwClose(fileHandle);
|
||||
if (hashHandle)
|
||||
BCryptDestroyHash(hashHandle);
|
||||
if (hash)
|
||||
ExFreePoolWithTag(hash, 'vhpK');
|
||||
if (hashObject)
|
||||
ExFreePoolWithTag(hashObject, 'vhpK');
|
||||
if (hashAlgHandle)
|
||||
BCryptCloseAlgorithmProvider(hashAlgHandle, 0);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS KphVerifyFile(
|
||||
__in PUNICODE_STRING FileName,
|
||||
__in_bcount(SignatureSize) PUCHAR Signature,
|
||||
__in ULONG SignatureSize
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
BCRYPT_ALG_HANDLE signAlgHandle = NULL;
|
||||
BCRYPT_KEY_HANDLE keyHandle = NULL;
|
||||
PVOID hash = NULL;
|
||||
ULONG hashSize;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
// Import the trusted public key.
|
||||
|
||||
if (!NT_SUCCESS(status = BCryptOpenAlgorithmProvider(&signAlgHandle, KPH_SIGN_ALGORITHM, NULL, 0)))
|
||||
goto CleanupExit;
|
||||
if (!NT_SUCCESS(status = BCryptImportKeyPair(signAlgHandle, NULL, KPH_BLOB_PUBLIC, &keyHandle,
|
||||
KphpTrustedPublicKey, sizeof(KphpTrustedPublicKey), 0)))
|
||||
{
|
||||
goto CleanupExit;
|
||||
}
|
||||
|
||||
// Hash the file.
|
||||
|
||||
if (!NT_SUCCESS(status = KphHashFile(FileName, &hash, &hashSize)))
|
||||
goto CleanupExit;
|
||||
|
||||
// Verify the hash.
|
||||
|
||||
if (!NT_SUCCESS(status = BCryptVerifySignature(keyHandle, NULL, hash, hashSize, Signature,
|
||||
SignatureSize, 0)))
|
||||
{
|
||||
goto CleanupExit;
|
||||
}
|
||||
|
||||
CleanupExit:
|
||||
if (hash)
|
||||
ExFreePoolWithTag(hash, 'vhpK');
|
||||
if (keyHandle)
|
||||
BCryptDestroyKey(keyHandle);
|
||||
if (signAlgHandle)
|
||||
BCryptCloseAlgorithmProvider(signAlgHandle, 0);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
VOID KphVerifyClient(
|
||||
__inout PKPH_CLIENT Client,
|
||||
__in PVOID CodeAddress,
|
||||
__in_bcount(SignatureSize) PUCHAR Signature,
|
||||
__in ULONG SignatureSize
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
PUNICODE_STRING processFileName = NULL;
|
||||
MEMORY_BASIC_INFORMATION memoryBasicInfo;
|
||||
PUNICODE_STRING mappedFileName = NULL;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
if (Client->VerificationPerformed)
|
||||
return;
|
||||
|
||||
if ((ULONG_PTR)CodeAddress > (ULONG_PTR)MmHighestUserAddress)
|
||||
{
|
||||
status = STATUS_ACCESS_VIOLATION;
|
||||
goto CleanupExit;
|
||||
}
|
||||
if (!NT_SUCCESS(status = SeLocateProcessImageName(PsGetCurrentProcess(), &processFileName)))
|
||||
goto CleanupExit;
|
||||
if (!NT_SUCCESS(status = ZwQueryVirtualMemory(NtCurrentProcess(), CodeAddress,
|
||||
MemoryBasicInformation, &memoryBasicInfo, sizeof(MEMORY_BASIC_INFORMATION), NULL)))
|
||||
{
|
||||
goto CleanupExit;
|
||||
}
|
||||
if (memoryBasicInfo.Type != MEM_IMAGE || memoryBasicInfo.State != MEM_COMMIT)
|
||||
{
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
goto CleanupExit;
|
||||
}
|
||||
if (!NT_SUCCESS(status = KphGetProcessMappedFileName(NtCurrentProcess(), CodeAddress,
|
||||
&mappedFileName)))
|
||||
{
|
||||
goto CleanupExit;
|
||||
}
|
||||
if (!RtlEqualUnicodeString(processFileName, mappedFileName, TRUE))
|
||||
{
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
goto CleanupExit;
|
||||
}
|
||||
|
||||
status = KphVerifyFile(processFileName, Signature, SignatureSize);
|
||||
|
||||
CleanupExit:
|
||||
if (mappedFileName)
|
||||
ExFreePoolWithTag(mappedFileName, 'ThpK');
|
||||
if (processFileName)
|
||||
ExFreePool(processFileName);
|
||||
|
||||
ExAcquireFastMutex(&Client->StateMutex);
|
||||
|
||||
if (NT_SUCCESS(status))
|
||||
{
|
||||
Client->VerifiedProcess = PsGetCurrentProcess();
|
||||
Client->VerifiedProcessId = PsGetCurrentProcessId();
|
||||
Client->VerifiedRangeBase = memoryBasicInfo.BaseAddress;
|
||||
Client->VerifiedRangeSize = memoryBasicInfo.RegionSize;
|
||||
}
|
||||
|
||||
Client->VerificationStatus = status;
|
||||
MemoryBarrier();
|
||||
Client->VerificationSucceeded = NT_SUCCESS(status);
|
||||
Client->VerificationPerformed = TRUE;
|
||||
|
||||
ExReleaseFastMutex(&Client->StateMutex);
|
||||
}
|
||||
|
||||
NTSTATUS KpiVerifyClient(
|
||||
__in PVOID CodeAddress,
|
||||
__in_bcount(SignatureSize) PUCHAR Signature,
|
||||
__in ULONG SignatureSize,
|
||||
__in PKPH_CLIENT Client
|
||||
)
|
||||
{
|
||||
PUCHAR signature;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
__try
|
||||
{
|
||||
ProbeForRead(Signature, SignatureSize, 1);
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
return GetExceptionCode();
|
||||
}
|
||||
|
||||
if (SignatureSize > KPH_SIGNATURE_MAX_SIZE)
|
||||
return STATUS_INVALID_PARAMETER_3;
|
||||
|
||||
signature = ExAllocatePoolWithTag(PagedPool, SignatureSize, 'ThpK');
|
||||
if (!signature)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
__try
|
||||
{
|
||||
memcpy(signature, Signature, SignatureSize);
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
ExFreePoolWithTag(signature, 'ThpK');
|
||||
return GetExceptionCode();
|
||||
}
|
||||
|
||||
KphVerifyClient(Client, CodeAddress, Signature, SignatureSize);
|
||||
ExFreePoolWithTag(signature, 'ThpK');
|
||||
|
||||
return Client->VerificationStatus;
|
||||
}
|
||||
|
||||
VOID KphGenerateKeysClient(
|
||||
__inout PKPH_CLIENT Client
|
||||
)
|
||||
{
|
||||
ULONGLONG interruptTime;
|
||||
ULONG seed;
|
||||
KPH_KEY l1Key;
|
||||
KPH_KEY l2Key;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
if (Client->KeysGenerated)
|
||||
return;
|
||||
|
||||
interruptTime = KeQueryInterruptTime();
|
||||
seed = (ULONG)(interruptTime >> 32) | (ULONG)interruptTime | PtrToUlong(Client);
|
||||
l1Key = RtlRandomEx(&seed) | 0x80000000; // Make sure the key is nonzero
|
||||
do
|
||||
{
|
||||
l2Key = RtlRandomEx(&seed) | 0x80000000;
|
||||
} while (l2Key == l1Key);
|
||||
|
||||
ExAcquireFastMutex(&Client->StateMutex);
|
||||
|
||||
if (!Client->KeysGenerated)
|
||||
{
|
||||
Client->L1Key = l1Key;
|
||||
Client->L2Key = l2Key;
|
||||
MemoryBarrier();
|
||||
Client->KeysGenerated = TRUE;
|
||||
}
|
||||
|
||||
ExReleaseFastMutex(&Client->StateMutex);
|
||||
}
|
||||
|
||||
NTSTATUS KphRetrieveKeyViaApc(
|
||||
__inout PKPH_CLIENT Client,
|
||||
__in KPH_KEY_LEVEL KeyLevel,
|
||||
__inout PIRP Irp
|
||||
)
|
||||
{
|
||||
PIO_APC_ROUTINE userApcRoutine;
|
||||
KPH_KEY key;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
if (!Client->VerificationSucceeded)
|
||||
return STATUS_ACCESS_DENIED;
|
||||
|
||||
MemoryBarrier();
|
||||
|
||||
if (PsGetCurrentProcess() != Client->VerifiedProcess ||
|
||||
PsGetCurrentProcessId() != Client->VerifiedProcessId)
|
||||
{
|
||||
return STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
userApcRoutine = Irp->Overlay.AsynchronousParameters.UserApcRoutine;
|
||||
|
||||
if (!userApcRoutine)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
if ((ULONG_PTR)userApcRoutine < (ULONG_PTR)Client->VerifiedRangeBase ||
|
||||
(ULONG_PTR)userApcRoutine >= (ULONG_PTR)Client->VerifiedRangeBase + Client->VerifiedRangeSize)
|
||||
{
|
||||
return STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
KphGenerateKeysClient(Client);
|
||||
|
||||
switch (KeyLevel)
|
||||
{
|
||||
case KphKeyLevel1:
|
||||
key = Client->L1Key;
|
||||
break;
|
||||
case KphKeyLevel2:
|
||||
key = Client->L2Key;
|
||||
break;
|
||||
default:
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Irp->Overlay.AsynchronousParameters.UserApcContext = UlongToPtr(key);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS KphValidateKey(
|
||||
__in KPH_KEY_LEVEL RequiredKeyLevel,
|
||||
__in_opt KPH_KEY Key,
|
||||
__in PKPH_CLIENT Client,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
if (AccessMode == KernelMode)
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
if (Key && Client->VerificationSucceeded && Client->KeysGenerated)
|
||||
{
|
||||
MemoryBarrier();
|
||||
|
||||
switch (RequiredKeyLevel)
|
||||
{
|
||||
case KphKeyLevel1:
|
||||
if (Key == Client->L1Key || Key == Client->L2Key)
|
||||
return STATUS_SUCCESS;
|
||||
else
|
||||
KphpBackoffKey(Client);
|
||||
break;
|
||||
case KphKeyLevel2:
|
||||
if (Key == Client->L2Key)
|
||||
return STATUS_SUCCESS;
|
||||
else
|
||||
KphpBackoffKey(Client);
|
||||
break;
|
||||
default:
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
}
|
||||
|
||||
return STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
VOID KphpBackoffKey(
|
||||
__in PKPH_CLIENT Client
|
||||
)
|
||||
{
|
||||
LARGE_INTEGER backoffTime;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
// Serialize to make it impossible for a single client to bypass the backoff by creating
|
||||
// multiple threads.
|
||||
ExAcquireFastMutex(&Client->KeyBackoffMutex);
|
||||
|
||||
backoffTime.QuadPart = -KPH_KEY_BACKOFF_TIME;
|
||||
KeDelayExecutionThread(KernelMode, FALSE, &backoffTime);
|
||||
|
||||
ExReleaseFastMutex(&Client->KeyBackoffMutex);
|
||||
}
|
||||
449
KProcessHacker/vm.c
Normal file
449
KProcessHacker/vm.c
Normal file
@@ -0,0 +1,449 @@
|
||||
/*
|
||||
* KProcessHacker
|
||||
*
|
||||
* Copyright (C) 2010-2016 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <kph.h>
|
||||
|
||||
ULONG KphpGetCopyExceptionInfo(
|
||||
__in PEXCEPTION_POINTERS ExceptionInfo,
|
||||
__out PBOOLEAN HaveBadAddress,
|
||||
__out PULONG_PTR BadAddress
|
||||
);
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, KphCopyVirtualMemory)
|
||||
#pragma alloc_text(PAGE, KpiReadVirtualMemoryUnsafe)
|
||||
#endif
|
||||
|
||||
#define KPH_STACK_COPY_BYTES 0x200
|
||||
#define KPH_POOL_COPY_BYTES 0x10000
|
||||
#define KPH_MAPPED_COPY_PAGES 14
|
||||
#define KPH_POOL_COPY_THRESHOLD 0x3ff
|
||||
|
||||
ULONG KphpGetCopyExceptionInfo(
|
||||
__in PEXCEPTION_POINTERS ExceptionInfo,
|
||||
__out PBOOLEAN HaveBadAddress,
|
||||
__out PULONG_PTR BadAddress
|
||||
)
|
||||
{
|
||||
PEXCEPTION_RECORD exceptionRecord;
|
||||
|
||||
*HaveBadAddress = FALSE;
|
||||
exceptionRecord = ExceptionInfo->ExceptionRecord;
|
||||
|
||||
if ((exceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION) ||
|
||||
(exceptionRecord->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION) ||
|
||||
(exceptionRecord->ExceptionCode == STATUS_IN_PAGE_ERROR))
|
||||
{
|
||||
if (exceptionRecord->NumberParameters > 1)
|
||||
{
|
||||
/* We have the address. */
|
||||
*HaveBadAddress = TRUE;
|
||||
*BadAddress = exceptionRecord->ExceptionInformation[1];
|
||||
}
|
||||
}
|
||||
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies memory from one process to another.
|
||||
*
|
||||
* \param FromProcess The source process.
|
||||
* \param FromAddress The source address.
|
||||
* \param ToProcess The target process.
|
||||
* \param ToAddress The target address.
|
||||
* \param BufferLength The number of bytes to copy.
|
||||
* \param AccessMode The mode in which to perform access checks.
|
||||
* \param ReturnLength A variable which receives the number of bytes copied.
|
||||
*/
|
||||
NTSTATUS KphCopyVirtualMemory(
|
||||
__in PEPROCESS FromProcess,
|
||||
__in PVOID FromAddress,
|
||||
__in PEPROCESS ToProcess,
|
||||
__in PVOID ToAddress,
|
||||
__in SIZE_T BufferLength,
|
||||
__in KPROCESSOR_MODE AccessMode,
|
||||
__out PSIZE_T ReturnLength
|
||||
)
|
||||
{
|
||||
UCHAR stackBuffer[KPH_STACK_COPY_BYTES];
|
||||
PVOID buffer;
|
||||
PFN_NUMBER mdlBuffer[(sizeof(MDL) / sizeof(PFN_NUMBER)) + KPH_MAPPED_COPY_PAGES + 1];
|
||||
PMDL mdl = (PMDL)mdlBuffer;
|
||||
PVOID mappedAddress;
|
||||
SIZE_T mappedTotalSize;
|
||||
SIZE_T blockSize;
|
||||
SIZE_T stillToCopy;
|
||||
KAPC_STATE apcState;
|
||||
PVOID sourceAddress;
|
||||
PVOID targetAddress;
|
||||
BOOLEAN doMappedCopy;
|
||||
BOOLEAN pagesLocked;
|
||||
BOOLEAN copyingToTarget = FALSE;
|
||||
BOOLEAN probing = FALSE;
|
||||
BOOLEAN mapping = FALSE;
|
||||
BOOLEAN haveBadAddress;
|
||||
ULONG_PTR badAddress;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
sourceAddress = FromAddress;
|
||||
targetAddress = ToAddress;
|
||||
|
||||
// We don't check if buffer == NULL when freeing. If buffer doesn't need to be freed, set to
|
||||
// stackBuffer, not NULL.
|
||||
buffer = stackBuffer;
|
||||
|
||||
mappedTotalSize = (KPH_MAPPED_COPY_PAGES - 2) * PAGE_SIZE;
|
||||
|
||||
if (mappedTotalSize > BufferLength)
|
||||
mappedTotalSize = BufferLength;
|
||||
|
||||
stillToCopy = BufferLength;
|
||||
blockSize = mappedTotalSize;
|
||||
|
||||
while (stillToCopy)
|
||||
{
|
||||
// If we're at the last copy block, copy the remaining bytes instead of the whole block
|
||||
// size.
|
||||
if (blockSize > stillToCopy)
|
||||
blockSize = stillToCopy;
|
||||
|
||||
// Choose the best method based on the number of bytes left to copy.
|
||||
if (blockSize > KPH_POOL_COPY_THRESHOLD)
|
||||
{
|
||||
doMappedCopy = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
doMappedCopy = FALSE;
|
||||
|
||||
if (blockSize <= KPH_STACK_COPY_BYTES)
|
||||
{
|
||||
if (buffer != stackBuffer)
|
||||
ExFreePoolWithTag(buffer, 'ChpK');
|
||||
|
||||
buffer = stackBuffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Don't allocate the buffer if we've done so already. Note that the block size
|
||||
// never increases, so this allocation will always be OK.
|
||||
if (buffer == stackBuffer)
|
||||
{
|
||||
// Keep trying to allocate a buffer.
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
buffer = ExAllocatePoolWithTag(NonPagedPool, blockSize, 'ChpK');
|
||||
|
||||
// Stop trying if we got a buffer.
|
||||
if (buffer)
|
||||
break;
|
||||
|
||||
blockSize /= 2;
|
||||
|
||||
// Use the stack buffer if we can.
|
||||
if (blockSize <= KPH_STACK_COPY_BYTES)
|
||||
{
|
||||
buffer = stackBuffer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reset state.
|
||||
mappedAddress = NULL;
|
||||
pagesLocked = FALSE;
|
||||
copyingToTarget = FALSE;
|
||||
|
||||
KeStackAttachProcess(FromProcess, &apcState);
|
||||
|
||||
__try
|
||||
{
|
||||
// Probe only if this is the first time.
|
||||
if (sourceAddress == FromAddress && AccessMode != KernelMode)
|
||||
{
|
||||
probing = TRUE;
|
||||
ProbeForRead(sourceAddress, BufferLength, sizeof(UCHAR));
|
||||
probing = FALSE;
|
||||
}
|
||||
|
||||
if (doMappedCopy)
|
||||
{
|
||||
// Initialize the MDL.
|
||||
MmInitializeMdl(mdl, sourceAddress, blockSize);
|
||||
MmProbeAndLockPages(mdl, AccessMode, IoReadAccess);
|
||||
pagesLocked = TRUE;
|
||||
|
||||
// Map the pages.
|
||||
mappedAddress = MmMapLockedPagesSpecifyCache(
|
||||
mdl,
|
||||
KernelMode,
|
||||
MmCached,
|
||||
NULL,
|
||||
FALSE,
|
||||
HighPagePriority
|
||||
);
|
||||
|
||||
if (!mappedAddress)
|
||||
{
|
||||
// Insufficient resources; exit.
|
||||
mapping = TRUE;
|
||||
ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(buffer, sourceAddress, blockSize);
|
||||
}
|
||||
|
||||
KeUnstackDetachProcess(&apcState);
|
||||
|
||||
// Attach to the target process and copy the contents out.
|
||||
KeStackAttachProcess(ToProcess, &apcState);
|
||||
|
||||
// Probe only if this is the first time.
|
||||
if (targetAddress == ToAddress && AccessMode != KernelMode)
|
||||
{
|
||||
probing = TRUE;
|
||||
ProbeForWrite(targetAddress, BufferLength, sizeof(UCHAR));
|
||||
probing = FALSE;
|
||||
}
|
||||
|
||||
// Copy the data.
|
||||
copyingToTarget = TRUE;
|
||||
|
||||
if (doMappedCopy)
|
||||
memcpy(targetAddress, mappedAddress, blockSize);
|
||||
else
|
||||
memcpy(targetAddress, buffer, blockSize);
|
||||
}
|
||||
__except (KphpGetCopyExceptionInfo(
|
||||
GetExceptionInformation(),
|
||||
&haveBadAddress,
|
||||
&badAddress
|
||||
))
|
||||
{
|
||||
KeUnstackDetachProcess(&apcState);
|
||||
|
||||
// If we mapped the pages, unmap them.
|
||||
if (mappedAddress)
|
||||
MmUnmapLockedPages(mappedAddress, mdl);
|
||||
|
||||
// If we locked the pages, unlock them.
|
||||
if (pagesLocked)
|
||||
MmUnlockPages(mdl);
|
||||
|
||||
// If we allocated pool storage, free it.
|
||||
if (buffer != stackBuffer)
|
||||
ExFreePoolWithTag(buffer, 'ChpK');
|
||||
|
||||
// If we failed when probing or mapping, return the error status.
|
||||
if (probing || mapping)
|
||||
return GetExceptionCode();
|
||||
|
||||
// Determine which copy failed.
|
||||
if (copyingToTarget && haveBadAddress)
|
||||
{
|
||||
*ReturnLength = (ULONG)(badAddress - (ULONG_PTR)sourceAddress);
|
||||
}
|
||||
else
|
||||
{
|
||||
*ReturnLength = BufferLength - stillToCopy;
|
||||
}
|
||||
|
||||
return STATUS_PARTIAL_COPY;
|
||||
}
|
||||
|
||||
KeUnstackDetachProcess(&apcState);
|
||||
|
||||
if (doMappedCopy)
|
||||
{
|
||||
MmUnmapLockedPages(mappedAddress, mdl);
|
||||
MmUnlockPages(mdl);
|
||||
}
|
||||
|
||||
stillToCopy -= blockSize;
|
||||
sourceAddress = (PVOID)((ULONG_PTR)sourceAddress + blockSize);
|
||||
targetAddress = (PVOID)((ULONG_PTR)targetAddress + blockSize);
|
||||
}
|
||||
|
||||
if (buffer != stackBuffer)
|
||||
ExFreePoolWithTag(buffer, 'ChpK');
|
||||
|
||||
*ReturnLength = BufferLength;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies process or kernel memory into the current process.
|
||||
*
|
||||
* \param ProcessHandle A handle to a process. The handle must have PROCESS_VM_READ access. This
|
||||
* parameter may be NULL if \a BaseAddress lies above the user-mode range.
|
||||
* \param BaseAddress The address from which memory is to be copied.
|
||||
* \param Buffer A buffer which receives the copied memory.
|
||||
* \param BufferSize The number of bytes to copy.
|
||||
* \param NumberOfBytesRead A variable which receives the number of bytes copied to the buffer.
|
||||
* \param Key An access key. If no valid L2 key is provided, the function fails.
|
||||
* \param Client The client that initiated the request.
|
||||
* \param AccessMode The mode in which to perform access checks.
|
||||
*/
|
||||
NTSTATUS KpiReadVirtualMemoryUnsafe(
|
||||
__in_opt HANDLE ProcessHandle,
|
||||
__in PVOID BaseAddress,
|
||||
__out_bcount(BufferSize) PVOID Buffer,
|
||||
__in SIZE_T BufferSize,
|
||||
__out_opt PSIZE_T NumberOfBytesRead,
|
||||
__in_opt KPH_KEY Key,
|
||||
__in PKPH_CLIENT Client,
|
||||
__in KPROCESSOR_MODE AccessMode
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
PEPROCESS process;
|
||||
SIZE_T numberOfBytesRead;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
if (!NT_SUCCESS(status = KphValidateKey(KphKeyLevel2, Key, Client, AccessMode)))
|
||||
return status;
|
||||
|
||||
if (AccessMode != KernelMode)
|
||||
{
|
||||
if (
|
||||
(ULONG_PTR)BaseAddress + BufferSize < (ULONG_PTR)BaseAddress ||
|
||||
(ULONG_PTR)Buffer + BufferSize < (ULONG_PTR)Buffer ||
|
||||
(ULONG_PTR)Buffer + BufferSize > (ULONG_PTR)MmHighestUserAddress
|
||||
)
|
||||
{
|
||||
return STATUS_ACCESS_VIOLATION;
|
||||
}
|
||||
|
||||
if (NumberOfBytesRead)
|
||||
{
|
||||
__try
|
||||
{
|
||||
ProbeForWrite(NumberOfBytesRead, sizeof(SIZE_T), sizeof(SIZE_T));
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
return GetExceptionCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (BufferSize != 0)
|
||||
{
|
||||
// Select the appropriate copy method.
|
||||
if ((ULONG_PTR)BaseAddress + BufferSize > (ULONG_PTR)MmHighestUserAddress)
|
||||
{
|
||||
ULONG_PTR page;
|
||||
ULONG_PTR pageEnd;
|
||||
|
||||
status = KphValidateAddressForSystemModules(BaseAddress, BufferSize);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
return status;
|
||||
|
||||
// Kernel memory copy (unsafe)
|
||||
|
||||
page = (ULONG_PTR)BaseAddress & ~(PAGE_SIZE - 1);
|
||||
pageEnd = ((ULONG_PTR)BaseAddress + BufferSize - 1) & ~(PAGE_SIZE - 1);
|
||||
|
||||
__try
|
||||
{
|
||||
// This will obviously fail if any of the pages aren't resident.
|
||||
for (; page <= pageEnd; page += PAGE_SIZE)
|
||||
{
|
||||
if (!MmIsAddressValid((PVOID)page))
|
||||
ExRaiseStatus(STATUS_ACCESS_VIOLATION);
|
||||
}
|
||||
|
||||
memcpy(Buffer, BaseAddress, BufferSize);
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
return GetExceptionCode();
|
||||
}
|
||||
|
||||
numberOfBytesRead = BufferSize;
|
||||
status = STATUS_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
// User memory copy (safe)
|
||||
|
||||
status = ObReferenceObjectByHandle(
|
||||
ProcessHandle,
|
||||
PROCESS_VM_READ,
|
||||
*PsProcessType,
|
||||
AccessMode,
|
||||
&process,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (NT_SUCCESS(status))
|
||||
{
|
||||
status = KphCopyVirtualMemory(
|
||||
process,
|
||||
BaseAddress,
|
||||
PsGetCurrentProcess(),
|
||||
Buffer,
|
||||
BufferSize,
|
||||
AccessMode,
|
||||
&numberOfBytesRead
|
||||
);
|
||||
ObDereferenceObject(process);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
numberOfBytesRead = 0;
|
||||
status = STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (NumberOfBytesRead)
|
||||
{
|
||||
if (AccessMode != KernelMode)
|
||||
{
|
||||
__try
|
||||
{
|
||||
*NumberOfBytesRead = numberOfBytesRead;
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
// Don't mess with the status.
|
||||
NOTHING;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*NumberOfBytesRead = numberOfBytesRead;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
Reference in New Issue
Block a user