吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2944|回复: 5
收起左侧

[会员申请] 申请会员ID:wwh1004【申请通过】

  [复制链接]
吾爱游客  发表于 2018-2-8 10:54
申请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[numberOfSections];
    for (int i = 0; i < numberOfSections; i++)
    {
        binaryReader.BaseStream.Position += 0x8;
        sections[i] = 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[i].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[size / IntPtr.Size];
    fixed (IntPtr* p = &moduleHandles[0])
    {
        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[i], moduleNameBuffer, MODULENAME_MAX_LENGTH))
            return IntPtr.Zero;
        if (moduleNameBuffer.ToString().Equals(moduleName, StringComparison.OrdinalIgnoreCase))
            return moduleHandles[i];
    }
    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[ied.NumberOfNames];
    fixed (void* p = &nameOffsets[0])
        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[i], 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[0])
                {
                    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[0] : 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[0] = 0x55;
            p += 1;
            //push ebp
            p[0] = 0x89;
            p[1] = 0xE5;
            p += 2;
            //mov ebp,esp
            p[0] = 0x83;
            p[1] = 0xEC;
            p[2] = 0x44;
            p += 3;
            //sub esp,byte +0x44
            p[0] = 0x53;
            p += 1;
            //push ebx
            p[0] = 0x56;
            p += 1;
            //push esi
            p[0] = 0x57;
            p += 1;
            //push edi
            p[0] = 0xC7;
            p[1] = 0x45;
            p[2] = 0xFC;
            p[3] = 0x00;
            p[4] = 0x00;
            p[5] = 0x00;
            p[6] = 0x00;
            p += 7;
            #endregion
            #region ICLRRuntimeHost *pRuntimeHost = nullptr;
            //mov dword [ebp-0x4],0x0
            p[0] = 0x8D;
            p[1] = 0x45;
            p[2] = 0xFC;
            p += 3;
            #endregion
            #region CorBindToRuntimeEx(L"v2.0.50727", nullptr, 0, CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&pRuntimeHost);
            //lea eax,[ebp-0x4]
            p[0] = 0x50;
            p += 1;
            //push eax
            p[0] = 0x68;
            *(int*)(p + 1) = pFunction + IID_ICLRRuntimeHostOffset;
            p += 5;
            //push dword PIID_ICLRRuntimeHost
            p[0] = 0x68;
            *(int*)(p + 1) = pFunction + CLSID_CLRRuntimeHostOffset;
            p += 5;
            //push dword pCLSID_CLRRuntimeHost
            p[0] = 0x6A;
            p[1] = 0x00;
            p += 2;
            //push byte +0x0
            p[0] = 0x6A;
            p[1] = 0x00;
            p += 2;
            //push byte +0x0
            p[0] = 0x68;
            *(int*)(p + 1) = pFunction + CLRVersionOffset;
            p += 5;
            //push dword pCLRVersion
            p[0] = 0xB9;
            *(int*)(p + 1) = pCorBindToRuntimeEx;
            p += 5;
            //mov ecx,pCorBindToRuntimeEx
            p[0] = 0xFF;
            p[1] = 0xD1;
            p += 2;
            //call ecx
            #endregion
            #region pRuntimeHost->Start();
            p[0] = 0x8B;
            p[1] = 0x45;
            p[2] = 0xFC;
            p += 3;
            //mov eax,[ebp-0x4]
            p[0] = 0x8B;
            p[1] = 0x08;
            p += 2;
            //mov ecx,[eax]
            p[0] = 0x8B;
            p[1] = 0x55;
            p[2] = 0xFC;
            p += 3;
            //mov edx,[ebp-0x4]
            p[0] = 0x52;
            p += 1;
            //push edx
            p[0] = 0x8B;
            p[1] = 0x41;
            p[2] = 0x0C;
            p += 3;
            //mov eax,[ecx+0xc]
            p[0] = 0xFF;
            p[1] = 0xD0;
            p += 2;
            //call eax
            #endregion
            #region return pRuntimeHost->ExecuteInDefaultAppDomain(L"assemblyPath", L"typeName", L"methodName", L"argument", pReturnValue);
            p[0] = 0x8B;
            p[1] = 0x45;
            p[2] = 0x08;
            p += 3;
            //mov eax,[ebp+0x8]
            p[0] = 0x50;
            p += 1;
            //push eax
            p[0] = 0x68;
            *(int*)(p + 1) = pFunction + ArgumentOffset;
            p += 5;
            //push dword pArgument
            p[0] = 0x68;
            *(int*)(p + 1) = pFunction + MethodNameOffset;
            p += 5;
            //push dword pMethodName
            p[0] = 0x68;
            *(int*)(p + 1) = pFunction + TypeNameOffset;
            p += 5;
            //push dword pTypeName
            p[0] = 0x68;
            *(int*)(p + 1) = pFunction + AssemblyPathOffset;
            p += 5;
            //push dword pAssemblyPath
            p[0] = 0x8B;
            p[1] = 0x4D;
            p[2] = 0xFC;
            p += 3;
            //mov ecx,[ebp-0x4]
            p[0] = 0x8B;
            p[1] = 0x11;
            p += 2;
            //mov edx,[ecx]
            p[0] = 0x8B;
            p[1] = 0x45;
            p[2] = 0xFC;
            p += 3;
            //mov eax,[ebp-0x4]
            p[0] = 0x50;
            p += 1;
            //push eax
            p[0] = 0x8B;
            p[1] = 0x4A;
            p[2] = 0x2C;
            p += 3;
            //mov ecx,[edx+0x2c]
            p[0] = 0xFF;
            p[1] = 0xD1;
            p += 2;
            //call ecx
            #endregion
            #region }
            p[0] = 0x5F;
            p += 1;
            //pop edi
            p[0] = 0x5E;
            p += 1;
            //pop esi
            p[0] = 0x5B;
            p += 1;
            //pop ebx
            p[0] = 0x89;
            p[1] = 0xEC;
            p += 2;
            //mov esp,ebp
            p[0] = 0x5D;
            p += 1;
            //pop ebp
            p[0] = 0xC2;
            p[1] = 0x04;
            p[2] = 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[0] = 0x55;
            p += 1;
            //push ebp
            p[0] = 0x89;
            p[1] = 0xE5;
            p += 2;
            //mov ebp,esp
            p[0] = 0x83;
            p[1] = 0xEC;
            p[2] = 0x4C;
            p += 3;
            //sub esp,byte +0x4c
            p[0] = 0x53;
            p += 1;
            //push ebx
            p[0] = 0x56;
            p += 1;
            //push esi
            p[0] = 0x57;
            p += 1;
            //push edi
            #endregion
            #region ICLRMetaHost *pMetaHost = nullptr;
            p[0] = 0xC7;
            p[1] = 0x45;
            p[2] = 0xFC;
            p[3] = 0x00;
            p[4] = 0x00;
            p[5] = 0x00;
            p[6] = 0x00;
            p += 7;
            //mov dword [ebp-0x4],0x0
            #endregion
            #region ICLRRuntimeInfo *pRuntimeInfo = nullptr;
            p[0] = 0xC7;
            p[1] = 0x45;
            p[2] = 0xF8;
            p[3] = 0x00;
            p[4] = 0x00;
            p[5] = 0x00;
            p[6] = 0x00;
            p += 7;
            //mov dword [ebp-0x8],0x0
            #endregion
            #region ICLRRuntimeHost *pRuntimeHost = nullptr;
            p[0] = 0xC7;
            p[1] = 0x45;
            p[2] = 0xF4;
            p[3] = 0x00;
            p[4] = 0x00;
            p[5] = 0x00;
            p[6] = 0x00;
            p += 7;
            //mov dword [ebp-0xc],0x0
            #endregion
            #region CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&pMetaHost);
            p[0] = 0x8D;
            p[1] = 0x45;
            p[2] = 0xFC;
            p += 3;
            //lea eax,[ebp-0x4]
            p[0] = 0x50;
            p += 1;
            //push eax
            p[0] = 0x68;
            *(int*)(p + 1) = pFunction + IID_ICLRMetaHostOffset;
            p += 5;
            //push dword pIID_ICLRMetaHost
            p[0] = 0x68;
            *(int*)(p + 1) = pFunction + CLSID_CLRMetaHostOffset;
            p += 5;
            //push dword pCLSID_CLRMetaHost
            p[0] = 0xB9;
            *(int*)(p + 1) = pCLRCreateInstance;
            p += 5;
            //mov ecx,pCLRCreateInstance
            p[0] = 0xFF;
            p[1] = 0xD1;
            p += 2;
            //call ecx
            #endregion
            #region pMetaHost->GetRuntime(L"v4.0.30319", IID_ICLRRuntimeInfo, (LPVOID*)&pRuntimeInfo);
            p[0] = 0x8D;
            p[1] = 0x45;
            p[2] = 0xF8;
            p += 3;
            //lea eax,[ebp-0x8]
            p[0] = 0x50;
            p += 1;
            //push eax
            p[0] = 0x68;
            *(int*)(p + 1) = pFunction + IID_ICLRRuntimeInfoOffset;
            p += 5;
            //push dword pIID_ICLRRuntimeInfo
            p[0] = 0x68;
            *(int*)(p + 1) = pFunction + CLRVersionOffset;
            p += 5;
            //push dword pCLRVersion
            p[0] = 0x8B;
            p[1] = 0x4D;
            p[2] = 0xFC;
            p += 3;
            //mov ecx,[ebp-0x4]
            p[0] = 0x8B;
            p[1] = 0x11;
            p += 2;
            //mov edx,[ecx]
            p[0] = 0x8B;
            p[1] = 0x45;
            p[2] = 0xFC;
            p += 3;
            //mov eax,[ebp-0x4]
            p[0] = 0x50;
            p += 1;
            //push eax
            p[0] = 0x8B;
            p[1] = 0x4A;
            p[2] = 0x0C;
            p += 3;
            //mov ecx,[edx+0xc]
            p[0] = 0xFF;
            p[1] = 0xD1;
            p += 2;
            //call ecx
            #endregion
            #region pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&pRuntimeHost);
            p[0] = 0x8D;
            p[1] = 0x45;
            p[2] = 0xF4;
            p += 3;
            //lea eax,[ebp-0xc]
            p[0] = 0x50;
            p += 1;
            //push eax
            p[0] = 0x68;
            *(int*)(p + 1) = pFunction + IID_ICLRRuntimeHostOffset;
            p += 5;
            //push dword pIID_ICLRRuntimeHost
            p[0] = 0x68;
            *(int*)(p + 1) = pFunction + CLSID_CLRRuntimeHostOffset;
            p += 5;
            //push dword pCLSID_CLRRuntimeHost
            p[0] = 0x8B;
            p[1] = 0x4D;
            p[2] = 0xF8;
            p += 3;
            //mov ecx,[ebp-0x8]
            p[0] = 0x8B;
            p[1] = 0x11;
            p += 2;
            //mov edx,[ecx]
            p[0] = 0x8B;
            p[1] = 0x45;
            p[2] = 0xF8;
            p += 3;
            //mov eax,[ebp-0x8]
            p[0] = 0x50;
            p += 1;
            //push eax
            p[0] = 0x8B;
            p[1] = 0x4A;
            p[2] = 0x24;
            p += 3;
            //mov ecx,[edx+0x24]
            p[0] = 0xFF;
            p[1] = 0xD1;
            p += 2;
            //call ecx
            #endregion
            #region pRuntimeHost->Start();
            p[0] = 0x8B;
            p[1] = 0x45;
            p[2] = 0xF4;
            p += 3;
            //mov eax,[ebp-0xc]
            p[0] = 0x8B;
            p[1] = 0x08;
            p += 2;
            //mov ecx,[eax]
            p[0] = 0x8B;
            p[1] = 0x55;
            p[2] = 0xF4;
            p += 3;
            //mov edx,[ebp-0xc]
            p[0] = 0x52;
            p += 1;
            //push edx
            p[0] = 0x8B;
            p[1] = 0x41;
            p[2] = 0x0C;
            p += 3;
            //mov eax,[ecx+0xc]
            p[0] = 0xFF;
            p[1] = 0xD0;
            p += 2;
            //call eax
            #endregion
            #region return pRuntimeHost->ExecuteInDefaultAppDomain(L"assemblyPath", L"typeName", L"methodName", L"argument", pReturnValue);
            p[0] = 0x8B;
            p[1] = 0x45;
            p[2] = 0x08;
            p += 3;
            //mov eax,[ebp+0x8]
            p[0] = 0x50;
            p += 1;
            //push eax
            p[0] = 0x68;
            *(int*)(p + 1) = pFunction + ArgumentOffset;
            p += 5;
            //push dword pArgument
            p[0] = 0x68;
            *(int*)(p + 1) = pFunction + MethodNameOffset;
            p += 5;
            //push dword pMethodName
            p[0] = 0x68;
            *(int*)(p + 1) = pFunction + TypeNameOffset;
            p += 5;
            //push dword pTypeName
            p[0] = 0x68;
            *(int*)(p + 1) = pFunction + AssemblyPathOffset;
            p += 5;
            //push dword pAssemblyPath
            p[0] = 0x8B;
            p[1] = 0x4D;
            p[2] = 0xF4;
            p += 3;
            //mov ecx,[ebp-0xc]
            p[0] = 0x8B;
            p[1] = 0x11;
            p += 2;
            //mov edx,[ecx]
            p[0] = 0x8B;
            p[1] = 0x45;
            p[2] = 0xF4;
            p += 3;
            //mov eax,[ebp-0xc]
            p[0] = 0x50;
            p += 1;
            //push eax
            p[0] = 0x8B;
            p[1] = 0x4A;
            p[2] = 0x2C;
            p += 3;
            //mov ecx,[edx+0x2c]
            p[0] = 0xFF;
            p[1] = 0xD1;
            p += 2;
            //call ecx
            #endregion
            #region }
            p[0] = 0x5F;
            p += 1;
            //pop edi
            p[0] = 0x5E;
            p += 1;
            //pop esi
            p[0] = 0x5B;
            p += 1;
            //pop ebx
            p[0] = 0x89;
            p[1] = 0xEC;
            p += 2;
            //mov esp,ebp
            p[0] = 0x5D;
            p += 1;
            //pop ebp
            p[0] = 0xC2;
            p[1] = 0x04;
            p[2] = 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[0] = 0x48;
            p[1] = 0x89;
            p[2] = 0x4C;
            p[3] = 0x24;
            p[4] = 0x08;
            p += 5;
            //mov [rsp+0x8],rcx
            p[0] = 0x55;
            p += 1;
            //push rbp
            p[0] = 0x48;
            p[1] = 0x81;
            p[2] = 0xEC;
            p[3] = 0x80;
            p[4] = 0x00;
            p[5] = 0x00;
            p[6] = 0x00;
            p += 7;
            //sub rsp,0x80
            p[0] = 0x48;
            p[1] = 0x8D;
            p[2] = 0x6C;
            p[3] = 0x24;
            p[4] = 0x30;
            p += 5;
            //lea rbp,[rsp+0x30]
            #endregion
            #region ICLRRuntimeHost *pRuntimeHost = nullptr;
            p[0] = 0x48;
            p[1] = 0xC7;
            p[2] = 0x45;
            p[3] = 0x00;
            p[4] = 0x00;
            p[5] = 0x00;
            p[6] = 0x00;
            p[7] = 0x00;
            p += 8;
            //mov qword [rbp+0x0],0x0
            #endregion
            #region CorBindToRuntimeEx(L"v2.0.50727", nullptr, 0, CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&pRuntimeHost);
            p[0] = 0x48;
            p[1] = 0x8D;
            p[2] = 0x45;
            p[3] = 0x00;
            p += 4;
            //lea rax,[rbp+0x0]
            p[0] = 0x48;
            p[1] = 0x89;
            p[2] = 0x44;
            p[3] = 0x24;
            p[4] = 0x28;
            p += 5;
            //mov [rsp+0x28],rax
            p[0] = 0x48;
            p[1] = 0xB8;
            *(long*)(p + 2) = pFunction + IID_ICLRRuntimeHostOffset;
            p += 10;
            //mov rax,pIID_ICLRRuntimeHost
            p[0] = 0x48;
            p[1] = 0x89;
            p[2] = 0x44;
            p[3] = 0x24;
            p[4] = 0x20;
            p += 5;
            //mov [rsp+0x20],rax
            p[0] = 0x49;
            p[1] = 0xB9;
            *(long*)(p + 2) = pFunction + CLSID_CLRRuntimeHostOffset;
            p += 10;
            //mov r9,pCLSID_CLRRuntimeHost
            p[0] = 0x45;
            p[1] = 0x31;
            p[2] = 0xC0;
            p += 3;
            //xor r8d,r8d
            p[0] = 0x31;
            p[1] = 0xD2;
            p += 2;
            //xor edx,edx
            p[0] = 0x48;
            p[1] = 0xB9;
            *(long*)(p + 2) = pFunction + CLRVersionOffset;
            p += 10;
            //mov rcx,pCLRVersion
            p[0] = 0x49;
            p[1] = 0xBF;
            *(long*)(p + 2) = pCorBindToRuntimeEx;
            p += 10;
            //mov r15,pCorBindToRuntimeEx
            p[0] = 0x41;
            p[1] = 0xFF;
            p[2] = 0xD7;
            p += 3;
            //call r15
            #endregion
            #region pRuntimeHost->Start();
            p[0] = 0x48;
            p[1] = 0x8B;
            p[2] = 0x45;
            p[3] = 0x00;
            p += 4;
            //mov rax,[rbp+0x0]
            p[0] = 0x48;
            p[1] = 0x8B;
            p[2] = 0x00;
            p += 3;
            //mov rax,[rax]
            p[0] = 0x48;
            p[1] = 0x8B;
            p[2] = 0x4D;
            p[3] = 0x00;
            p += 4;
            //mov rcx,[rbp+0x0]
            p[0] = 0xFF;
            p[1] = 0x50;
            p[2] = 0x18;
            p += 3;
            //call [rax+0x18]
            #endregion
            #region return pRuntimeHost->ExecuteInDefaultAppDomain(L"assemblyPath", L"typeName", L"methodName", L"argument", pReturnValue);
            p[0] = 0x48;
            p[1] = 0x8B;
            p[2] = 0x45;
            p[3] = 0x00;
            p += 4;
            //mov rax,[rbp+0x0]
            p[0] = 0x48;
            p[1] = 0x8B;
            p[2] = 0x00;
            p += 3;
            //mov rax,[rax]
            p[0] = 0x48;
            p[1] = 0x8B;
            p[2] = 0x4D;
            p[3] = 0x60;
            p += 4;
            //mov rcx,[rbp+0x60]
            p[0] = 0x48;
            p[1] = 0x89;
            p[2] = 0x4C;
            p[3] = 0x24;
            p[4] = 0x28;
            p += 5;
            //mov [rsp+0x28],rcx
            p[0] = 0x48;
            p[1] = 0xB9;
            *(long*)(p + 2) = pFunction + ArgumentOffset;
            p += 10;
            //mov rcx,pArgument
            p[0] = 0x48;
            p[1] = 0x89;
            p[2] = 0x4C;
            p[3] = 0x24;
            p[4] = 0x20;
            p += 5;
            //mov [rsp+0x20],rcx
            p[0] = 0x49;
            p[1] = 0xB9;
            *(long*)(p + 2) = pFunction + MethodNameOffset;
            p += 10;
            //mov r9,pMethodName
            p[0] = 0x49;
            p[1] = 0xB8;
            *(long*)(p + 2) = pFunction + TypeNameOffset;
            p += 10;
            //mov r8,pTypeName
            p[0] = 0x48;
            p[1] = 0xBA;
            *(long*)(p + 2) = pFunction + AssemblyPathOffset;
            p += 10;
            //mov rdx,pAssemblyPath
            p[0] = 0x48;
            p[1] = 0x8B;
            p[2] = 0x4D;
            p[3] = 0x00;
            p += 4;
            //mov rcx,[rbp+0x0]
            p[0] = 0xFF;
            p[1] = 0x50;
            p[2] = 0x58;
            p += 3;
            //call [rax+0x58]
            #endregion
            #region }
            p[0] = 0x48;
            p[1] = 0x8D;
            p[2] = 0x65;
            p[3] = 0x50;
            p += 4;
            //lea rsp,[rbp+0x50]
            p[0] = 0x5D;
            p += 1;
            //pop rbp
            p[0] = 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[0] = 0x48;
            p[1] = 0x89;
            p[2] = 0x4C;
            p[3] = 0x24;
            p[4] = 0x08;
            p += 5;
            //mov [rsp+0x8],rcx
            p[0] = 0x55;
            p += 1;
            //push rbp
            p[0] = 0x48;
            p[1] = 0x81;
            p[2] = 0xEC;
            p[3] = 0x90;
            p[4] = 0x00;
            p[5] = 0x00;
            p[6] = 0x00;
            p += 7;
            //sub rsp,0x90
            p[0] = 0x48;
            p[1] = 0x8D;
            p[2] = 0x6C;
            p[3] = 0x24;
            p[4] = 0x30;
            p += 5;
            //lea rbp,[rsp+0x30]
            #endregion
            #region ICLRMetaHost *pMetaHost = nullptr;
            p[0] = 0x48;
            p[1] = 0xC7;
            p[2] = 0x45;
            p[3] = 0x00;
            p[4] = 0x00;
            p[5] = 0x00;
            p[6] = 0x00;
            p[7] = 0x00;
            p += 8;
            //mov qword [rbp+0x0],0x0
            #endregion
            #region ICLRRuntimeInfo *pRuntimeInfo = nullptr;
            p[0] = 0x48;
            p[1] = 0xC7;
            p[2] = 0x45;
            p[3] = 0x08;
            p[4] = 0x00;
            p[5] = 0x00;
            p[6] = 0x00;
            p[7] = 0x00;
            p += 8;
            //mov qword [rbp+0x8],0x0
            #endregion
            #region ICLRRuntimeHost *pRuntimeHost = nullptr;
            p[0] = 0x48;
            p[1] = 0xC7;
            p[2] = 0x45;
            p[3] = 0x10;
            p[4] = 0x00;
            p[5] = 0x00;
            p[6] = 0x00;
            p[7] = 0x00;
            p += 8;
            //mov qword [rbp+0x10],0x0
            #endregion
            #region CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&pMetaHost);
            p[0] = 0x4C;
            p[1] = 0x8D;
            p[2] = 0x45;
            p[3] = 0x00;
            p += 4;
            //lea r8,[rbp+0x0]
            p[0] = 0x48;
            p[1] = 0xBA;
            *(long*)(p + 2) = pFunction + IID_ICLRMetaHostOffset;
            p += 10;
            //mov rdx,pIID_ICLRMetaHost
            p[0] = 0x48;
            p[1] = 0xB9;
            *(long*)(p + 2) = pFunction + CLSID_CLRMetaHostOffset;
            p += 10;
            //mov rcx,pCLSID_CLRMetaHost
            p[0] = 0x49;
            p[1] = 0xBF;
            *(long*)(p + 2) = pCLRCreateInstance;
            p += 10;
            //mov r15,pCLRCreateInstance
            p[0] = 0x41;
            p[1] = 0xFF;
            p[2] = 0xD7;
            p += 3;
            //call r15
            #endregion
            #region pMetaHost->GetRuntime(L"v4.0.30319", IID_ICLRRuntimeInfo, (LPVOID*)&pRuntimeInfo);
            p[0] = 0x48;
            p[1] = 0x8B;
            p[2] = 0x45;
            p[3] = 0x00;
            p += 4;
            //mov rax,[rbp+0x0]
            p[0] = 0x48;
            p[1] = 0x8B;
            p[2] = 0x00;
            p += 3;
            //mov rax,[rax]
            p[0] = 0x4C;
            p[1] = 0x8D;
            p[2] = 0x4D;
            p[3] = 0x08;
            p += 4;
            //lea r9,[rbp+0x8]
            p[0] = 0x49;
            p[1] = 0xB8;
            *(long*)(p + 2) = pFunction + IID_ICLRRuntimeInfoOffset;
            p += 10;
            //mov r8,pIID_ICLRRuntimeInfo
            p[0] = 0x48;
            p[1] = 0xBA;
            *(long*)(p + 2) = pFunction + CLRVersionOffset;
            p += 10;
            //mov rdx,pCLRVersion
            p[0] = 0x48;
            p[1] = 0x8B;
            p[2] = 0x4D;
            p[3] = 0x00;
            p += 4;
            //mov rcx,[rbp+0x0]
            p[0] = 0xFF;
            p[1] = 0x50;
            p[2] = 0x18;
            p += 3;
            //call [rax+0x18]
            #endregion
            #region pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&pRuntimeHost);
            p[0] = 0x48;
            p[1] = 0x8B;
            p[2] = 0x45;
            p[3] = 0x08;
            p += 4;
            //mov rax,[rbp+0x8]
            p[0] = 0x48;
            p[1] = 0x8B;
            p[2] = 0x00;
            p += 3;
            //mov rax,[rax]
            p[0] = 0x4C;
            p[1] = 0x8D;
            p[2] = 0x4D;
            p[3] = 0x10;
            p += 4;
            //lea r9,[rbp+0x10]
            p[0] = 0x49;
            p[1] = 0xB8;
            *(long*)(p + 2) = pFunction + IID_ICLRRuntimeHostOffset;
            p += 10;
            //mov r8,pIID_ICLRRuntimeHost
            p[0] = 0x48;
            p[1] = 0xBA;
            *(long*)(p + 2) = pFunction + CLSID_CLRRuntimeHostOffset;
            p += 10;
            //mov rdx,pCLSID_CLRRuntimeHost
            p[0] = 0x48;
            p[1] = 0x8B;
            p[2] = 0x4D;
            p[3] = 0x08;
            p += 4;
            //mov rcx,[rbp+0x8]
            p[0] = 0xFF;
            p[1] = 0x50;
            p[2] = 0x48;
            p += 3;
            //call [rax+0x48]
            #endregion
            #region pRuntimeHost->Start();
            p[0] = 0x48;
            p[1] = 0x8B;
            p[2] = 0x45;
            p[3] = 0x10;
            p += 4;
            //mov rax,[rbp+0x10]
            p[0] = 0x48;
            p[1] = 0x8B;
            p[2] = 0x00;
            p += 3;
            //mov rax,[rax]
            p[0] = 0x48;
            p[1] = 0x8B;
            p[2] = 0x4D;
            p[3] = 0x10;
            p += 4;
            //mov rcx,[rbp+0x10]
            p[0] = 0xFF;
            p[1] = 0x50;
            p[2] = 0x18;
            p += 3;
            //call [rax+0x18]
            #endregion
            #region return pRuntimeHost->ExecuteInDefaultAppDomain(L"assemblyPath", L"typeName", L"methodName", L"argument", pReturnValue);
            p[0] = 0x48;
            p[1] = 0x8B;
            p[2] = 0x45;
            p[3] = 0x10;
            p += 4;
            //mov rax,[rbp+0x10]
            p[0] = 0x48;
            p[1] = 0x8B;
            p[2] = 0x00;
            p += 3;
            //mov rax,[rax]
            p[0] = 0x48;
            p[1] = 0x8B;
            p[2] = 0x4D;
            p[3] = 0x70;
            p += 4;
            //mov rcx,[rbp+0x70]
            p[0] = 0x48;
            p[1] = 0x89;
            p[2] = 0x4C;
            p[3] = 0x24;
            p[4] = 0x28;
            p += 5;
            //mov [rsp+0x28],rcx
            p[0] = 0x48;
            p[1] = 0xB9;
            *(long*)(p + 2) = pFunction + ArgumentOffset;
            p += 10;
            //mov rcx,pArgument
            p[0] = 0x48;
            p[1] = 0x89;
            p[2] = 0x4C;
            p[3] = 0x24;
            p[4] = 0x20;
            p += 5;
            //mov [rsp+0x20],rcx
            p[0] = 0x49;
            p[1] = 0xB9;
            *(long*)(p + 2) = pFunction + MethodNameOffset;
            p += 10;
            //mov r9,pMethodName
            p[0] = 0x49;
            p[1] = 0xB8;
            *(long*)(p + 2) = pFunction + TypeNameOffset;
            p += 10;
            //mov r8,pTypeName
            p[0] = 0x48;
            p[1] = 0xBA;
            *(long*)(p + 2) = pFunction + AssemblyPathOffset;
            p += 10;
            //mov rdx,pAssemblyPath
            p[0] = 0x48;
            p[1] = 0x8B;
            p[2] = 0x4D;
            p[3] = 0x10;
            p += 4;
            //mov rcx,[rbp+0x10]
            p[0] = 0xFF;
            p[1] = 0x50;
            p[2] = 0x58;
            p += 3;
            //call [rax+0x58]
            #endregion
            #region }
            p[0] = 0x48;
            p[1] = 0x8D;
            p[2] = 0x65;
            p[3] = 0x60;
            p += 4;
            //lea rsp,[rbp+0x60]
            p[0] = 0x5D;
            p += 1;
            //pop rbp
            p[0] = 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[numberOfSections];
            for (int i = 0; i < numberOfSections; i++)
            {
                binaryReader.BaseStream.Position += 0x8;
                sections[i] = 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
发帖起码看看格式要求啊。
D小小贱 发表于 2018-2-8 23:40 来自手机
吾爱游客  发表于 2018-2-9 17:27
Hmily 发表于 2018-2-8 15:55
发帖起码看看格式要求啊。

现在补一个可以么..sorry
1、申 请 I D :wwh1004
2、个人邮箱:wwh1004@hotmail.com
Hmily 发表于 2018-2-9 17:38
I D:wwh1004
邮箱:wwh1004@hotmail.com

申请通过,欢迎光临吾爱破解论坛,期待吾爱破解有你更加精彩,ID和密码自己通过邮件密码找回功能修改,请即时登陆并修改密码!
登陆后请在一周内在此帖报道,否则将删除ID信息。
wwh1004 发表于 2018-2-9 19:06
wwh1004报道
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-15 15:04

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表