Как получить доступ к структуре в памяти другой программы?

Я знаю, как импортировать и использовать read / writeprocessmomory в C#. Я работаю над игровым тренером. Мне нужно иметь "прямой" доступ к другой памяти процесса, приведенной к struct. Я могу использовать 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#? Каков самый простой способ достичь sth, как это:

//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#?

2 ответов


Если вам нужна двоичная структура, совместимая с неуправляемой программой, вы можете использовать [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, основной принцип все равно будет держаться (только на этот раз вам нужно будет управлять памятью для структуры).


Если вы хотите читать или записывать память, принадлежащую другому процессу, вам нужно использовать ReadProcessMemory и WriteProcessMemory. Это единственный способ сделать это.

для того, что вы пытаетесь сделать, недостаточно будет записать значения памяти в другой процесс. Вероятно, вам также потребуется вызвать некоторые методы. Если изменяемые переменные являются свойствами, то необходимо вызвать метод доступа к свойствам. Если переменная содержит что-то динамическое (например, список, string), то WriteProcessMemory не собирается выполнять работу.

такие вещи обычно делаются с хорошо продуманным интерфейсом (и API), какой-то плагин в архитектуре и т. д.