235 lines
7 KiB
C++
235 lines
7 KiB
C++
|
|
||
|
// 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 <windows.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <sys\stat.h>
|
||
|
#include <string.h>
|
||
|
#include <shlwapi.h>
|
||
|
#include "symres.h"
|
||
|
#include <dbghelp.h>
|
||
|
|
||
|
#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;
|
||
|
}
|
||
|
|