我正在将代码从C ++转换为我的VB.NET应用程序。这是c ++代码:
typedef int (__stdcall *init_t)(uint32_t value,uint32_t param1,uint32_t* param2);
static init_t fnInit;
...
...
memory = (uint8_t*)VirtualAlloc(NULL,5000,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
memset(memory,5000,0);
memmove(memory,data,datalen);
fnInit = (init_t )&memory[0];
如您所见,它在堆栈中定义了一个函数。如何在VB.NET中模拟它?
注意:您可以编写C#代码,这没问题。
编辑:
我根据你的建议写了一堂课。
<Flags> _
Public Enum AllocationType As UInteger
COMMIT = &H1000
RESERVE = &H2000
RESET = &H80000
LARGE_PAGES = &H20000000
PHYSICAL = &H400000
TOP_DOWN = &H100000
WRITE_WATCH = &H200000
End Enum
<Flags> _
Public Enum MemoryProtection As UInteger
EXECUTE = &H10
EXECUTE_READ = &H20
EXECUTE_READWRITE = &H40
EXECUTE_WRITECOPY = &H80
NOACCESS = &H1
[READONLY] = &H2
READWRITE = &H4
WRITECOPY = &H8
GUARD_Modifierflag = &H100
NOCACHE_Modifierflag = &H200
WRITECOMBINE_Modifierflag = &H400
End Enum
<DllImport("kernel32.dll", SetLastError:=True)> _
Private Shared Function VirtualAlloc(lpAddress As IntPtr, dwSize As UIntPtr, flAllocationType As AllocationType, flProtect As MemoryProtection) As IntPtr
End Function
<DllImport("msvcrt.dll", EntryPoint:="memset", CallingConvention:=CallingConvention.Cdecl, SetLastError:=False)> _
Public Shared Function MemSet(dest As IntPtr, c As Integer, count As IntPtr) As IntPtr
End Function
<DllImport("msvcrt.dll", SetLastError:=False)> _
Private Shared Function memmove(dest As IntPtr, src As IntPtr, count As Integer) As IntPtr
End Function
<UnmanagedFunctionPointer(CallingConvention.StdCall)> _
Public Delegate Sub Init(ByVal Value As UInt32, ByVal Param1 As UInt32, ByVal Param2 As IntPtr)
Dim Func_Init As Init
Sub New(ByRef Bytes() As Byte)
Dim OffSetInit As Int32 = &H0 'This is correct
Dim MemoryPtr As IntPtr
MemoryPtr = VirtualAlloc(Nothing, 5000, AllocationType.COMMIT, MemoryProtection.EXECUTE_READWRITE)
MemSet(MemoryPtr, 0, 5000)
Marshal.Copy(Bytes, 0, MemoryPtr, Bytes.Length)
Dim InitPtr As IntPtr = MemoryPtr + OffSetInit
Func_Init = CType(Marshal.GetDelegateForFunctionPointer(InitPtr, GetType(Init)), Init)
Func_Init.Invoke(0, 0, Nothing)
End Sub
执行此操作时,“Func_Init.Invoke(0,0,Nothing)”行给出了这个错误:
System.AccessViolationException
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
EDIT2:
我在字节变体中添加了汇编代码的第一部分:
seg000:00000000 ;
seg000:00000000 ; +-------------------------------------------------------------------------+
seg000:00000000 ; | This file has been generated by The Interactive Disassembler (IDA) |
seg000:00000000 ; | Copyright (c) 2011 Hex-Rays, <support@hex-rays.com> |
seg000:00000000 ; | License info: B3-432E-F558-21 |
seg000:00000000 ; | Ilfak Guilfanov |
seg000:00000000 ; +-------------------------------------------------------------------------+
seg000:00000000 ;
seg000:00000000 ; Input MD5 : 55D6B96FEF969A18F927BC5A7A21FAEE
seg000:00000000 ; Input CRC32 : 9A6D4B33
seg000:00000000
seg000:00000000 ; File Name : C:\****************.dll
seg000:00000000 ; Format : Binary file
seg000:00000000 ; Base Address: 0000h Range: 0000h - 4174h Loaded length: 4174h
seg000:00000000
seg000:00000000 include uni.inc ; see unicode subdir of ida for info on unicode
seg000:00000000
seg000:00000000 .686p
seg000:00000000 .mmx
seg000:00000000 .model flat
seg000:00000000
seg000:00000000 ; ===========================================================================
seg000:00000000
seg000:00000000 ; Segment type: Pure code
seg000:00000000 seg000 segment byte public 'CODE' use32
seg000:00000000 assume cs:seg000
seg000:00000000 assume es:nothing, ss:nothing, ds:nothing, fs:nothing, gs:nothing
seg000:00000000
seg000:00000000 ; =============== S U B R O U T I N E =======================================
seg000:00000000
seg000:00000000 ; Attributes: bp-based frame
seg000:00000000
seg000:00000000 sub_0 proc near
seg000:00000000
seg000:00000000 var_4 = dword ptr -4
seg000:00000000 arg_0 = dword ptr 8
seg000:00000000 arg_4 = dword ptr 0Ch
seg000:00000000 arg_8 = dword ptr 10h
seg000:00000000
...
答案 0 :(得分:5)
该代码分配内存,将数据复制到分配的内存,然后生成一个引用它的函数指针。据推测,下一步是执行该代码。
虽然您可以在.NET中分配内存并将数据复制到它,但您将无法将控制转移到该内存块。
有关从.NET调用VirtualAlloc
的信息,请参阅pinvoke.net: VirtualAlloc。
要将数据复制到分配的块,您需要调用某种形式的Marshal.Copy。
如果由于某种未知原因你想要在那个内存块中执行代码,你将不得不调用一个非托管函数(例如用C或C ++编写),传递它返回的地址。 VirtualAlloc
,并 it 执行代码。
(来自评论)
如果由于某种原因你真的想要在那块内存中执行代码,你可以调用Marshal.GetDelegateForFunctionPointer,并传递该内存块的地址。然后,您可以通过委托调用该函数。
顺便说一下,委托类型是这样的:
delegate int test_t (uint32 type, IntPtr data, uint32 length);
我不确定你是如何指定调用约定的,有几种方法可以编组数据。您可以固定数组并传递指针,使用不安全的指针并传递byte*
,或者可能将参数声明为byte[]
并编组数据(尽管我不确定你是怎么做的指定编组)。也许其他人有答案。
您将代理人定义为:
Public Delegate Sub Init(
ByVal Value As UInt32,
ByVal Param1 As UInt32,
ByVal Param2 As IntPtr)
这与C定义不匹配。我认为Param1
应该是IntPtr
而Param2
应该是UInt32
。
另外,您没有说这是32位还是64位代码。如果您正在运行64位应用程序并且正在执行的代码(Bytes
中的任何内容)是32位,那么它将不起作用。
我不知道Bytes
中的内容,所以我甚至无法猜出可能导致您的访问权限违规的原因。但是,您传递的是空指针,因此可能会出现问题。如果要调试它,则必须使用汇编级调试器。