Created
December 20, 2022 22:19
-
-
Save rasta-mouse/2f6316083dd2f38bb91f160cca2088df to your computer and use it in GitHub Desktop.
Attempt at NtCreateUserProcess in C# (not working)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Diagnostics; | |
using System.Runtime.InteropServices; | |
namespace CreateProcess; | |
internal static class Program | |
{ | |
public static void Main(string[] args) | |
{ | |
var imagePath = new UNICODE_STRING(); | |
RtlInitUnicodeString(ref imagePath, @"\\??\\C:\\Windows\\System32\\mmc.exe"); | |
var processParams = IntPtr.Zero; | |
var status = RtlCreateProcessParametersEx( | |
ref processParams, | |
ref imagePath, | |
IntPtr.Zero, | |
IntPtr.Zero, | |
IntPtr.Zero, | |
IntPtr.Zero, | |
IntPtr.Zero, | |
IntPtr.Zero, | |
IntPtr.Zero, | |
IntPtr.Zero, | |
0x01); | |
if (status != 0) | |
{ | |
Console.WriteLine("RtlCreateProcessParametersEx failed"); | |
return; | |
} | |
var ci = new PS_CREATE_INFO(); | |
ci.Size = (UIntPtr) Marshal.SizeOf(ci); | |
ci.State = PS_CREATE_STATE.PsCreateInitialState; | |
var attributeList = new PS_ATTRIBUTE_LIST(); | |
attributeList.TotalLength = (UIntPtr) Marshal.SizeOf(attributeList); | |
attributeList.Attributes = new PS_ATTRIBUTE[2]; | |
attributeList.Attributes[0].Attribute = 0x20005; | |
attributeList.Attributes[0].Size = imagePath.Length; | |
attributeList.Attributes[0].Value = imagePath.Buffer; | |
using var self = Process.GetCurrentProcess(); | |
attributeList.Attributes[1].Attribute = 0x60000; | |
attributeList.Attributes[1].Size = (ushort) IntPtr.Size; | |
attributeList.Attributes[1].Value = self.Handle; | |
var hProcess = IntPtr.Zero; | |
var hThread = IntPtr.Zero; | |
status = NtCreateUserProcess( | |
ref hProcess, | |
ref hThread, | |
2097151, | |
2097151, | |
IntPtr.Zero, | |
IntPtr.Zero, | |
0, | |
0, | |
processParams, | |
ref ci, | |
ref attributeList); | |
if (status != 0) | |
Console.WriteLine("NtCreateUserProcess failed"); | |
} | |
[DllImport("ntdll.dll")] | |
private static extern void RtlInitUnicodeString( | |
ref UNICODE_STRING destinationString, | |
[MarshalAs(UnmanagedType.LPWStr)] string sourceString); | |
[DllImport("ntdll.dll")] | |
private static extern uint RtlCreateProcessParametersEx( | |
ref IntPtr processParameters, | |
ref UNICODE_STRING imagePathName, | |
IntPtr dllPath, | |
IntPtr currentDirectory, | |
IntPtr commandLine, | |
IntPtr environment, | |
IntPtr windowTitle, | |
IntPtr desktopInfo, | |
IntPtr shellInfo, | |
IntPtr runtimeData, | |
uint flags); | |
[DllImport("ntdll.dll")] | |
private static extern uint NtCreateUserProcess( | |
ref IntPtr processHandle, | |
ref IntPtr threadHandle, | |
long processDesiredAccess, | |
long threadDesiredAccess, | |
IntPtr processObjectAttributes, | |
IntPtr threadObjectAttributes, | |
uint processFlags, | |
uint threadFlags, | |
IntPtr processParameters, | |
ref PS_CREATE_INFO psCreateInfo, | |
ref PS_ATTRIBUTE_LIST psAttributeList); | |
[StructLayout(LayoutKind.Sequential)] | |
private struct PS_CREATE_INFO | |
{ | |
public UIntPtr Size; | |
public PS_CREATE_STATE State; | |
} | |
private enum PS_CREATE_STATE | |
{ | |
PsCreateInitialState = 0, | |
PsCreateFailOnFileOpen = 1, | |
PsCreateFailOnSectionCreate = 2, | |
PsCreateFailExeFormat = 3, | |
PsCreateFailMachineMismatch = 4, | |
PsCreateFailExeName = 5, | |
PsCreateSuccess = 6, | |
PsCreateMaximumStates = 7 | |
}; | |
[StructLayout(LayoutKind.Sequential)] | |
private struct PS_ATTRIBUTE | |
{ | |
public ulong Attribute; | |
public ushort Size; | |
public IntPtr Value; | |
public IntPtr ReturnLength; | |
} | |
[StructLayout(LayoutKind.Sequential)] | |
private struct PS_ATTRIBUTE_LIST | |
{ | |
public UIntPtr TotalLength; | |
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] | |
public PS_ATTRIBUTE[] Attributes; | |
} | |
[StructLayout(LayoutKind.Sequential)] | |
private struct UNICODE_STRING | |
{ | |
public ushort Length; | |
public ushort MaximumLength; | |
public IntPtr Buffer; | |
} | |
} |
@Kudaes , Thanks for the update. I was able to further simplify the code and arrived at a weird conclusion that the Marshaled pointers are not being set up correctly. Not sure how as my C# and NT Internals is a bit rusty. :(
@rasta-mouse Is the original code setting up the Marshal.SizeOf pointers correctly? Seems like these variables are the root cause of the issues:
#L35 ci.Size = (UIntPtr) Marshal.SizeOf(ci);
#L39 attributeList.TotalLength = (UIntPtr) Marshal.SizeOf(attributeList);
#L12 Thinking the image path can be single slashes, as that produces a different error code even with the marshal fixes that Kudaes mentioned.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi, i fixed a few things from your code and it's working for me. Still a dirty code, I guess it can be improved a little bit.