2011-02-13 60 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),某種插件架構等來完成的。