[英]How to translate DLL Function Call / DllImport from vb6 to C# .NET
VB6中的代码工作得非常好,我相信dll是为了提高速度而进行编码的,我正尝试通过C#或VB.NET移植它,无论我不介意..我尝试了许多不同的技巧都无济于事,调用方式应类似于通过偏移量传递的Array地址调用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 Function OpCodes中的其他值是写入的字符串存储器,其中打印了人类可读的asm代码的字符串。 同样,通过同一DLL函数调用填充DisA结构。 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.
有人在Google链接上推荐了一个我尝试过的工具,称为P/Invoke Interop Assistant
,该工具应该是基于将.DLL文件加载到其中来生成DLLImport的。我也从中得到一个错误,因为.dll文件是缺少程序集清单。
您可能会遇到32位与64位平台的问题。 VB6仅是32位,因此DisAssemble.dll是32位dll。
.Net支持32位和64位,默认为AnyCpu。 AnyCpu将在64位操作系统上以64位运行,这很可能是这种情况。
尝试将目标平台更改为x86。
您不能在64位进程中加载32位dll。 同样,在64位CLR上运行时,IntPtr为8字节;在32位CLR上运行时,IntPtr为4字节。
好极了! 我接到电话了。
问题是.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
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.