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库也不能混用。

posted @ 2023-09-11 15:05  念秋  阅读(39)  评论(0编辑  收藏  举报