DBG: symdownload now works without dbghelp
This commit is contained in:
parent
ba6ad4cefc
commit
637815b63d
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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[])
|
||||
|
|
|
|||
Loading…
Reference in New Issue