简体   繁体   中英

VB.NET Dynamic API calls x64

First of all, i'm new here so please not take the bad if I missed something. This is my first question on this forum, and I hope to get the right answer.

Problem description:

I'm trying to use CallWindowProc to call API dynamically, but as all of you know it's complicated cause CallWindowProc have limited number of arguments.So there is a need to use asm codes.With the help of various resources from the internet I was able to get the code that works, but only for x86 architecture (compiled for x86 on x64 machine).The problem is that x64 architecture strictly using __fastcall calling convention while x86 not.

Question:

I need some advices why the code below not working.I'm also tried some combinations using opcode from Asm example but without success.

Asm code {MASM 64}

; Sample x64 Assembly Program
; Chris Lomont 2009 www.lomont.org
extrn ExitProcess: PROC   ; external functions in system libraries
extrn MessageBoxA: PROC
.data
caption db 'Test', 0
message db 'Test msg!', 0
.code
Start PROC
  sub    rsp,28h      ; shadow space, aligns stack
  mov    rcx, 0       ; hWnd = HWND_DESKTOP
  lea    rdx, message ; LPCSTR lpText
  lea    r8,  caption ; LPCSTR lpCaption
  mov    r9d, 0       ; uType = MB_OK
  call   MessageBoxA  ; call MessageBox API function
  mov    ecx, eax     ; uExitCode = MessageBox(...)
  call ExitProcess
Start ENDP
End

Code from disassembly window.

  sub    rsp,28h      ; shadow space, aligns stack
000000013F4C1010 48 83 EC 28          sub         rsp,28h  
  mov    rcx, 0       ; hWnd = HWND_DESKTOP
000000013F4C1014 48 C7 C1 00 00 00 00 mov         rcx,0  
  lea    rdx, message ; LPCSTR lpText
000000013F4C101B 48 8D 15 E3 2F 00 00 lea         rdx,[message (13F4C4005h)]  
  lea    r8,  caption ; LPCSTR lpCaption
000000013F4C1022 4C 8D 05 D7 2F 00 00 lea         r8,[caption (13F4C4000h)]  
  mov    r9d, 0       ; uType = MB_OK
000000013F4C1029 41 B9 00 00 00 00    mov         r9d,0  
  call   MessageBoxA  ; call MessageBox API function
000000013F4C102F E8 18 00 00 00       call        MessageBoxA (13F4C104Ch)  
  mov    ecx, eax     ; uExitCode = MessageBox(...)
000000013F4C1034 8B C8                mov         ecx,eax  
  call ExitProcess
000000013F4C1036 E8 0B 00 00 00       call        ExitProcess (13F4C1046h)  

Vb.net code

    Imports System.Runtime.InteropServices
Module CallApiByName64

#Region "Declaration"

#Region "Functions"

    Private Declare Unicode Function CallWindowProc Lib "user32.dll" Alias "CallWindowProcW" (ByVal lpPrevWndFunc As IntPtr, ByVal hWnd As IntPtr, ByVal Msg As UInteger, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr

    Private Declare Unicode Function GetModuleHandle Lib "kernel32.dll" Alias "GetModuleHandleW" (ByVal moduleName As String) As IntPtr

    Private Declare Unicode Function LoadLibraryEx Lib "kernel32.dll" Alias "LoadLibraryExW" (ByVal lpFileName As String, ByVal hFile As IntPtr, ByVal dwFlags As Integer) As IntPtr

    Private Declare Function FreeLibrary Lib "kernel32.dll" Alias "FreeLibrary" (ByVal hModule As IntPtr) As Integer

    Private Declare Function VirtualAlloc Lib "kernel32.dll" Alias "VirtualAlloc" (ByVal lpAddress As IntPtr, ByVal dwSize As Integer, ByVal flAllocationType As Integer, ByVal flProtect As Integer) As IntPtr

    Private Declare Function VirtualFree Lib "kernel32.dll" Alias "VirtualFree" (ByVal lpAddress As IntPtr, ByVal dwSize As Integer, ByVal dwFreeType As Integer) As Integer

    Private Declare Function GetProcAddress Lib "kernel32.dll" Alias "GetProcAddress" (ByVal hModule As IntPtr, ByVal methodName As String) As IntPtr

    Private Declare Sub RtlMoveMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByVal Destination As IntPtr, ByVal Source() As Byte, ByVal Length As Integer)

#End Region

#Region "Constants"

    Private Const MEM_COMMIT As Integer = &H1000
    Private Const MEM_RESERVE As Integer = &H2000
    Private Const MEM_EXECUTE_READWRITE As Integer = &H40

#End Region

#End Region

    Dim FunctionAdress As IntPtr
    Dim MemAdressOffset As IntPtr

    Function Call_64(ByVal sLib As String, ByVal sMod As String, ByVal ParamArray Params() As IntPtr) As IntPtr
        Dim MemAdress As IntPtr

        '## CODE
        FunctionAdress = GetProcAddress(LoadLibraryEx(sLib, IntPtr.Zero, 0), sMod)
        If FunctionAdress = 0 Then Exit Function

        MemAdress = VirtualAlloc(IntPtr.Zero, 256, MEM_COMMIT Or MEM_RESERVE, MEM_EXECUTE_READWRITE)
        MemAdressOffset = MemAdress

        '## PREPARE STACK

        AddBytes({&H48, &H83, &HEC, &H28})

        '## FUNCTION PARAMETERS

        AddBytes({&H48, &HC7}) 'mov {opcode}
        AddBytes(BitConverter.GetBytes(CInt(Params(0)))) 'Parameter 1 (stored in 4 bytes)

        AddBytes({&H48, &H8D}) 'lea {opcode}
        AddBytes(BitConverter.GetBytes(CInt(Params(1)))) 'Parameter 2 (stored in 4 bytes) (address of string)

        AddBytes({&H4C, &H8D}) 'lea {opcode}
        AddBytes(BitConverter.GetBytes(CInt(Params(2)))) 'Parameter 3 (stored in 4 bytes) (address of string)

        AddBytes({&H41, &HB9}) 'mov {opcode} {B8+r}
        AddBytes(BitConverter.GetBytes(CInt(Params(3)))) 'Parameter 4 (stored in 4 bytes)

        '## CALL FUNCTION

        AddBytes({&HE8}) 'call {opcode}
        AddBytes(BitConverter.GetBytes(CInt(FunctionAdress) - CInt(MemAdressOffset) - 16))

        AddBytes({&H8B, &HC8}) ' mov         ecx,eax  

        '% IGNORE %
        Dim DumpBytes(CInt(MemAdressOffset) - CInt(MemAdress)) As Byte
        Marshal.Copy(MemAdress, DumpBytes, 0, CInt(MemAdressOffset) - CInt(MemAdress))
        '% END %

        '## EXECUTE CODE
        Call_64 = CallWindowProc(MemAdressOffset, 0, 0, 0, 0)

    End Function

    Private Sub AddBytes(ByVal Data() As Byte)
        RtlMoveMemory(MemAdressOffset, Data, Data.Length)
        MemAdressOffset = CInt(MemAdressOffset) + Data.Length
    End Sub

End Module

Call function

Call_64("user32", "MessageBoxW", 0, Marshal.StringToHGlobalUni("Test"), Marshal.StringToHGlobalUni("Test msg!"), 0)

It looks like you forgot the REX prefix bytes when you generate the machine code sequence in your VB function. These are 0x4n -bytes present at the beginning of some of the instructions in the disassembly you showed in your question.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM