[英]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.