修改http请求文件为本地文件的一种方法:hook InternetReadFile 和 HttpOpenRequest
今天没事的时候学了一下easyhook来hook本进程API,确实很简单就能hook。然后想到这个问题:替换webbrowser请求的文件为本地文件。有什么用就不说了,都懂。因为没有用API写过http方面的东西,所以先hook了几个函数,其中InternetReadFile是webbrowser用来获取文件的,而文件句柄可以来源于internetopenurl和 HttpOpenRequest等API,挨个下一下钩子就知道用的是 HttpOpenRequest。当然,获取方法是多种多样的,也可以用x64dbg等调试工具。确定下来hook这两个可以达成目标就可以了:
1、从HttpOpenRequest知道要下载的是哪个文件,过滤需要替换的那个。
2、HttpOpenRequest的返回值就是打开文件句柄了,在InternetReadFile中识别这个句柄就可以。
3、在给InternetReadFile的自定义例程中,对需要替换的文件进行替换。
接下来,让我们考虑一下替换的流程:webbrowser调用InternetReadFile的时候,先到达我们的自定义例程,然后由我们调用API函数InternetReadFile,于是我们可以在自定义函数中把相应文件句柄的数据请求吃掉——把我们的数据写入缓冲区,而后直接返回不掉用API。对于我们不关心的文件句柄调用API。
查看InternetReadFile的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
可以知道,第一个参数是HttpOpenRequest返回的文件句柄,lpbuffer是接收数据的缓冲区,dwnumberofbytestoread是期望读取的字节数,即缓冲区大小,lpdwnumberofbytesread是实际写入缓冲区的字节数。返回值表示函数调用是否成功。所以,当lpdwnumberofbytesread为0且函数返回值为true时,达到文件结尾——函数调用成功却没有数据写入,说明数据写完了。于是,在我们的自定义例程中也需要遵守该约定——当写入数据时返回实际写入的数据大小,写完数据后再次被调用时返回0并进行清理。首先,来看一下比较简单的一个hook:
Imports System.Runtime.InteropServices
Imports System.Text 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() {})
End Using
End Sub Friend Shared Sub UnInstall()
Using hook
If hook IsNot Nothing Then
hook.ThreadACL.SetExclusiveACL(New Integer() {})
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("/56896-20170216102630488-270057596.jpg") Then '根据名称区分要替换的图片.
HookInternetReadFile.CheatFileHandle = result End If Return result End Function End Class
easyhook用起来确实比较简单,首先是注入过程,因为webbrowser对wininte.dll的加载是请求第一个页面时,所以可能导致这个DLL不在进程空间,那么先加载它。之后的hook非常易懂(函数名我没有修改,复制粘贴的之前写的sendhook),唯一需要注意的是实际hook的过程调用的是ThreadACL.SetInclusiveACL,unhook类似。在自定义函数中,首先调用API,得到句柄,然后根据要替换的名称来确定是否启动给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 = 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() {})
End Using
End Sub Friend Shared Sub UnInstall()
Using hook
If hook IsNot Nothing Then
hook.ThreadACL.SetExclusiveACL(New Integer() {})
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 =
lpdwNumberOfBytesRead =
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
因为是一个基本结构范例,所以偷懒直接用了参数,这里应该有错误处理过程才行。hook的过程和前面一致,只是在自定义函数中处理把自定义数据写入缓冲区然后返回了。具体的API过程没有跟踪,所以不知道不调用InternetReadFile这个API会不会有内存泄漏之类的什么问题,如果需要调用也非常简单:在恰当的时机循环读取一次就可以了。最后是窗体代码:
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 butGotoUrl_Click(sender As Object, e As EventArgs) Handles butGotoUrl.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
窗体上一个webbrowser重命名为wb,一个checkbox重命名为chkcheat,一个button重命名为butgotourl,另外,在程序所在目录放一个abc.jpg。对,这个范例就是这么简陋,好在现在就可以测试了。如果图片换名字了,那需要修改url地址的同时修改
If uri.Contains("/56896-20170216102630488-270057596.jpg") Then '根据名称区分要替换的图片
才可以正确运行。
修改http请求文件为本地文件的一种方法:hook InternetReadFile 和 HttpOpenRequest的更多相关文章
- chrome浏览器调试线上文件映射本地文件
chrome浏览器调试线上文件映射本地文件 通过ReRes让chrome拥有路径映射的autoResponse功能. 前端开发过程中,经常会有需要对远程环境调试的需求.比如,修改线上bug,开发环境不 ...
- iOS 获取文件的目录路径的几种方法 [转]
iOS 获取文件的目录路径的几种方法 2 years ago davidzhang iphone沙箱模型的有四个文件夹,分别是什么,永久数据存储一般放在什么位置,得到模拟器的路径的简单方式是什么. d ...
- 提交(post)xml文件给指定url的2种方法
原文:提交(post)xml文件给指定url的2种方法 1 这段代码是在网上搜到的,拿来共享,项目正好要用到.其中的data你只需要传递一个xml字符串就可以 protected string ...
- 使用c#检测文件正在被那个进程占用 判断文件是否被占用的两种方法
C# 判断文件是否被占用的三种方法 using System.IO; using System.Runtime.InteropServices; [DllImport("kernel32.d ...
- 关于FileZilla上传文件后服务器端文件与本地文件大小不一致的解决方法
最近在调试网站时发现,通过ftp上传工具FileZilla上传至服务器端的文件与本地文件大小不一致,虽然没有影响网站的最终显示效果,但仍让我困惑不解.后发现是传输类型的原因,解决方法如下: 中文版Fi ...
- datagrid数据导出到excel文件给客户端下载的几种方法
方法一:导出到csv文件,存放在服务器端任一路径,然后给客户下载 优点: 1.可以进行身份认证后给客户下载,如果放到非web目录就没有对应的url,客户无法随时下载. 2.也是因为生成了文件,所以占用 ...
- 通过InputStream访问文件中的数据的四种方法
//方法一(每次只读取一个字节) public static void getFile() throws IOException { File file = new File("D:\\a. ...
- [C#.Net]判断文件是否被占用的两种方法
今天开发产线测试Tool时发现日志文件会几率性的被占用,上网浏览找到最简单的代码(API或者FileStream),在这里抛砖引玉下. 第一种方法:API using System.IO; using ...
- QML中文件的加载(三种方法)
在这里小小总结一下QML文件中如何加载QML文件与JavaScript文件. 1.QML文件中加载JavaScript文件 语法: import <ModuleIdentifier> &l ...
随机推荐
- hdu 4081 Qin Shi Huang's National Road System 树的基本性质 or 次小生成树思想 难度:1
During the Warring States Period of ancient China(476 BC to 221 BC), there were seven kingdoms in Ch ...
- ping命令知识 Ping命令工作原理详解
在网络应用中,ping网速与IP地址等都是非常常用的命令,但大家知道ping命令的工作原理吗?要知道这其中的奥秘,我们有必要来看看Ping命令的工作过程到底是怎么样的.下面介绍下ping命令的详细知识 ...
- 第8课:异常处理、面向对象编程、发送邮件、url编码
1. 异常处理 import traceback import pymysql import requests def calc(a, b): res = a / b return res def m ...
- L169 Komodo dragons
Komodo dragons live on a handful of islands in Indonesia, but their reputation has spread far and wi ...
- Hibernate主键生成策略详解
转载自:http://blog.csdn.net/wanghuan203/article/details/7562395 hibernate提供的主键生成策略,使我们可以在实体类的映射xml文件中设定 ...
- Git远程操作详解(转)
转自:http://www.ruanyifeng.com/blog/2014/06/git_remote.html Git远程操作详解 Git是目前最流行的版本管理系统,学会Git几乎成了开发者的 ...
- 安装visio 2010:您的计算机上的Office 2003安装已损坏,安装程序无法继续。请删除或修复office 2003产品并重新运行安装程序
您的计算机上的Office 2003安装已损坏,安装程序无法继续.请删除或修复office 2003产品并重新运行安装程序 最近打算安装visio 2010时出现 以下错误: “您的计算机上的Of ...
- Inception 初探
1,安装 下载组件 wget clone https:/github.com/mysql-inception/inception.git rz ll unzip inception-master.zi ...
- python最重要的模块logging
logging模块 这个模块是目前最重要的模块!!!我一定给讲透彻一点 很多程序都有记录日志的需求,并且日志中包含的信息即有正常的程序访问日志,还可能有错误.警告等信息输出,python中的loggi ...
- emacs编辑器的使用
尽管有许多ide,但是,各种软件使用各种不同,设置等,受不了.觉得应该有一手好的编辑器就可以了.尤其是受不了ide什么lib,.h,exe,dll等路径设置,让人心烦.再加上黑盒子的感觉很不爽.一旦出 ...