另一种修改在线SWF的方法

  这次公开的这种方式有一定的局限性,通过努力可以克服。它也有一定的优越性。与以前所用的内存搜索和局部修改不同,这种方式不仅可以局部修改,也可以完全重新编译而不受文件大小的限制。推而广之,这种方法可以替换很多东西而不仅限于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的,所以自己实现的话,简单起见还是使用EAT\IAT 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
各个名称都可以顾名思义,具体就不说了。怎么样,这个还算是一个比较好玩的玩具吧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

清晨曦月

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值