// Adapted from Minidbg.c // Original Authors : Matthew Hendel (math) and Matt Ruhlen (mruhlen) // Copyright (c) 1999 Microsoft Corporation // // Changed by (smahesh) // The MdpExc Program which resolves sym files has been adapted to match sym files with // the corresponding binary images. This is done by comparing the RVA's of the exported // functions in the binary image with the RVA's of their symbols in the sym file. #include #include #include #include #include #include #include "symres.h" #include #define MAX_PATH 260 #define MAXSYMNAME 512 // parameter is used to typecast the result to the appropriate pointer type. #define MakePtr( cast, ptr, addValue ) (cast)( (DWORD)(ptr) + (addValue) ) typedef DWORD ULONG_PTR; PVOID OpenMapping( IN PCWSTR FilePath ) { HANDLE hFile; HANDLE hMappedFile; PVOID MappedFile; hFile = CreateFileW( FilePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); if (hFile == INVALID_HANDLE_VALUE) { return NULL; } hMappedFile = CreateFileMapping( hFile, NULL, PAGE_READONLY, 0, 0, NULL ); if (!hMappedFile) { CloseHandle (hFile); return FALSE; } MappedFile = MapViewOfFile ( hMappedFile, FILE_MAP_READ, 0, 0, 0 ); CloseHandle (hMappedFile); CloseHandle (hFile); return MappedFile; } PIMAGE_SECTION_HEADER GetEnclosingSectionHeader(DWORD rva, PIMAGE_NT_HEADERS pNTHeader) { PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(pNTHeader); unsigned i; for ( i=0; i < pNTHeader->FileHeader.NumberOfSections; i++, section++ ) { // Is the RVA within this section? if ( (rva >= section->VirtualAddress) && (rva < (section->VirtualAddress + section->Misc.VirtualSize))) return section; } return 0; } // Compares the RVA's of the Exported Methods in the Binary with the RVA's of the corresponding // Symbols in the Sym file. bool CheckSymFile(LPWSTR wszDllFileName, LPWSTR wszSymFileName) { PVOID Mapping; PIMAGE_DOS_HEADER dosHeader; PIMAGE_EXPORT_DIRECTORY exportDir; PIMAGE_SECTION_HEADER header; PIMAGE_NT_HEADERS pNTHeader; INT delta; LPSTR filename; DWORD base; DWORD i; PDWORD functions; PWORD ordinals; LPSTR *name; DWORD exportsStartRVA, exportsEndRVA; bool fResult = true; Mapping = OpenMapping(wszDllFileName); dosHeader = (PIMAGE_DOS_HEADER)Mapping; if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE ) { return false; } base = (DWORD) dosHeader; pNTHeader = MakePtr(PIMAGE_NT_HEADERS, dosHeader, dosHeader->e_lfanew ); exportsStartRVA = pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; exportsEndRVA = exportsStartRVA + pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; // Get the IMAGE_SECTION_HEADER that contains the exports. This is // usually the .edata section, but doesn't have to be. header = GetEnclosingSectionHeader(exportsStartRVA, pNTHeader); if ( !header ) { printf("No Exports Table Found:"); return false; } delta = (INT)(header->VirtualAddress - header->PointerToRawData); exportDir = MakePtr(PIMAGE_EXPORT_DIRECTORY, base, exportsStartRVA - delta); filename = (PSTR)(exportDir->Name - delta + base); functions = (PDWORD)((DWORD)exportDir->AddressOfFunctions - delta + base); ordinals = (PWORD)((DWORD)exportDir->AddressOfNameOrdinals - delta + base); name = (PSTR *)((DWORD)exportDir->AddressOfNames - delta + base); PIMAGE_SECTION_HEADER pSecHeader; for (i=0; i < exportDir->NumberOfFunctions; i++) { DWORD entryPointRVA = functions[i]; DWORD j; if ( entryPointRVA == 0 ) // Skip over gaps in exported function continue; // ordinals (the entrypoint is 0 for // these functions). pSecHeader = ImageRvaToSection(pNTHeader, Mapping, entryPointRVA); // See if this function has an associated name exported for it. for ( j=0; j < exportDir->NumberOfNames; j++ ) { if ( ordinals[j] == i ) { SymbolResolver sr; WCHAR wszFunctionName[MAX_NAME]; wszFunctionName[0] = L'\0'; if (sr.GetNameFromAddr(wszSymFileName, 1, pSecHeader->VirtualAddress, entryPointRVA, wszFunctionName)) ; else if (sr.GetNameFromAddr(wszSymFileName, 2, pSecHeader->VirtualAddress, entryPointRVA, wszFunctionName)) ; else { printf("\nNot Found %s %S", (char *)(name[j] - delta + base), wszFunctionName ); fResult = false; } } } // Is it a forwarder? If so, the entry point RVA is inside the // .edata section, and is an RVA to the DllName.EntryPointName if ((entryPointRVA >= exportsStartRVA) && (entryPointRVA <= exportsEndRVA)) { SymbolResolver sr; WCHAR wszFunctionName[MAX_NAME]; wszFunctionName[0] = L'\0'; if (sr.GetNameFromAddr(wszSymFileName, 1, pSecHeader->VirtualAddress, entryPointRVA, wszFunctionName)) ; else if (sr.GetNameFromAddr(wszSymFileName, 2, pSecHeader->VirtualAddress, entryPointRVA, wszFunctionName)) ; else { printf("Not Found %s %S", (char *)(entryPointRVA - delta + base), wszFunctionName ); fResult = false; } } } return fResult; } void __cdecl wmain(int argc,WCHAR ** argv) { WCHAR wszDllFileName[MAX_PATH] = L""; WCHAR wszSymFileName[MAX_PATH] = L""; bool fVerbose = false; int nCount = 0; __try { if (argc < 2 || argc > 4) { printf("\nUsage: Symchk [-v] [Binary] [Sym File]"); printf("\n[v] Verbose"); return; } nCount++; if (argv[nCount][0] == L'-' && argc > 3) { fVerbose = true; nCount++; } StrCpyNW(wszDllFileName, argv[nCount], MAX_NAME); nCount++; StrCpyNW(wszSymFileName, argv[nCount], MAX_NAME); if (CheckSymFile(wszDllFileName, wszSymFileName)) printf("\n Result: Sym File Matched"); } __except(1) { // do nothing, just don't pass it to the user. } return; }