HookWinInet库实现类似fiddler的替换url
fiddler正常情况下只能捕获WinInet库的请求,所以,只要浏览器设置代理服务器为fiddler,且fiddler可以正常抓包,就可以推测这些请求所使用的网络库是WinInet库。
本文想要通过hook的方式实现类似于fiddler的替换响应,也就是替换一个url链接,访问的时候,响应变成了另外一个服务器发出来的。
编译环境为MSVC2015,编译输出为dll
只是,普通的代码注入dll对浏览器通常没有效果,因为它们大多有保护。
代码只有一个cpp文件
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include <windows.h>
#include <wininet.h>
#include <iostream>
#include<fstream>
#include<map>
#include<set>
#include <locale>
#include <codecvt>
#include <string>
#include<sstream>
#pragma comment(lib, "wininet.lib")
//定义MSVC编译,可以在MSVC里面使用,不定义MSVC,编译出来在易语言里面可用,区别
#define MSVC
using namespace std;
class MyHook
{
public:
MyHook()
{
funcAddr = NULL;
ZeroMemory(oldBytes, 5);
ZeroMemory(newBytes, 5);
onhook = false;
}
~MyHook()
{
UnHook();
funcAddr = NULL;
ZeroMemory(oldBytes, 5);
ZeroMemory(newBytes, 5);
}
BOOL Hook(LPSTR ModuleName, LPSTR FuncName, PROC HookFunc)
{
if (onhook) {
return true;
}
BOOL bRet = FALSE;
funcAddr = (PROC)GetProcAddress(GetModuleHandleA(ModuleName), FuncName);
if (funcAddr != NULL)
{
DWORD num = 0;
ReadProcessMemory(GetCurrentProcess(), (void*)funcAddr, oldBytes, 5, &num);
newBytes[0] = 0xe9;
*(DWORD *)(newBytes + 1) = (DWORD)HookFunc - (DWORD)funcAddr - 5;
WriteProcessMemory(GetCurrentProcess(), (void*)funcAddr, newBytes, 5, &num);
bRet = TRUE;
onhook = true;
//MessageBoxW(0, L"成功", L"title", MB_OK);
}
else {
//MessageBoxW(0, L"失败", L"title", MB_OK);
}
return bRet;
}
void UnHook()
{
if (onhook == false)
{
return;
}
if (funcAddr != 0)
{
DWORD num = 0;
WriteProcessMemory(GetCurrentProcess(), (void*)funcAddr, oldBytes, 5, &num);
onhook = false;
}
}
BOOL ReHook()
{
if (onhook == true) {
return true;
}
BOOL ret = FALSE;
if (funcAddr != 0)
{
DWORD num;
WriteProcessMemory(GetCurrentProcess(), (void*)funcAddr, newBytes, 5, &num);
ret = TRUE;
onhook = true;
}
return ret;
}
private:
PROC funcAddr;
BYTE oldBytes[5];
BYTE newBytes[5];
bool onhook;
};
MyHook hook1, hook2, hook3,hook4;
struct Compare {
bool operator()(const std::pair<LPCWSTR, LPCWSTR>& a, const std::pair<LPCWSTR, LPCWSTR>& b) const {
int schemeCompare = wcscmp(a.first, b.first);
if (schemeCompare < 0) return true;
if (schemeCompare > 0) return false;
return wcscmp(a.second, b.second) < 0;
}
};
struct CompareTuple {
bool operator() (const std::tuple<LPCWSTR, LPCWSTR, LPCWSTR>& lhs, const std::tuple<LPCWSTR, LPCWSTR, LPCWSTR>& rhs) const {
int cmp1 = wcscmp(std::get<0>(lhs), std::get<0>(rhs));
if (cmp1 != 0) return cmp1 < 0;
int cmp2 = wcscmp(std::get<1>(lhs), std::get<1>(rhs));
if (cmp2 != 0) return cmp2 < 0;
return wcscmp(std::get<2>(lhs), std::get<2>(rhs)) < 0;
}
};
std::set<std::pair<LPCWSTR, LPCWSTR>, Compare> g_urlMappings;
std::set<std::wstring> g_schemes;
std::set<std::wstring> g_hostNames;
std::set<std::wstring> g_newPaths;
//协议+域名+url后缀的三元map,从一个url替换为另一个url的三部分
std::map<std::tuple<LPCWSTR, LPCWSTR, LPCWSTR>, std::tuple<LPCWSTR, LPCWSTR, LPCWSTR>, CompareTuple> g_urlMaps;
std::multimap<std::pair<LPCWSTR, LPCWSTR>, LPCWSTR, Compare> g_urlPaths;
std::multimap<std::pair<LPCWSTR, LPCWSTR>, LPCWSTR, Compare> g_newurlPaths;
//根据替换的url协议+域名,预先创建了相应的连接
std::map<std::pair<LPCWSTR, LPCWSTR>, HINTERNET> g_newInet;
DWORD bufferSize = 1024;
wchar_t* buffer = new wchar_t[bufferSize];
//保存全部的url
//replace https://example.com/a.html to https://test.com/h.php
//不是很熟悉宽字符串的使用,貌似不插入到集合里面,字符串自己就释放了。
#ifdef MSVC
extern "C" __declspec(dllexport) void SetUrlToReplace(LPCWSTR lpszOriginalUrl, LPCWSTR lpszNewUrl)
{
std::wstring originalUrl = wstring(lpszOriginalUrl);
std::wstring newUrl = wstring(lpszNewUrl);
#endif
#ifndef MSVC
extern "C" __declspec(dllexport) void WINAPI SetUrlToReplace(char* lpszOriginalUrl, char* lpszNewUrl)
{
// Convert char* to std::wstring
auto charToWstring = [](char* cstr) {
int requiredSize = MultiByteToWideChar(CP_ACP, 0, cstr, -1, NULL, 0);
wchar_t* buffer = new wchar_t[requiredSize];
MultiByteToWideChar(CP_ACP, 0, cstr, -1, buffer, requiredSize);
std::wstring wstr(buffer);
delete[] buffer;
return wstr;
};
std::wstring originalUrl = charToWstring(lpszOriginalUrl);
std::wstring newUrl = charToWstring(lpszNewUrl);
#endif
// Find the scheme
size_t pos = originalUrl.find(L"://");
std::wstring scheme = originalUrl.substr(0, pos);
originalUrl = originalUrl.substr(pos + 3);
// Find the host name
pos = originalUrl.find(L"/");
std::wstring hostName = originalUrl.substr(0, pos);
originalUrl = originalUrl.substr(pos);
// The remaining part is the URL path
std::wstring urlPath = originalUrl;
// Find the new scheme
pos = newUrl.find(L"://");
std::wstring newScheme = newUrl.substr(0, pos);
newUrl = newUrl.substr(pos + 3);
// Find the new host name
pos = newUrl.find(L"/");
std::wstring newHostName = newUrl.substr(0, pos);
newUrl = newUrl.substr(pos);
// The remaining part is the new URL path
std::wstring newPath = newUrl;
g_schemes.insert(scheme);
g_schemes.insert(newScheme);
g_hostNames.insert(hostName);
g_hostNames.insert(newHostName);
//g_newSchemes.insert(newScheme);
g_newPaths.insert(urlPath);
g_newPaths.insert(newPath);
//保存完整url的映射
g_urlMaps[std::make_tuple(g_schemes.find(scheme)->c_str(), g_hostNames.find(hostName)->c_str(), g_newPaths.find(urlPath)->c_str())] = std::make_tuple(g_schemes.find(newScheme)->c_str(), g_hostNames.find(newHostName)->c_str(), g_newPaths.find(newPath)->c_str());
// Save the new URL
//g_urlMappings[std::make_pair(g_schemes.find(scheme)->c_str(), g_hostNames.find(hostName)->c_str())] = std::make_pair(g_hostNames.find(newHostName)->c_str(), nullptr);
g_urlMappings.insert(make_pair(g_schemes.find(scheme)->c_str(), g_hostNames.find(hostName)->c_str()));
//保存原始url的映射 multimap
g_urlPaths.insert({ std::make_pair(g_schemes.find(scheme)->c_str(), g_hostNames.find(hostName)->c_str()), g_newPaths.find(urlPath)->c_str() });
//保存替换url的映射 multimap
g_newurlPaths.insert({ std::make_pair(g_schemes.find(newScheme)->c_str(), g_hostNames.find(newHostName)->c_str()), g_newPaths.find(newPath)->c_str() });
}
// Function to close the set and create the connections
// 本质就是结束输入,然后按照协议和域名,预先创建一些连接进行保存
#ifdef MSVC
extern "C" __declspec(dllexport) void CloseSet()
#endif
#ifndef MSVC
extern "C" __declspec(dllexport) void WINAPI CloseSet()
#endif
{
hook1.UnHook();
hook2.UnHook();
HINTERNET hInternet = InternetOpen(L"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
std::pair<LPCWSTR, LPCWSTR> lastKey = { nullptr, nullptr };
for (auto& urlMapping : g_newurlPaths) {
if (urlMapping.first != lastKey) {
HINTERNET hConnect;
if (wcscmp(urlMapping.first.first, L"https") == 0) {
hConnect = InternetConnect(hInternet, urlMapping.first.second, INTERNET_DEFAULT_HTTPS_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
}
else {
hConnect = InternetConnect(hInternet, urlMapping.first.second, INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
}
g_newInet[urlMapping.first] = hConnect;
//cout << hConnect << endl;
lastKey = urlMapping.first;
}
}
hook1.ReHook();
hook2.ReHook();
}
// Global variable to store the marked connections
std::map<HINTERNET, std::pair<LPCWSTR, LPCWSTR>> g_markedConnections;
//没办法像fiddler那样预先知道完整的url,所以只能在这里标记,获取协议+域名,判断可能是所需要的url。
HINTERNET WINAPI MyInternetConnect(
HINTERNET hInternet,
LPCWSTR lpszServerName,
INTERNET_PORT nServerPort,
LPCWSTR lpszUsername,
LPCWSTR lpszPassword,
DWORD dwService,
DWORD dwFlags,
DWORD_PTR dwContext
)
{
hook1.UnHook();
LPCWSTR lpszScheme = (nServerPort == INTERNET_DEFAULT_HTTPS_PORT) ? L"https" : L"http";
HINTERNET ret = InternetConnect(hInternet, lpszServerName, nServerPort, lpszUsername, lpszPassword, dwService, dwFlags, dwContext);
auto it = g_urlMappings.find(std::make_pair(lpszScheme, lpszServerName));
if (it != g_urlMappings.end()) {
g_markedConnections[ret] = *it; // Mark the connection
}
hook1.ReHook();
return ret;
}
//这里获得url后缀,组合起来,才能知道是不是需要替换的url
HINTERNET WINAPI MyHttpOpenRequestW(
HINTERNET hConnect,
LPCWSTR lpszVerb,
LPCWSTR lpszObjectName,
LPCWSTR lpszVersion,
LPCWSTR lpszReferer,
LPCWSTR *lplpszAcceptTypes,
DWORD dwFlags,
DWORD_PTR dwContext
)
{
hook2.UnHook();
buffer[0] = L'\0';
auto markedConnection = g_markedConnections.find(hConnect);
if (markedConnection != g_markedConnections.end()) {
auto urlMapping = g_urlMaps.find(std::make_tuple(markedConnection->second.first, markedConnection->second.second, lpszObjectName));
if (urlMapping != g_urlMaps.end()) {
hConnect = g_newInet[std::make_pair(std::get<0>(urlMapping->second), std::get<1>(urlMapping->second))];//取出预先创建的链接
lpszObjectName = std::get<2>(urlMapping->second);//取出url后缀
std::wstringstream ss;
ss << markedConnection->second.first << L"://" << markedConnection->second.second << L"/" ;
std::wstring fullUrl = ss.str();//还原完整的域名,用来取出cookie
// Get the cookie
BOOL result = InternetGetCookieEx(fullUrl.c_str(), NULL, buffer, &bufferSize, INTERNET_COOKIE_HTTPONLY | INTERNET_COOKIE_THIRD_PARTY, NULL);
if (result) {
dwFlags |= INTERNET_FLAG_RELOAD;
dwFlags |= INTERNET_COOKIE_THIRD_PARTY;
dwFlags |= INTERNET_FLAG_NO_COOKIES;//不设置这些标志就不能设置cookie
}
if (wcscmp(std::get<0>(urlMapping->second), L"https") == 0)
{
dwFlags = INTERNET_FLAG_RELOAD | INTERNET_FLAG_SECURE;
DWORD flags = SECURITY_FLAG_IGNORE_REVOCATION | SECURITY_FLAG_IGNORE_UNKNOWN_CA;
InternetSetOption(hConnect, INTERNET_OPTION_SECURITY_FLAGS, &flags, sizeof(flags));
}
else {
dwFlags &= ~INTERNET_FLAG_SECURE;//取消为https设置的安全标志
}
}
g_markedConnections.erase(markedConnection);//标记只用一次,用完就删除
}
HINTERNET ret = HttpOpenRequestW(hConnect, lpszVerb, lpszObjectName, lpszVersion, lpszReferer, lplpszAcceptTypes, dwFlags, dwContext);
hook2.ReHook();
if (wcslen(buffer) > 0) {
// Add the Cookie header
std::wstring cookieHeader = L"Cookie: ";
cookieHeader += buffer;
cookieHeader += L"\r\n";
HttpAddRequestHeadersW(ret, cookieHeader.c_str(), -1, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE);
buffer[0] = '\0';
}
return ret;
}
BOOL WINAPI MyInternetReadFile(
HINTERNET hFile,
LPVOID lpBuffer,
DWORD dwNumberOfBytesToRead,
LPDWORD lpdwNumberOfBytesRead
)
{
hook3.UnHook();
BOOL ret = InternetReadFile(hFile, lpBuffer, dwNumberOfBytesToRead, lpdwNumberOfBytesRead);
hook3.ReHook();
return ret;
}
BOOL WINAPI MyHttpSendRequest(
HINTERNET hRequest,
LPCWSTR lpszHeaders,
DWORD dwHeadersLength,
LPVOID lpOptional,
DWORD dwOptionalLength
)
{
hook4.UnHook();
BOOL ret = HttpSendRequestW(hRequest, lpszHeaders, dwHeadersLength, lpOptional, dwOptionalLength);
hook4.ReHook();
return ret;
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
hook1.Hook((LPSTR)"wininet.dll", (LPSTR)"InternetConnectW", (PROC)&MyInternetConnect);
hook2.Hook((LPSTR)"wininet.dll", (LPSTR)"HttpOpenRequestW", (PROC)&MyHttpOpenRequestW);
//hook3.Hook((LPSTR)"wininet.dll", (LPSTR)"InternetReadFile", (PROC)&MyInternetReadFile);
//hook4.Hook((LPSTR)"wininet.dll", (LPSTR)"HttpSendRequestW", (PROC)&MyHttpSendRequest);
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
hook1.UnHook();
hook2.UnHook();
//hook4.UnHook();
//hook3.UnHook();
break;
}
return TRUE;
}
测试代码:(需要修改上面的代码为普通项目,也就是去掉导出函数的部分,以及dllmain)
#define _CRT_SECURE_NO_WARNINGS 1
#define MSVC
#include <windows.h>
#include <wininet.h>
#include <iostream>
#include<fstream>
#include<map>
#include<set>
#include <locale>
#include <codecvt>
#include <string>
#include<sstream>
#pragma comment(lib, "wininet.lib")
void test() {
HINTERNET hInternet, hConnect;
LPCWSTR szHeaders = L"Content-Type: application/x-www-form-urlencoded";
LPCSTR szData = "time=123456";
// Initialize WinINet
hInternet = InternetOpen(L"User-Agent", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
if (hInternet == NULL) {
// Handle error
}
// Connect to the website
hConnect = InternetConnect(hInternet, L"baidu.com", INTERNET_DEFAULT_HTTPS_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);//协议+域名
if (hConnect == NULL) {
// Handle error
}
// Open an HTTP request handle
HINTERNET hRequest = HttpOpenRequest(hConnect, L"GET", L"/index.html", NULL, NULL, NULL, INTERNET_FLAG_SECURE, 0);//后缀
if (hRequest == NULL) {
// Handle error
}
DWORD dwFlags = INTERNET_FLAG_RELOAD | INTERNET_FLAG_SECURE;
DWORD flags = SECURITY_FLAG_IGNORE_REVOCATION | SECURITY_FLAG_IGNORE_UNKNOWN_CA;
InternetSetOption(hConnect, INTERNET_OPTION_SECURITY_FLAGS, &flags, sizeof(flags));
if (!HttpSendRequestW(hRequest, NULL, 0, NULL, 0))
{
std::cout << "Failed to send request. Error: " << GetLastError() << std::endl;
while (1);
return;
}
std::cout << "GetLastError" << GetLastError() << std::endl;
// 读取服务器的响应
char buffer[4096];
DWORD bytesRead;
while (InternetReadFile(hRequest, buffer, sizeof(buffer), &bytesRead) && bytesRead > 0) {
std::cout.write(buffer, bytesRead);
}
// 关闭句柄
InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
InternetCloseHandle(hInternet);
}
int main()
{
hook1.Hook((LPSTR)"wininet.dll", (LPSTR)"InternetConnectW", (PROC)&MyInternetConnect);
hook2.Hook((LPSTR)"wininet.dll", (LPSTR)"HttpOpenRequestW", (PROC)&MyHttpOpenRequestW);
// Call the functions
SetUrlToReplace(L"https://baidu.com/index.html", L"http://sogou.com/");
CloseSet();
test();//使用WinInet库发出对被替换url的请求,输出结果应该是替换url发回的请求
while (1);
}
目前,只是实现了替换完整的url,不像fiddler,可以有很多规则来实现替换。比如正则之类的。
现在好像用WinHttp网络库比较多,而这个和WinInet库是差不多的,就写了类似的。
#pragma once
#include <windows.h>
#include <winhttp.h>
#include <iostream>
#include<fstream>
#include<map>
#include<set>
#include <locale>
#include <codecvt>
#include <string>
#include<sstream>
#pragma comment(lib, "winhttp.lib")
using namespace std;
class MyHook1
{
public:
MyHook1()
{
funcAddr = NULL;
ZeroMemory(oldBytes, 5);
ZeroMemory(newBytes, 5);
onhook = false;
}
~MyHook1()
{
UnHook();
funcAddr = NULL;
ZeroMemory(oldBytes, 5);
ZeroMemory(newBytes, 5);
}
BOOL Hook(LPSTR ModuleName, LPSTR FuncName, PROC HookFunc)
{
if (onhook) {
return true;
}
BOOL bRet = FALSE;
funcAddr = (PROC)GetProcAddress(GetModuleHandleA(ModuleName), FuncName);
if (funcAddr != NULL)
{
DWORD num = 0;
ReadProcessMemory(GetCurrentProcess(), (void*)funcAddr, oldBytes, 5, &num);
newBytes[0] = 0xe9;
*(DWORD *)(newBytes + 1) = (DWORD)HookFunc - (DWORD)funcAddr - 5;
WriteProcessMemory(GetCurrentProcess(), (void*)funcAddr, newBytes, 5, &num);
bRet = TRUE;
onhook = true;
}
return bRet;
}
void UnHook()
{
if (onhook == false)
{
return;
}
if (funcAddr != 0)
{
DWORD num = 0;
WriteProcessMemory(GetCurrentProcess(), (void*)funcAddr, oldBytes, 5, &num);
onhook = false;
}
}
BOOL ReHook()
{
if (onhook == true) {
return true;
}
BOOL ret = FALSE;
if (funcAddr != 0)
{
DWORD num;
WriteProcessMemory(GetCurrentProcess(), (void*)funcAddr, newBytes, 5, &num);
ret = TRUE;
onhook = true;
}
return ret;
}
private:
PROC funcAddr;
BYTE oldBytes[5];
BYTE newBytes[5];
bool onhook;
};
struct Compare {
bool operator()(const std::pair<LPCWSTR, LPCWSTR>& a, const std::pair<LPCWSTR, LPCWSTR>& b) const {
int schemeCompare = wcscmp(a.first, b.first);
if (schemeCompare < 0) return true;
if (schemeCompare > 0) return false;
return wcscmp(a.second, b.second) < 0;
}
};
struct CompareTuple {
bool operator() (const std::tuple<LPCWSTR, LPCWSTR, LPCWSTR>& lhs, const std::tuple<LPCWSTR, LPCWSTR, LPCWSTR>& rhs) const {
int cmp1 = wcscmp(std::get<0>(lhs), std::get<0>(rhs));
if (cmp1 != 0) return cmp1 < 0;
int cmp2 = wcscmp(std::get<1>(lhs), std::get<1>(rhs));
if (cmp2 != 0) return cmp2 < 0;
return wcscmp(std::get<2>(lhs), std::get<2>(rhs)) < 0;
}
};
MyHook1 hook1, hook2,hook3;
std::set<std::pair<LPCWSTR, LPCWSTR>, Compare> g_urlMappings1;
std::set<std::wstring> g_schemes1;
std::set<std::wstring> g_hostNames1;
std::set<std::wstring> g_newPaths1;
//协议+域名+url后缀的三元map
std::map<std::tuple<LPCWSTR, LPCWSTR, LPCWSTR>, std::tuple<LPCWSTR, LPCWSTR, LPCWSTR>, CompareTuple> g_urlMaps1;
std::multimap<std::pair<LPCWSTR, LPCWSTR>, LPCWSTR, Compare> g_urlPaths1;
std::multimap<std::pair<LPCWSTR, LPCWSTR>, LPCWSTR, Compare> g_newurlPaths1;
//根据替换的url协议+域名,保存了对应的连接
std::map<std::pair<LPCWSTR, LPCWSTR>, HINTERNET> g_newInet1;
void SetUrlToReplace1(LPCWSTR lpszOriginalUrl, LPCWSTR lpszNewUrl)
{
std::wstring originalUrl = wstring(lpszOriginalUrl);
std::wstring newUrl = wstring(lpszNewUrl);
// Find the scheme
size_t pos = originalUrl.find(L"://");
std::wstring scheme = originalUrl.substr(0, pos);
originalUrl = originalUrl.substr(pos + 3);
// Find the host name
pos = originalUrl.find(L"/");
std::wstring hostName = originalUrl.substr(0, pos);
originalUrl = originalUrl.substr(pos);
// The remaining part is the URL path
std::wstring urlPath = originalUrl;
// Find the new scheme
pos = newUrl.find(L"://");
std::wstring newScheme = newUrl.substr(0, pos);
newUrl = newUrl.substr(pos + 3);
// Find the new host name
pos = newUrl.find(L"/");
std::wstring newHostName = newUrl.substr(0, pos);
newUrl = newUrl.substr(pos);
// The remaining part is the new URL path
std::wstring newPath = newUrl;
g_schemes1.insert(scheme);
g_schemes1.insert(newScheme);
g_hostNames1.insert(hostName);
g_hostNames1.insert(newHostName);
g_newPaths1.insert(urlPath);
g_newPaths1.insert(newPath);
//保存完整url的映射
g_urlMaps1[std::make_tuple(g_schemes1.find(scheme)->c_str(), g_hostNames1.find(hostName)->c_str(), g_newPaths1.find(urlPath)->c_str())] = std::make_tuple(g_schemes1.find(newScheme)->c_str(), g_hostNames1.find(newHostName)->c_str(), g_newPaths1.find(newPath)->c_str());
// Save the new URL
g_urlMappings1.insert(make_pair(g_schemes1.find(scheme)->c_str(), g_hostNames1.find(hostName)->c_str()));
//保存原始url的映射 multimap
g_urlPaths1.insert({ std::make_pair(g_schemes1.find(scheme)->c_str(), g_hostNames1.find(hostName)->c_str()), g_newPaths1.find(urlPath)->c_str() });
//保存替换url的映射 multimap
g_newurlPaths1.insert({ std::make_pair(g_schemes1.find(newScheme)->c_str(), g_hostNames1.find(newHostName)->c_str()), g_newPaths1.find(newPath)->c_str() });
}
// Function to close the set and create the connections
void CloseSet1()
{
hook1.UnHook();
hook2.UnHook();
HINTERNET hInternet = WinHttpOpen(L"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
std::pair<LPCWSTR, LPCWSTR> lastKey = { nullptr, nullptr };
for (auto& urlMapping : g_newurlPaths1) {
if (urlMapping.first != lastKey) {
HINTERNET hConnect;
if (wcscmp(urlMapping.first.first, L"https") == 0) {
hConnect = WinHttpConnect(hInternet, urlMapping.first.second, INTERNET_DEFAULT_HTTPS_PORT, 0);
}
else {
hConnect = WinHttpConnect(hInternet, urlMapping.first.second, INTERNET_DEFAULT_HTTP_PORT, 0);
}
g_newInet1[urlMapping.first] = hConnect;
//cout << hConnect << endl;
lastKey = urlMapping.first;
}
}
hook1.ReHook();
hook2.ReHook();
}
std::map<HINTERNET, std::pair<LPCWSTR, LPCWSTR>> g_markedConnections1;
DWORD bufferSizea = 1024;
wchar_t* buffera = new wchar_t[bufferSizea];
// 定义自定义的WinHttpConnect函数,参数和返回值与原始函数一致
HINTERNET WINAPI MyWinHttpConnect(
HINTERNET hSession,
LPCWSTR lpszServerName,
INTERNET_PORT nServerPort,
DWORD dwReserved
)
{
// 卸载hook,以免影响原始函数的执行
hook1.UnHook();
LPCWSTR lpszScheme = (nServerPort == INTERNET_DEFAULT_HTTPS_PORT) ? L"https" : L"http";
// 调用原始函数,注意要使用hook对象保存的目标函数地址
HINTERNET ret = WinHttpConnect(hSession, lpszServerName, nServerPort, dwReserved);
auto it = g_urlMappings1.find(std::make_pair(lpszScheme, lpszServerName));
if (it != g_urlMappings1.end()) {
g_markedConnections1[ret] = *it; // Mark the connection
}
// 重新安装hook,以便下次拦截
hook1.ReHook();
return ret;
}
// 定义自定义的WinHttpOpenRequest函数,参数和返回值与原始函数一致
HINTERNET WINAPI MyWinHttpOpenRequest(
HINTERNET hConnect,
LPCWSTR pwszVerb,
LPCWSTR lpszObjectName,
LPCWSTR pwszVersion,
LPCWSTR pwszReferrer,
LPCWSTR *ppwszAcceptTypes,
DWORD dwFlags
)
{
// 卸载hook,以免影响原始函数的执行
hook2.UnHook();
buffera[0] = L'\0';
auto markedConnection = g_markedConnections1.find(hConnect);
if (markedConnection != g_markedConnections1.end()) {
//wcout << "Found marked connection: " << markedConnection->second.first << " " << markedConnection->second.second << endl;
auto urlMapping = g_urlMaps1.find(std::make_tuple(markedConnection->second.first, markedConnection->second.second, lpszObjectName));
if (urlMapping != g_urlMaps1.end()) {
hConnect = g_newInet1[std::make_pair(std::get<0>(urlMapping->second), std::get<1>(urlMapping->second))];
lpszObjectName = std::get<2>(urlMapping->second);
std::wstringstream ss;
ss << markedConnection->second.first << L"://" << markedConnection->second.second << L"/";
std::wstring fullUrl = ss.str();
if (wcscmp(std::get<0>(urlMapping->second), L"https") == 0)
{
dwFlags |= WINHTTP_FLAG_SECURE;
}
else {
dwFlags &= ~WINHTTP_FLAG_SECURE;
}
}
g_markedConnections1.erase(markedConnection);//标记只用一次,用完就删除
}
// 调用原始函数,注意要使用hook对象保存的目标函数地址
HINTERNET hRequest = WinHttpOpenRequest(hConnect, pwszVerb, lpszObjectName, pwszVersion, pwszReferrer, ppwszAcceptTypes, dwFlags);
// 重新安装hook,以便下次拦截
hook2.ReHook();
return hRequest;
}
BOOL WINAPI MyWinHttpSendRequest(
HINTERNET hRequest,
LPCWSTR lpszHeaders,
DWORD dwHeadersLength,
LPVOID lpOptional,
DWORD dwOptionalLength,
DWORD dwTotalLength,
DWORD_PTR dwContext)
{
hook3.UnHook();
BOOL ret = WinHttpSendRequest(hRequest, lpszHeaders, dwHeadersLength, lpOptional, dwOptionalLength, dwTotalLength, dwContext);
hook3.ReHook();
return ret;
}
int test()
{
// 初始化WinHttp
HINTERNET hSession = WinHttpOpen(L"WinHttp Example/1.0", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
//WINHTTP_PROXY_INFO proxy = { 0 };
//proxy.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY; // 使用指定的代理
//proxy.lpszProxy = L"http://127.0.0.1:7788"; // 代理的地址,包含用户名和密码
//proxy.lpszProxyBypass = L"local"; // 代理的旁路列表,可以为NULL
// // 设置会话的代理选项
//if (!WinHttpSetOption(hSession, WINHTTP_OPTION_PROXY, &proxy, sizeof(proxy)))
//{
// cout << "设置失败\n";
//}
//else
//{
// cout << "设置成功\n";
//}
if (hSession == NULL)
{
std::cout << "WinHttpOpen failed: " << GetLastError() << std::endl;
return -1;
}
// 连接到目标服务器
HINTERNET hConnect = WinHttpConnect(hSession, L"baidu.com", INTERNET_DEFAULT_HTTPS_PORT, 0);
if (hConnect == NULL)
{
std::cout << "WinHttpConnect failed: " << GetLastError() << std::endl;
WinHttpCloseHandle(hSession);
return -1;
}
// 创建一个POST请求
HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"GET", L"/index.html", NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE);
if (hRequest == NULL)
{
std::cout << "WinHttpOpenRequest failed: " << GetLastError() << std::endl;
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return -1;
}
// 设置请求头
LPCWSTR szHeaders = L"Content-Type: application/x-www-form-urlencoded\r\n";
if (!WinHttpAddRequestHeaders(hRequest, szHeaders, -1L, WINHTTP_ADDREQ_FLAG_ADD))
{
std::cout << "WinHttpAddRequestHeaders failed: " << GetLastError() << std::endl;
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return -1;
}
// 设置请求体
//LPCSTR szPostData = "time=12345";
//DWORD dwPostDataLength = strlen(szPostData);
// 发送请求
if (!WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, NULL, 0, 0, 0))
{
std::cout << "WinHttpSendRequest failed: " << GetLastError() << std::endl;
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return -1;
}
// 等待响应
if (!WinHttpReceiveResponse(hRequest, NULL))
{
std::cout << "WinHttpReceiveResponse failed: " << GetLastError() << std::endl;
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return -1;
}
// 读取响应状态码
DWORD dwStatusCode = 0;
DWORD dwSize = sizeof(dwStatusCode);
if (!WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &dwStatusCode, &dwSize, NULL))
{
std::cout << "WinHttpQueryHeaders failed: " << GetLastError() << std::endl;
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return -1;
}
// 输出响应状态码
std::cout << "Status code: " << dwStatusCode << std::endl;
// 读取响应内容
DWORD dwRead = 0;
char szBuffer[1024] = { 0 };
do
{
// 检查是否有可用数据
if (!WinHttpQueryDataAvailable(hRequest, &dwSize))
{
std::cout << "WinHttpQueryDataAvailable failed: " << GetLastError() << std::endl;
break;
}
// 如果没有数据,退出循环
if (dwSize == 0)
break;
// 如果缓冲区太小,调整大小
if (dwSize > sizeof(szBuffer) - 1)
dwSize = sizeof(szBuffer) - 1;
// 读取数据
if (!WinHttpReadData(hRequest, (LPVOID)szBuffer, dwSize, &dwRead))
{
std::cout << "WinHttpReadData failed: " << GetLastError() << std::endl;
break;
}
// 输出数据
std::cout.write(szBuffer, dwRead);
} while (dwRead > 0);
// 关闭句柄
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return 0;
}
只是winhttp不像WinINet,不能再设置本地的cookie给服务器了。而且,winhttp和wininet库也不能混用。