首先说下代码原理
1.使用CreateProcess 创建一个带 CREATE_SUSPENDED标记的进程
自然进程创建加载完DLL后会被挂起。 CREATE_SUSPENDED 标记本是为调试器准备的。
2.然后用GetThreadContext获取该进程的线程上下文,保存下来(重要)。。。。
3.用VirtualAllocEx 在进程空间申请一段 dll路径长度 + 32字节的内存(这里直接申请了1k) 用来存放shellcode
和dll路径。
4.把 DLL路径用 WriteProcessMemory 写入到申请的内存空间地址
5.然后组合计算shellcode代码(这里将不解释计算,具体看代码注释)
6.把shellcode用WriteProcessMemory 写入到申请的内存空间地址
7.修改上下文状态的 Eip为刚用VirtualAllocEx 申请的内存地址
8.用 SetThreadContext 设置线程上下文状态
9.用 ResumeThread 恢复线程。
下面给出代码 两个类 一个 注入, 一个API
使用方式
Win32.Injection.EipInject EI = new Win32.Injection.EipInject();
EI.CreateProcess(@"D:\Test.exe",@"D:\Test.dll");
using System;
using System.Runtime.InteropServices;
namespace Win32.Injection
{
public static class WinApi
{
public const int CREATE_SUSPENDED = 0x00000004;
public const UInt32 MEM_COMMIT = 0x00001000;
public const UInt32 CONTEXT_i386 = 0x00010000; // this assumes that i386 and
public const UInt32 CONTEXT_CONTROL = (CONTEXT_i386 | 0x00000001); // SS:SP, CS:IP, FLAGS, BP
[DllImport("kernel32")]
public static extern IntPtr LoadLibrary(string lpLibFileName);
[DllImport("kernel32")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
[DllImport("kernel32", EntryPoint = "VirtualAllocEx")]
public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, Int32 dwSize, UInt32 flAllocationType, PAGE_EXECUTE_ENUM flProtect);
[DllImport("kernel32", EntryPoint = "GetThreadContext")]
public static extern int GetThreadContext(IntPtr hThread, ref CONTEXT lpContext);
[DllImport("kernel32")]
public static extern Int32 WriteProcessMemory(IntPtr hProcess, IntPtr lpBassAddress, byte[] lpBuffer, Int32 nSize, IntPtr lpNumberOfBytesRead);
[DllImport("kernel32", EntryPoint = "SetThreadContext")]
public static extern int SetThreadContext(IntPtr hThread, ref CONTEXT lpContext);
[DllImport("kernel32", EntryPoint = "ResumeThread")]
public static extern int ResumeThread(IntPtr hThread);
public enum PAGE_EXECUTE_ENUM
{
PAGE_EXECUTE_READ = 0x20,
PAGE_EXECUTE_READWRITE = 0x40
}
public struct STARTUPINFO
{
public int cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public int dwX;
public int dwY;
public int dwXSize;
public int dwYSize;
public int dwXCountChars;
public int dwYCountChars;
public int dwFillAttribute;
public int dwFlags;
public short wShowWindow;
public short cbReserved2;
public int lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
public struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public int dwProcessId;
public int dwThreadId;
}
[DllImport("kernel32", EntryPoint = "CreateProcess")]
public static extern int CreateProcess(
string lpApplicationName,
string lpCommandLine,
IntPtr lpProcessAttributes,
IntPtr lpThreadAttributes,
bool bInheritHandles,
int dwCreationFlags,
IntPtr lpEnvironment,
String lpCurrentDriectory,
ref STARTUPINFO lpStartupInfo,
ref PROCESS_INFORMATION lpProcessInformation);
public struct FLOATING_SAVE_AREA
{
public UInt32 ControlWord;
public UInt32 StatusWord;
public UInt32 TagWord;
public UInt32 ErrorOffset;
public UInt32 ErrorSelector;
public UInt32 DataOffset;
public UInt32 DataSelector;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 80)]
public Byte[] RegisterArea;
public UInt32 Spare0;
}
/// <summary>
/// 寄存器上下文
/// </summary>
public struct CONTEXT
{
public UInt32 ContextFlags;
//
// This section is specified/returned if CONTEXT_DEBUG_REGISTERS is
// set in ContextFlags. Note that CONTEXT_DEBUG_REGISTERS is NOT
// included in CONTEXT_FULL.
//
public UInt32 Dr0;
public UInt32 Dr1;
public UInt32 Dr2;
public UInt32 Dr3;
public UInt32 Dr6;
public UInt32 Dr7;
//
// This section is specified/returned if the
// ContextFlags word contians the flag CONTEXT_FLOATING_POINT.
//
public FLOATING_SAVE_AREA FloatSave;
//
// This section is specified/returned if the
// ContextFlags word contians the flag CONTEXT_SEGMENTS.
//
public UInt32 SegGs;
public UInt32 SegFs;
public UInt32 SegEs;
public UInt32 SegDs;
//
// This section is specified/returned if the
// ContextFlags word contians the flag CONTEXT_INTEGER.
//
public UInt32 Edi;
public UInt32 Esi;
public UInt32 Ebx;
public UInt32 Edx;
public UInt32 Ecx;
public UInt32 Eax;
//
// This section is specified/returned if the
// ContextFlags word contians the flag CONTEXT_CONTROL.
//
public UInt32 Ebp;
public UInt32 Eip;
public UInt32 SegCs; // MUST BE SANITIZED
public UInt32 EFlags; // MUST BE SANITIZED
public UInt32 Esp;
public UInt32 SegSs;
//
// This section is specified/returned if the ContextFlags word
// contains the flag CONTEXT_EXTENDED_REGISTERS.
// The format and contexts are processor specific
//
//BYTE ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)]
public Byte[] ExtendedRegisters;
}
}
}
using System;
using System.Text;
namespace Win32.Injection
{
public class EipInject
{
public EipInject()
{
// pushad
ShellCode[0] = 0x60;
// pushfd
ShellCode[1] = 0x9c;
// push
ShellCode[2] = 0x68;
//call
ShellCode[7] = 0xE8;
// popfd
ShellCode[12] = 0x9d;
// popad
ShellCode[13] = 0x61;
// jmp
ShellCode[14] = 0xE9;
hModule = WinApi.LoadLibrary("Kernel32.dll");
//获取MessageBoxA地址
LoadLibrary_addr = WinApi.GetProcAddress(hModule, "LoadLibraryA");
}
/// <summary>
/// 创建指定进程并加载DLL
/// </summary>
/// <param name="AppPath"></param>
/// <param name="DllPath"></param>
/// <returns></returns>
public bool CreateProcess(String AppPath, String DllPath)
{
WinApi.CONTEXT context = new WinApi.CONTEXT();
Byte[] DllPathData = Encoding.Default.GetBytes(DllPath);
if (!_CreateProcess(AppPath))
{
return false;
}
//获取线程上下文
context.ContextFlags = WinApi.CONTEXT_CONTROL;
if (WinApi.GetThreadContext(hThread, ref context) != 0)
{
Int32 dwSize = 1024;
//申请内存
IntPtr pProcessMem = AllocMemory(dwSize);
if (pProcessMem == IntPtr.Zero)
{
return false;
}
//DLL路径地址 pProcessMem + 0x100
BuilderValue(ShellCode, 3, pProcessMem + 0x100);
//LoadLibrary地址 地址等于 CALL绝对地址 - 下条指令地址
BuilderValue(ShellCode, 8, LoadLibrary_addr - (pProcessMem.ToInt32() + 12));
// 跳回 旧的 eip 地址 ct.Eip - (pProcessMem + 19); (绝对地址-下条指令地址)
BuilderValue(ShellCode, 15, (int)context.Eip - (pProcessMem.ToInt32() + 19));
//先把 ShellCode 写进地址
WinApi.WriteProcessMemory(hProcess, pProcessMem, ShellCode, ShellCode.Length, IntPtr.Zero);
//把DLL路径写到内存里,从0x100(256)开始
WinApi.WriteProcessMemory(hProcess, (pProcessMem + 0x100), DllPathData, DllPathData.Length, IntPtr.Zero);
//改写EIP
context.Eip = (UInt32)pProcessMem;
//把线程上下文写回去
WinApi.SetThreadContext(hThread, ref context);
//恢复挂起线程
WinApi.ResumeThread(hThread);
return true;
}
else
{
return false;
}
}
/// <summary>
/// 负责创建一个被挂起的进程
/// </summary>
/// <param name="AppPath"></param>
/// <returns></returns>
private bool _CreateProcess(String AppPath)
{
WinApi.STARTUPINFO si = new WinApi.STARTUPINFO();
WinApi.PROCESS_INFORMATION PI = new WinApi.PROCESS_INFORMATION();
int HResult = WinApi.CreateProcess(
null,
// 程序路径 命令行
AppPath,
IntPtr.Zero,
IntPtr.Zero,
false,
// 挂起进程 只调试这个进程
WinApi.CREATE_SUSPENDED,
IntPtr.Zero,
//工作目录
System.IO.Path.GetDirectoryName(AppPath),
ref si,
ref PI);
if (HResult == 0)
return false;
hProcess = PI.hProcess;
hThread = PI.hThread;
return true;
}
/// <summary>
/// 负责申请一段内存
/// </summary>
/// <param name="Size"></param>
/// <returns></returns>
private IntPtr AllocMemory(Int32 Size)
{
return WinApi.VirtualAllocEx(hProcess, IntPtr.Zero, Size, WinApi.MEM_COMMIT, WinApi.PAGE_EXECUTE_ENUM.PAGE_EXECUTE_READWRITE);
}
/// <summary>
/// 负责把四字节整数写进shellcode
/// </summary>
/// <param name="ShellCode"></param>
/// <param name="Index"></param>
/// <param name="Value"></param>
private void BuilderValue(Byte[] ShellCode, Int32 Index, IntPtr Value)
{
Byte[] DATA = BitConverter.GetBytes(Value.ToInt32());
Array.Copy(DATA, 0, ShellCode, Index, 4);
}
/// <summary>
/// 负责把四字节整数写进shellcode
/// </summary>
/// <param name="ShellCode"></param>
/// <param name="Index"></param>
/// <param name="Value"></param>
private void BuilderValue(Byte[] ShellCode, Int32 Index, Int32 Value)
{
Byte[] DATA = BitConverter.GetBytes(Value);
Array.Copy(DATA, 0, ShellCode, Index, 4);
}
/// <summary>
/// 创建进程句柄
/// </summary>
public IntPtr hProcess = IntPtr.Zero;
/// <summary>
/// 创建进程线程句柄
/// </summary>
public IntPtr hThread = IntPtr.Zero;
private IntPtr hModule = IntPtr.Zero;
private IntPtr LoadLibrary_addr = IntPtr.Zero;
private Byte[] ShellCode = new byte[32];
}
}