Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/279.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用反射在C#中查找字段指针_C#_Memory_Reflection_Jit - Fatal编程技术网

使用反射在C#中查找字段指针

使用反射在C#中查找字段指针,c#,memory,reflection,jit,C#,Memory,Reflection,Jit,此问题仅用于教育目的。 我知道本地程序是如何工作的。编译器获取每个原语并给它一个地址,然后在程序中使用该地址。对于结构,它只是将地址堆叠在一起(加上一些填充)-但基本上,结构并不真正“存在”。 本机程序不会告诉我它有哪些字段和变量。它只访问不同的地址——如果我查看程序集,我可以根据需要命名每个地址,但程序不会提供这些信息。因此,假设我正在寻找一个特定的变量,如果不检查程序的执行或程序集,我就无法完成它。 NET环境确实告诉我它有哪些变量以及它有哪些字段。使用Assembly类和Reflectio

此问题仅用于教育目的。
我知道本地程序是如何工作的。编译器获取每个原语并给它一个地址,然后在程序中使用该地址。对于结构,它只是将地址堆叠在一起(加上一些填充)-但基本上,结构并不真正“存在”。

本机程序不会告诉我它有哪些字段和变量。它只访问不同的地址——如果我查看程序集,我可以根据需要命名每个地址,但程序不会提供这些信息。因此,假设我正在寻找一个特定的变量,如果不检查程序的执行或程序集,我就无法完成它。

NET环境确实告诉我它有哪些变量以及它有哪些字段。使用
Assembly
类和
Reflection
命名空间,我可以加载一个文件并查看它有哪些字段和类。
然后,使用一个搜索内存的程序(无论它是否为本机内存),我可以找到字段的物理位置(通过使用它的值、过滤等),就像
作弊引擎那样。它将给出内存中字段的实际地址,由
JIT

生成的程序集访问该地址 我知道MSIL不包含特定字段所需位置的信息。我几乎可以肯定的是,
JIT
永远不会通过删除任何类来优化代码。

我知道.NET调试器是程序中的一个实际类,它允许Visual Studio与应用程序的内部信息进行交互。当调试器丢失时,
Visual Studio
无法读取或写入字段,也无法以任何方式检查应用程序。


如果不使用
作弊引擎
或类似工具在运行.NET进程的静态类(或特定实例)中查找字段的物理位置,是否有任何方法每次执行后地址是否相同(如在本机程序中)?它可能只在不同的平台或机器上有所不同吗?
JIT
如何决定字段的放置位置?


如果我不清楚,我希望在不访问程序代码的情况下执行此操作,即通过另一个进程(如调试器,但对于在发行版下编译的程序)从外部执行此操作。

在Paint.net中的下一个代码注入注入器方法和获取MainForm字段

NInject.exe 输出:
如果我不清楚,我希望在不访问程序代码的情况下执行此操作,即通过另一个进程(如调试器,但对于在发行版下编译的程序)进行外部操作。一个问题是,即使您知道相对字段地址,由于堆压缩和引用重新分配,绝对地址在GC后仍然可以更改。为了确保在外部有一个有效的指针,您必须保留一条指向静态根的相对引用的线索,然后必须注意进程何时被劫持以及引用何时被更改。因为您的进程是外部的,所以当.NET进程被劫持时,您不会得到更新的好处;你会想在访问内存时冻结进程(需要非常低级别的访问)。我只能想到这样做的恶意用途。如果这纯粹是学术性的,我认为有更好的方法来花费你的时间(也许是在思考更具潜在生产性而不是有害的用途)。你可能可以对公开用于调试的api做些什么。任何非静态实例的问题在于必须找到它们。现在,应用程序中长期存在的任何内容都将静态地锚定在某个地方,但是所有仅锚定在堆栈中的临时内容将很难使用反射找到。除此之外,您还可以使用反射和不安全代码提取指向对象的指针-您可以加载exe程序集并手动调用线程中的main方法,然后使用反射遍历代码。呃,您能解释一下这是什么以及它的外观吗?从代码上看,似乎您正在注入一个DLL,但我仍然无法理解这是什么。
public static int Injector(string parameter)
{
  try
  {
    var mainForm = Application.OpenForms.OfType<Form>().FirstOrDefault(form => form.GetType().FullName.EndsWith("MainForm"));

    var builder = new StringBuilder();
    builder.AppendFormat("process: {0}\r\n\r\n", Application.ExecutablePath);
    builder.AppendFormat("type: {0}\r\n", mainForm.GetType().FullName);
    foreach (var field in mainForm.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
    {
      builder.AppendFormat("field {0}: {1}\r\n", field.Name, field.GetValue(mainForm));
    }


    new Form()
    {
      Controls = 
      {
        new TextBox
        {
          Text = builder.ToString(),
          Multiline = true,
          Dock = DockStyle.Fill
        }
      }
    }
    .ShowDialog();
  }
  catch (Exception exc)
  {
    MessageBox.Show(exc.ToString());
  }
  return 0;      
}

static void Main(string[] args)
{
  var process = System.Diagnostics.Process.GetProcessesByName("PaintDotNet").FirstOrDefault();

  var processHandle = OpenProcess(ProcessAccessFlags.All, false, process.Id);

  var proxyPath = System.IO.Path.Combine(System.Windows.Forms.Application.StartupPath, "NInjector.dll");

  var pathBytes = System.Text.Encoding.ASCII.GetBytes(proxyPath);

  var remoteBuffer = VirtualAllocEx(processHandle, IntPtr.Zero, (uint)pathBytes.Length, AllocationType.Commit, MemoryProtection.ReadWrite);
  WriteProcessMemory(process.Handle, remoteBuffer, pathBytes, (uint)pathBytes.Length, IntPtr.Zero);


  var remoteThread = CreateRemoteThread(processHandle, IntPtr.Zero, 0, GetProcAddress(GetModuleHandle("kernel32"), "LoadLibraryA") , remoteBuffer, 0, IntPtr.Zero);

  WaitForSingleObject(remoteThread, unchecked((uint)-1)); 

  CloseHandle(remoteThread);

}
#include "MSCorEE.h"
#pragma comment  (lib, "MSCorEE")

void StartTheDotNetRuntime()
{
    MessageBox(0, L"Started", L"proxy", 0);

    ICLRRuntimeHost *pClrHost = NULL;
    HRESULT hr = CorBindToRuntimeEx(
        NULL, L"wks", 0, CLSID_CLRRuntimeHost,
        IID_ICLRRuntimeHost, (PVOID*)&pClrHost);


    hr = pClrHost->Start();


    DWORD dwRet = 0;
    hr = pClrHost->ExecuteInDefaultAppDomain(
        L"bla-bla\\NInject.exe",
        L"NInject.NInject_Program", L"Injector", L"MyParameter", &dwRet);



    hr = pClrHost->Stop();

    pClrHost->Release();
}


BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    StartTheDotNetRuntime();
    break;
    case DLL_THREAD_ATTACH:
    break;
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:


        break;
    }
    return TRUE;
}
process: C:\Program Files\Paint.NET\PaintDotNet.exe

type: PaintDotNet.Dialogs.MainForm
field appWorkspace: PaintDotNet.Controls.AppWorkspace
field defaultButton: System.Windows.Forms.Button, Text: 
field floaters: PaintDotNet.Dialogs.FloatingToolForm[]
field floaterOpacityTimer:  [System.Windows.Forms.Timer], Interval: 25
field deferredInitializationTimer: 
field components: System.ComponentModel.Container
field killAfterInit: False
field singleInstanceManager: PaintDotNet.SystemLayer.SingleInstanceManager
field queuedInstanceMessages: System.Collections.Generic.List`1[System.String]
field processingOpen: False
field scrollPosition: {X=0,Y=0}