2011-02-13 58 views
7

我知道如何导入和使用C#中的读/写过程。 我正在研究游戏教练。我需要对其他进程内存进行“直接”访问才能结构化。我可以使用readprocessmemory或writeprocessmemory,但这会花费很多时间来实现许多结构。如何访问其他程序内存中的结构?

有这种结构在C++:

class CRenderer 
{ 
public: 
    char unknown0[1692]; //0x0000 
    BYTE ID07D54FC8; //0x069C 
    BYTE drawObjects; //0x069D 
    BYTE drawDeferred; //0x069E 
    BYTE drawParticles; //0x069F 
    BYTE ID07E1CA70; //0x06A0 
    BYTE drawBundledMeshes; //0x06A1 
    BYTE drawStaticMeshes; //0x06A2 
    BYTE drawSkinnedMeshes; //0x06A3 
    BYTE drawRoads; //0x06A4 
    BYTE drawTerrain; //0x06A5 
    BYTE drawUnderGrowth; //0x06A6 
    BYTE drawOverGrowth; //0x06A7 
    BYTE drawNameTags; //0x06A8 
    BYTE drawTrees; //0x06A9 
    BYTE ID07E1CE70; //0x06AA 
    BYTE ID07E1CDF0; //0x06AB 
    BYTE DrawFPS; //0x06AC 
    BYTE ID07E1CEF0; //0x06AD 
    BYTE ID07E1C8F0; //0x06AE 
    BYTE ID07E1C870; //0x06AF 
    BYTE drawGraphs; //0x06B0 
    BYTE ID07D55048; //0x06B1 
    BYTE drawSkyDome; //0x06B2 
    BYTE drawSunFlare; //0x06B3 
    BYTE drawPostProduction; //0x06B4 
    BYTE ID07D550C8; //0x06B5 
    char unknown1718[6534]; //0x06B6 
};//Size=0x203C(8252) 

如何代表在C#中该结构? 什么是才达到某事像这样的最简单的方法:

//C++ 
DWORD RendererBase = (DWORD)GetModuleHandle("RendDx9.dll"); //Gets the base address of RenDX9.dll 
DWORD RendererOffset = RendererBase + 0x23D098; //Static address 
CRenderer *cRenderer = *(CRenderer**)RendererOffset; //Points to the class using the static offset 

cRenderer->drawSkyDome = 0; //No Sky 
cRenderer->DrawFPS = 1; //Show FPS 

在C#中我希望能够利用这样的:

cRenderer.drawSkyDome = 0; //No Sky 
cRenderer.DrawFPS = 1; //Show FPS 

如何使用其他进程的内存为结构在我的C#应用?

回答

8

如果您需要与非托管程序二进制兼容的结构,则可以使用[StructLayout]属性及其朋友。例如。在你的情况下,它会是这样的:

[DllImport("kernel32.dll", CharSet=CharSet.Auto)] 
public static extern IntPtr GetModuleHandle(string lpModuleName); 

[StructLayout(LayoutKind.Sequential, Pack = 1)] 
public struct RendererData 
{ 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1692)] 
    public byte[] Unknown; 
    public byte ID07D54FC8; 
    public byte DrawObjects; 
    public byte DrawDeferred; 
    // ... 
    public byte DrawFPS; 
    // ... 
    public byte DrawSkyDome; 
    // ... 
} 

void Main() 
{ 
    IntPtr rendererBase = GetModuleHandle("RendDx9.dll"); 
    if (rendererBase == IntPtr.Zero) 
    { 
     throw new InvalidOperationException("RendDx9.dll not found"); 
    } 
    IntPtr rendererAddr = IntPtr.Add(rendererBase, 0x23D098); 

    var data = new RendererData(); 
    Marshal.PtrToStructure(rendererAddr, data); 

    data.DrawSkyDome = 0; 
    data.DrawFPS = 1; 

    Marshal.StructureToPtr(data, rendererAddr, false); 
} 

我不知道您是否能够访问在这种直接的方式其他模块的数据,但你可以ReadProcessMemory/WriteProcessMemory更换方法,基本原则仍然成立(只有这一次,你需要管理结构的内存)。

3

如果要读取或写入由不同进程拥有的内存,则需要使用ReadProcessMemoryWriteProcessMemory。这是做到这一点的唯一方法。

对于你正在尝试做的事情,将内存值写入其他进程是不够的。您可能还需要调用一些方法。如果您正在修改的这些变量是属性,则需要调用属性访问方法。如果变量包含动态变量(例如列表,字符串),那么WriteProcessMemory不会完成工作。

这种事通常是通过一个定义良好的接口(和API),某种插件架构等来完成的。