Skip to content

Commit

Permalink
use boost asio to download the pdb files.
Browse files Browse the repository at this point in the history
  • Loading branch information
BeneficialCode committed Dec 27, 2024
1 parent 6c260e1 commit 528bd78
Show file tree
Hide file tree
Showing 9 changed files with 257 additions and 133 deletions.
1 change: 1 addition & 0 deletions WinArk/GotoKeyDlg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ LRESULT CGotoKeyDlg::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lPa
{ L"DisablePath",LR"(HKEY_CURRENT_USER\SOFTWARE\Policies\Microsoft\Windows\Safer\CodeIdentifiers\0\Paths)"},
{ L"Internet Settings",LR"(HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings)"},
{ L"Session Manager",LR"(HKLM\System\CurrentControlSet\Control\Session Manager)"},
{ L"NetworkCards",LR"(HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkCards)"},
};

for (const auto& [name, path] : locations) {
Expand Down
2 changes: 1 addition & 1 deletion WinArk/ImportsHandling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ void ImportsHandling::UpdateImportInTreeView(const ImportThunk* pImportThunk, CT
}

void ImportsHandling::UpdateModuleInTreeView(const ImportModuleThunk* importThunk, CTreeItem item) {
swprintf_s(Text, L"%s (%d) FThunk: " PRINTF_DWORD_PTR_HALF, importThunk->m_ModuleName, importThunk->m_ThunkMap.size(), importThunk->m_FirstThunk);
swprintf_s(Text, L"%s (%lld) FThunk: " PRINTF_DWORD_PTR_HALF, importThunk->m_ModuleName, importThunk->m_ThunkMap.size(), importThunk->m_FirstThunk);

item.SetText(Text);
int icon = (int)GetAppropiateIcon(importThunk->IsValid());
Expand Down
8 changes: 7 additions & 1 deletion WinArk/ObjectCallbackTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,17 @@ PCWSTR CObjectCallbackTable::TypeToString(ObjectCallbackType type) {

CString CObjectCallbackTable::DecodeOperations(ULONG operations) {
CString result;
bool needSeparator = false;

if ((operations & OB_OPERATION_HANDLE_CREATE) == OB_OPERATION_HANDLE_CREATE) {
result += L"HANDLE_CREATE" + CString(L" | ");
result += L"HANDLE_CREATE";
needSeparator = true;
}

if ((operations & OB_OPERATION_HANDLE_DUPLICATE) == OB_OPERATION_HANDLE_DUPLICATE) {
if (needSeparator) {
result += L" | ";
}
result += L"HANDLE_DUPLICATE";
}

Expand Down
326 changes: 230 additions & 96 deletions WinArk/SymbolFileInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,15 @@
#include <filesystem>
#include <Helpers.h>
#include <fstream>
#include <asio.hpp>
#include <asio\ssl.hpp>


using Poco::URIStreamOpener;
using Poco::StreamCopier;
using Poco::Path;
using Poco::Exception;
using Poco::Net::HTTPStreamFactory;
using Poco::Net::FTPStreamFactory;
using Poco::SharedPtr;
using Poco::Net::HTTPSStreamFactory;
using Poco::Net::SSLManager;
using Poco::Net::Context;
using Poco::Net::InvalidCertificateHandler;
using Poco::Net::ConsoleCertificateHandler;
using Poco::Net::HTTPSClientSession;
using Poco::Net::HTTPRequest;
using Poco::Net::HTTPMessage;
using Poco::Net::HTTPResponse;
using Poco::Net::HTTPClientSession;

#pragma comment(lib,"Ws2_32")
#pragma comment(lib,"Iphlpapi")
#pragma comment(lib,"Crypt32")


bool SymbolFileInfo::SymDownloadSymbol(std::wstring localPath) {
std::wstring path = localPath + L"\\" + _path.GetString();
std::filesystem::create_directories(path);
Expand Down Expand Up @@ -113,90 +98,239 @@ bool SymbolFileInfo::GetPdbSignature(ULONG_PTR imageBase,PIMAGE_DEBUG_DIRECTORY
}

downslib_error SymbolFileInfo::Download(std::string url, std::wstring fileName, std::string userAgent,
unsigned int timeout,downslib_cb cb, void* userdata){
std::ofstream fileStream;
fileStream.open(fileName, std::ios::out | std::ios::trunc | std::ios::binary);

SharedPtr<InvalidCertificateHandler> pCertHandler = new ConsoleCertificateHandler(false); // ask the user via console
Context::Ptr pContext = new Context(Context::CLIENT_USE, "", Context::VerificationMode::VERIFY_NONE);
SSLManager::instance().initializeClient(0, pCertHandler, pContext);
Poco::URI uri(url);
if (uri.getScheme() == "http") {
try
{
std::string path(uri.getPathAndQuery());
if (path.empty()) path = "/";
HTTPClientSession session(uri.getHost(), uri.getPort());
HTTPRequest request(HTTPRequest::HTTP_GET, path, HTTPMessage::HTTP_1_1);
session.sendRequest(request);
HTTPResponse response;
session.peekResponse(response);
if (response.getStatus() == HTTPResponse::HTTPStatus::HTTP_FOUND) {
uri = response.get("Location");
}
}
catch (Poco::Exception& exc)
{
fileStream << exc.displayText() << std::endl;
return downslib_error::incomplete;
}
}
else if (uri.getScheme() == "https") {
try
{
HTTPSClientSession session(uri.getHost(), uri.getPort());
std::string path(uri.getPathAndQuery());
if (path.empty()) path = "/";
HTTPRequest request(HTTPRequest::HTTP_GET, path, HTTPMessage::HTTP_1_1);
session.sendRequest(request);
HTTPResponse response;
session.peekResponse(response);
if (response.getStatus() == HTTPResponse::HTTPStatus::HTTP_FOUND) {
uri = response.get("Location");
}
}
catch (Poco::Exception& exc)
{
fileStream << exc.displayText() << std::endl;
return downslib_error::incomplete;
}

}
downslib_error ret = PdbDownLoader(uri, fileStream);
cb(userdata, 100, 100);
fileStream.close();
return ret;
}
unsigned int timeout, downslib_cb cb, void* userdata) {
std::ofstream fileStream(fileName, std::ios::out | std::ios::trunc | std::ios::binary);
if (!fileStream) {
return downslib_error::incomplete;
}

unsigned long long SymbolFileInfo::GetPdbSize(std::string url, std::wstring fileName, std::string userAgent,
unsigned int timeout) {

using tcp = asio::ip::tcp;
namespace ssl = asio::ssl;

try {
asio::io_context ioc;
ssl::context ctx(ssl::context::sslv23_client);

int redirect_count = 0;
const int max_redirects = 5;

while (redirect_count < max_redirects) {
std::string protocol, host, path;

if (url.substr(0, 8) == "https://") {
protocol = "https";
url = url.substr(8);
}
else if (url.substr(0, 7) == "http://") {
protocol = "http";
url = url.substr(7);
}
else {
throw std::runtime_error("Invalid URL protocol");
}

size_t path_pos = url.find('/');
host = (path_pos == std::string::npos) ? url : url.substr(0, path_pos);
path = (path_pos == std::string::npos) ? "/" : url.substr(path_pos);

tcp::resolver resolver(ioc);
auto const results = resolver.resolve(host, protocol);

std::string request = "GET " + path + " HTTP/1.1\r\n"
"Host: " + host + "\r\n"
"User-Agent: " + userAgent + "\r\n"
"Accept: */*\r\n"
"Connection: close\r\n\r\n";

if (protocol == "https") {
ssl::stream<tcp::socket> stream(ioc, ctx);
SSL_set_tlsext_host_name(stream.native_handle(), host.c_str());

asio::connect(stream.next_layer(), results.begin(), results.end());
stream.handshake(ssl::stream_base::client);
asio::write(stream, asio::buffer(request));

asio::streambuf response;
asio::error_code header_ec;
asio::read_until(stream, response, "\r\n\r\n", header_ec);
if (header_ec) {
throw asio::system_error(header_ec);
}

std::istream response_stream(&response);
std::string http_version;
unsigned int status_code;
std::string status_message;

response_stream >> http_version >> status_code;
std::getline(response_stream, status_message);

if (status_code == 301 || status_code == 302 || status_code == 307 || status_code == 308) {
std::string header;
while (std::getline(response_stream, header) && header != "\r") {
if (header.substr(0, 9) == "Location:") {
std::string new_url = header.substr(10);
new_url.erase(0, new_url.find_first_not_of(" \t"));
new_url.erase(new_url.find_last_not_of(" \r\n") + 1);

if (new_url[0] == '/') {
new_url = protocol + "://" + host + new_url;
}
url = new_url;
redirect_count++;
goto continue_redirect;
}
}
}

if (status_code != 200) {
return downslib_error::incomplete;
}

return 0;
// Skip remaining headers
std::string header;
while (std::getline(response_stream, header) && header != "\r");

// Write any data that was already read along with the headers
if (response.size() > 0) {
fileStream << &response;
}

// Read the response body in chunks
const size_t chunk_size = 8192;
std::vector<char> buffer(chunk_size);
asio::error_code ec;
size_t bytes_transferred = 0;

while (true) {
bytes_transferred = stream.read_some(asio::buffer(buffer), ec);

if (ec) {
// Check if this is a normal end of stream
if (ec == asio::error::eof ||
ec.value() == 1 || // stream_truncated
ec == asio::ssl::error::stream_truncated) {
break; // Normal termination
}
throw asio::system_error(ec);
}

if (bytes_transferred > 0) {
fileStream.write(buffer.data(), bytes_transferred);
if (!fileStream) {
throw std::runtime_error("Failed to write to file");
}
}

if (bytes_transferred == 0) {
break;
}
}
break;
}
else { // HTTP
tcp::socket socket(ioc);
asio::connect(socket, results.begin(), results.end());
asio::write(socket, asio::buffer(request));

asio::streambuf response;
asio::error_code header_ec;
asio::read_until(socket, response, "\r\n\r\n", header_ec);
if (header_ec) {
throw asio::system_error(header_ec);
}

std::istream response_stream(&response);
std::string http_version;
unsigned int status_code;
std::string status_message;

response_stream >> http_version >> status_code;
std::getline(response_stream, status_message);

if (status_code == 301 || status_code == 302 || status_code == 307 || status_code == 308) {
std::string header;
while (std::getline(response_stream, header) && header != "\r") {
if (header.substr(0, 9) == "Location:") {
std::string new_url = header.substr(10);
new_url.erase(0, new_url.find_first_not_of(" \t"));
new_url.erase(new_url.find_last_not_of(" \r\n") + 1);

if (new_url[0] == '/') {
new_url = protocol + "://" + host + new_url;
}
url = new_url;
redirect_count++;
goto continue_redirect;
}
}
}

if (status_code != 200) {
return downslib_error::incomplete;
}

// Skip remaining headers
std::string header;
while (std::getline(response_stream, header) && header != "\r");

// Write any data that was already read along with the headers
if (response.size() > 0) {
fileStream << &response;
}

// Read the response body in chunks
const size_t chunk_size = 8192;
std::vector<char> buffer(chunk_size);
asio::error_code ec;
size_t bytes_transferred = 0;

while (true) {
bytes_transferred = socket.read_some(asio::buffer(buffer), ec);

if (ec) {
if (ec == asio::error::eof || ec.value() == 1) {
break; // Normal termination
}
throw asio::system_error(ec);
}

if (bytes_transferred > 0) {
fileStream.write(buffer.data(), bytes_transferred);
if (!fileStream) {
throw std::runtime_error("Failed to write to file");
}
}

if (bytes_transferred == 0) {
break;
}
}
break;
}

continue_redirect:
continue;
}

if (redirect_count >= max_redirects) {
throw std::runtime_error("Too many redirects");
}
}
catch (std::exception&) {
fileStream.close();
return downslib_error::incomplete;
}

if (cb) {
cb(userdata, 100, 100);
}
fileStream.close();
return downslib_error::ok;
}

SymbolFileInfo::SymbolFileInfo() {
Poco::Net::initializeSSL();
HTTPStreamFactory::registerFactory();
HTTPSStreamFactory::registerFactory();
FTPStreamFactory::registerFactory();
}

SymbolFileInfo::~SymbolFileInfo() {
FTPStreamFactory::unregisterFactory();
HTTPSStreamFactory::unregisterFactory();
HTTPStreamFactory::unregisterFactory();
Poco::Net::uninitializeSSL();
}

downslib_error SymbolFileInfo::PdbDownLoader(Poco::URI& uri, std::ostream& ostr) {
try {
std::unique_ptr<std::istream> pStr(URIStreamOpener::defaultOpener().open(uri));
StreamCopier::copyStream(*pStr.get(), ostr);
return downslib_error::ok;
}
catch (Exception& exc) {
ostr << exc.displayText() << std::endl;
return downslib_error::incomplete;
}
}
Loading

0 comments on commit 528bd78

Please sign in to comment.