Skip to content

Instantly share code, notes, and snippets.

@dev-zzo
Last active October 28, 2025 00:03
Show Gist options
  • Select an option

  • Save dev-zzo/2e9f89742311f37916317adb86fcfda9 to your computer and use it in GitHub Desktop.

Select an option

Save dev-zzo/2e9f89742311f37916317adb86fcfda9 to your computer and use it in GitHub Desktop.
A libcurl.dll proxy
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files
#include <windows.h>
#include <stdio.h>
#include <malloc.h>
#include <string.h>
HMODULE hRealCurl;
HANDLE ghMutex;
char gszLogPath[1024];
#define DEFINE_THUNK(name) \
PVOID (*name##_p)(); \
PVOID __declspec(dllexport) name() { return name##_p(); }
#define LOAD_THUNK(name) name##_p = GetProcAddress(hRealCurl, #name);
DEFINE_THUNK(curl_easy_cleanup);
DEFINE_THUNK(curl_easy_duphandle);
DEFINE_THUNK(curl_easy_escape);
DEFINE_THUNK(curl_easy_getinfo);
DEFINE_THUNK(curl_easy_header);
DEFINE_THUNK(curl_easy_init);
DEFINE_THUNK(curl_easy_nextheader);
DEFINE_THUNK(curl_easy_option_by_id);
DEFINE_THUNK(curl_easy_option_by_name);
DEFINE_THUNK(curl_easy_option_next);
DEFINE_THUNK(curl_easy_pause);
//DEFINE_THUNK(curl_easy_perform);
DEFINE_THUNK(curl_easy_recv);
DEFINE_THUNK(curl_easy_reset);
DEFINE_THUNK(curl_easy_send);
DEFINE_THUNK(curl_easy_setopt);
DEFINE_THUNK(curl_easy_ssls_export);
DEFINE_THUNK(curl_easy_ssls_import);
DEFINE_THUNK(curl_easy_strerror);
DEFINE_THUNK(curl_easy_unescape);
DEFINE_THUNK(curl_easy_upkeep);
DEFINE_THUNK(curl_escape);
DEFINE_THUNK(curl_formadd);
DEFINE_THUNK(curl_formfree);
DEFINE_THUNK(curl_formget);
DEFINE_THUNK(curl_free);
DEFINE_THUNK(curl_getdate);
DEFINE_THUNK(curl_getenv);
DEFINE_THUNK(curl_global_cleanup);
DEFINE_THUNK(curl_global_init);
DEFINE_THUNK(curl_global_init_mem);
DEFINE_THUNK(curl_global_sslset);
DEFINE_THUNK(curl_global_trace);
DEFINE_THUNK(curl_maprintf);
DEFINE_THUNK(curl_mfprintf);
DEFINE_THUNK(curl_mime_addpart);
DEFINE_THUNK(curl_mime_data);
DEFINE_THUNK(curl_mime_data_cb);
DEFINE_THUNK(curl_mime_encoder);
DEFINE_THUNK(curl_mime_filedata);
DEFINE_THUNK(curl_mime_filename);
DEFINE_THUNK(curl_mime_free);
DEFINE_THUNK(curl_mime_headers);
DEFINE_THUNK(curl_mime_init);
DEFINE_THUNK(curl_mime_name);
DEFINE_THUNK(curl_mime_subparts);
DEFINE_THUNK(curl_mime_type);
DEFINE_THUNK(curl_mprintf);
DEFINE_THUNK(curl_msnprintf);
DEFINE_THUNK(curl_msprintf);
DEFINE_THUNK(curl_multi_add_handle);
DEFINE_THUNK(curl_multi_assign);
DEFINE_THUNK(curl_multi_cleanup);
DEFINE_THUNK(curl_multi_fdset);
DEFINE_THUNK(curl_multi_get_handles);
DEFINE_THUNK(curl_multi_info_read);
DEFINE_THUNK(curl_multi_init);
DEFINE_THUNK(curl_multi_perform);
DEFINE_THUNK(curl_multi_poll);
DEFINE_THUNK(curl_multi_remove_handle);
DEFINE_THUNK(curl_multi_setopt);
DEFINE_THUNK(curl_multi_socket);
DEFINE_THUNK(curl_multi_socket_action);
DEFINE_THUNK(curl_multi_socket_all);
DEFINE_THUNK(curl_multi_strerror);
DEFINE_THUNK(curl_multi_timeout);
DEFINE_THUNK(curl_multi_wait);
DEFINE_THUNK(curl_multi_waitfds);
DEFINE_THUNK(curl_multi_wakeup);
DEFINE_THUNK(curl_mvaprintf);
DEFINE_THUNK(curl_mvfprintf);
DEFINE_THUNK(curl_mvprintf);
DEFINE_THUNK(curl_mvsnprintf);
DEFINE_THUNK(curl_mvsprintf);
DEFINE_THUNK(curl_pushheader_byname);
DEFINE_THUNK(curl_pushheader_bynum);
DEFINE_THUNK(curl_share_cleanup);
DEFINE_THUNK(curl_share_init);
DEFINE_THUNK(curl_share_setopt);
DEFINE_THUNK(curl_share_strerror);
DEFINE_THUNK(curl_slist_append);
DEFINE_THUNK(curl_slist_free_all);
DEFINE_THUNK(curl_strequal);
DEFINE_THUNK(curl_strnequal);
DEFINE_THUNK(curl_unescape);
DEFINE_THUNK(curl_url);
DEFINE_THUNK(curl_url_cleanup);
DEFINE_THUNK(curl_url_dup);
DEFINE_THUNK(curl_url_get);
DEFINE_THUNK(curl_url_set);
DEFINE_THUNK(curl_url_strerror);
DEFINE_THUNK(curl_version);
DEFINE_THUNK(curl_version_info);
DEFINE_THUNK(curl_ws_meta);
DEFINE_THUNK(curl_ws_recv);
DEFINE_THUNK(curl_ws_send);
typedef struct
{
LPBYTE buffer_out;
ULONGLONG buffer_out_length;
ULONGLONG buffer_out_capacity;
LPBYTE buffer_in;
ULONGLONG buffer_in_length;
ULONGLONG buffer_in_capacity;
} DEBUG_LOG_DATA, *PDEBUG_LOG_DATA;
int debug_callback(PVOID handle, int type, char* data, size_t size, void* clientp)
{
PDEBUG_LOG_DATA log_data = (PDEBUG_LOG_DATA)clientp;
switch (type)
{
case 1: // HEADER_IN
case 3: // DATA_IN
if (log_data->buffer_in_capacity < log_data->buffer_in_length + size)
{
log_data->buffer_in = realloc(log_data->buffer_in, log_data->buffer_in_capacity + size * 2);
log_data->buffer_in_capacity = log_data->buffer_in_capacity + size * 2;
}
memcpy(&log_data->buffer_in[log_data->buffer_in_length], data, size);
log_data->buffer_in_length += size;
break;
case 2: // HEADER_OUT
case 4: // DATA_OUT
if (log_data->buffer_out_capacity < log_data->buffer_out_length + size)
{
log_data->buffer_out = realloc(log_data->buffer_out, log_data->buffer_out_capacity + size * 2);
log_data->buffer_out_capacity = log_data->buffer_out_capacity + size * 2;
}
memcpy(&log_data->buffer_out[log_data->buffer_out_length], data, size);
log_data->buffer_out_length += size;
break;
}
return 0;
}
INT(*curl_easy_perform_p)(PVOID handle);
INT __declspec(dllexport) curl_easy_perform(PVOID handle)
{
INT result;
HANDLE hFile;
char buffer[256];
curl_easy_setopt_p(handle, 20094, debug_callback); // CURLOPT_DEBUGFUNCTION
curl_easy_setopt_p(handle, 41, 1L); // CURLOPT_VERBOSE
PDEBUG_LOG_DATA log_data = calloc(1, sizeof(*log_data));
curl_easy_setopt_p(handle, 10095, log_data); // CURLOPT_DEBUGDATA
result = curl_easy_perform_p(handle);
WaitForSingleObject(ghMutex, INFINITE);
hFile = CreateFileA(gszLogPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
hFile = CreateFileA(gszLogPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
MessageBoxA(NULL, "Welp, can't create/open the log file.", "Welp!", MB_OK);
}
SetFilePointer(hFile, 0, 0, FILE_END);
WriteFile(hFile, "================================================================\r\n", 66, NULL, NULL);
sprintf_s(buffer, 256, ">>> PID: %d TID: %d Handle: %p\r\n", GetCurrentProcessId(), GetCurrentThreadId(), handle);
WriteFile(hFile, buffer, lstrlenA(buffer), NULL, NULL);
WriteFile(hFile, "================================================================\r\n", 66, NULL, NULL);
WriteFile(hFile, log_data->buffer_out, log_data->buffer_out_length, NULL, NULL);
WriteFile(hFile, "\r\n----------------------------------------------------------------\r\n", 68, NULL, NULL);
WriteFile(hFile, log_data->buffer_in, log_data->buffer_in_length, NULL, NULL);
WriteFile(hFile, "\r\n----------------------------------------------------------------\r\n\r\n", 70, NULL, NULL);
CloseHandle(hFile);
ReleaseMutex(ghMutex);
curl_easy_setopt_p(handle, 10095, NULL);
free(log_data->buffer_out);
free(log_data->buffer_in);
free(log_data);
curl_easy_setopt_p(handle, 41, 0L);
curl_easy_setopt_p(handle, 20094, NULL);
return result;
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
hRealCurl = LoadLibraryA("libcurw.dll");
if (hRealCurl == INVALID_HANDLE_VALUE)
{
MessageBoxA(NULL, "Welp, LoadLibrary failed.", "Welp!", MB_OK);
return FALSE;
}
LOAD_THUNK(curl_easy_cleanup);
LOAD_THUNK(curl_easy_duphandle);
LOAD_THUNK(curl_easy_escape);
LOAD_THUNK(curl_easy_getinfo);
LOAD_THUNK(curl_easy_header);
LOAD_THUNK(curl_easy_init);
LOAD_THUNK(curl_easy_nextheader);
LOAD_THUNK(curl_easy_option_by_id);
LOAD_THUNK(curl_easy_option_by_name);
LOAD_THUNK(curl_easy_option_next);
LOAD_THUNK(curl_easy_pause);
LOAD_THUNK(curl_easy_perform);
LOAD_THUNK(curl_easy_recv);
LOAD_THUNK(curl_easy_reset);
LOAD_THUNK(curl_easy_send);
LOAD_THUNK(curl_easy_setopt);
LOAD_THUNK(curl_easy_ssls_export);
LOAD_THUNK(curl_easy_ssls_import);
LOAD_THUNK(curl_easy_strerror);
LOAD_THUNK(curl_easy_unescape);
LOAD_THUNK(curl_easy_upkeep);
LOAD_THUNK(curl_escape);
LOAD_THUNK(curl_formadd);
LOAD_THUNK(curl_formfree);
LOAD_THUNK(curl_formget);
LOAD_THUNK(curl_free);
LOAD_THUNK(curl_getdate);
LOAD_THUNK(curl_getenv);
LOAD_THUNK(curl_global_cleanup);
LOAD_THUNK(curl_global_init);
LOAD_THUNK(curl_global_init_mem);
LOAD_THUNK(curl_global_sslset);
LOAD_THUNK(curl_global_trace);
LOAD_THUNK(curl_maprintf);
LOAD_THUNK(curl_mfprintf);
LOAD_THUNK(curl_mime_addpart);
LOAD_THUNK(curl_mime_data);
LOAD_THUNK(curl_mime_data_cb);
LOAD_THUNK(curl_mime_encoder);
LOAD_THUNK(curl_mime_filedata);
LOAD_THUNK(curl_mime_filename);
LOAD_THUNK(curl_mime_free);
LOAD_THUNK(curl_mime_headers);
LOAD_THUNK(curl_mime_init);
LOAD_THUNK(curl_mime_name);
LOAD_THUNK(curl_mime_subparts);
LOAD_THUNK(curl_mime_type);
LOAD_THUNK(curl_mprintf);
LOAD_THUNK(curl_msnprintf);
LOAD_THUNK(curl_msprintf);
LOAD_THUNK(curl_multi_add_handle);
LOAD_THUNK(curl_multi_assign);
LOAD_THUNK(curl_multi_cleanup);
LOAD_THUNK(curl_multi_fdset);
LOAD_THUNK(curl_multi_get_handles);
LOAD_THUNK(curl_multi_info_read);
LOAD_THUNK(curl_multi_init);
LOAD_THUNK(curl_multi_perform);
LOAD_THUNK(curl_multi_poll);
LOAD_THUNK(curl_multi_remove_handle);
LOAD_THUNK(curl_multi_setopt);
LOAD_THUNK(curl_multi_socket);
LOAD_THUNK(curl_multi_socket_action);
LOAD_THUNK(curl_multi_socket_all);
LOAD_THUNK(curl_multi_strerror);
LOAD_THUNK(curl_multi_timeout);
LOAD_THUNK(curl_multi_wait);
LOAD_THUNK(curl_multi_waitfds);
LOAD_THUNK(curl_multi_wakeup);
LOAD_THUNK(curl_mvaprintf);
LOAD_THUNK(curl_mvfprintf);
LOAD_THUNK(curl_mvprintf);
LOAD_THUNK(curl_mvsnprintf);
LOAD_THUNK(curl_mvsprintf);
LOAD_THUNK(curl_pushheader_byname);
LOAD_THUNK(curl_pushheader_bynum);
LOAD_THUNK(curl_share_cleanup);
LOAD_THUNK(curl_share_init);
LOAD_THUNK(curl_share_setopt);
LOAD_THUNK(curl_share_strerror);
LOAD_THUNK(curl_slist_append);
LOAD_THUNK(curl_slist_free_all);
LOAD_THUNK(curl_strequal);
LOAD_THUNK(curl_strnequal);
LOAD_THUNK(curl_unescape);
LOAD_THUNK(curl_url);
LOAD_THUNK(curl_url_cleanup);
LOAD_THUNK(curl_url_dup);
LOAD_THUNK(curl_url_get);
LOAD_THUNK(curl_url_set);
LOAD_THUNK(curl_url_strerror);
LOAD_THUNK(curl_version);
LOAD_THUNK(curl_version_info);
LOAD_THUNK(curl_ws_meta);
LOAD_THUNK(curl_ws_recv);
LOAD_THUNK(curl_ws_send);
ghMutex = CreateMutex(NULL, FALSE, NULL);
ExpandEnvironmentStringsA("%USERPROFILE%\\CurlLog.txt", gszLogPath, sizeof(gszLogPath));
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
CloseHandle(ghMutex);
ghMutex = INVALID_HANDLE_VALUE;
FreeLibrary(hRealCurl);
break;
}
return TRUE;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment