using System;
using ProcessHacker.Native.Api;
using ProcessHacker.Native.Objects;
using ProcessHacker.Native.Security;
namespace ProcessHacker.Native
{
///
/// Provides various utility methods.
///
public static class NativeUtils
{
///
/// Calls a function.
///
/// The address of the function.
/// The first parameter to pass.
/// The second parameter to pass.
/// The third parameter to pass.
public static void Call(IntPtr address, IntPtr param1, IntPtr param2, IntPtr param3)
{
// Queue a user-mode APC to the current thread.
ThreadHandle.Current.QueueApc(address, param1, param2, param3);
// Flush the APC queue.
ThreadHandle.TestAlert();
}
public unsafe static void CopyProcessParameters(
ProcessHandle processHandle,
IntPtr peb,
ProcessCreationFlags creationFlags,
string imagePathName,
string dllPath,
string currentDirectory,
string commandLine,
EnvironmentBlock environment,
string windowTitle,
string desktopInfo,
string shellInfo,
string runtimeInfo,
ref StartupInfo startupInfo
)
{
// Create the unicode strings.
UnicodeString imagePathNameStr = new UnicodeString(imagePathName);
UnicodeString dllPathStr = new UnicodeString(dllPath);
UnicodeString currentDirectoryStr = new UnicodeString(currentDirectory);
UnicodeString commandLineStr = new UnicodeString(commandLine);
UnicodeString windowTitleStr = new UnicodeString(windowTitle);
UnicodeString desktopInfoStr = new UnicodeString(desktopInfo);
UnicodeString shellInfoStr = new UnicodeString(shellInfo);
UnicodeString runtimeInfoStr = new UnicodeString(runtimeInfo);
try
{
IntPtr processParameters;
// Create the process parameter block.
Win32.RtlCreateProcessParameters(
out processParameters,
ref imagePathNameStr,
ref dllPathStr,
ref currentDirectoryStr,
ref commandLineStr,
environment,
ref windowTitleStr,
ref desktopInfoStr,
ref shellInfoStr,
ref runtimeInfoStr
).ThrowIf();
try
{
// Allocate a new memory region in the remote process for
// the environment block and copy it over.
int environmentLength = environment.Length;
IntPtr newEnvironment = processHandle.AllocateMemory(
environmentLength,
MemoryProtection.ReadWrite
);
processHandle.WriteMemory(
newEnvironment,
environment,
environmentLength
);
// Copy over the startup info data.
RtlUserProcessParameters* paramsStruct = (RtlUserProcessParameters*)processParameters;
paramsStruct->Environment = newEnvironment;
paramsStruct->StartingX = startupInfo.X;
paramsStruct->StartingY = startupInfo.Y;
paramsStruct->CountX = startupInfo.XSize;
paramsStruct->CountY = startupInfo.YSize;
paramsStruct->CountCharsX = startupInfo.XCountChars;
paramsStruct->CountCharsY = startupInfo.YCountChars;
paramsStruct->FillAttribute = startupInfo.FillAttribute;
paramsStruct->WindowFlags = startupInfo.Flags;
paramsStruct->ShowWindowFlags = startupInfo.ShowWindow;
if ((startupInfo.Flags & StartupFlags.UseStdHandles) == StartupFlags.UseStdHandles)
{
paramsStruct->StandardInput = startupInfo.StdInputHandle;
paramsStruct->StandardOutput = startupInfo.StdOutputHandle;
paramsStruct->StandardError = startupInfo.StdErrorHandle;
}
// TODO: Add console support.
// Allocate a new memory region in the remote process for
// the process parameters.
IntPtr regionSize = paramsStruct->Length.ToIntPtr();
IntPtr newProcessParameters = processHandle.AllocateMemory(
IntPtr.Zero,
ref regionSize,
MemoryFlags.Commit,
MemoryProtection.ReadWrite
);
paramsStruct->MaximumLength = regionSize.ToInt32();
processHandle.WriteMemory(newProcessParameters, processParameters, paramsStruct->Length);
// Modify the process parameters pointer in the PEB.
processHandle.WriteMemory(
peb.Increment(Peb.ProcessParametersOffset),
&newProcessParameters,
IntPtr.Size
);
}
finally
{
Win32.RtlDestroyProcessParameters(processParameters);
}
}
finally
{
imagePathNameStr.Dispose();
dllPathStr.Dispose();
currentDirectoryStr.Dispose();
commandLineStr.Dispose();
windowTitleStr.Dispose();
desktopInfoStr.Dispose();
shellInfoStr.Dispose();
runtimeInfoStr.Dispose();
}
}
public static string FormatNativeKeyName(string nativeKeyName)
{
const string hklmString = @"\REGISTRY\MACHINE";
const string hkcrString = @"\REGISTRY\MACHINE\SOFTWARE\CLASSES";
string hkcuString = @"\REGISTRY\USER\" + Sid.CurrentUser.StringSid;
string hkcucrString = @"\REGISTRY\USER\" + Sid.CurrentUser.StringSid + "_Classes";
const string hkuString = @"\REGISTRY\USER";
if (nativeKeyName.StartsWith(hkcrString, StringComparison.OrdinalIgnoreCase))
return "HKCR" + nativeKeyName.Substring(hkcrString.Length);
if (nativeKeyName.StartsWith(hklmString, StringComparison.OrdinalIgnoreCase))
return "HKLM" + nativeKeyName.Substring(hklmString.Length);
if (nativeKeyName.StartsWith(hkcucrString, StringComparison.OrdinalIgnoreCase))
return @"HKCU\Software\Classes" + nativeKeyName.Substring(hkcucrString.Length);
if (nativeKeyName.StartsWith(hkcuString, StringComparison.OrdinalIgnoreCase))
return "HKCU" + nativeKeyName.Substring(hkcuString.Length);
if (nativeKeyName.StartsWith(hkuString, StringComparison.OrdinalIgnoreCase))
return "HKU" + nativeKeyName.Substring(hkuString.Length);
return nativeKeyName;
}
public static string GetMessage(IntPtr dllHandle, int messageTableId, int messageLanguageId, int messageId)
{
IntPtr messageEntry;
string message;
NtStatus status = Win32.RtlFindMessage(
dllHandle,
messageTableId,
messageLanguageId,
messageId,
out messageEntry
);
if (status.IsError())
return null;
MemoryRegion region = new MemoryRegion(messageEntry);
MessageResourceEntry entry = region.ReadStruct();
// Read the message, depending on format.
if ((entry.Flags & MessageResourceFlags.Unicode) == MessageResourceFlags.Unicode)
{
message = region.ReadUnicodeString(MessageResourceEntry.TextOffset);
}
else
{
message = region.ReadAnsiString(MessageResourceEntry.TextOffset);
}
return message;
}
public static bool ObjectExists(string name)
{
if (string.IsNullOrEmpty(name))
return false;
if (name == "\\")
return true;
string[] s = name.Split('\\');
string lastPart = s[s.Length - 1];
string dirPart = name.Substring(0, name.Length - lastPart.Length - 1); // -1 char to leave out the trailing backslash
try
{
using (var dhandle = new DirectoryHandle(dirPart, DirectoryAccess.Query))
{
var objects = dhandle.GetObjects();
foreach (var obj in objects)
{
if (obj.Name.Equals(lastPart, StringComparison.OrdinalIgnoreCase))
return true;
}
return false;
}
}
catch (WindowsException)
{
return false;
}
}
public static NativeHandle OpenObject(int access, string name, ObjectFlags objectFlags, NativeHandle rootDirectory)
{
ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory);
try
{
return null;// new NativeHandle(KProcessHacker.Instance.KphOpenNamedObject(access, oa).ToIntPtr(), true);
}
finally
{
oa.Dispose();
}
}
}
}