概述
这次公开的这种方式有一定的局限性,通过努力可以克服。它也有一定的优越性。与以前所用的内存搜索和局部修改不同,这种方式不仅可以局部修改,也可以完全重新编译而不受文件大小的限制。推而广之,这种方法可以替换很多东西而不仅限于SWF,凡是从服务器申请来的都可以。当然,缓存是一个问题,前面也说过,通过努力都可以克服。这种方式基于对网络请求和文件下载API的HOOK,在下面的范例中HOOK本进程的WEBBROWSER控件的调用的两个WININET.DLL的API函数即可达到目的:
<DllImport("wininet.dll", SetLastError:=True)>
Public Shared Function InternetReadFile(ByVal hFile As IntPtr, ByVal lpBuffer As IntPtr, ByVal dwNumberOfBytesToRead As Integer, ByRef lpdwNumberOfBytesRead As Integer) As Boolean
End Function
以及
<DllImport("wininet.dll")>
Public Shared Function HttpOpenRequestW(hConnect As IntPtr, szVerb As IntPtr, szURI As IntPtr, szHttpVersion As IntPtr, szReferer As IntPtr, accetpType As IntPtr, dwflags As Integer, dwcontext As IntPtr) As IntPtr
End Function
其实,HOOK internetreadfile 就可以达成目标。但是有一个问题,从hfile难于识别正在下载的文件是哪一个,而从lpbuffer来识别需要大量对比。所以,我们来查看一下hfile的来源,它可以由好几个API获得,而httpopenrequest正是webbrowser所使用的那个。通过HOOK 就可以得到szuri,它就是请求的文件,而函数返回值就是hfile这个家伙。所以,HOOK这两个API看起来是不错的做法。
然后,让我们分析一下具体实现过程:我们知道,HOOK internetreadfile之后,这个API被调用时会进入我们的自定义函数,而在自定义函数中会调用真正的API来填充其传入的lpbuffer所指向的数组。那么机会来了,如果我们识别到一个hfile,它恰好是我们想要替换掉的那个请求来的文件,这时我们不调用真正的API而自己填充lbuffer就把请求的文件换成了本地文件。而这时服务器和webbrowser还蒙在鼓里。当然,真正实施之前,我们还需要的理解一下internetreadfile的调用方法,否则一切都是空谈。可以在网上找一些使用这个API的代码来查看一下,很容易得到这样的结论:这个API被循环调用,直到lpdwnumberofbytesread为0且返回值为true。此时,将历次读取的缓冲区内容放在一起,就是整个文件。
于是,我们替换时,无需担心调用多少次,webbrowser会不断调用,每调用一次我们就写入一次数据,并模仿API的其他行为:设置真实写入字节数,如此直到数据被完全写入。此时,该API还会被调用,因为我们从来都设置lpdwnumberofbytesread为写入lpbuffer的字节数,那么现在没有数据写了,所以实际写入数据数为0,亦即lpdwnumberofbytesread为0时,调用者认为文件传输完成。这与我们用这个API去编写程序的思路是完全一样的。
因为今天看了看easyhook,所以当作练习就直接用了这个第三方库。如果想自己完成hook部分,可以参考我cnblogs的博客。在x64上,这两个API中至少有一个前面没有90的,所以自己实现的话,简单起见还是使用EATIAT HOOK。而直接使用easyhook或者微软库都没有这些问题,虽然它们也都采用inlinehook。所以,下面的代码都是基于easyhook的,使用前先下载这个库并放置easyhook.dll,easyhook32.dll,easyhook64.dll到程序目录。
1、hook httpopenrequestw
Imports System.Runtime.InteropServices
Public Class HookHttpOpenRequest
<DllImport("wininet.dll")>
Public Shared Function HttpOpenRequestW(hConnect As IntPtr, szVerb As IntPtr, szURI As IntPtr, szHttpVersion As IntPtr, szReferer As IntPtr, accetpType As IntPtr, dwflags As Integer, dwcontext As IntPtr) As IntPtr
End Function
Private Delegate Function HttpOpenRequestDelegate(hConnect As IntPtr, szVerb As IntPtr, szURI As IntPtr, szHttpVersion As IntPtr, szReferer As IntPtr, accetpType As IntPtr, dwflags As Integer, dwcontext As IntPtr) As IntPtr
Private Shared hook As EasyHook.LocalHook = Nothing
Friend Shared Sub Install()
Using hook
If EasyHook.NativeAPI.GetModuleHandle("wininet.dll") = IntPtr.Zero Then
EasyHook.NativeAPI.LoadLibrary("wininet.dll")
End If
hook = EasyHook.LocalHook.Create(EasyHook.LocalHook.GetProcAddress("wininet.dll", "HttpOpenRequestW"), New HttpOpenRequestDelegate(AddressOf sendProc), Nothing)
hook.ThreadACL.SetInclusiveACL(New Integer() {0})
End Using
End Sub
Friend Shared Sub UnInstall()
Using hook
If hook IsNot Nothing Then
hook.ThreadACL.SetExclusiveACL(New Integer() {0})
End If
End Using
End Sub
Private Shared Function sendProc(hConnect As IntPtr, szVerb As IntPtr, szURI As IntPtr, szHttpVersion As IntPtr, szReferer As IntPtr, accetpType As IntPtr, dwflags As Integer, dwcontext As IntPtr) As IntPtr
Dim uri As String = Marshal.PtrToStringUni(szURI)
Dim result As IntPtr = HttpOpenRequestW(hConnect, szVerb, szURI, szHttpVersion, szReferer, accetpType, dwflags, dwcontext)
If uri.Contains("bd_logo1_31bdc765.png") Then '根据名称区分要替换的图片.
HookInternetReadFile.CheatFileHandle = result
End If
Return result
End Function
End Class
这个非常简单,没有什么好说的。哦对了,那个替换函数的名就不用关心了,代码是在工程中另外一个类sendhook.vb里面复制的,忘了改名。然后是另一个:
2、hook internetreadfile
Imports System.IO
Imports System.Runtime.InteropServices
Public Class HookInternetReadFile
<DllImport("wininet.dll", SetLastError:=True)>
Public Shared Function InternetReadFile(ByVal hFile As IntPtr, ByVal lpBuffer As IntPtr, ByVal dwNumberOfBytesToRead As Integer, ByRef lpdwNumberOfBytesRead As Integer) As Boolean
End Function
Private Delegate Function InternetReadFileDelegate(ByVal hFile As IntPtr, ByVal lpBuffer As IntPtr, ByVal dwNumberOfBytesToRead As Integer, ByRef lpdwNumberOfBytesRead As Integer) As Boolean
Private Shared hook As EasyHook.LocalHook = Nothing
Friend Shared CheatFileHandle As IntPtr = IntPtr.Zero '要替换的文件的句柄,来源于HttpOpenRequest的返回值。
Friend Shared CheatFile() As Byte = File.ReadAllBytes(My.Application.Info.DirectoryPath & "abc.jpg") '用于替换的文件
Private Shared curcnt As Integer = 0
Friend Shared Sub Install()
Using hook
If EasyHook.NativeAPI.GetModuleHandle("wininet.dll") = IntPtr.Zero Then
EasyHook.NativeAPI.LoadLibrary("wininet.dll")
End If
hook = EasyHook.LocalHook.Create(EasyHook.LocalHook.GetProcAddress("wininet.dll", "InternetReadFile"), New InternetReadFileDelegate(AddressOf sendProc), Nothing)
hook.ThreadACL.SetInclusiveACL(New Integer() {0})
End Using
End Sub
Friend Shared Sub UnInstall()
Using hook
If hook IsNot Nothing Then
hook.ThreadACL.SetExclusiveACL(New Integer() {0})
End If
End Using
End Sub
Private Shared Function sendProc(ByVal hFile As IntPtr, ByVal lpBuffer As IntPtr, ByVal dwNumberOfBytesToRead As Integer, ByRef lpdwNumberOfBytesRead As Integer) As Boolean
If hFile = CheatFileHandle Then
If curcnt = CheatFile.Length Then
CheatFileHandle = IntPtr.Zero
curcnt = 0
lpdwNumberOfBytesRead = 0
Else
If curcnt + dwNumberOfBytesToRead <= CheatFile.Length Then
lpdwNumberOfBytesRead = dwNumberOfBytesToRead
Marshal.Copy(CheatFile, curcnt, lpBuffer, lpdwNumberOfBytesRead)
curcnt += dwNumberOfBytesToRead
Else
lpdwNumberOfBytesRead = CheatFile.Length - curcnt
Marshal.Copy(CheatFile, curcnt, lpBuffer, lpdwNumberOfBytesRead)
curcnt = CheatFile.Length
End If
End If
Return True
Else
Return InternetReadFile(hFile, lpBuffer, dwNumberOfBytesToRead, lpdwNumberOfBytesRead)
End If
End Function
End Class
作为一个demo,还需要一个窗体:
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
wb.Navigate("http://images2015.cnblogs.com/blog/56896/201702/56896-20170216102630488-270057596.jpg")
End Sub
Private Sub butRef_Click(sender As Object, e As EventArgs) Handles butRef.Click
wb.Refresh()
End Sub
Private Sub chkCheat_CheckedChanged(sender As Object, e As EventArgs) Handles chkCheat.CheckedChanged
If chkCheat.Checked Then
HookHttpOpenRequest.Install()
HookInternetReadFile.Install()
Else
HookHttpOpenRequest.UnInstall()
HookInternetReadFile.UnInstall()
End If
End Sub
End Class
各个名称都可以顾名思义,具体就不说了。怎么样,这个还算是一个比较好玩的玩具吧。
最后
以上就是灵巧流沙为你收集整理的另一种修改在线SWF的方法的全部内容,希望文章能够帮你解决另一种修改在线SWF的方法所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复