我知道如何在C#中导入和使用read / writeprocessmomory。 我正在研究游戏培训师。我需要“直接”访问转换为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#中表示该结构? 这样做最简单的方法是什么:
//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#应用程序中使用其他进程内存作为struct?
答案 0 :(得分: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
替换该方法,基本原则仍然是保持(只有这一次,你需要管理结构的内存)。
答案 1 :(得分:3)
如果要读取或写入由其他进程拥有的内存,则需要使用ReadProcessMemory
和WriteProcessMemory
。这是唯一的方法。
对于您要执行的操作,将内存值写入其他进程是不够的。你可能也需要调用一些方法。如果要修改的这些变量是属性,则需要调用属性访问方法。如果变量保持动态(例如列表,字符串),那么WriteProcessMemory
将无法完成工作。
这种事情通常使用定义良好的接口(和API),某种插件架构等来完成。