簡體   English   中英

如何將DLL函數調用/ DllImport從vb6轉換為C#.NET

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM