Как получить доступ к структуре в памяти другой программы?
Я знаю, как импортировать и использовать 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), какой-то плагин в архитектуре и т. д.