Quantcast
Channel: VBForums - CodeBank - Visual Basic 6 and earlier
Viewing all articles
Browse latest Browse all 1529

Binary Code Thunk Experiment

$
0
0
Here's the VB6 code for Form1
Code:

Private Declare Function CallProc Lib "user32.dll" Alias "CallWindowProcA" (ByVal ProcAddr As Long, ByVal Param1 As Long, ByVal Param2 As Long, ByVal Param3 As Long, ByVal Param4 As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)

Private Const ThunkStrConst As String = "55 89 E5 8B 45 08 03 45 0C 03 45 10 03 45 14 C9 C2 10 00"
Dim VM As New clsVirtualMemory
Dim MemAddr As Long
Dim ThunkRetVal As Long



Private Sub Form_Load()
Main
End Sub



Private Sub Main()
AllocateMem
CheckAllocation
CopyMem
ExecuteMem
DeallocateMem
PrintRetVal
End Sub



Private Sub AllocateMem()
MemAddr = VM.Allocate(&H10000000, &H1000, True)
End Sub



Private Sub CheckAllocation()
If MemAddr = 0 Then End
If MemAddr <> &H10000000 Then
    DeallocateMem
    End
End If
End Sub



Private Sub CopyMem()
Dim ThunkStr As String
Dim Thunk() As Byte
Dim n As Long

ThunkStr = Replace(ThunkStrConst, " ", "")
ReDim Thunk(Len(ThunkStr) \ 2 - 1)

For n = 0 To UBound(Thunk)
    Thunk(n) = "&h" & Mid$(ThunkStr, n * 2 + 1, 2)
Next n

CopyMemory ByVal MemAddr, Thunk(0), UBound(Thunk) + 1
End Sub



Private Sub ExecuteMem()
ThunkRetVal = CallProc(MemAddr, 1, 2, 3, 4)
End Sub



Private Sub PrintRetVal()
Print ThunkRetVal
End Sub



Private Sub DeallocateMem()
VM.Free
End Sub



Private Sub Form_Unload(Cancel As Integer)
DeallocateMem
End Sub



Here's the code for the class module.
Code:

Private Declare Function VirtualAlloc Lib "kernel32.dll" (ByVal lpAddress As Long, ByVal dwSize As Long, ByVal flAllocationType As Long, ByVal flProtect As Long) As Long
Private Declare Function VirtualFree Lib "kernel32.dll" (ByVal lpAddress As Long, ByVal dwSize As Long, ByVal dwFreeType As Long) As Long
Private Declare Function VirtualQuery Lib "kernel32.dll" (ByVal lpAddress As Long, ByRef lpBuffer As MEMORY_BASIC_INFORMATION, ByVal dwLength As Long) As Long
Private Type MEMORY_BASIC_INFORMATION
    BaseAddress As Long
    AllocationBase As Long
    AllocationProtect As Long
    RegionSize As Long
    State As Long
    Protect As Long
    lType As Long
End Type



Dim MemAddr As Long
Dim MemSize As Long
Dim MemExec As Boolean



Public Property Get Address() As Long
Address = MemAddr
End Property

Public Property Get Size() As Long
Size = MemSize
End Property

Public Property Get IsExecutable() As Boolean
IsExecutable = MemExec
End Property



Public Function Allocate(ByVal DesiredAddress As Long, ByVal DesiredSize As Long, Optional ByVal MakeExecutable As Boolean) As Long
Dim AccessType As Long
Dim MemInfo As MEMORY_BASIC_INFORMATION

If MemAddr <> 0 Then Exit Function
If MakeExecutable Then AccessType = &H40 Else AccessType = 4
Allocate = VirtualAlloc(DesiredAddress, DesiredSize, &H3000, AccessType)
If Allocate = 0 Then Exit Function
MemAddr = Allocate
If VirtualQuery(MemAddr, MemInfo, Len(MemInfo)) = 0 Then
    Free
    Allocate = 0
    Exit Function
End If
MemSize = MemInfo.RegionSize
MemExec = MakeExecutable
End Function



Public Function Free() As Long
If MemAddr = 0 Then Exit Function
Free = VirtualFree(MemAddr, 0, &H8000&)
If Free = 0 Then Exit Function
MemAddr = 0
MemSize = 0
End Function



Note that Form1's AutoRedraw property should be set to True for this project, so that the text that is Printed to the form before the form is shown won't be gone when it is shown. Note also that this project may or may not work if run from the VB6 IDE. It depends on if a 4096 byte block of memory starting at virtual memory address 0x10000000 is available when the allocation attempt occurs, or whether that memory happens to be being used by the VB6 IDE at the time. It has ALWAYS worked when running the compiled EXE file. Note that I'm assuming it's being compiled in Native (not P-Code) mode when making that statement, as that's how I've tested it.


Some interesting things you may notice include that the only thing in Form1's Load event is a call to a sub called Main. This is because I wanted to be able to easily debug the EXE file in an external debugger (OllyDbg 2.01 in my case), and there's quite a bit of overhead in terms of the amount of machine-code present in the Load event, but not so much with a sub. So I didn't "pollute" the already crowded Load event with even more code. This makes looking at the code in a debugger much easier. You'll also note that the Main sub simply contains a series of calls to other subs, and that the actual work is divided up into these other subs. The reason for this is so that if you want to only debug certain portions of the code, it's easy to look through the short list of calls, as these calls to other subs are commands that have very little overhead (compared to something like even a simple VB command like a Print statement, which has a TON of overhead in machine-code). Again, this makes looking at it in a debugger much easier.

I'll quickly describe here what each of these subs do:

AllocateMem allocates an executable block of virtual memory, via the Allocate function in an instance of the class module clsVirtualMemory.

CheckAllocation verifies that the memory allocation was successful, and that it successfully put it in the allocated it in the requested location. There's no guaranty that if it is successful, that it will actually be put where you want it. If a given location is already in use, it may do one of 2 things. It may fail, but not necessarily. Alternatively it may succeed but instead of putting it where you wanted it, it may put it somewhere else nearby, and return the corresponding memory address (not good for my thunk, which if it used more advanced code than it currently does, it could fail if not located at the expected address). If the location is not where it is expected, or if the allocation failed altogether, the program is immediately terminated (though if the allocation didn't fail but was at the wrong address, it deallocates the memory just before terminating the program).

CopyMem converts the hex string for the thunk into raw data, and copies it to the allocated executable memory block.

ExecuteMem uses the function CallProc (which aliases to the actual API function CallWindowProcA) to start execution of the thunk code, as well as providing it with 4 parameters. The thunk code in this very simple case just adds the 4 numbers together and returns the sum.

DeallocateMem deallocates the virtual memory block via the Free function in the instance of the clsVirtualMemory class module.

PrintRetVal prints the value returned by the thunk code to the form.



If this program is working properly on your computer, when your form appears you should see the number 10 printed on it.

Viewing all articles
Browse latest Browse all 1529

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>