1
0
Fork 0

DBG: symdownload now works without dbghelp

This commit is contained in:
Duncan Ogilvie 2018-02-09 15:08:47 +01:00
parent ba6ad4cefc
commit 637815b63d
No known key found for this signature in database
GPG Key ID: FC89E0AAA0C1AAD8
3 changed files with 176 additions and 220 deletions

View File

@ -3,6 +3,7 @@
#include "downslib.h"
#include <windows.h>
#include <stdio.h>
#include <Wininet.h>
#pragma comment(lib, "Wininet.lib")
@ -10,130 +11,7 @@
#define DEFAULT_TIMEOUT 3000
#define DEFAULT_USERAGENT "downslib"
char* _strchr(const char* str, char c)
{
const char* p;
for(p = str; *p != '\0'; p = AnsiNext(p))
{
if(*p == c)
return (char*)p;
}
return NULL;
}
static const char* _path_from_url(const char* url)
{
const char* path = NULL;
/* First look for a dot to get to domain part of URL */
path = _strchr(url, '.');
if(path != NULL)
++path;
else
path = url;
path = _strchr(path, '/');
return path;
}
static int _get_content_length(const char* host,
const char* object,
int use_ssl,
const char* useragent,
unsigned int timeout,
int* total_bytes)
{
HINTERNET hInternet = NULL;
HINTERNET hConnection = NULL;
HINTERNET hRequest = NULL;
DWORD dwRead = 0;
DWORD dwLen = 0;
DWORD dwFlags = 0;
/* */
int ret = 0;
hInternet = InternetOpenA(useragent,
INTERNET_OPEN_TYPE_PRECONFIG,
NULL,
NULL,
0);
if(hInternet == NULL)
{
return 1;
}
InternetSetOptionA(hInternet,
INTERNET_OPTION_RECEIVE_TIMEOUT,
&timeout,
sizeof(DWORD));
hConnection = InternetConnectA(hInternet,
host,
INTERNET_DEFAULT_HTTP_PORT,
NULL,
NULL,
INTERNET_SERVICE_HTTP,
0,
0);
dwFlags = INTERNET_FLAG_RELOAD;
if(use_ssl)
{
dwFlags |= INTERNET_FLAG_SECURE;
dwFlags |= INTERNET_FLAG_IGNORE_CERT_DATE_INVALID;
dwFlags |= INTERNET_FLAG_IGNORE_CERT_CN_INVALID;
}
hRequest = HttpOpenRequestA(hConnection,
"HEAD",
object,
NULL,
NULL,
NULL,
dwFlags,
0);
if(HttpSendRequestA(hRequest, NULL, 0, NULL, 0) == FALSE)
{
if(GetLastError() == ERROR_INTERNET_INVALID_CA && use_ssl)
{
dwFlags = 0;
dwLen = sizeof(dwFlags);
InternetQueryOptionA(hRequest, INTERNET_OPTION_SECURITY_FLAGS, (LPVOID)&dwFlags, &dwLen);
dwFlags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA;
InternetSetOptionA(hRequest, INTERNET_OPTION_SECURITY_FLAGS, &dwFlags, sizeof(dwFlags));
}
}
dwLen = sizeof(*total_bytes);
if(HttpQueryInfoA(hRequest,
HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,
(LPVOID)total_bytes,
&dwLen,
0) == FALSE)
{
ret = 2;
}
if(hRequest != NULL)
InternetCloseHandle(hRequest);
if(hConnection != NULL)
InternetCloseHandle(hConnection);
if(hInternet != NULL)
InternetCloseHandle(hInternet);
return ret;
}
static int _download(const char* url,
const char* host,
const char* object,
int use_ssl,
const wchar_t* filename,
const char* useragent,
unsigned int timeout,
@ -148,19 +26,17 @@ static int _download(const char* url,
DWORD dwRead = 0;
DWORD dwLen = 0;
BOOL bRet = FALSE;
/* */
int read_bytes = 0;
int total_bytes = 0;
unsigned long long read_bytes = 0;
unsigned long long total_bytes = 0;
char buffer[2048];
int ret = 0;
int ret = DOWNSLIB_ERROR_OK;
/* Try to retrieve content-length, not essential */
_get_content_length(host,
object,
use_ssl,
useragent,
timeout,
&total_bytes);
hFile = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
if(hFile == INVALID_HANDLE_VALUE)
{
ret = DOWNSLIB_ERROR_CREATEFILE;
goto cleanup;
}
hInternet = InternetOpenA(useragent,
INTERNET_OPEN_TYPE_PRECONFIG,
@ -170,28 +46,50 @@ static int _download(const char* url,
if(hInternet == NULL)
{
return 1;
return DOWNSLIB_ERROR_INETOPEN;
}
/* Set timeout as specified */
InternetSetOptionA(hInternet,
INTERNET_OPTION_RECEIVE_TIMEOUT,
&timeout,
sizeof(timeout));
dwFlags = INTERNET_FLAG_RELOAD;
if(use_ssl)
if(strncmp(url, "https://", 8) == 0)
{
dwFlags |= INTERNET_FLAG_SECURE;
dwFlags |= INTERNET_FLAG_IGNORE_CERT_DATE_INVALID;
dwFlags |= INTERNET_FLAG_IGNORE_CERT_CN_INVALID;
//dwFlags |= INTERNET_FLAG_IGNORE_CERT_DATE_INVALID;
//dwFlags |= INTERNET_FLAG_IGNORE_CERT_CN_INVALID;
}
if((hUrl = InternetOpenUrlA(hInternet, url, NULL, 0, dwFlags, 0)) == NULL)
{
ret = 2;
ret = DOWNSLIB_ERROR_OPENURL;
goto cleanup;
}
hFile = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
if(hFile == NULL)
/* Get HTTP content length */
dwLen = sizeof(buffer);
if(HttpQueryInfoA(hUrl, HTTP_QUERY_CONTENT_LENGTH, buffer, &dwLen, 0))
{
ret = 3;
goto cleanup;
if(sscanf_s(buffer, "%llu", &total_bytes) != 1)
total_bytes = 0;
}
/* Get HTTP status code */
dwLen = sizeof(buffer);
if(HttpQueryInfoA(hUrl, HTTP_QUERY_STATUS_CODE, buffer, &dwLen, 0))
{
int status_code = 0;
if(sscanf_s(buffer, "%d", &status_code) != 1)
status_code = 500;
if(status_code != 200)
{
ret = DOWNSLIB_ERROR_STATUSCODE;
SetLastError(status_code);
goto cleanup;
}
}
while(InternetReadFile(hUrl, buffer, sizeof(buffer), &dwRead))
@ -204,13 +102,11 @@ static int _download(const char* url,
total_bytes = read_bytes;
}
if(cb != NULL)
/* Call the callback to report progress and cancellation */
if(cb && !cb(read_bytes, total_bytes))
{
if(cb(read_bytes, total_bytes) != 0)
{
ret = 4;
goto cleanup;
}
ret = DOWNSLIB_ERROR_CANCEL;
goto cleanup;
}
/* Exit if nothing more to read */
@ -220,16 +116,15 @@ static int _download(const char* url,
}
WriteFile(hFile, buffer, dwRead, &dwWritten, NULL);
/* FlushFileBuffers(hFile); */
}
if(total_bytes > 0 && read_bytes != total_bytes)
{
ret = 5;
ret = DOWNSLIB_ERROR_INCOMPLETE;
}
cleanup:
if(hFile != NULL)
if(hFile != INVALID_HANDLE_VALUE)
CloseHandle(hFile);
if(hUrl != NULL)
InternetCloseHandle(hUrl);
@ -239,82 +134,23 @@ cleanup:
return ret;
}
static int _host_and_object_from_url(const char* url, char** host, const char** object)
{
const char* object_tmp = _path_from_url(url);
char* past_protocol = NULL;
char* host_tmp = NULL;
int ret = 0;
int len = 0;
// Point past the protocol part of URL, e.g past "HTTP://"
past_protocol = _strchr(url, '/');
if(past_protocol == NULL)
{
// Malformed url
return 1;
}
past_protocol += 2; // Move past the two slashes in protocol specification
if(object_tmp == NULL)
{
len = lstrlenA(past_protocol) + 1;
}
else
{
len = object_tmp - past_protocol + 1;
}
host_tmp = (char*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len + 1);
lstrcpynA(host_tmp, past_protocol, len);
*host = host_tmp;
*object = object_tmp;
return 0;
}
static void _free_host(char* host)
{
HeapFree(GetProcessHeap(), 0, host);
}
int downslib_download(const char* url,
const wchar_t* filename,
int use_ssl,
const char* useragent,
unsigned int timeout,
downslib_cb cb)
{
const char* object = NULL;
char* host = NULL;
int ret = 0;
ret = _host_and_object_from_url(url, &host, &object);
if(ret != 0)
{
return ret;
}
ret = _download(url,
host,
object,
use_ssl,
filename,
useragent ? useragent : DEFAULT_USERAGENT,
timeout ? timeout : DEFAULT_TIMEOUT,
cb);
_free_host(host);
return ret;
return _download(url,
filename,
useragent ? useragent : DEFAULT_USERAGENT,
timeout ? timeout : DEFAULT_TIMEOUT,
cb);
}
int downslib_easy_download(const char* url, const wchar_t* filename, int use_ssl)
int downslib_easy_download(const char* url, const wchar_t* filename)
{
return downslib_download(url,
filename,
use_ssl,
DEFAULT_USERAGENT,
DEFAULT_TIMEOUT,
NULL);

View File

@ -4,17 +4,34 @@
#define __DOWNSLIB_H_DEF__
#include <wchar.h>
#include <stdbool.h>
int downslib_easy_download(const char* url, const wchar_t* filename, int use_ssl);
#ifdef __cplusplus
extern "C"
{
#endif //__cplusplus
typedef int (*downslib_cb)(int read_bytes, int total_bytes);
#define DOWNSLIB_ERROR_OK 0
#define DOWNSLIB_ERROR_CREATEFILE 1
#define DOWNSLIB_ERROR_INETOPEN 2
#define DOWNSLIB_ERROR_OPENURL 3
#define DOWNSLIB_ERROR_STATUSCODE 4
#define DOWNSLIB_ERROR_CANCEL 5
#define DOWNSLIB_ERROR_INCOMPLETE 6
int downslib_easy_download(const char* url, const wchar_t* filename);
typedef bool (*downslib_cb)(unsigned long long read_bytes, unsigned long long total_bytes);
int downslib_download(const char* url,
const wchar_t* filename,
int use_ssl,
const char* useragent,
unsigned int timeout,
downslib_cb cb);
#ifdef __cplusplus
}
#endif //__cplusplus
#endif

View File

@ -16,6 +16,7 @@
#include "exception.h"
#include "TraceRecord.h"
#include "dbghelp_safe.h"
#include "WinInet-Downloader/downslib.h"
bool cbInstrAnalyse(int argc, char* argv[])
{
@ -154,6 +155,107 @@ bool cbInstrVirtualmod(int argc, char* argv[])
bool cbDebugDownloadSymbol(int argc, char* argv[])
{
if(argc < 2) //no arguments
{
dputs("not enough arguments...");
return false;
}
duint modbase = ModBaseFromName(argv[1]);
String pdbSignature, pdbFile;
{
SHARED_ACQUIRE(LockModules);
auto info = ModInfoFromAddr(modbase);
if(!info)
{
dputs("module not found...");
return false;
}
pdbSignature = info->pdbSignature;
pdbFile = info->pdbFile;
}
if(pdbSignature.empty() || pdbFile.empty()) // TODO: allow using module filename instead of pdbFile ?
{
dputs("module has no symbol information...");
return false;
}
auto found = strrchr(pdbFile.c_str(), '\\');
auto pdbBaseFile = found ? found + 1 : pdbFile.c_str();
// TODO: strict checks if this path is absolute
WString destinationPath(StringUtils::Utf8ToUtf16(szSymbolCachePath));
if(destinationPath.empty())
{
dputs("no destination symbol path specified...");
return false;
}
CreateDirectoryW(destinationPath.c_str(), nullptr);
if(destinationPath.back() != L'\\')
destinationPath += L'\\';
destinationPath += StringUtils::Utf8ToUtf16(pdbBaseFile);
CreateDirectoryW(destinationPath.c_str(), nullptr);
destinationPath += L'\\';
destinationPath += StringUtils::Utf8ToUtf16(pdbSignature);
CreateDirectoryW(destinationPath.c_str(), nullptr);
destinationPath += '\\';
destinationPath += StringUtils::Utf8ToUtf16(pdbBaseFile);
Memory<char*> szDefaultStore(MAX_SETTING_SIZE + 1);
const char* szSymbolStore = szDefaultStore();
if(!BridgeSettingGet("Symbols", "DefaultStore", szDefaultStore())) //get default symbol store from settings
{
strcpy_s(szDefaultStore(), MAX_SETTING_SIZE, "https://msdl.microsoft.com/download/symbols");
BridgeSettingSet("Symbols", "DefaultStore", szDefaultStore());
}
String symbolUrl(szSymbolStore);
if(symbolUrl.empty())
{
dputs("no symbol store URL specified...");
return false;
}
if(symbolUrl.back() != '/')
symbolUrl += '/';
symbolUrl += StringUtils::sprintf("%s/%s/%s", pdbBaseFile, pdbSignature.c_str(), pdbBaseFile);
dprintf("downloading symbol \"%s\", signature: %s, destination: \"%S\", url: \"%s\"\n", pdbBaseFile, pdbSignature.c_str(), destinationPath.c_str(), symbolUrl.c_str());
auto result = downslib_download(symbolUrl.c_str(), destinationPath.c_str(), "x64dbg", 1000, [](unsigned long long read_bytes, unsigned long long total_bytes)
{
if(total_bytes)
{
auto progress = (double)read_bytes / (double)total_bytes;
GuiSymbolSetProgress((int)(progress * 100.0));
}
return true;
});
GuiSymbolSetProgress(0);
dprintf("download_download = %d\n", result);
// TODO: handle errors
switch(result)
{
case DOWNSLIB_ERROR_OK:
break;
case DOWNSLIB_ERROR_INETOPEN:
break;
case DOWNSLIB_ERROR_OPENURL:
break;
case DOWNSLIB_ERROR_STATUSCODE:
break;
case DOWNSLIB_ERROR_CREATEFILE:
break;
case DOWNSLIB_ERROR_CANCEL:
break;
case DOWNSLIB_ERROR_INCOMPLETE:
break;
default:
__debugbreak();
}
// TODO: actually load the symbol from the cache
return true;
/*
dputs(QT_TRANSLATE_NOOP("DBG", "This may take very long, depending on your network connection and data in the debug directory..."));
Memory<char*> szDefaultStore(MAX_SETTING_SIZE + 1);
const char* szSymbolStore = szDefaultStore();
@ -221,6 +323,7 @@ bool cbDebugDownloadSymbol(int argc, char* argv[])
GuiSymbolRefreshCurrent();
dputs(QT_TRANSLATE_NOOP("DBG", "Done! See symbol log for more information"));
return true;
*/
}
bool cbInstrImageinfo(int argc, char* argv[])