VB6中的代码运行得非常好,我相信dll的编码速度很快,我试图在C#或VB.NET中调用它,无论我不介意......我试过许多不同的技巧都没有用,它应该被调用类似于如何通过偏移传递的数组地址调用RltMoveMemory(CopyMemory)。
VB6代码如下所示
Public Type REGTYPE
REG_Kind As Byte ' ;1=8 bits \ 2=16 bits \ 3=32 bits \ 4=MMX \ 5=XMM \ 6=Float stack \ 7=Segment \ 8=Debug \ 9=Control \ 10=Test
REG_Ptr_Kind As Byte ' ;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)
REG_Type As Byte ' ;0-7= direct register index \ 16 register=byte && 7 \ 32 register=(byte && 63)/8 \ 64=[32/16 address only] \ 128=[using x86 relatives]
REG_BaseAsReg As Byte ' ? ;1=Register only (BASE exposed)!
End Type
Public Type REGSTRUCT
SEG_TYPE As Long
Base As Long
INDEX As Long
SCALE As Long
DISPLACEMENTS As Long
DISPLACEMENT_TYPE As Long
REG_Kind As REGTYPE
PTR_TYPE As Long
End Type
Public Type IMMSTRUCT
VALUE_LO As Long
VALUE_HI As Long
VALUE_TYPE As Long ' 1=Byte \ 2=Word \ 4=Dword \ 8=ByteToWord \ 16=ByteToDword \ 32=AbsJump \ 64=ShortJump \ 128=LongJump
End Type
Public Type DisAsmStruct
Instruction_Prefix As Long
Instruction As Long
Reg1 As REGSTRUCT
Reg2 As REGSTRUCT
Reg_Reg As Long '1=from ptr
Imm As IMMSTRUCT
Instruction_Length As Long
End Type
'return buffer length
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 FDATA() as byte
Dim DisA As DisAsmStruct
DLL调用将是
BufferLength = DisAssemble(FDATA(CNT), BaseAddress + CNT, ByVal Opcodes, DisA, 0)
CNT值是一个计数器,根据发现反汇编指令的持续时间,它会在调用后递增
CNT = CNT + DisA.Instruction_Length
DLL函数OpCodes中的其他值是写入字符串存储器,其中打印了人类可读的asm代码的字符串。 DisA结构也由相同的DLL函数调用填充。 BufferLength作为函数返回值返回我不认为我以后用它将OpCodes字符串修剪为正确的字符串大小有任何问题。
OpCodes声明如此。
Dim Opcodes As String
Opcodes = String(128, 0)
以下是我在C#中尝试过的内容
我所有的失败尝试
//return buffer length
[DllImport("disASM.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
public static extern int DisAssemble(IntPtr Data, uint BaseAddress, IntPtr DisAsmString, IntPtr DisAsmS, uint DisasmOpt);
[DllImport("disASM.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
public static extern int DisAssemble(IntPtr Data, uint BaseAddress, string DisAsmString, DisAsmStruct DisAsmS, uint DisasmOpt);
[DllImport("disASM.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
public static extern short DisAssemble(
[MarshalAs(UnmanagedType.LPArray)] [In] ref byte[] data,
uint BaseAddress,
ref string DisAsmString,
ref DisAsmStruct DisAsmS,
uint DisasmOpt);
[DllImport("disASM.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
public static extern short DisAssemble(
[MarshalAs(UnmanagedType.LPArray)] [In] ref byte[] data,
uint BaseAddress,
ref string DisAsmString,
ref DisAsmStruct DisAsmS,
uint DisasmOpt);
[DllImport("disASM.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
public static extern short DisAssemble(
[MarshalAs(UnmanagedType.LPArray)] [In] ref byte[] data,
uint BaseAddress,
[MarshalAs(UnmanagedType.LPStr)] ref string DisAsmString,
[MarshalAs(UnmanagedType.LPStruct)]ref DisAsmStruct DisAsmS,
uint DisasmOpt);
//this looks like the best one
[DllImport("disASM.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
public static extern int DisAssemble(IntPtr Data, uint BaseAddress, out string DisAsmString, out DisAsmStruct DisAsmS, uint DisasmOpt);
我做不到
[DllImport("disASM.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
public static extern short DisAssemble(
byte* data,
uint BaseAddress,
string* DisAsmString,
DisAsmStruct* DisAsmS,
uint DisasmOpt);
因为它会产生错误指针和固定大小的缓冲区只能在不安全的上下文中使用
最接近的尝试就是这个,它没有用,但我只觉得这很好,因为指针被CNT计数器暴露并正常递增,只是由于一些保护它没有通过在.NET中,我不知道。
unsafe
{
fixed(byte* test = &GLOBALDATA.FDATA[CNT])
{
IntPtr codeBuf = new IntPtr((void*)test);
BufferLength = ModuleASM.DisAssemble(codeBuf, BaseAddress + CNT, out Opcodes, out DisA, 0);
}
}
在线研究表明我喜欢这样(当然没有工作)
GCHandle fileDataPointered = GCHandle.Alloc(GLOBALDATA.FDATA[CNT], GCHandleType.Pinned);
BufferLength = ModuleASM.DisAssemble(fileDataPointered.AddrOfPinnedObject(), BaseAddress + CNT, ref Opcodes, ref DisA, 0);
//BufferLength = ModuleASM.DisAssemble(fileDataPointered.AddrOfPinnedObject(), BaseAddress + CNT, Opcodes, DisA, 0);
fileDataPointered.Free();
在线研究示例编译了与不安全代码示例相同但错误但类似的错误
An unhandled exception of type 'System.AccessViolationException' occurred in {$1}.exe
Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
有人在谷歌链接上推荐了一个工具,我尝试调用P/Invoke Interop Assistant
,假设根据加载.DLL文件生成DLLImport ..我也得到了一个错误。 dll文件缺少程序集清单。
答案 0 :(得分:1)
您可能遇到32位与64位平台的问题。 VB6只有32位,因此DisAssemble.dll是32位dll。
.Net支持32位和64位,默认为AnyCpu。 AnyCpu将在64位操作系统上以64位运行,很可能就是这种情况。
尝试将目标平台更改为x86。
您无法在64位进程中加载32位dll。此外,IntPtr在64位CLR上运行时为8个字节,在32位CLR上运行时为4个字节。
答案 1 :(得分:0)
耶!我接到了电话。
问题是.NET string
与vb6不同String
我完全不知道它的区别......但是
VB6
Dim OpCodes As String
改变C#
string OpCodes;
到
IntPtr OpCodes;
完全解决了这个问题,是的,它不是很漂亮,但我现在必须把它从指针中取出来,我现在就开始研究它了。
起初我想也许我不得不将所有变量都移到不安全的范围内..我这样做了,不知道它是否有助于修复......但我认为不是那么重要,是的,我测试了外面的变量不安全的范围仍然可以正常使用!
完整的工作代码看起来像这样,好吧它不适用于字符串..我会坚持下去,修复它
[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);
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(OpcodesPtr.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
}
}