Muhammed Uğur Nazlı
Muhammed Uğur Nazlı

Reputation: 61

VirtualAlloc And StdCall

I am translating codes from C++ to my VB.NET application. This is the c++ codes:

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];

As you see, it defines a function in stack. How can I simulate it in VB.NET?

Note: You can write C# codes, It is no problem.

Edit:

I wrote a class under the light of your suggestions.

        <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

When I execute this, "Func_Init.Invoke(0, 0, Nothing)" line gives me this error:

System.AccessViolationException
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

Edit2:

I added first part of the assembly codes in Bytes variant:

seg000:00000000     ;
seg000:00000000     ; +-------------------------------------------------------------------------+
seg000:00000000     ; |   This file has been generated by The Interactive Disassembler (IDA)    |
seg000:00000000     ; |           Copyright (c) 2011 Hex-Rays, <[email protected]>           |
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
...

Upvotes: 1

Views: 1684

Answers (1)

Jim Mischel
Jim Mischel

Reputation: 134125

That code is allocating memory, copying data to the allocated memory, and then making a function pointer that references it. Presumably the next step is to execute that code.

Whereas you can allocate the memory in .NET, and copy data to it, you won't be able to transfer control to that block of memory.

For information on calling VirtualAlloc from .NET, see pinvoke.net: VirtualAlloc.

To copy data to that allocated block, you'll need to call some form of Marshal.Copy.

If for some unknown reason you do want to execute the code in that block of memory, you'll have to call an unmanaged function (written in C or C++, for example), pass it the address returned by VirtualAlloc, and have it execute the code.

(From comments)

If for some reason you really want to execute the code in that block of memory, you call Marshal.GetDelegateForFunctionPointer, passing it the address of that memory block. You can then call that function through the delegate.

The delegate type, by the way, would be something like:

delegate int test_t (uint32 type, IntPtr data, uint32 length);

I'm not sure how you'd specify the calling convention, and there are several ways you could marshal the data. You could pin an array and pass the pointer, use an unsafe pointer and pass a byte*, or potentially declare the parameter as a byte[] and marshal the data (although I'm not sure how you'd specify the marshaling). Perhaps somebody else has the answer to that.

Update

You defined your delegate as:

Public Delegate Sub Init(
    ByVal Value As UInt32,
    ByVal Param1 As UInt32,
    ByVal Param2 As IntPtr)

That doesn't match the C definition. I think Param1 should be IntPtr and Param2 should be UInt32.

Also, you don't say if this is 32-bit or 64-bit code. If you're running a 64-bit app and the code you're executing (whatever is in the Bytes) is 32-bit, then it's not going to work.

I don't know what's in the Bytes, so I can't even guess what might be causing your access violation. You are passing it a null pointer, though, so that could be a problem. You'll have to use the assembly level debugger if you want to debug that.

Upvotes: 5

Related Questions