#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable : 4018)
#include <Windows.h>
#include <WinInet.h>
#pragma comment(lib,"Wininet.lib")
#include <iostream>
#include <string>
#include <sstream>
#include <iomanip>
#include <memory>
/**
* 下载url网络文件到本地
* url : 网络程序路径
* path : 保存到本地的路径
* 成功返回0,失败返回负数
*/
int
download_http(
std::string url,
std::string path)
{
// 初始化
HINTERNET it_open = InternetOpenA("", INTERNET_OPEN_TYPE_PRECONFIG, 0, 0, 0);
if (it_open == NULL) return -1;
// 打开url
HINTERNET it_url = InternetOpenUrlA(it_open, url.c_str(), 0, 0, INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_UI | INTERNET_FLAG_PRAGMA_NOCACHE, 0);
if (it_url == NULL)
{
InternetCloseHandle(it_open);
return -2;
}
// 查询程序大小
DWORD file_size = 0, buf_size = sizeof(DWORD);
BOOL is_valid_url = HttpQueryInfo(it_url, HTTP_QUERY_FLAG_NUMBER | HTTP_QUERY_CONTENT_LENGTH, &file_size, &buf_size, 0);
if (is_valid_url == FALSE || file_size == 0)
{
InternetCloseHandle(it_url);
InternetCloseHandle(it_open);
return -3;
}
// 创建本地文件
HANDLE h = CreateFileA(path.c_str(), GENERIC_ALL, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
if (h == INVALID_HANDLE_VALUE)
{
InternetCloseHandle(it_url);
InternetCloseHandle(it_open);
return -4;
}
// 开始循环读取网络程序数据
const unsigned int max_tcp = 4000;
unsigned int total = 0;
unsigned int last_value = 0;
unsigned char buffer[max_tcp]{ 0 };
memset(buffer, 0, max_tcp);
while (InternetReadFile(it_url, buffer, max_tcp, &buf_size))
{
if (buf_size)
{
WriteFile(h, buffer, max_tcp, &buf_size, 0);
total += buf_size;
unsigned int value = (unsigned int)((double)total / (double)file_size * (double)100.0f);
if (value != last_value)
{
last_value = value;
printf("%d%% \n", value);
}
}
else break;
}
InternetCloseHandle(it_url);
InternetCloseHandle(it_open);
return 0;
}
/*
* 获取指定微软官方程序的pdb下载路径
* path : 程序路径
* url : 返回url下载路径
* 成功返回0,失败返回负数
*/
int
get_pdb_url(
std::string path,
std::string& url)
{
// 打开文件
HANDLE h = CreateFileA(path.c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (h == INVALID_HANDLE_VALUE) return -1;
// 获取文件大小并申请空间
DWORD size = GetFileSize(h, 0);
std::shared_ptr<unsigned char> buffer(new unsigned char[size]);
if (buffer == nullptr)
{
CloseHandle(h);
return -2;
}
// 将文件数据读出
DWORD bytes = 0;
DWORD ret = ReadFile(h, buffer.get(), size, &bytes, 0);
if (ret == FALSE || bytes != size)
{
CloseHandle(h);
return -3;
}
// 关闭句柄
CloseHandle(h);
// 验证dos标识
PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)buffer.get();
if (dos->e_magic != IMAGE_DOS_SIGNATURE) return -4;
// 验证nt标识
PIMAGE_NT_HEADERS32 nt32 = (PIMAGE_NT_HEADERS32)(dos->e_lfanew + buffer.get());
if (nt32->Signature != IMAGE_NT_SIGNATURE) return -5;
// 读取基本信息
PIMAGE_SECTION_HEADER sec = IMAGE_FIRST_SECTION(nt32);
DWORD sec_count = nt32->FileHeader.NumberOfSections;
DWORD debug_rva = nt32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
DWORD debug_size = nt32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
// 64和32位不同
PIMAGE_NT_HEADERS64 nt64 = (PIMAGE_NT_HEADERS64)(dos->e_lfanew + buffer.get());
if (nt64->FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64)
{
sec = IMAGE_FIRST_SECTION(nt64);
sec_count = nt64->FileHeader.NumberOfSections;
debug_rva = nt64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
debug_size = nt64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
}
// 程序没有调试数据信息
if (debug_rva == 0 || debug_size == 0) return -6;
// 相对虚拟地址转化文件偏移
auto rva_to_file = [](PIMAGE_SECTION_HEADER sec, int count, int rva) -> int
{
for (int i = 0; i < count; i++)
if (sec[i].VirtualAddress < rva && sec[i].VirtualAddress + sec[i].Misc.VirtualSize > rva)
return rva - sec[i].VirtualAddress + sec[i].PointerToRawData;
return 0;
};
// 取得调试数据的文件偏移
int debug_file_offset = rva_to_file(sec, sec_count, debug_rva);
if (debug_file_offset == 0) return -7;
// 调试信息结构体
typedef struct _debug_information_
{
unsigned long signature;
GUID guid;
unsigned long age;
char pdb[1];
}debug_information, * pdebug_information;
// 取得第一个调试结构指针
PIMAGE_DEBUG_DIRECTORY debug_dir = (PIMAGE_DEBUG_DIRECTORY)(debug_file_offset + buffer.get());
for (int i = 0; i * sizeof(IMAGE_DEBUG_DIRECTORY) < debug_size; i++)
{
// 类型要求
if (debug_dir[i].Type != IMAGE_DEBUG_TYPE_CODEVIEW) continue;
pdebug_information info = (pdebug_information)(buffer.get() + debug_dir[i].PointerToRawData);
// 格式化网络url路径
std::stringstream sym;
sym << info->pdb << "/";
sym << std::setfill('0') << std::setw(8) << std::hex << info->guid.Data1 << std::setw(4) << std::hex << info->guid.Data2 << std::setw(4) << std::hex << info->guid.Data3;
for (const auto i : info->guid.Data4) sym << std::setw(2) << std::hex << +i;
sym << "1/" << info->pdb;
url = "http://msdl.microsoft.com/download/symbols/" + sym.str();
// 返回成功
return 0;
}
// 返回失败
return -99;
}
int main(int argc, char* argv[])
{
if (argc != 3)
{
printf("程序路径 pdb保存路径\n");
return -1;
}
std::string url;
int ret = get_pdb_url(argv[1], url);
if (ret == 0)
{
std::cout << url << std::endl;
download_http(url, argv[2]);
}
return 0;
}
PDB下载
最新推荐文章于 2024-06-04 15:20:56 发布