如何从 IntPtr 检索字符串
本文关键字:检索 字符串 IntPtr | 更新日期: 2023-09-27 18:30:38
我调用一个为 vb6 制作的 P/Invoke DLL 函数。
它有效..我之前的问题是关于让它工作,我设法让它运行,但现在我无法从它的输出中检索完整的字符串。
DLL 函数及其结构是这样声明的。
static class ModuleASM
{
public struct REGTYPE
{
public byte REG_Kind; // ;1=8 bits ' 2=16 bits ' 3=32 bits ' 4=MMX ' 5=XMM ' 6=Float stack ' 7=Segment ' 8=Debug ' 9=Control ' 10=Test
public byte REG_Ptr_Kind; // ;1=Byte PTR ' 2=Word PTR ' 3=Dword PTR ' 4=Qword PTR ' 5=mmword ptr ' 6=xmmword ptr ' 7=FWord PTR ' 8=tbyte ptr ' 9=null ptr (LEA)
public byte REG_Type; // ;0-7= direct register index ' 16 register=byte && 7 ' 32 register=(byte && 63)/8 ' 64=[32/16 address only] ' 128=[using x86 relatives]
public byte REG_BaseAsReg; // ? ;1=Register only (BASE exposed)!
}
public struct REGSTRUCT
{
public uint SEG_TYPE;
public uint Base;
public uint INDEX;
public uint SCALE;
public uint DISPLACEMENTS;
public uint DISPLACEMENT_TYPE;
public ModuleASM.REGTYPE REG_Kind;
public uint PTR_TYPE;
}
public struct IMMSTRUCT
{
public uint VALUE_LO;
public uint VALUE_HI;
public uint VALUE_TYPE; // 1=Byte ' 2=Word ' 4=Dword ' 8=ByteToWord ' 16=ByteToDword ' 32=AbsJump ' 64=ShortJump ' 128=LongJump
}
public struct DisAsmStruct
{
public uint Instruction_Prefix;
public uint Instruction;
public ModuleASM.REGSTRUCT Reg1;
public ModuleASM.REGSTRUCT Reg2;
public uint Reg_Reg; //1=from ptr
public ModuleASM.IMMSTRUCT Imm;
public uint Instruction_Length;
}
[DllImport("disASM.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
public static extern int DisAssemble(IntPtr Data, uint BaseAddress, out IntPtr DisAsmString, out DisAsmStruct DisAsmS, uint DisasmOpt);
}
//FDATA is the file data it's a huge byte array.
uint BufferLength;
uint CNT;
uint BaseAddress = 0x401000;
//The call is like this
unsafe
{
string Opcodes = new string((char)0, 128);
IntPtr OpcodesTest;
ModuleASM.DisAsmStruct DisAa = new ModuleASM.DisAsmStruct();
fixed (byte* dataPtr = &GLOBALDATA.FDATA[CNT])
{
IntPtr dataBuf = new IntPtr((void*)dataPtr);
BufferLength = ModuleASM.DisAssemble(dataBuf, BaseAddress + CNT, out OpcodesTest, out DisAa, 0);
//Kinda like it.. need more characters like, PUSH ECX
ASCIIEncoding.ASCII.GetString(BitConverter.GetBytes(OpcodesTest.ToInt64())) //return "PUSH'0'0'0'0"
byte testbbb = Marshal.ReadByte(OpcodesTest); //fail error
string testa = Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(OpcodesTest)); //fail error
string testb = Marshal.PtrToStringAnsi(OpcodesTest); //blank return
string testc = Marshal.PtrToStringUni(OpcodesTest); //fail error
string testd = Marshal.PtrToStringUni(Marshal.ReadIntPtr(OpcodesTest)); //fail error
string teste = Marshal.PtrToStringAuto(Marshal.ReadIntPtr(OpcodesTest)); //fail error
string testf = Marshal.PtrToStringAuto(OpcodesTest); //fail error
}
}
有人知道我必须做什么才能修复才能获得完整的字符串吗? 不仅仅是前 4 个字母.. 像一个例子是假设显示 8 个字符。
最初在 vb6 中声明是这样
Declare Function DisAssemble Lib "disASM" (Data As Any, ByVal BaseAddress As Long, DisAsmString As Any, DisAsmS As Any, ByVal DisasmOpt As Long) As Long
Dim Opcodes As String
Opcodes = String(128, 0)
Dim CleanOpCode As String
Dim DisA As DisAsmStruct
BufferLength = DisAssemble(FDATA(CNT), BaseAddress + CNT, ByVal Opcodes, DisA, 0)
CleanOpCode = Left(Opcodes, BufferLength)
修复了它,事实证明,如果您将DLLImport声明为不安全,则可以使用C#
中的byte*
作为参数之一。
这样
[DllImport("disASM.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
public static extern unsafe int DisAssemble(IntPtr Data, uint BaseAddress, byte* DisAsmString, out DisAsmStruct DisAsmS, uint DisasmOpt);
用法需要 2 个固定语句,因为我无法弄清楚如何在 1 个固定语句中做到这一点,它不适用于研究建议的逗号。
unsafe
{
byte[] OpcodesBuffer = new byte[128];
fixed (byte* dataPtr = &GLOBALDATA.FDATA[CNT])
{
fixed (byte* OpcodesPointer = &OpcodesBuffer[0])
{
BufferLength = ModuleASM.DisAssemble(new IntPtr((void*)dataPtr), BaseAddress + CNT, OpcodesPointer, out DisA, 0);
MessageBox.Show(ASCIIEncoding.ASCII.GetString(OpcodesBuffer, 0, BufferLength));
CNT += DisA.Instruction_Length;
}
}
}