修改http请求文件为本地文件的一种方法hook InternetReadFile 和 HttpOpenRequest.docx
《修改http请求文件为本地文件的一种方法hook InternetReadFile 和 HttpOpenRequest.docx》由会员分享,可在线阅读,更多相关《修改http请求文件为本地文件的一种方法hook InternetReadFile 和 HttpOpenRequest.docx(7页珍藏版)》请在冰点文库上搜索。
修改http请求文件为本地文件的一种方法hookInternetReadFile和HttpOpenRequest
修改http请求文件为本地文件的一种方法:
hookInternetReadFile和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)>
PublicSharedFunctionInternetReadFile(ByValhFileAsIntPtr,ByVallpBufferAsIntPtr,ByValdwNumberOfBytesToReadAsInteger,ByReflpdwNumberOfBytesReadAsInteger)AsBoolean
EndFunction
可以知道,第一个参数是HttpOpenRequest返回的文件句柄,lpbuffer是接收数据的缓冲区,dwnumberofbytestoread是期望读取的字节数,即缓冲区大小,lpdwnumberofbytesread是实际写入缓冲区的字节数。
返回值表示函数调用是否成功。
所以,当lpdwnumberofbytesread为0且函数返回值为true时,达到文件结尾——函数调用成功却没有数据写入,说明数据写完了。
于是,在我们的自定义例程中也需要遵守该约定——当写入数据时返回实际写入的数据大小,写完数据后再次被调用时返回0并进行清理。
首先,来看一下比较简单的一个hook:
ImportsSystem.Runtime.InteropServices
ImportsSystem.Text
PublicClassHookHttpOpenRequest
<DllImport("wininet.dll")>
PublicSharedFunctionHttpOpenRequestW(hConnectAsIntPtr,szVerbAsIntPtr,szURIAsIntPtr,szHttpVersionAsIntPtr,szRefererAsIntPtr,accetpTypeAsIntPtr,dwflagsAsInteger,dwcontextAsIntPtr)AsIntPtr
EndFunction
PrivateDelegateFunctionHttpOpenRequestDelegate(hConnectAsIntPtr,szVerbAsIntPtr,szURIAsIntPtr,szHttpVersionAsIntPtr,szRefererAsIntPtr,accetpTypeAsIntPtr,dwflagsAsInteger,dwcontextAsIntPtr)AsIntPtr
PrivateSharedhookAsEasyHook.LocalHook=Nothing
FriendSharedSubInstall()
Usinghook
IfEasyHook.NativeAPI.GetModuleHandle("wininet.dll")=IntPtr.ZeroThen
EasyHook.NativeAPI.LoadLibrary("wininet.dll")
EndIf
hook=EasyHook.LocalHook.Create(EasyHook.LocalHook.GetProcAddress("wininet.dll","HttpOpenRequestW"),NewHttpOpenRequestDelegate(AddressOfsendProc),Nothing)
hook.ThreadACL.SetInclusiveACL(NewInteger(){0})
EndUsing
EndSub
FriendSharedSubUnInstall()
Usinghook
IfhookIsNotNothingThen
hook.ThreadACL.SetExclusiveACL(NewInteger(){0})
EndIf
EndUsing
EndSub
PrivateSharedFunctionsendProc(hConnectAsIntPtr,szVerbAsIntPtr,szURIAsIntPtr,szHttpVersionAsIntPtr,szRefererAsIntPtr,accetpTypeAsIntPtr,dwflagsAsInteger,dwcontextAsIntPtr)AsIntPtr
DimuriAsString=Marshal.PtrToStringUni(szURI)
DimresultAsIntPtr=HttpOpenRequestW(hConnect,szVerb,szURI,szHttpVersion,szReferer,accetpType,dwflags,dwcontext)
Ifuri.Contains("/56896-20170216102630488-270057596.jpg")Then'根据名称区分要替换的图片.
HookInternetReadFile.CheatFileHandle=resultEndIfReturnresultEndFunctionEndClass
easyhook用起来确实比较简单,首先是注入过程,因为webbrowser对wininte.dll的加载是请求第一个页面时,所以可能导致这个DLL不在进程空间,那么先加载它。
之后的hook非常易懂(函数名我没有修改,复制粘贴的之前写的sendhook),唯一需要注意的是实际hook的过程调用的是ThreadACL.SetInclusiveACL,unhook类似。
在自定义函数中,首先调用API,得到句柄,然后根据要替换的名称来确定是否启动给InternetReadFile的自定义例程。
而后,看一下对数据的处理过程:
ImportsSystem.IO
ImportsSystem.Runtime.InteropServices
PublicClassHookInternetReadFile
<DllImport("wininet.dll",SetLastError:
=True)>
PublicSharedFunctionInternetReadFile(ByValhFileAsIntPtr,ByVallpBufferAsIntPtr,ByValdwNumberOfBytesToReadAsInteger,ByReflpdwNumberOfBytesReadAsInteger)AsBoolean
EndFunction
PrivateDelegateFunctionInternetReadFileDelegate(ByValhFileAsIntPtr,ByVallpBufferAsIntPtr,ByValdwNumberOfBytesToReadAsInteger,ByReflpdwNumberOfBytesReadAsInteger)AsBoolean
PrivateSharedhookAsEasyHook.LocalHook=Nothing
FriendSharedCheatFileHandleAsIntPtr=IntPtr.Zero'要替换的文件的句柄,来源于HttpOpenRequest的返回值。
FriendSharedCheatFile()AsByte=File.ReadAllBytes(My.Application.Info.DirectoryPath&"\abc.jpg")'用于替换的文件
PrivateSharedcurcntAsInteger=0
FriendSharedSubInstall()
Usinghook
IfEasyHook.NativeAPI.GetModuleHandle("wininet.dll")=IntPtr.ZeroThen
EasyHook.NativeAPI.LoadLibrary("wininet.dll")
EndIf
hook=EasyHook.LocalHook.Create(EasyHook.LocalHook.GetProcAddress("wininet.dll","InternetReadFile"),NewInternetReadFileDelegate(AddressOfsendProc),Nothing)
hook.ThreadACL.SetInclusiveACL(NewInteger(){0})
EndUsing
EndSub
FriendSharedSubUnInstall()
Usinghook
IfhookIsNotNothingThen
hook.ThreadACL.SetExclusiveACL(NewInteger(){0})
EndIf
EndUsing
EndSub
PrivateSharedFunctionsendProc(ByValhFileAsIntPtr,ByVallpBufferAsIntPtr,ByValdwNumberOfBytesToReadAsInteger,ByReflpdwNumberOfBytesReadAsInteger)AsBoolean
IfhFile=CheatFileHandleThen
Ifcurcnt=CheatFile.LengthThen
CheatFileHandle=IntPtr.Zero
curcnt=0
lpdwNumberOfBytesRead=0
Else
Ifcurcnt+dwNumberOfBytesToRead<=CheatFile.LengthThen
lpdwNumberOfBytesRead=dwNumberOfBytesToRead
Marshal.Copy(CheatFile,curcnt,lpBuffer,lpdwNumberOfBytesRead)
curcnt+=dwNumberOfBytesToRead
Else
lpdwNumberOfBytesRead=CheatFile.Length-curcnt
Marshal.Copy(CheatFile,curcnt,lpBuffer,lpdwNumberOfBytesRead)
curcnt=CheatFile.Length
EndIf
EndIf
ReturnTrue
Else
ReturnInternetReadFile(hFile,lpBuffer,dwNumberOfBytesToRead,lpdwNumberOfBytesRead)
EndIf
EndFunction
EndClass
因为是一个基本结构范例,所以偷懒直接用了参数,这里应该有错误处理过程才行。
hook的过程和前面一致,只是在自定义函数中处理把自定义数据写入缓冲区然后返回了。
具体的API过程没有跟踪,所以不知道不调用InternetReadFile这个API会不会有内存泄漏之类的什么问题,如果需要调用也非常简单:
在恰当的时机循环读取一次就可以了。
最后是窗体代码:
PublicClassForm1
PrivateSubForm1_Load(senderAsObject,eAsEventArgs)HandlesMyBase.Load
wb.Navigate("
EndSub
PrivateSubbutGotoUrl_Click(senderAsObject,eAsEventArgs)HandlesbutGotoUrl.Click
wb.Refresh()
EndSub
PrivateSubchkCheat_CheckedChanged(senderAsObject,eAsEventArgs)HandleschkCheat.CheckedChanged
IfchkCheat.CheckedThen
HookHttpOpenRequest.Install()
HookInternetReadFile.Install()
Else
HookHttpOpenRequest.UnInstall()
HookInternetReadFile.UnInstall()
EndIf
EndSub
EndClass
窗体上一个webbrowser重命名为wb,一个checkbox重命名为chkcheat,一个button重命名为butgotourl,另外,在程序所在目录放一个abc.jpg。
对,这个范例就是这么简陋,好在现在就可以测试了。
如果图片换名字了,那需要修改url地址的同时修改
Ifuri.Contains("/56896-20170216102630488-270057596.jpg")Then'根据名称区分要替换的图片
才可以正确运行。