official way is as pointed out by other answers use symchk.exe from windbg installation
but you can also fetch it by putting together few dbghelp and winsock functions
find below a poc that uses wget.exe
#include <stdio.h>
#include <windows.h>
#include <dbghelp.h>
#pragma comment(lib,"dbghelp.lib")
#pragma comment(lib,"user32.lib")
const char *formatstr =
"wget -c -U=\"Microsoft-Symbol-Server/10.0.0.0\" "
"\"http://msdl.microsoft.com/download/symbols/"
"%s/%08x%04x%04x%02x%02x%02x%02x%02x%02x%02x%02x%x/%s\"";
char fetchpdb[0x1000];
int main(int argc,char *argv[]) {
if(argc !=2){
printf("usage %s path to binary\n",argv[0]);
exit(0);
}
SYMSRV_INDEX_INFO syminf ={0};
syminf.sizeofstruct = sizeof(SYMSRV_INDEX_INFO);
BOOL ret = SymSrvGetFileIndexInfo(argv[1],&syminf,0);
if(ret) {
wsprintfA(
fetchpdb,formatstr,syminf.pdbfile,syminf.guid.Data1,
syminf.guid.Data2, syminf.guid.Data3,syminf.guid.Data4[0],
syminf.guid.Data4[1],syminf.guid.Data4[2],syminf.guid.Data4[3],
syminf.guid.Data4[4],syminf.guid.Data4[5],syminf.guid.Data4[6],
syminf.guid.Data4[7],syminf.age,syminf.pdbfile
);
// Depricated use CreateProcess and/or Winsock functions needs wget.exe in path
WinExec(fetchpdb,1);
}
else {
printf("%x\n",GetLastError());
}
return 0;
}