lots done
This commit is contained in:
parent
1ba7c39c30
commit
fbd0ba445a
59 changed files with 6074 additions and 3598 deletions
110
src/Automata.Memory/MsvcStringReader.cs
Normal file
110
src/Automata.Memory/MsvcStringReader.cs
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
using System.Text;
|
||||
|
||||
namespace Automata.Memory;
|
||||
|
||||
/// <summary>
|
||||
/// Reads MSVC std::string and std::wstring from process memory.
|
||||
/// Handles SSO (Small String Optimization) for both narrow and wide strings.
|
||||
/// </summary>
|
||||
public sealed class MsvcStringReader
|
||||
{
|
||||
private readonly MemoryContext _ctx;
|
||||
|
||||
public MsvcStringReader(MemoryContext ctx)
|
||||
{
|
||||
_ctx = ctx;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads an MSVC std::wstring (UTF-16) from the given address.
|
||||
/// Layout: _Bx (16 bytes: SSO buffer or heap ptr), _Mysize (8), _Myres (8).
|
||||
/// wchar_t is 2 bytes on Windows. SSO threshold: capacity <= 7.
|
||||
/// </summary>
|
||||
public string? ReadMsvcWString(nint stringAddr)
|
||||
{
|
||||
var mem = _ctx.Memory;
|
||||
var size = mem.Read<long>(stringAddr + 0x10);
|
||||
var capacity = mem.Read<long>(stringAddr + 0x18);
|
||||
|
||||
if (size <= 0 || size > 512 || capacity < size) return null;
|
||||
|
||||
nint dataAddr;
|
||||
if (capacity <= 7)
|
||||
dataAddr = stringAddr; // SSO: inline in _Bx buffer
|
||||
else
|
||||
{
|
||||
dataAddr = mem.ReadPointer(stringAddr);
|
||||
if (dataAddr == 0) return null;
|
||||
}
|
||||
|
||||
var bytes = mem.ReadBytes(dataAddr, (int)size * 2);
|
||||
if (bytes is null) return null;
|
||||
|
||||
var str = Encoding.Unicode.GetString(bytes);
|
||||
if (str.Length > 0 && str[0] >= 0x20 && str[0] <= 0x7E)
|
||||
return str;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads an MSVC std::string (narrow, UTF-8/ASCII) from the given address.
|
||||
/// Layout: _Bx (16 bytes: SSO buffer or heap ptr), _Mysize (8), _Myres (8).
|
||||
/// SSO threshold: capacity <= 15.
|
||||
/// </summary>
|
||||
public string? ReadMsvcString(nint stringAddr)
|
||||
{
|
||||
var mem = _ctx.Memory;
|
||||
var size = mem.Read<long>(stringAddr + 0x10);
|
||||
var capacity = mem.Read<long>(stringAddr + 0x18);
|
||||
|
||||
if (size <= 0 || size > 512 || capacity < size) return null;
|
||||
|
||||
nint dataAddr;
|
||||
if (capacity <= 15)
|
||||
dataAddr = stringAddr; // SSO: inline in _Bx buffer
|
||||
else
|
||||
{
|
||||
dataAddr = mem.ReadPointer(stringAddr);
|
||||
if (dataAddr == 0) return null;
|
||||
}
|
||||
|
||||
var bytes = mem.ReadBytes(dataAddr, (int)size);
|
||||
if (bytes is null) return null;
|
||||
|
||||
var str = Encoding.UTF8.GetString(bytes);
|
||||
if (str.Length > 0 && str[0] >= 0x20 && str[0] <= 0x7E)
|
||||
return str;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a null-terminated char* string from a module-range or heap address.
|
||||
/// Component names are char* literals in .rdata, e.g. "Life", "Render", "Monster".
|
||||
/// </summary>
|
||||
public string? ReadCharPtr(nint ptr)
|
||||
{
|
||||
if (ptr == 0) return null;
|
||||
var data = _ctx.Memory.ReadBytes(ptr, 64);
|
||||
if (data is null) return null;
|
||||
var end = Array.IndexOf(data, (byte)0);
|
||||
if (end < 1 || end > 50) return null;
|
||||
var str = Encoding.ASCII.GetString(data, 0, end);
|
||||
if (str.Length > 0 && str.All(c => c >= 0x20 && c <= 0x7E))
|
||||
return str;
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a null-terminated UTF-8 string (up to 256 bytes).
|
||||
/// </summary>
|
||||
public string ReadNullTermString(nint addr)
|
||||
{
|
||||
var data = _ctx.Memory.ReadBytes(addr, 256);
|
||||
if (data is null) return "Error: read failed";
|
||||
var end = Array.IndexOf(data, (byte)0);
|
||||
if (end < 0) end = data.Length;
|
||||
return Encoding.UTF8.GetString(data, 0, end);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue