申请会员ID:wwh1004【申请通过】
申请I D:wwh1004申请邮箱:wwh1004@hotmail.com
csdn上的http://blog.csdn.net/wwh1004就是我,非冒充
- 由来
网上流传的注入托管DLL说是纯C#,实际上还是调用了C++编写的DLL用于在远程进程中启动CLR。这样做会让被注入进程多一个已加载DLL,发布的程序也会带一个启动CLR的DLL(比如CLRInjection还带着LoadCLR2.dll和LoadCLR4.dll),看着很不舒服。所以我看了下MegaDumper.exe的注入方式,发现是手写机器码,所以我也手写机器码实现了,并且支持32位/64位,无CLR环境/有CLR环境,不同CLR版本的注入器(MegaDumper.exe是只支持32位且被注入进程必须存在CLRv2环境)。
- 注入过程
注入器是这样注入托管程序集的:
先注入对应的mscoree.dll
再注入托管程序集
- 过程分析
这2步都是难点,第一步的难点是如果判断DLL是否为托管程序集并且获取到DLL的目标CLR版本。也许有人会说用Assembly.Load*系列方法,但是很遗憾,这种方法稳定性极差,如果同时判断同名不同目标CLR版本程序集,第二次判断的结果将与第一次相同。举个例子,有2个同名程序集A和B,A的目标CLR版本是v2,B的目标CLR版本是v4,先用Assembly.Load*系列方法判断了A,获取了A的目标CLR版本,我再用Assembly.Load*系列方法判断B并获取B的目标CLR版本,返回的将是A的目标CLR版本。这是一个藏的很深的BUG,我也是很久才发现有这个问题。
我本打算用dnlib.dll直接读取程序集的目标CLR版本,但是dnlib.dll太大了,1MB有多,于是自己解析PE头。
```
private struct Section
{
public uint VirtualSize;
public uint VirtualAddress;
public uint SizeOfRawData;
public uint PointerToRawData;
public Section(uint virtualSize, uint virtualAddress, uint sizeOfRawData, uint pointerToRawData)
{
VirtualSize = virtualSize;
VirtualAddress = virtualAddress;
SizeOfRawData = sizeOfRawData;
PointerToRawData = pointerToRawData;
}
}
/// <summary>
/// 获取CLR版本
/// </summary>
/// <param name="binaryReader"></param>
/// <returns></returns>
private static string GetVersionString(BinaryReader binaryReader)
{
uint ntHeaderOffset;
bool is64;
Section[] sections;
uint rva;
Section? section;
GetPEInfo(binaryReader, out ntHeaderOffset, out is64);
binaryReader.BaseStream.Position = ntHeaderOffset + (is64 ? 0xF8 : 0xE8);
rva = binaryReader.ReadUInt32();
//.Net MetaData Directory RVA
if (rva == 0)
throw new BadImageFormatException("文件不是程序集");
sections = GetSections(binaryReader);
section = GetSection(rva, sections);
if (section == null)
throw new InvalidDataException("未知格式的二进制文件");
binaryReader.BaseStream.Position = section.Value.PointerToRawData + rva - section.Value.VirtualAddress + 0x8;
//.Net MetaData Directory FileOffset
rva = binaryReader.ReadUInt32();
//.Net MetaData Header RVA
if (rva == 0)
throw new BadImageFormatException("文件不是程序集");
section = GetSection(rva, sections);
if (section == null)
throw new InvalidDataException("未知格式的二进制文件");
binaryReader.BaseStream.Position = section.Value.PointerToRawData + rva - section.Value.VirtualAddress + 0xC;
//.Net MetaData Header FileOffset
return Encoding.UTF8.GetString(binaryReader.ReadBytes(binaryReader.ReadInt32() - 2));
}
/// <summary>
/// 获取PE信息
/// </summary>
/// <param name="binaryReader"></param>
/// <param name="ntHeaderOffset"></param>
/// <param name="is64"></param>
private static void GetPEInfo(BinaryReader binaryReader, out uint ntHeaderOffset, out bool is64)
{
ushort machine;
binaryReader.BaseStream.Position = 0x3C;
ntHeaderOffset = binaryReader.ReadUInt32();
binaryReader.BaseStream.Position = ntHeaderOffset + 0x4;
machine = binaryReader.ReadUInt16();
if (machine != 0x14C && machine != 0x8664)
throw new InvalidDataException("未知格式的二进制文件");
is64 = machine == 0x8664;
}
/// <summary>
/// 获取节
/// </summary>
/// <param name="binaryReader"></param>
/// <returns></returns>
private static Section[] GetSections(BinaryReader binaryReader)
{
uint ntHeaderOffset;
bool is64;
ushort numberOfSections;
Section[] sections;
GetPEInfo(binaryReader, out ntHeaderOffset, out is64);
numberOfSections = binaryReader.ReadUInt16();
binaryReader.BaseStream.Position = ntHeaderOffset + (is64 ? 0x108 : 0xF8);
sections = new Section;
for (int i = 0; i < numberOfSections; i++)
{
binaryReader.BaseStream.Position += 0x8;
sections = new Section(binaryReader.ReadUInt32(), binaryReader.ReadUInt32(), binaryReader.ReadUInt32(), binaryReader.ReadUInt32());
binaryReader.BaseStream.Position += 0x10;
}
return sections;
}
/// <summary>
/// 获取RVA对应节
/// </summary>
/// <param name="rva"></param>
/// <param name="sections"></param>
/// <returns></returns>
private static Section? GetSection(uint rva, Section[] sections)
{
foreach (Section section in sections)
if (rva >= section.VirtualAddress && rva < section.VirtualAddress + Math.Max(section.VirtualSize, section.SizeOfRawData))
return section;
return null;
}
```
第一个难点解决了,接下来看第二个难点,如何注入?全手写机器码意味着极大的工作量,为什么不用c++写好函数,提取出编译好的机器码呢?提取出来的机器码是固定了变量地址的,所以还要自己改。手改机器码肯定难,于是写了一段新代码用来帮助修改
```
public static class AsmCodeHelper
{
public static bool Is64;
public static void SetCode()
{
string codes;
Assembler.NasmPath = "nasm.exe";
Assembler.NdisasmPath = "ndisasm.exe";
codes = string.Join(Environment.NewLine, BytesToCSharpCode(File.ReadAllText("strbytes.txt")));
Clipboard.SetText(codes);
}
private static List<string> BytesToCSharpCode(string strBytes)
{
byte[] bytes;
bytes = strBytes.Split(' ').Select(s => Convert.ToByte(s, 16)).ToArray();
return BytesToCSharpCode(bytes);
}
private static List<string> BytesToCSharpCode(byte[] bytes)
{
IList<AsmData> asmDataList;
List<string> codeList;
File.WriteAllLines("opcodes.txt", Assembler.BytesToOpcodes(bytes, Is64).GetAllOpcodes());
Process.Start(@"C:\Software\Notepad++\notepad++.exe", Path.GetFullPath("opcodes.txt"));
Console.WriteLine("反编译完成,按任意键继续......");
Console.ReadKey();
asmDataList = Assembler.OpcodesToBytes(File.ReadAllLines("opcodes.txt"), Is64);
codeList = new List<string>(asmDataList.Count * 8);
foreach (AsmData asmData in asmDataList)
codeList.AddRange(BytesToCSharpCodeSub(asmData.Bytes, asmData.Opcode));
return codeList;
}
private static List<string> BytesToCSharpCodeSub(byte[] bytes, string opcode)
{
List<string> codeList;
codeList = new List<string>(bytes.Length + 2);
for (int i = 0; i < bytes.Length; i++)
codeList.Add(string.Format("p[{0}] = 0x{1};", i.ToString(), bytes.ToString("X2")));
codeList.Add(string.Format("p += {0};", bytes.Length.ToString()));
codeList.Add(string.Format("//{0}", opcode));
return codeList;
}
}
```
利用ndisasm和nasm轻松反编译与编译,修改好后直接生成c#写机器码的代码。在改的时候会发现,CorBindToRuntimeEx和CLRCreateInstance函数的地址是不确定的,这又要自己获取。GetProcAddress只能获取当前进程的,并不能获取远程进程,所以这又需要我们熟悉PE结构。利用DLL的导出表,可以自己获取,代码如下:
```
/// <summary>
/// 获取模块句柄,获取失败时返回 <see cref="IntPtr.Zero"/>
/// </summary>
/// <param name="processHandle">进程句柄</param>
/// <param name="first">是否返回第一个模块句柄</param>
/// <param name="moduleName">模块名</param>
/// <param name="flag">过滤标识</param>
/// <returns></returns>
internal static unsafe IntPtr GetHandleInternal(IntPtr processHandle, bool first, string moduleName, uint flag)
{
if (!first && string.IsNullOrEmpty(moduleName))
throw new ArgumentNullException("first为false时moduleName不能为空");
bool is64;
bool isXP;
IntPtr moduleHandle;
uint size;
IntPtr[] moduleHandles;
StringBuilder moduleNameBuffer;
if (processHandle == IntPtr.Zero)
return IntPtr.Zero;
if (!Process32.Is64ProcessInternal(processHandle, out is64))
return IntPtr.Zero;
if (is64 && !Environment.Is64BitProcess)
throw new NotSupportedException("目标进程为64位但当前进程为32位");
moduleHandle = IntPtr.Zero;
isXP = Environment.OSVersion.Version.Major == 5;
if (isXP)
{
//XP兼容
if (!EnumProcessModules(processHandle, &moduleHandle, (uint)IntPtr.Size, out size))
return IntPtr.Zero;
}
else
{
if (!EnumProcessModulesEx(processHandle, &moduleHandle, (uint)IntPtr.Size, out size, flag))
//先获取储存所有模块句柄所需的字节数
return IntPtr.Zero;
}
if (first)
//返回第一个模块句柄
return moduleHandle;
moduleHandles = new IntPtr;
fixed (IntPtr* p = &moduleHandles)
{
if (isXP)
{
//XP兼容
if (!EnumProcessModules(processHandle, p, size, out size))
return IntPtr.Zero;
}
else
{
if (!EnumProcessModulesEx(processHandle, p, size, out size, flag))
//获取所有模块句柄
return IntPtr.Zero;
}
}
moduleNameBuffer = new StringBuilder((int)MODULENAME_MAX_LENGTH);
for (int i = 0; i < moduleHandles.Length; i++)
{
if (!GetModuleBaseName(processHandle, moduleHandles, moduleNameBuffer, MODULENAME_MAX_LENGTH))
return IntPtr.Zero;
if (moduleNameBuffer.ToString().Equals(moduleName, StringComparison.OrdinalIgnoreCase))
return moduleHandles;
}
return IntPtr.Zero;
}
/// <summary>
/// 获取远程进程函数地址
/// </summary>
/// <param name="processHandle">进程句柄</param>
/// <param name="moduleName">模块名</param>
/// <param name="functionName">函数名</param>
/// <returns></returns>
internal static unsafe IntPtr GetProcAddressInternal(IntPtr processHandle, string moduleName, string functionName)
{
IntPtr moduleHandle;
int ntHeaderOffset;
bool is64;
int iedRVA;
IMAGE_EXPORT_DIRECTORY ied;
int[] nameOffsets;
string name;
short ordinal;
int addressOffset;
moduleHandle = GetHandleInternal(processHandle, false, moduleName, EnumModulesFilterFlag.ALL);
if (moduleHandle == IntPtr.Zero)
return IntPtr.Zero;
if (!MemoryIO.ReadInt32Internal(processHandle, moduleHandle + 0x3C, out ntHeaderOffset))
return IntPtr.Zero;
if (!Process32.Is64ProcessInternal(processHandle, out is64))
return IntPtr.Zero;
if (is64)
{
if (!MemoryIO.ReadInt32Internal(processHandle, moduleHandle + ntHeaderOffset + 0x88, out iedRVA))
return IntPtr.Zero;
}
else
{
if (!MemoryIO.ReadInt32Internal(processHandle, moduleHandle + ntHeaderOffset + 0x78, out iedRVA))
return IntPtr.Zero;
}
if (!ReadProcessMemory(processHandle, moduleHandle + iedRVA, &ied, 40, null))
return IntPtr.Zero;
nameOffsets = new int;
fixed (void* p = &nameOffsets)
if (!ReadProcessMemory(processHandle, moduleHandle + (int)ied.AddressOfNames, p, ied.NumberOfNames * 4, null))
return IntPtr.Zero;
for (int i = 0; i < ied.NumberOfNames; i++)
{
if (!MemoryIO.ReadStringInternal(processHandle, moduleHandle + nameOffsets, out name, 40, false, Encoding.ASCII))
return IntPtr.Zero;
if (name == functionName)
{
if (!MemoryIO.ReadInt16Internal(processHandle, moduleHandle + (int)ied.AddressOfNameOrdinals + i * 2, out ordinal))
return IntPtr.Zero;
if (!MemoryIO.ReadInt32Internal(processHandle, moduleHandle + (int)ied.AddressOfFunctions + ordinal * 4, out addressOffset))
return IntPtr.Zero;
return moduleHandle + addressOffset;
}
}
return IntPtr.Zero;
}
```
完整的注入器代码:
```
using System;
using System.IO;
using System.Text;
using FastWin32.Memory;
using static FastWin32.NativeMethods;
namespace FastWin32.Diagnostics
{
/// <summary>
/// 注入
/// </summary>
public static class Injector
{
#region Constant
private const int AsmSize = 0x2000;
private const int MachineCodeSize = 0x200;
private const int AssemblyPathOffset = 0x200;
private const int TypeNameOffset = 0x800;
private const int MethodNameOffset = 0x980;
private const int ArgumentOffset = 0xA00;
private const int ReturnValueOffset = 0x1200;
private const int CLRVersionOffset = 0x1210;
private const int CLSID_CLRMetaHostOffset = 0x1260;
private const int IID_ICLRMetaHostOffset = 0x1270;
private const int IID_ICLRRuntimeInfoOffset = 0x1280;
private const int CLSID_CLRRuntimeHostOffset = 0x1290;
private const int IID_ICLRRuntimeHostOffset = 0x12A0;
private const int AvailableOffset = 0x12B0;
private readonly static byte[] CLSID_CLRMetaHost = new Guid(0x9280188D, 0x0E8E, 0x4867, 0xB3, 0x0C, 0x7F, 0xA8, 0x38, 0x84, 0xE8, 0xDE).ToByteArray();
private readonly static byte[] IID_ICLRMetaHost = new Guid(0xD332DB9E, 0xB9B3, 0x4125, 0x82, 0x07, 0xA1, 0x48, 0x84, 0xF5, 0x32, 0x16).ToByteArray();
private readonly static byte[] IID_ICLRRuntimeInfo = new Guid(0xBD39D1D2, 0xBA2F, 0x486A, 0x89, 0xB0, 0xB4, 0xB0, 0xCB, 0x46, 0x68, 0x91).ToByteArray();
private readonly static byte[] CLSID_CLRRuntimeHost = new Guid(0x90F1A06E, 0x7712, 0x4762, 0x86, 0xB5, 0x7A, 0x5E, 0xBA, 0x6B, 0xDB, 0x02).ToByteArray();
private readonly static byte[] IID_ICLRRuntimeHost = new Guid(0x90F1A06C, 0x7712, 0x4762, 0x86, 0xB5, 0x7A, 0x5E, 0xBA, 0x6B, 0xDB, 0x02).ToByteArray();
#endregion
private struct Section
{
public uint VirtualSize;
public uint VirtualAddress;
public uint SizeOfRawData;
public uint PointerToRawData;
public Section(uint virtualSize, uint virtualAddress, uint sizeOfRawData, uint pointerToRawData)
{
VirtualSize = virtualSize;
VirtualAddress = virtualAddress;
SizeOfRawData = sizeOfRawData;
PointerToRawData = pointerToRawData;
}
}
/// <summary>
/// 打开进程(注入使用)
/// </summary>
/// <param name="processId">进程句柄</param>
/// <returns></returns>
private static IntPtr OpenProcessInjecting(uint processId)
{
return OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_QUERY_INFORMATION, false, processId);
}
/// <summary>
/// 注入非托管DLL
/// </summary>
/// <param name="processId">要注入的进程ID</param>
/// <param name="assemblyPath">要注入程序集的路径</param>
/// <param name="typeName">类型名(命名空间+类型名,比如NamespaceA.ClassB)</param>
/// <param name="methodName">方法名(比如MethodC),该方法必须具有此类签名static int MethodName(string),比如private static int InjectingMain(string argument)</param>
/// <param name="argument">参数,长度必须小于1024个字符,可传入null。</param>
/// <returns></returns>
public static bool InjectManaged(uint processId, string assemblyPath, string typeName, string methodName, string argument)
{
if (string.IsNullOrEmpty(assemblyPath))
throw new ArgumentNullException();
if (!File.Exists(assemblyPath))
throw new FileNotFoundException();
if (string.IsNullOrEmpty(typeName))
throw new ArgumentNullException();
if (string.IsNullOrEmpty(methodName))
throw new ArgumentNullException();
if (argument != null && argument.Length >= 1024)
throw new ArgumentOutOfRangeException(nameof(argument) + "长度必须小于1024个字符");
IntPtr processHandle;
int returnValue;
processHandle = OpenProcessInjecting(processId);
if (processHandle == IntPtr.Zero)
return false;
try
{
return InjectManagedInternal(processHandle, assemblyPath, typeName, methodName, argument, out returnValue, false);
}
finally
{
CloseHandle(processHandle);
}
}
/// <summary>
/// 注入非托管DLL,并获取被调用方法的返回值(警告:被调用方法返回后才能获取到返回值,<see cref="InjectManaged(uint, string, string, string, string, out int)"/>方法将一直等待到被调用方法返回。如果仅注入程序集而不需要获取返回值,请使用重载版本<see cref="InjectManaged(uint, string, string, string, string)"/>)
/// </summary>
/// <param name="processId">要注入的进程ID</param>
/// <param name="assemblyPath">要注入程序集的路径</param>
/// <param name="typeName">类型名(命名空间+类型名,比如NamespaceA.ClassB)</param>
/// <param name="methodName">方法名(比如MethodC),该方法必须具有此类签名static int MethodName(string),比如private static int InjectingMain(string argument)</param>
/// <param name="argument">参数,长度必须小于1024个字符,可传入null。</param>
/// <param name="returnValue">被调用方法返回的整数值</param>
/// <returns></returns>
public static bool InjectManaged(uint processId, string assemblyPath, string typeName, string methodName, string argument, out int returnValue)
{
if (string.IsNullOrEmpty(assemblyPath))
throw new ArgumentNullException();
if (!File.Exists(assemblyPath))
throw new FileNotFoundException();
if (string.IsNullOrEmpty(typeName))
throw new ArgumentNullException();
if (string.IsNullOrEmpty(methodName))
throw new ArgumentNullException();
if (argument != null && argument.Length >= 1024)
throw new ArgumentOutOfRangeException(nameof(argument) + "长度必须小于1024个字符");
IntPtr processHandle;
returnValue = 0;
processHandle = OpenProcessInjecting(processId);
if (processHandle == IntPtr.Zero)
return false;
try
{
return InjectManagedInternal(processHandle, assemblyPath, typeName, methodName, argument, out returnValue, true);
}
finally
{
CloseHandle(processHandle);
}
}
/// <summary>
/// 注入非托管DLL
/// </summary>
/// <param name="processHandle">进程句柄</param>
/// <param name="assemblyPath">要注入程序集的路径</param>
/// <param name="typeName">类型名(命名空间+类型名,比如NamespaceA.ClassB)</param>
/// <param name="methodName">方法名(比如MethodC),该方法必须具有此类签名static int MethodName(string),比如private static int InjectingMain(string argument)</param>
/// <param name="argument">参数,长度必须小于1024个字符,可传入null。</param>
/// <param name="returnValue">被调用方法返回的整数值</param>
/// <param name="wait">是否等待返回值</param>
/// <returns></returns>
internal static unsafe bool InjectManagedInternal(IntPtr processHandle, string assemblyPath, string typeName, string methodName, string argument, out int returnValue, bool wait)
{
bool isAssembly;
bool is64;
string clrVersion;
IntPtr pFunction;
IntPtr threadHandle;
uint exitCode;
returnValue = 0;
assemblyPath = Path.GetFullPath(assemblyPath);
//获取绝对路径
IsAssembly(assemblyPath, out isAssembly, out clrVersion);
if (!isAssembly)
throw new NotSupportedException("将注入的DLL为不是程序集,应该调用InjectUnmanaged方法而非调用InjectManaged方法");
if (!Process32.Is64ProcessInternal(processHandle, out is64))
return false;
if (!InjectUnmanagedInternal(processHandle, Path.Combine(GetSystemPath(is64), "mscoree.dll")))
return false;
//加载对应进程位数的mscoree.dll
pFunction = WriteAsm(processHandle, clrVersion, assemblyPath, typeName, methodName, argument);
//获取远程进程中启动CLR的函数指针
if (pFunction == IntPtr.Zero)
return false;
threadHandle = CreateRemoteThread(processHandle, null, 0, pFunction, pFunction + ReturnValueOffset, 0, null);
if (threadHandle == IntPtr.Zero)
return false;
if (wait)
{
WaitForSingleObject(threadHandle, INFINITE);
//等待线程结束
if (!GetExitCodeThread(threadHandle, out exitCode))
return false;
if (!MemoryIO.ReadInt32Internal(processHandle, pFunction + ReturnValueOffset, out returnValue))
return false;
//获取程序集中被调用方法的返回值
if (!MemoryManagement.FreeMemoryInternal(processHandle, pFunction))
return false;
return exitCode == 0;
//ICLRRuntimeHost::ExecuteInDefaultAppDomain返回S_OK(0)表示成功
}
return true;
}
/// <summary>
/// 注入非托管DLL
/// </summary>
/// <param name="processId">要注入的进程ID</param>
/// <param name="dllPath">要注入DLL的路径</param>
/// <returns></returns>
public static bool InjectUnmanaged(uint processId, string dllPath)
{
if (string.IsNullOrEmpty(dllPath))
throw new ArgumentNullException();
if (!File.Exists(dllPath))
throw new FileNotFoundException();
IntPtr processHandle;
bool isAssembly;
string clrVersion;
processHandle = OpenProcessInjecting(processId);
if (processHandle == IntPtr.Zero)
return false;
try
{
dllPath = Path.GetFullPath(dllPath);
//获取绝对路径
IsAssembly(dllPath, out isAssembly, out clrVersion);
if (isAssembly)
throw new NotSupportedException("将注入的DLL为程序集,应该调用InjectManaged方法而非调用InjectUnmanaged方法");
return InjectUnmanagedInternal(processHandle, dllPath);
//注入非托管DLL
}
finally
{
CloseHandle(processHandle);
}
}
/// <summary>
/// 注入非托管Dll
/// </summary>
/// <param name="processHandle">进程句柄</param>
/// <param name="dllPath">要注入的Dll的路径</param>
/// <returns></returns>
internal static unsafe bool InjectUnmanagedInternal(IntPtr processHandle, string dllPath)
{
bool is64;
IntPtr pLoadLibrary;
IntPtr pDllPath;
IntPtr threadHandle;
uint exitCode;
if (!Process32.Is64ProcessInternal(processHandle, out is64))
return false;
pLoadLibrary = Module32.GetProcAddressInternal(processHandle, "kernel32.dll", "LoadLibraryW");
//获取LoadLibrary的函数地址
pDllPath = MemoryManagement.AllocMemoryInternal(processHandle, (uint)dllPath.Length * 2 + 2, PAGE_EXECUTE_READ);
try
{
if (pDllPath == IntPtr.Zero)
return false;
if (!MemoryIO.WriteStringInternal(processHandle, pDllPath, dllPath))
return false;
threadHandle = CreateRemoteThread(processHandle, null, 0, pLoadLibrary, pDllPath, 0, null);
if (threadHandle == IntPtr.Zero)
return false;
WaitForSingleObject(threadHandle, INFINITE);
//等待线程结束
GetExitCodeThread(threadHandle, out exitCode);
return exitCode != 0;
//LoadLibrary返回值不为0则调用成功,否则失败
}
finally
{
MemoryManagement.FreeMemoryInternal(processHandle, pDllPath);
}
}
/// <summary>
/// 获取系统文件夹路径
/// </summary>
/// <param name="is64">是否64位</param>
/// <returns></returns>
private static string GetSystemPath(bool is64)
{
if (!Environment.Is64BitOperatingSystem)
return @"C:\Windows\System32";
else if (is64)
return @"C:\Windows\System32";
else
return @"C:\Windows\SysWOW64";
}
/// <summary>
/// 写入启动CLR的机器码,返回函数指针
/// </summary>
/// <param name="processHandle">进程句柄</param>
/// <param name="clrVersion">CLR版本</param>
/// <param name="assemblyPath">程序集路径(绝对路径)</param>
/// <param name="typeName">类型名</param>
/// <param name="methodName">方法名</param>
/// <param name="argument">参数(可空,如果非空,长度必须小于2000)</param>
/// <returns></returns>
private static unsafe IntPtr WriteAsm(IntPtr processHandle, string clrVersion, string assemblyPath, string typeName, string methodName, string argument)
{
bool is64;
byte[] asm;
IntPtr pFunction;
IntPtr pCorBindToRuntimeEx;
IntPtr pCLRCreateInstance;
if (!Process32.Is64ProcessInternal(processHandle, out is64))
return IntPtr.Zero;
asm = GetAsmCommon(clrVersion, assemblyPath, typeName, methodName, argument);
pFunction = MemoryManagement.AllocMemoryInternal(processHandle, AsmSize, PAGE_EXECUTE_READWRITE);
if (pFunction == IntPtr.Zero)
return IntPtr.Zero;
try
{
fixed (byte* p = &asm)
{
switch (clrVersion)
{
case "v2.0.50727":
pCorBindToRuntimeEx = Module32.GetProcAddressInternal(processHandle, "mscoree.dll", "CorBindToRuntimeEx");
if (pCorBindToRuntimeEx == IntPtr.Zero)
return IntPtr.Zero;
if (is64)
SetAsm64V2(p, (long)pFunction, (long)pCorBindToRuntimeEx);
else
SetAsm32V2(p, (int)pFunction, (int)pCorBindToRuntimeEx);
break;
case "v4.0.30319":
pCLRCreateInstance = Module32.GetProcAddressInternal(processHandle, "mscoree.dll", "CLRCreateInstance");
if (pCLRCreateInstance == IntPtr.Zero)
return IntPtr.Zero;
if (is64)
SetAsm64V4(p, (long)pFunction, (long)pCLRCreateInstance);
else
SetAsm32V4(p, (int)pFunction, (int)pCLRCreateInstance);
break;
default:
return IntPtr.Zero;
}
}
if (!MemoryIO.WriteBytesInternal(processHandle, pFunction, asm))
return IntPtr.Zero;
}
catch
{
MemoryManagement.FreeMemoryInternal(processHandle, pFunction);
return IntPtr.Zero;
}
return pFunction;
}
/// <summary>
/// 获取设置好参数的机器码
/// </summary>
/// <param name="clrVersion">CLR版本</param>
/// <param name="assemblyPath">程序集路径(绝对路径)</param>
/// <param name="typeName">类型名</param>
/// <param name="methodName">方法名</param>
/// <param name="argument">参数(可空,如果非空,长度必须小于2000)</param>
/// <returns></returns>
private static byte[] GetAsmCommon(string clrVersion, string assemblyPath, string typeName, string methodName, string argument)
{
byte[] bytes;
using (MemoryStream memoryStream = new MemoryStream(AsmSize))
{
bytes = Encoding.Unicode.GetBytes(assemblyPath);
memoryStream.Position = AssemblyPathOffset;
memoryStream.Write(bytes, 0, bytes.Length);
//assemblyPath
bytes = Encoding.Unicode.GetBytes(typeName);
memoryStream.Position = TypeNameOffset;
memoryStream.Write(bytes, 0, bytes.Length);
//typeName
bytes = Encoding.Unicode.GetBytes(methodName);
memoryStream.Position = MethodNameOffset;
memoryStream.Write(bytes, 0, bytes.Length);
//methodName
bytes = argument == null ? new byte : Encoding.Unicode.GetBytes(argument);
memoryStream.Position = ArgumentOffset;
memoryStream.Write(bytes, 0, bytes.Length);
//argument
bytes = Encoding.Unicode.GetBytes(clrVersion);
memoryStream.Position = CLRVersionOffset;
memoryStream.Write(bytes, 0, bytes.Length);
//clrVersion
memoryStream.Position = CLSID_CLRMetaHostOffset;
memoryStream.Write(CLSID_CLRMetaHost, 0, CLSID_CLRMetaHost.Length);
memoryStream.Position = IID_ICLRMetaHostOffset;
memoryStream.Write(IID_ICLRMetaHost, 0, IID_ICLRMetaHost.Length);
memoryStream.Position = IID_ICLRRuntimeInfoOffset;
memoryStream.Write(IID_ICLRRuntimeInfo, 0, IID_ICLRRuntimeInfo.Length);
memoryStream.Position = CLSID_CLRRuntimeHostOffset;
memoryStream.Write(CLSID_CLRRuntimeHost, 0, CLSID_CLRRuntimeHost.Length);
memoryStream.Position = IID_ICLRRuntimeHostOffset;
memoryStream.Write(IID_ICLRRuntimeHost, 0, IID_ICLRRuntimeHost.Length);
memoryStream.SetLength(AsmSize);
return memoryStream.ToArray();
}
}
/// <summary>
/// 设置启动32位CLR V2的机器码
/// </summary>
/// <param name="p">机器码指针</param>
/// <param name="pFunction">函数指针</param>
/// <param name="pCorBindToRuntimeEx">CorBindToRuntimeEx的函数指针</param>
private static unsafe void SetAsm32V2(byte* p, int pFunction, int pCorBindToRuntimeEx)
{
//HRESULT WINAPI LoadCLR2(DWORD *pReturnValue)
#region {
p = 0x55;
p += 1;
//push ebp
p = 0x89;
p = 0xE5;
p += 2;
//mov ebp,esp
p = 0x83;
p = 0xEC;
p = 0x44;
p += 3;
//sub esp,byte +0x44
p = 0x53;
p += 1;
//push ebx
p = 0x56;
p += 1;
//push esi
p = 0x57;
p += 1;
//push edi
p = 0xC7;
p = 0x45;
p = 0xFC;
p = 0x00;
p = 0x00;
p = 0x00;
p = 0x00;
p += 7;
#endregion
#region ICLRRuntimeHost *pRuntimeHost = nullptr;
//mov dword ,0x0
p = 0x8D;
p = 0x45;
p = 0xFC;
p += 3;
#endregion
#region CorBindToRuntimeEx(L"v2.0.50727", nullptr, 0, CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&pRuntimeHost);
//lea eax,
p = 0x50;
p += 1;
//push eax
p = 0x68;
*(int*)(p + 1) = pFunction + IID_ICLRRuntimeHostOffset;
p += 5;
//push dword PIID_ICLRRuntimeHost
p = 0x68;
*(int*)(p + 1) = pFunction + CLSID_CLRRuntimeHostOffset;
p += 5;
//push dword pCLSID_CLRRuntimeHost
p = 0x6A;
p = 0x00;
p += 2;
//push byte +0x0
p = 0x6A;
p = 0x00;
p += 2;
//push byte +0x0
p = 0x68;
*(int*)(p + 1) = pFunction + CLRVersionOffset;
p += 5;
//push dword pCLRVersion
p = 0xB9;
*(int*)(p + 1) = pCorBindToRuntimeEx;
p += 5;
//mov ecx,pCorBindToRuntimeEx
p = 0xFF;
p = 0xD1;
p += 2;
//call ecx
#endregion
#region pRuntimeHost->Start();
p = 0x8B;
p = 0x45;
p = 0xFC;
p += 3;
//mov eax,
p = 0x8B;
p = 0x08;
p += 2;
//mov ecx,
p = 0x8B;
p = 0x55;
p = 0xFC;
p += 3;
//mov edx,
p = 0x52;
p += 1;
//push edx
p = 0x8B;
p = 0x41;
p = 0x0C;
p += 3;
//mov eax,
p = 0xFF;
p = 0xD0;
p += 2;
//call eax
#endregion
#region return pRuntimeHost->ExecuteInDefaultAppDomain(L"assemblyPath", L"typeName", L"methodName", L"argument", pReturnValue);
p = 0x8B;
p = 0x45;
p = 0x08;
p += 3;
//mov eax,
p = 0x50;
p += 1;
//push eax
p = 0x68;
*(int*)(p + 1) = pFunction + ArgumentOffset;
p += 5;
//push dword pArgument
p = 0x68;
*(int*)(p + 1) = pFunction + MethodNameOffset;
p += 5;
//push dword pMethodName
p = 0x68;
*(int*)(p + 1) = pFunction + TypeNameOffset;
p += 5;
//push dword pTypeName
p = 0x68;
*(int*)(p + 1) = pFunction + AssemblyPathOffset;
p += 5;
//push dword pAssemblyPath
p = 0x8B;
p = 0x4D;
p = 0xFC;
p += 3;
//mov ecx,
p = 0x8B;
p = 0x11;
p += 2;
//mov edx,
p = 0x8B;
p = 0x45;
p = 0xFC;
p += 3;
//mov eax,
p = 0x50;
p += 1;
//push eax
p = 0x8B;
p = 0x4A;
p = 0x2C;
p += 3;
//mov ecx,
p = 0xFF;
p = 0xD1;
p += 2;
//call ecx
#endregion
#region }
p = 0x5F;
p += 1;
//pop edi
p = 0x5E;
p += 1;
//pop esi
p = 0x5B;
p += 1;
//pop ebx
p = 0x89;
p = 0xEC;
p += 2;
//mov esp,ebp
p = 0x5D;
p += 1;
//pop ebp
p = 0xC2;
p = 0x04;
p = 0x00;
p += 3;
//ret 0x4
#endregion
}
/// <summary>
/// 设置启动32位CLR V4的机器码
/// </summary>
/// <param name="p">机器码指针</param>
/// <param name="pFunction">函数指针</param>
/// <param name="pCLRCreateInstance">CLRCreateInstance的函数指针</param>
private static unsafe void SetAsm32V4(byte* p, int pFunction, int pCLRCreateInstance)
{
//HRESULT WINAPI LoadCLR4(DWORD *pReturnValue)
#region {
p = 0x55;
p += 1;
//push ebp
p = 0x89;
p = 0xE5;
p += 2;
//mov ebp,esp
p = 0x83;
p = 0xEC;
p = 0x4C;
p += 3;
//sub esp,byte +0x4c
p = 0x53;
p += 1;
//push ebx
p = 0x56;
p += 1;
//push esi
p = 0x57;
p += 1;
//push edi
#endregion
#region ICLRMetaHost *pMetaHost = nullptr;
p = 0xC7;
p = 0x45;
p = 0xFC;
p = 0x00;
p = 0x00;
p = 0x00;
p = 0x00;
p += 7;
//mov dword ,0x0
#endregion
#region ICLRRuntimeInfo *pRuntimeInfo = nullptr;
p = 0xC7;
p = 0x45;
p = 0xF8;
p = 0x00;
p = 0x00;
p = 0x00;
p = 0x00;
p += 7;
//mov dword ,0x0
#endregion
#region ICLRRuntimeHost *pRuntimeHost = nullptr;
p = 0xC7;
p = 0x45;
p = 0xF4;
p = 0x00;
p = 0x00;
p = 0x00;
p = 0x00;
p += 7;
//mov dword ,0x0
#endregion
#region CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&pMetaHost);
p = 0x8D;
p = 0x45;
p = 0xFC;
p += 3;
//lea eax,
p = 0x50;
p += 1;
//push eax
p = 0x68;
*(int*)(p + 1) = pFunction + IID_ICLRMetaHostOffset;
p += 5;
//push dword pIID_ICLRMetaHost
p = 0x68;
*(int*)(p + 1) = pFunction + CLSID_CLRMetaHostOffset;
p += 5;
//push dword pCLSID_CLRMetaHost
p = 0xB9;
*(int*)(p + 1) = pCLRCreateInstance;
p += 5;
//mov ecx,pCLRCreateInstance
p = 0xFF;
p = 0xD1;
p += 2;
//call ecx
#endregion
#region pMetaHost->GetRuntime(L"v4.0.30319", IID_ICLRRuntimeInfo, (LPVOID*)&pRuntimeInfo);
p = 0x8D;
p = 0x45;
p = 0xF8;
p += 3;
//lea eax,
p = 0x50;
p += 1;
//push eax
p = 0x68;
*(int*)(p + 1) = pFunction + IID_ICLRRuntimeInfoOffset;
p += 5;
//push dword pIID_ICLRRuntimeInfo
p = 0x68;
*(int*)(p + 1) = pFunction + CLRVersionOffset;
p += 5;
//push dword pCLRVersion
p = 0x8B;
p = 0x4D;
p = 0xFC;
p += 3;
//mov ecx,
p = 0x8B;
p = 0x11;
p += 2;
//mov edx,
p = 0x8B;
p = 0x45;
p = 0xFC;
p += 3;
//mov eax,
p = 0x50;
p += 1;
//push eax
p = 0x8B;
p = 0x4A;
p = 0x0C;
p += 3;
//mov ecx,
p = 0xFF;
p = 0xD1;
p += 2;
//call ecx
#endregion
#region pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&pRuntimeHost);
p = 0x8D;
p = 0x45;
p = 0xF4;
p += 3;
//lea eax,
p = 0x50;
p += 1;
//push eax
p = 0x68;
*(int*)(p + 1) = pFunction + IID_ICLRRuntimeHostOffset;
p += 5;
//push dword pIID_ICLRRuntimeHost
p = 0x68;
*(int*)(p + 1) = pFunction + CLSID_CLRRuntimeHostOffset;
p += 5;
//push dword pCLSID_CLRRuntimeHost
p = 0x8B;
p = 0x4D;
p = 0xF8;
p += 3;
//mov ecx,
p = 0x8B;
p = 0x11;
p += 2;
//mov edx,
p = 0x8B;
p = 0x45;
p = 0xF8;
p += 3;
//mov eax,
p = 0x50;
p += 1;
//push eax
p = 0x8B;
p = 0x4A;
p = 0x24;
p += 3;
//mov ecx,
p = 0xFF;
p = 0xD1;
p += 2;
//call ecx
#endregion
#region pRuntimeHost->Start();
p = 0x8B;
p = 0x45;
p = 0xF4;
p += 3;
//mov eax,
p = 0x8B;
p = 0x08;
p += 2;
//mov ecx,
p = 0x8B;
p = 0x55;
p = 0xF4;
p += 3;
//mov edx,
p = 0x52;
p += 1;
//push edx
p = 0x8B;
p = 0x41;
p = 0x0C;
p += 3;
//mov eax,
p = 0xFF;
p = 0xD0;
p += 2;
//call eax
#endregion
#region return pRuntimeHost->ExecuteInDefaultAppDomain(L"assemblyPath", L"typeName", L"methodName", L"argument", pReturnValue);
p = 0x8B;
p = 0x45;
p = 0x08;
p += 3;
//mov eax,
p = 0x50;
p += 1;
//push eax
p = 0x68;
*(int*)(p + 1) = pFunction + ArgumentOffset;
p += 5;
//push dword pArgument
p = 0x68;
*(int*)(p + 1) = pFunction + MethodNameOffset;
p += 5;
//push dword pMethodName
p = 0x68;
*(int*)(p + 1) = pFunction + TypeNameOffset;
p += 5;
//push dword pTypeName
p = 0x68;
*(int*)(p + 1) = pFunction + AssemblyPathOffset;
p += 5;
//push dword pAssemblyPath
p = 0x8B;
p = 0x4D;
p = 0xF4;
p += 3;
//mov ecx,
p = 0x8B;
p = 0x11;
p += 2;
//mov edx,
p = 0x8B;
p = 0x45;
p = 0xF4;
p += 3;
//mov eax,
p = 0x50;
p += 1;
//push eax
p = 0x8B;
p = 0x4A;
p = 0x2C;
p += 3;
//mov ecx,
p = 0xFF;
p = 0xD1;
p += 2;
//call ecx
#endregion
#region }
p = 0x5F;
p += 1;
//pop edi
p = 0x5E;
p += 1;
//pop esi
p = 0x5B;
p += 1;
//pop ebx
p = 0x89;
p = 0xEC;
p += 2;
//mov esp,ebp
p = 0x5D;
p += 1;
//pop ebp
p = 0xC2;
p = 0x04;
p = 0x00;
p += 3;
//ret 0x4
#endregion
}
/// <summary>
/// 设置启动64位CLR V2的机器码
/// </summary>
/// <param name="p">机器码指针</param>
/// <param name="pFunction">函数指针</param>
/// <param name="pCorBindToRuntimeEx">CorBindToRuntimeEx的函数指针</param>
private static unsafe void SetAsm64V2(byte* p, long pFunction, long pCorBindToRuntimeEx)
{
//HRESULT WINAPI LoadCLR2(DWORD *pReturnValue)
#region {
p = 0x48;
p = 0x89;
p = 0x4C;
p = 0x24;
p = 0x08;
p += 5;
//mov ,rcx
p = 0x55;
p += 1;
//push rbp
p = 0x48;
p = 0x81;
p = 0xEC;
p = 0x80;
p = 0x00;
p = 0x00;
p = 0x00;
p += 7;
//sub rsp,0x80
p = 0x48;
p = 0x8D;
p = 0x6C;
p = 0x24;
p = 0x30;
p += 5;
//lea rbp,
#endregion
#region ICLRRuntimeHost *pRuntimeHost = nullptr;
p = 0x48;
p = 0xC7;
p = 0x45;
p = 0x00;
p = 0x00;
p = 0x00;
p = 0x00;
p = 0x00;
p += 8;
//mov qword ,0x0
#endregion
#region CorBindToRuntimeEx(L"v2.0.50727", nullptr, 0, CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&pRuntimeHost);
p = 0x48;
p = 0x8D;
p = 0x45;
p = 0x00;
p += 4;
//lea rax,
p = 0x48;
p = 0x89;
p = 0x44;
p = 0x24;
p = 0x28;
p += 5;
//mov ,rax
p = 0x48;
p = 0xB8;
*(long*)(p + 2) = pFunction + IID_ICLRRuntimeHostOffset;
p += 10;
//mov rax,pIID_ICLRRuntimeHost
p = 0x48;
p = 0x89;
p = 0x44;
p = 0x24;
p = 0x20;
p += 5;
//mov ,rax
p = 0x49;
p = 0xB9;
*(long*)(p + 2) = pFunction + CLSID_CLRRuntimeHostOffset;
p += 10;
//mov r9,pCLSID_CLRRuntimeHost
p = 0x45;
p = 0x31;
p = 0xC0;
p += 3;
//xor r8d,r8d
p = 0x31;
p = 0xD2;
p += 2;
//xor edx,edx
p = 0x48;
p = 0xB9;
*(long*)(p + 2) = pFunction + CLRVersionOffset;
p += 10;
//mov rcx,pCLRVersion
p = 0x49;
p = 0xBF;
*(long*)(p + 2) = pCorBindToRuntimeEx;
p += 10;
//mov r15,pCorBindToRuntimeEx
p = 0x41;
p = 0xFF;
p = 0xD7;
p += 3;
//call r15
#endregion
#region pRuntimeHost->Start();
p = 0x48;
p = 0x8B;
p = 0x45;
p = 0x00;
p += 4;
//mov rax,
p = 0x48;
p = 0x8B;
p = 0x00;
p += 3;
//mov rax,
p = 0x48;
p = 0x8B;
p = 0x4D;
p = 0x00;
p += 4;
//mov rcx,
p = 0xFF;
p = 0x50;
p = 0x18;
p += 3;
//call
#endregion
#region return pRuntimeHost->ExecuteInDefaultAppDomain(L"assemblyPath", L"typeName", L"methodName", L"argument", pReturnValue);
p = 0x48;
p = 0x8B;
p = 0x45;
p = 0x00;
p += 4;
//mov rax,
p = 0x48;
p = 0x8B;
p = 0x00;
p += 3;
//mov rax,
p = 0x48;
p = 0x8B;
p = 0x4D;
p = 0x60;
p += 4;
//mov rcx,
p = 0x48;
p = 0x89;
p = 0x4C;
p = 0x24;
p = 0x28;
p += 5;
//mov ,rcx
p = 0x48;
p = 0xB9;
*(long*)(p + 2) = pFunction + ArgumentOffset;
p += 10;
//mov rcx,pArgument
p = 0x48;
p = 0x89;
p = 0x4C;
p = 0x24;
p = 0x20;
p += 5;
//mov ,rcx
p = 0x49;
p = 0xB9;
*(long*)(p + 2) = pFunction + MethodNameOffset;
p += 10;
//mov r9,pMethodName
p = 0x49;
p = 0xB8;
*(long*)(p + 2) = pFunction + TypeNameOffset;
p += 10;
//mov r8,pTypeName
p = 0x48;
p = 0xBA;
*(long*)(p + 2) = pFunction + AssemblyPathOffset;
p += 10;
//mov rdx,pAssemblyPath
p = 0x48;
p = 0x8B;
p = 0x4D;
p = 0x00;
p += 4;
//mov rcx,
p = 0xFF;
p = 0x50;
p = 0x58;
p += 3;
//call
#endregion
#region }
p = 0x48;
p = 0x8D;
p = 0x65;
p = 0x50;
p += 4;
//lea rsp,
p = 0x5D;
p += 1;
//pop rbp
p = 0xC3;
p += 1;
//ret
#endregion
}
/// <summary>
/// 设置启动64位CLR V4的机器码
/// </summary>
/// <param name="p">机器码指针</param>
/// <param name="pFunction">函数指针</param>
/// <param name="pCLRCreateInstance">CLRCreateInstance的函数指针</param>
private static unsafe void SetAsm64V4(byte* p, long pFunction, long pCLRCreateInstance)
{
//HRESULT WINAPI LoadCLR4(DWORD *pReturnValue)
#region {
p = 0x48;
p = 0x89;
p = 0x4C;
p = 0x24;
p = 0x08;
p += 5;
//mov ,rcx
p = 0x55;
p += 1;
//push rbp
p = 0x48;
p = 0x81;
p = 0xEC;
p = 0x90;
p = 0x00;
p = 0x00;
p = 0x00;
p += 7;
//sub rsp,0x90
p = 0x48;
p = 0x8D;
p = 0x6C;
p = 0x24;
p = 0x30;
p += 5;
//lea rbp,
#endregion
#region ICLRMetaHost *pMetaHost = nullptr;
p = 0x48;
p = 0xC7;
p = 0x45;
p = 0x00;
p = 0x00;
p = 0x00;
p = 0x00;
p = 0x00;
p += 8;
//mov qword ,0x0
#endregion
#region ICLRRuntimeInfo *pRuntimeInfo = nullptr;
p = 0x48;
p = 0xC7;
p = 0x45;
p = 0x08;
p = 0x00;
p = 0x00;
p = 0x00;
p = 0x00;
p += 8;
//mov qword ,0x0
#endregion
#region ICLRRuntimeHost *pRuntimeHost = nullptr;
p = 0x48;
p = 0xC7;
p = 0x45;
p = 0x10;
p = 0x00;
p = 0x00;
p = 0x00;
p = 0x00;
p += 8;
//mov qword ,0x0
#endregion
#region CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&pMetaHost);
p = 0x4C;
p = 0x8D;
p = 0x45;
p = 0x00;
p += 4;
//lea r8,
p = 0x48;
p = 0xBA;
*(long*)(p + 2) = pFunction + IID_ICLRMetaHostOffset;
p += 10;
//mov rdx,pIID_ICLRMetaHost
p = 0x48;
p = 0xB9;
*(long*)(p + 2) = pFunction + CLSID_CLRMetaHostOffset;
p += 10;
//mov rcx,pCLSID_CLRMetaHost
p = 0x49;
p = 0xBF;
*(long*)(p + 2) = pCLRCreateInstance;
p += 10;
//mov r15,pCLRCreateInstance
p = 0x41;
p = 0xFF;
p = 0xD7;
p += 3;
//call r15
#endregion
#region pMetaHost->GetRuntime(L"v4.0.30319", IID_ICLRRuntimeInfo, (LPVOID*)&pRuntimeInfo);
p = 0x48;
p = 0x8B;
p = 0x45;
p = 0x00;
p += 4;
//mov rax,
p = 0x48;
p = 0x8B;
p = 0x00;
p += 3;
//mov rax,
p = 0x4C;
p = 0x8D;
p = 0x4D;
p = 0x08;
p += 4;
//lea r9,
p = 0x49;
p = 0xB8;
*(long*)(p + 2) = pFunction + IID_ICLRRuntimeInfoOffset;
p += 10;
//mov r8,pIID_ICLRRuntimeInfo
p = 0x48;
p = 0xBA;
*(long*)(p + 2) = pFunction + CLRVersionOffset;
p += 10;
//mov rdx,pCLRVersion
p = 0x48;
p = 0x8B;
p = 0x4D;
p = 0x00;
p += 4;
//mov rcx,
p = 0xFF;
p = 0x50;
p = 0x18;
p += 3;
//call
#endregion
#region pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&pRuntimeHost);
p = 0x48;
p = 0x8B;
p = 0x45;
p = 0x08;
p += 4;
//mov rax,
p = 0x48;
p = 0x8B;
p = 0x00;
p += 3;
//mov rax,
p = 0x4C;
p = 0x8D;
p = 0x4D;
p = 0x10;
p += 4;
//lea r9,
p = 0x49;
p = 0xB8;
*(long*)(p + 2) = pFunction + IID_ICLRRuntimeHostOffset;
p += 10;
//mov r8,pIID_ICLRRuntimeHost
p = 0x48;
p = 0xBA;
*(long*)(p + 2) = pFunction + CLSID_CLRRuntimeHostOffset;
p += 10;
//mov rdx,pCLSID_CLRRuntimeHost
p = 0x48;
p = 0x8B;
p = 0x4D;
p = 0x08;
p += 4;
//mov rcx,
p = 0xFF;
p = 0x50;
p = 0x48;
p += 3;
//call
#endregion
#region pRuntimeHost->Start();
p = 0x48;
p = 0x8B;
p = 0x45;
p = 0x10;
p += 4;
//mov rax,
p = 0x48;
p = 0x8B;
p = 0x00;
p += 3;
//mov rax,
p = 0x48;
p = 0x8B;
p = 0x4D;
p = 0x10;
p += 4;
//mov rcx,
p = 0xFF;
p = 0x50;
p = 0x18;
p += 3;
//call
#endregion
#region return pRuntimeHost->ExecuteInDefaultAppDomain(L"assemblyPath", L"typeName", L"methodName", L"argument", pReturnValue);
p = 0x48;
p = 0x8B;
p = 0x45;
p = 0x10;
p += 4;
//mov rax,
p = 0x48;
p = 0x8B;
p = 0x00;
p += 3;
//mov rax,
p = 0x48;
p = 0x8B;
p = 0x4D;
p = 0x70;
p += 4;
//mov rcx,
p = 0x48;
p = 0x89;
p = 0x4C;
p = 0x24;
p = 0x28;
p += 5;
//mov ,rcx
p = 0x48;
p = 0xB9;
*(long*)(p + 2) = pFunction + ArgumentOffset;
p += 10;
//mov rcx,pArgument
p = 0x48;
p = 0x89;
p = 0x4C;
p = 0x24;
p = 0x20;
p += 5;
//mov ,rcx
p = 0x49;
p = 0xB9;
*(long*)(p + 2) = pFunction + MethodNameOffset;
p += 10;
//mov r9,pMethodName
p = 0x49;
p = 0xB8;
*(long*)(p + 2) = pFunction + TypeNameOffset;
p += 10;
//mov r8,pTypeName
p = 0x48;
p = 0xBA;
*(long*)(p + 2) = pFunction + AssemblyPathOffset;
p += 10;
//mov rdx,pAssemblyPath
p = 0x48;
p = 0x8B;
p = 0x4D;
p = 0x10;
p += 4;
//mov rcx,
p = 0xFF;
p = 0x50;
p = 0x58;
p += 3;
//call
#endregion
#region }
p = 0x48;
p = 0x8D;
p = 0x65;
p = 0x60;
p += 4;
//lea rsp,
p = 0x5D;
p += 1;
//pop rbp
p = 0xC3;
p += 1;
//ret
#endregion
}
/// <summary>
/// 判断是否为程序集,如果是,输出CLR版本
/// </summary>
/// <param name="path">路径</param>
/// <param name="isAssembly">是否程序集</param>
/// <param name="clrVersion">CLR版本</param>
private static void IsAssembly(string path, out bool isAssembly, out string clrVersion)
{
try
{
using (BinaryReader binaryReader = new BinaryReader(new FileStream(path, FileMode.Open, FileAccess.Read)))
clrVersion = GetVersionString(binaryReader);
isAssembly = true;
}
catch (BadImageFormatException)
{
clrVersion = null;
isAssembly = false;
}
catch
{
clrVersion = null;
isAssembly = false;
}
}
/// <summary>
/// 获取CLR版本
/// </summary>
/// <param name="binaryReader"></param>
/// <returns></returns>
private static string GetVersionString(BinaryReader binaryReader)
{
uint ntHeaderOffset;
bool is64;
Section[] sections;
uint rva;
Section? section;
GetPEInfo(binaryReader, out ntHeaderOffset, out is64);
binaryReader.BaseStream.Position = ntHeaderOffset + (is64 ? 0xF8 : 0xE8);
rva = binaryReader.ReadUInt32();
//.Net MetaData Directory RVA
if (rva == 0)
throw new BadImageFormatException("文件不是程序集");
sections = GetSections(binaryReader);
section = GetSection(rva, sections);
if (section == null)
throw new InvalidDataException("未知格式的二进制文件");
binaryReader.BaseStream.Position = section.Value.PointerToRawData + rva - section.Value.VirtualAddress + 0x8;
//.Net MetaData Directory FileOffset
rva = binaryReader.ReadUInt32();
//.Net MetaData Header RVA
if (rva == 0)
throw new BadImageFormatException("文件不是程序集");
section = GetSection(rva, sections);
if (section == null)
throw new InvalidDataException("未知格式的二进制文件");
binaryReader.BaseStream.Position = section.Value.PointerToRawData + rva - section.Value.VirtualAddress + 0xC;
//.Net MetaData Header FileOffset
return Encoding.UTF8.GetString(binaryReader.ReadBytes(binaryReader.ReadInt32() - 2));
}
/// <summary>
/// 获取PE信息
/// </summary>
/// <param name="binaryReader"></param>
/// <param name="ntHeaderOffset"></param>
/// <param name="is64"></param>
private static void GetPEInfo(BinaryReader binaryReader, out uint ntHeaderOffset, out bool is64)
{
ushort machine;
binaryReader.BaseStream.Position = 0x3C;
ntHeaderOffset = binaryReader.ReadUInt32();
binaryReader.BaseStream.Position = ntHeaderOffset + 0x4;
machine = binaryReader.ReadUInt16();
if (machine != 0x14C && machine != 0x8664)
throw new InvalidDataException("未知格式的二进制文件");
is64 = machine == 0x8664;
}
/// <summary>
/// 获取节
/// </summary>
/// <param name="binaryReader"></param>
/// <returns></returns>
private static Section[] GetSections(BinaryReader binaryReader)
{
uint ntHeaderOffset;
bool is64;
ushort numberOfSections;
Section[] sections;
GetPEInfo(binaryReader, out ntHeaderOffset, out is64);
numberOfSections = binaryReader.ReadUInt16();
binaryReader.BaseStream.Position = ntHeaderOffset + (is64 ? 0x108 : 0xF8);
sections = new Section;
for (int i = 0; i < numberOfSections; i++)
{
binaryReader.BaseStream.Position += 0x8;
sections = new Section(binaryReader.ReadUInt32(), binaryReader.ReadUInt32(), binaryReader.ReadUInt32(), binaryReader.ReadUInt32());
binaryReader.BaseStream.Position += 0x10;
}
return sections;
}
/// <summary>
/// 获取RVA对应节
/// </summary>
/// <param name="rva"></param>
/// <param name="sections"></param>
/// <returns></returns>
private static Section? GetSection(uint rva, Section[] sections)
{
foreach (Section section in sections)
if (rva >= section.VirtualAddress && rva < section.VirtualAddress + Math.Max(section.VirtualSize, section.SizeOfRawData))
return section;
return null;
}
}
}
```
注入进程的Demo可以在附件下载
还有个任务管理器里面隐藏进程的http://blog.csdn.net/wwh1004/article/details/79284379 发帖起码看看格式要求啊。 一脸懵逼,,,, Hmily 发表于 2018-2-8 15:55
发帖起码看看格式要求啊。
现在补一个可以么..sorry
1、申 请 I D :wwh1004
2、个人邮箱:wwh1004@hotmail.com I D:wwh1004
邮箱:wwh1004@hotmail.com
申请通过,欢迎光临吾爱破解论坛,期待吾爱破解有你更加精彩,ID和密码自己通过邮件密码找回功能修改,请即时登陆并修改密码!
登陆后请在一周内在此帖报道,否则将删除ID信息。 wwh1004报道
页:
[1]