远线程运行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