公共模块代码
Option Explicit
'//////////////////////////////////////////////////////////////
'//// callback 函数是个虚函数,代码无意义只为分配内存空间 ////
'//// 参数布局 模仿 callwindowproc 的参数格式 ////
'//////////////////////////////////////////////////////////////
Public Function Callback(ByVal addr As Long, ByVal a As Long, ByVal b As Long, _
ByVal c As Long, ByVal d As Long) As Long
Dim r As Long
r = a + b + c + d
r = a + b + c + d
r = a + b + c + d
Callback = r
End Function
'/// 测试范例: 加法 /////
Public Function FAdd(ByVal a As Long, ByVal b As Long, _
ByVal c As Long, ByVal d As Long) As Long
Dim r As Long
r = a + b + c + d
MsgBox "加法:" & a & " + " & b & " + " & c & " + " & d & " = " & r
FAdd = r
End Function
'/// 测试范例: 乘法 /////
Public Function FMul(ByVal a As Long, ByVal b As Long, _
ByVal c As Long, ByVal d As Long) As Long
Dim r As Long
r = a * b * c * d
MsgBox "乘法:" & a & " * " & b & " * " & c & " * " & d & " = " & r
FMul = r
End Function
'////// 返回通过 addressof 传入的函数指针 ////
Public Function GetAddr(ByVal addr As Long) As Long
GetAddr = addr
End Function
类模块ClsInjectCode代码:
Option Explicit
' 修改内存保护属性(使代码段可写)
Private Declare Function VirtualProtect Lib "kernel32" ( _
ByVal lpAddress As Long, _
ByVal dwSize As Long, _
ByVal flNewProtect As Long, _
lpflOldProtect As Long) As Long
' 拷贝内存(用于写入机器码)
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
ByVal Destination As Long, _
ByRef Source As Any, _
ByVal Length As Long)
' 记录最后一次注入地址和机器码
Private mLastAddress As Long
Private mLastHexCode As String
Private Const PAGE_EXECUTE_READWRITE As Long = &H40
'//// 代码注入接口 //////
Public Sub InjectCode(ByVal addr As Long, ByVal hexStr As String)
Dim patch() As Byte
patch = HexStringToBytes(hexStr)
Call ModifyFun(addr, patch)
mLastAddress = addr
mLastHexCode = hexStr
End Sub
'//////// 机器码字符串转成byte数组 /////
Private Function HexStringToBytes(hexStr As String) As Byte()
Dim parts() As String
Dim result() As Byte
Dim i As Long
parts = Split(Trim$(hexStr))
ReDim result(0 To UBound(parts))
For i = 0 To UBound(parts)
result(i) = CByte("&H" & parts(i))
Next
HexStringToBytes = result
End Function
'////// 机器码注入 //////
Private Sub ModifyFun(ByVal addr As Long, patch() As Byte)
Dim patchLength As Long
patchLength = UBound(patch) - LBound(patch) + 1
Dim oldProtect As Long
Call VirtualProtect(addr, patchLength, &H40, oldProtect)
Call CopyMemory(ByVal addr, ByVal VarPtr(patch(LBound(patch))), patchLength)
Call VirtualProtect(addr, patchLength, oldProtect, oldProtect)
End Sub
配合IDE模式下调试的回调函数Dll库C代码,可自己编译:
编译后在VB的声明格式:
Private Declare Sub Callback Lib "Callback.dll" Alias "_Callback@20" _
(ByVal addr As Long, ByVal a As Long, ByVal b As Long, ByVal c As Long, ByVal d As Long)
'///// 回调函数接口定义 ,通过汇编实现 ////
Public Function callback(ByVal addr As Long, ByVal a As Long, ByVal b As Long, ByVal c As Long, ByVal d As Long) As Long
'这条只为避免编译时,函数体接口和逻辑相同被优化成同一个入口,比如下面的Testadd4。
MsgBox "看到这就没有进入回调"
End Function
'///// 求和函数接口定义:通过汇编计算 ////
Public Function Testadd4(ByVal addr As Long, ByVal a As Long, ByVal b As Long, ByVal c As Long, ByVal d As Long) As Long
End Function
'////// 测试范例:通过callback回调间接执行 ////
Public Function ByCallbackFunc(ByVal a As Long, ByVal b As Long, ByVal c As Long, ByVal d As Long) As Long
Dim result As Long
MsgBox "现在在被回调函数中,传入参数为:" & a & " " & b & " " & c & " " & d
result = (a + b + c + d) * 10
ByCallbackFunc = result
End Function
------------------
类模块:
Option Explicit
' ===== API 声明 =====
Private Declare Function VirtualProtect Lib "kernel32" (ByVal lpAddress As Long, ByVal dwSize As Long, ByVal flNewProtect As Long, lpflOldProtect As Long) As Long
Private Declare Function VirtualAlloc Lib "kernel32" ( _
ByVal lpAddress As Long, _
ByVal dwSize As Long, _
ByVal flAllocationType As Long, _
ByVal flProtect As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
ByVal Destination As Long, _
ByVal Source As Long, _
ByVal length As Long)
Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" ( _
ByVal lpPrevWndFunc As Long, _
ByVal hWnd As Long, _
ByVal Msg As Long, _
ByVal wParam As Long, _
ByVal lParam As Long) As Long
Dim MAXLength As Long '最大可存储字节数
'Dim AsmCode() As Byte '用数组仿真内存存储代码段
Dim SlidePtr As Long '当前可用空间首地址
Dim RemainLength As Long '剩余可用机器码空间
Dim tempCode() As Byte '字符串转机器码数据暂存
Dim SaveCodeFlag As Boolean '写机器码到内存是否成功标志
Private Sub Class_Initialize()
'申请2k可用空间
'采用硬编码不够自己修改,能写2k的机器码也不是一般人
'不想写属性接口,让引用初始化简单点。
MAXLength = 2048 '2K
ReDim AsmCode(MAXLength - 1)
SlidePtr = 0
RemainLength = MAXLength
End Sub
Public Sub start(ByVal addr As Long, ByVal HexStr As String)
'处理字符串
Call HexStringToBytes(HexStr)
'字节码写入内存空间
Call SaveHexCodetoArray
If Not SaveCodeFlag Then Exit Sub '写入失败即退出
''''' 修改函数jmp
Call changeCalltoJmp(ByVal addr)
'//////// 机器码字符串转成byte数组 /////
Private Sub HexStringToBytes(HexStr As String)
Dim parts() As String
Dim result() As Byte
Dim i As Long
'!!!这里本要错误检测处理,检查输入参数hexstr是否为空或是有效机器码!!
'!!!配合开发程序内部使用,自己控制机器码串正确性。
parts = Split(Trim$(HexStr))
ReDim tempCode(0 To UBound(parts))
For i = 0 To UBound(parts)
tempCode(i) = CByte("&H" & parts(i))
Next
End Sub
' /////// 机器码保存到内存 //////
Private Sub SaveHexCodetoArray()
Dim length As Long
length = UBound(tempCode) + 1
If length > RemainLength Then
MsgBox ("可用空间不足!")
SaveCodeFlag = False
Exit Sub
End If
Dim i As Long
For i = 0 To UBound(tempCode)
AsmCode(SlidePtr + i) = tempCode(i)
Next
SaveCodeFlag = True
End Sub
'///////////// 将callback函数的call指令 改为 jmp //////////////
Private Sub changeCalltoJmp(ByVal Funcaddr As Long)
Dim patchAddr(5) As Byte 'jmp 指令需要五个字节
Dim oldProtect As Long
Dim TargetAddress As Long
Dim offset As Long