远线程运行API2011-06-06 博客园 zcsor继续前面一篇所写的——远线程调用ASM在上一篇中的类的基础上,继承并发扬了一个类:远线程运行API,里面采用 的技术就是:1、构造远线程调用代码及参数2、通过线性搜索获取对方进程中的API入口地址由于2是提取自一个以前的代码,并且调用API的函数中用了多个循环判定, 导致……效率低下的很呢代码中关键部分就是:1、E8后面偏移地址的计算:E8后面是相对地址……2、不同类型参数的处理:除了INTEGER以外,都“按指针”传递——调用时 采用了字节数组3、参数反向压栈:注意一下就可以了4、实现了一个泛接口类,用以把结构转化为字节数组,但未测试,若不成功 应自己把参数转化为字节数组后传入5、有个修改内存页属性的函数,没有用到,其实是给后面程序用的,添加到 这里了,要用也可以,只是在这个类里直接调用了API这个完整的文件就是这样的了:(记得添加上篇那个类到工程才能用……继 承并发扬么!)Imports System.Runtime.InteropServicesPublic Class RunRemoteAPI : Inherits RunRemoteASMCode
""" <summary>
""" 远程DLL函数导出函数信息
""" </summary>
""" <remarks></remarks>
Protected avExports() As avExportOrImports
""" <summary>
""" 函数导出信息
""" </summary>
""" <remarks></remarks>
Public Structure avExportOrImports
Dim LibName As String "库名(在导出中未使 用)
Dim ExportsIndex As Integer "函数导入/出序号
Dim Name As String "函数名
Dim ExportsRVA As Integer "函数导入/出表RVA
Dim FunctionRVA As Integer "函数入口RVA
End Structure
""" <summary>
""" 基地址
""" </summary>
""" <value></value>
""" <returns>为对方进程申请的内存的基地址 </returns>
""" <remarks></remarks>
ReadOnly Property BaseAddress() As Integer
Get
Return MyBase.AllocBaseAddress
End Get
End Property
""" <summary>
""" 对方进程
""" </summary>
""" <value></value>
""" <returns>对方进程对象</returns>
""" <remarks></remarks>
ReadOnly Property RotateProcess() As Process
Get
Return MyBase.RemoteProcess
End Get
End Property
""" <summary>
""" 用ProcessID初始化
""" </summary>
""" <param name="PID"></param>
""" <remarks></remarks>
Sub New(ByVal PID As Integer)
MyBase.New(PID)
End Sub
""" <summary>
""" 根据名称调用对方进程的API
""" </summary>
""" <param name="DllName">API所在DLL名称 </param>
""" <param name="FuncName">API函数名称 </param>
""" <param name="FuncParams">参数列表</param>
""" <returns>API返回值,此返回值只有当Wait为True时才可信 </returns>
""" <remarks></remarks>
Function CallRemoteAPIByName(ByVal DllName As String, ByVal FuncName As String, ByVal Wait As Boolean, ByVal ParamArray FuncParams() As mFuncParam) As Integer
If MyBase.RemoteProcess Is Nothing Then
MsgBox("未找到指定进程")
Return -1
End If
"初始化数据
ClearCodeAndData()
Dim DllHandle As Integer = -1
Dim FuncAddress As Integer = -1
"枚举对方进程模块列表,找到对方进程中相应DLL的基地址 (Handle)
For Each m As ProcessModule In Process.GetProcessById(MyBase.RemoteProcess.Id).Modules
If InStr(m.FileName.ToUpper, DllName.ToUpper) > 0 Then
DllHandle = m.BaseAddress
Exit For
End If
Next
If DllHandle = -1 Then
MsgBox("未发现对方进程中的 " & DllName & " 模块", , "进程 : " & MyBase.RemoteProcess.Id)
Return -1
End If
"枚举对方进程中相应DLL中全部函数信息(暴力搜索)
avExports = GetExports(MyBase.RemoteProcess.Handle, DllHandle)
"遍历信息表,获取我们需要的函数入口地址
For Each e As avExportOrImports In avExports
If Not e.Name Is Nothing AndAlso e.Name.ToUpper = FuncName.ToUpper Then
FuncAddress = e.FunctionRVA
Exit For
End If
Next
If FuncAddress = -1 Then
MsgBox("未发现 " & DllName & " 模块中 的函数 " & FuncName, , "进程 : " & MyBase.RemoteProcess.Id)
Return -1
End If
"以下构造调用API的ASM CODE
"首先将参数依次压栈
Dim Ubound As Integer = FuncParams.Length - 1
For i As Integer = Ubound To 0 Step -1 "参数反向
If FuncParams(i).Ptr Then "如果需要按指 针封送,作为数据处理并添加指针段。否则,直接添加
Dim addr As Integer = MyBase.AddData (FuncParams(i).Obj)
MyBase.AddByte2Code(&H68) "按4字节 对齐 prush
MyBase.AddInt2Code(addr + MyBase.AllocBaseAddress) "将数据部分的地址写入到为对 方申请的内存的代码部分
Else
MyBase.AddByte2Code(&H68) "按4字节 对齐
MyBase.AddBytes2Code(FuncParams (i).Obj)
End If
Next
"向代码添加调用
AddCallToCode(FuncAddress)
"向代码添加RET(RET 10)
MyBase.AddByte2Code(&HC3)
"int3
MyBase.AddByte2Code(&HCC)
Return MyBase.Run(Wait)
End Function
""" <summary>
""" 读BYREF型返回值,例如GETWINDOWSTEXTA,第二个参数
""" </summary>
""" <param name="index">要传回的BYREF参数索引,如 GETWINDOWSTEXTA中,第二个参数是第一个BYREF传入值,要返回它则传入 1</param>
""" <returns></returns>
""" <remarks></remarks>
Public Function RemoteBytesFromIndex(ByVal index As Integer) As Byte()
Dim odata As mData = CType(MyBase.DataArraylist(index - 1), mData)
Dim ret(odata.len - 1) As Byte
ReadProcessMemory(MyBase.RemoteProcess.Handle, odata.prt, ret, odata.len, 0)
Return ret
End Function
""" <summary>
""" 将CALL语句添加到ASM CODE
""" </summary>
""" <param name="FuncAddr">API函数入口地址 </param>
""" <remarks>注意地址偏移计算</remarks>
Protected Sub AddCallToCode(ByVal FuncAddr As Integer)
"E8指令要调用的地址是相对地址
MyBase.AddByte2Code(&HE8)
Dim CallAddress As Integer = Math.Abs (MyBase.AllocBaseAddress + MyBase.PtrAddressOffset - FuncAddr) - 4
MyBase.AddInt2Code(CallAddress)
End Sub
""" <summary>
""" 获取指定DLL函数的导出函数信息
""" </summary>
""" <param name="pHandle">DLL所在进程句柄 </param>
""" <param name="ModuleBaseAddress">DLL句柄(基地址) </param>
""" <remarks></remarks>
Public Function GetExports(ByVal pHandle As IntPtr, ByVal ModuleBaseAddress As Integer) As avExportOrImports()
Dim ret() As avExportOrImports = Nothing
Try
Dim lpEXPORT_TABLE As Integer = ModuleBaseAddress + MemValue(pHandle, ModuleBaseAddress + MemValue (pHandle, ModuleBaseAddress + &H3C) + &H78)
Dim lNumberOfNames As Integer = MemValue (pHandle, lpEXPORT_TABLE + &H18)
Dim lNumberOfFunctions As Integer = MemValue (pHandle, lpEXPORT_TABLE + &H14)
Dim lBase As Integer = MemValue(pHandle, lpEXPORT_TABLE + &H10)
Dim lpNamesTable As Integer = ModuleBaseAddress + MemValue(pHandle, lpEXPORT_TABLE + &H20)
Dim lpFunctionsTable As Integer = ModuleBaseAddress + MemValue(pHandle, lpEXPORT_TABLE + &H1C)
Dim lpOrdinalsTable As Integer = ModuleBaseAddress + MemValue(pHandle, lpEXPORT_TABLE + &H24)
Dim lpFunction As Integer
Dim lNameOrdinal As Integer
ReDim ret(lNumberOfFunctions - 1)
Dim i As Integer
For i = 0 To lNumberOfFunctions - 1 " 识别入口
ret(i).ExportsIndex = i + lBase
ret(i).ExportsRVA = lpFunctionsTable + 4 * i
ret(i).FunctionRVA = MemValue (pHandle, lpFunctionsTable + 4 * i) + ModuleBaseAddress
Next
Do While lNumberOfNames > 0 "从入 口识别函数名
lNumberOfNames = lNumberOfNames - 1
lpFunction = ModuleBaseAddress + MemValue(pHandle, lpNamesTable + lNumberOfNames * 4)
lNameOrdinal = MemValue(pHandle, (lpOrdinalsTable + lNumberOfNames * 2), True)
If lNameOrdinal >= lNumberOfFunctions Then Exit Do
ret(lNameOrdinal).Name = RemoteStrFromPtr(pHandle, lpFunction)
Loop
Return ret
Catch ex As Exception
"Debug.Print(Err.Description)
Return ret
End Try
End Function
""" <summary>
""" 读取指定内存4,2字节
""" </summary>
""" <param name="lAddress">地址</param>
""" <param name="TooByte">二字节还是四字节 </param>
""" <returns></returns>
""" <remarks></remarks>
Protected Function MemValue(ByVal pHandle As IntPtr, ByVal lAddress As Integer, Optional ByVal TooByte As Boolean = False) As Object
Dim tmpArr() As Byte
If TooByte Then ReDim tmpArr(1) Else ReDim tmpArr(3)
Try
Dim lOldProtect As Integer
VirtualProtectEx(pHandle, lAddress, 1, &H40, lOldProtect)
ReadProcessMemory(pHandle, lAddress, tmpArr, tmpArr.Length, 0)
VirtualProtectEx(pHandle, lAddress, 1, lOldProtect, lOldProtect)
Catch ex As Exception
If Err.Number = 5 Then Return 0
End Try
If TooByte Then
Return BitConverter.ToInt16(tmpArr, 0)
Else
Return BitConverter.ToInt32(tmpArr, 0)
End If
End Function
""" <summary>
""" 根据内存地址指针读字符串
""" </summary>
""" <param name="lpString">地址(指针) </param>
""" <returns></returns>
""" <remarks>最多读会1024个字符</remarks>
Protected Function RemoteStrFromPtr(ByVal pHandle As IntPtr, ByVal lpString As Integer) As String
Dim b(1023) As Byte
Dim lPosOfZero As Integer
Dim lOldProtect As Integer
Try
VirtualProtectEx(pHandle, lpString, 1, &H40, lOldProtect)
ReadProcessMemory(pHandle, lpString, b, 1024, 0)
VirtualProtectEx(pHandle, lpString, 1, lOldProtect, lOldProtect)
Dim i As Integer
For i = 0 To b.Length - 1
If b(i) = 0 Then
lPosOfZero = i
Exit For
End If
Next
Return System.Text.Encoding.ASCII.GetString (b, 0, lPosOfZero)
Catch ex As Exception
"Debug.Print(Err.Number & " " & Err.Description)
Return String.Empty
End Try
End Function
Enum Protect "内存保护属性枚举
PAGE_NOACCESS = &H1
PAGE_READONLY = &H2
PAGE_READWRITE = &H4
PAGE_WRITECOPY = &H8
PAGE_EXECUTE = &H10
PAGE_EXECUTE_READ = &H20
PAGE_EXECUTE_READWRITE = &H40
PAGE_EXECUTE_READWRITECOPY = &H50
PAGE_EXECUTE_WRITECOPY = &H80
PAGE_GUARD = &H100
PAGE_NOCACHE = &H200
PAGE_WRITECOMBINE = &H400
End Enum
Shared Function SetVirtualProtect(ByVal hProcess As IntPtr, ByVal lpBaseAddress As Integer, Optional ByVal nSize As Integer = 8, Optional ByVal nProtect As Protect = Protect.PAGE_EXECUTE_READWRITECOPY) As Integer
Dim lProtect As Integer
If VirtualProtectEx(hProcess, lpBaseAddress, nSize, nProtect, lProtect) <> 0 Then Return lProtect Else Return -1
End Function
End Class
""" <summary>
""" 函数参数
""" </summary>
""" <remarks></remarks>
Public Class mFuncParam
Public Obj As Byte()
Public Ptr As Boolean
Sub New(ByVal obj As Integer)
Me.Obj = BitConverter.GetBytes(obj)
Me.Ptr = False
End Sub
Sub New(ByVal obj As Byte())
Me.Obj = obj.Clone
Me.Ptr = True
End Sub
End Class
""" <summary>
""" 用于将结构体转化为BYTE类型,只提供了一个共享成员方法
""" </summary>
""" <typeparam name="T">必须传入自定义类型,系统类型将引发错误 </typeparam>
""" <remarks>系统类型应自行转化为BYTE数组或INTEGER类型 </remarks>
Public Class Param(Of T)
Shared Function GetBytes(ByVal Value As T) As Byte()
Try
Dim size As Integer = Marshal.SizeOf(Value)
Dim ret(size) As Byte
Dim ptr As IntPtr = Marshal.AllocHGlobal (size)
Marshal.StructureToPtr(Value, ptr, True)
Marshal.Copy(ptr, ret, 0, size)
Marshal.FreeHGlobal(ptr)
Return ret
Catch ex As Exception
MsgBox(ex.ToString)
Return Nothing
End Try
End Function
End Class