|
|
/*++
Copyright (c) 1994 Microsoft Corporation
Module Name:
bindi.c
Abstract: Implementation for the BindImage API
Author:
Revision History:
--*/
#ifndef _STRSAFE_H_INCLUDED_
#include <strsafe.h>
#endif
typedef struct _BOUND_FORWARDER_REFS { struct _BOUND_FORWARDER_REFS *Next; ULONG TimeDateStamp; LPSTR ModuleName; } BOUND_FORWARDER_REFS, *PBOUND_FORWARDER_REFS;
typedef struct _IMPORT_DESCRIPTOR { struct _IMPORT_DESCRIPTOR *Next; LPSTR ModuleName; ULONG TimeDateStamp; USHORT NumberOfModuleForwarderRefs; PBOUND_FORWARDER_REFS Forwarders; } IMPORT_DESCRIPTOR, *PIMPORT_DESCRIPTOR;
typedef struct _BINDP_PARAMETERS { DWORD Flags; BOOLEAN fNoUpdate; BOOLEAN fNewImports; LPSTR ImageName; LPSTR DllPath; LPSTR SymbolPath; PIMAGEHLP_STATUS_ROUTINE StatusRoutine; } BINDP_PARAMETERS, *PBINDP_PARAMETERS;
BOOL BindpLookupThunk( PBINDP_PARAMETERS Parms, PIMAGE_THUNK_DATA ThunkName, PLOADED_IMAGE Image, PIMAGE_THUNK_DATA SnappedThunks, PIMAGE_THUNK_DATA FunctionAddress, PLOADED_IMAGE Dll, PIMAGE_EXPORT_DIRECTORY Exports, PIMPORT_DESCRIPTOR NewImport, LPSTR DllPath, PULONG *ForwarderChain );
PVOID BindpRvaToVa( PBINDP_PARAMETERS Parms, ULONG Rva, PLOADED_IMAGE Image );
ULONG64 BindpRvaToTargetVa64( PBINDP_PARAMETERS Parms, ULONG Rva, PLOADED_IMAGE Image );
ULONG BindpRvaToTargetVa32( PBINDP_PARAMETERS Parms, ULONG Rva, PLOADED_IMAGE Image );
VOID BindpWalkAndProcessImports( PBINDP_PARAMETERS Parms, PLOADED_IMAGE Image, LPSTR DllPath, PBOOL ImageModified );
BOOL BindImage( IN LPSTR ImageName, IN LPSTR DllPath, IN LPSTR SymbolPath ) { return BindImageEx( 0, ImageName, DllPath, SymbolPath, NULL ); }
UCHAR BindpCapturedModuleNames[4096]; LPSTR BindpEndCapturedModuleNames;
LPSTR BindpCaptureImportModuleName( LPSTR DllName ) { LPSTR s;
s = (LPSTR) BindpCapturedModuleNames; if (BindpEndCapturedModuleNames == NULL) { *s = '\0'; BindpEndCapturedModuleNames = s; }
while (*s) { if (!_stricmp(s, DllName)) { return s; }
s += strlen(s)+1; }
StringCchCopy(s, 4095 - (s - (LPSTR)BindpCapturedModuleNames), DllName); BindpEndCapturedModuleNames = s + strlen(s) + 1; *BindpEndCapturedModuleNames = '\0'; return s; }
PIMPORT_DESCRIPTOR BindpAddImportDescriptor( PBINDP_PARAMETERS Parms, PIMPORT_DESCRIPTOR *NewImportDescriptor, PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor, LPSTR ModuleName, PLOADED_IMAGE Dll ) { PIMPORT_DESCRIPTOR p, *pp;
if (!Parms->fNewImports) { return NULL; }
pp = NewImportDescriptor; while (p = *pp) { if (!_stricmp( p->ModuleName, ModuleName )) { return p; }
pp = &p->Next; } #ifdef STANDALONE_BIND
p = (PIMPORT_DESCRIPTOR) calloc( sizeof( *p ), 1); #else
p = (PIMPORT_DESCRIPTOR) MemAlloc( sizeof( *p ) ); #endif
if (p != NULL) { if (Dll != NULL) { p->TimeDateStamp = ((PIMAGE_NT_HEADERS32)Dll->FileHeader)->FileHeader.TimeDateStamp; } p->ModuleName = BindpCaptureImportModuleName( ModuleName ); *pp = p; } else if (Parms->StatusRoutine != NULL) { if (Parms->Flags & BIND_REPORT_64BIT_VA) ((PIMAGEHLP_STATUS_ROUTINE64)(Parms->StatusRoutine)) ( BindOutOfMemory, NULL, NULL, 0, sizeof( *p ) ); else (Parms->StatusRoutine)( BindOutOfMemory, NULL, NULL, 0, sizeof( *p ) ); }
return p; }
ULONG64 BindpAddForwarderReference( PBINDP_PARAMETERS Parms, LPSTR ImageName, LPSTR ImportName, PIMPORT_DESCRIPTOR NewImportDescriptor, LPSTR DllPath, PUCHAR ForwarderString, PBOOL BoundForwarder ) { CHAR DllName[ MAX_PATH + 1 ]; PUCHAR s; PLOADED_IMAGE Dll; ULONG cb; USHORT OrdinalNumber; USHORT HintIndex; ULONG ExportSize; PIMAGE_EXPORT_DIRECTORY Exports; ULONG64 ExportBase; PULONG NameTableBase; PUSHORT NameOrdinalTableBase; PULONG FunctionTableBase; LPSTR NameTableName; ULONG64 ForwardedAddress; PBOUND_FORWARDER_REFS p, *pp;
*BoundForwarder = FALSE; BindAnotherForwarder:
//
// A forwarder string looks like "dllname.apiname". See what we've got.
//
s = ForwarderString; while (*s && *s != '.') { s++; } if (*s != '.') { // Missing period - malformed.
return (ULONG64)ForwarderString; } cb = (ULONG) (s - ForwarderString); if (cb >= MAX_PATH) { // Name of dll is too long - malformed.
return (ULONG64)ForwarderString; } strncpy( DllName, (LPSTR) ForwarderString, cb ); DllName[ cb ] = '\0'; StringCchCat( DllName, MAX_PATH, ".DLL" );
//
// Got the dll name - try loading.
//
Dll = ImageLoad( DllName, DllPath ); if (!Dll) { // No luck - exit.
return (ULONG64)ForwarderString; }
//
// Look for exports in the loaded image.
//
Exports = (PIMAGE_EXPORT_DIRECTORY)ImageDirectoryEntryToData( Dll->MappedAddress, FALSE, IMAGE_DIRECTORY_ENTRY_EXPORT, &ExportSize ); if (!Exports) { // No luck - exit.
return (ULONG64)ForwarderString; }
//
// Advance past the '.' and let's see what the api name is.
//
s += 1;
if ( *s == '#' ) { // Binding for ordinal forwarders
OrdinalNumber = (atoi((PCHAR)s + 1)) - (USHORT)Exports->Base;
if (OrdinalNumber >= Exports->NumberOfFunctions) { return (ULONG64)ForwarderString; } } else { // Regular binding for named forwarders
OrdinalNumber = 0xFFFF; }
NameTableBase = (PULONG) BindpRvaToVa( Parms, Exports->AddressOfNames, Dll ); NameOrdinalTableBase = (PUSHORT) BindpRvaToVa( Parms, Exports->AddressOfNameOrdinals, Dll ); FunctionTableBase = (PULONG) BindpRvaToVa( Parms, Exports->AddressOfFunctions, Dll );
if (OrdinalNumber == 0xFFFF) { for ( HintIndex = 0; HintIndex < Exports->NumberOfNames; HintIndex++){ NameTableName = (LPSTR) BindpRvaToVa( Parms, NameTableBase[HintIndex], Dll ); if ( NameTableName ) { OrdinalNumber = NameOrdinalTableBase[HintIndex];
if (!strcmp((PCHAR)s, NameTableName)) { break; } } }
if (HintIndex >= Exports->NumberOfNames) { return (ULONG64)ForwarderString; } }
do { pp = &NewImportDescriptor->Forwarders;
// See if we've already added this dll to the list of forwarder dll's
while (p = *pp) { if (!_stricmp(DllName, p->ModuleName)) { break; }
pp = &p->Next; }
if (!p) {
// Nope - allocate a new record and add it to the list.
#ifdef STANDALONE_BIND
p = (PBOUND_FORWARDER_REFS) calloc( sizeof( *p ), 1 ); #else
p = (PBOUND_FORWARDER_REFS) MemAlloc( sizeof( *p ) ); #endif
if (!p) {
// Unable to allocate a new import descriptor - can't bind this one.
if (Parms->StatusRoutine) { if (Parms->Flags & BIND_REPORT_64BIT_VA) ((PIMAGEHLP_STATUS_ROUTINE64)(Parms->StatusRoutine)) ( BindOutOfMemory, NULL, NULL, 0, sizeof( *p ) ); else (Parms->StatusRoutine)( BindOutOfMemory, NULL, NULL, 0, sizeof( *p ) ); }
return (ULONG64)ForwarderString;
} else {
// Save the timestamp and module name
p->ModuleName = BindpCaptureImportModuleName( DllName ); p->TimeDateStamp = Dll->FileHeader->FileHeader.TimeDateStamp; *pp = p; NewImportDescriptor->NumberOfModuleForwarderRefs += 1; } }
// Convert to real address.
ForwardedAddress = FunctionTableBase[OrdinalNumber]; if (Dll->FileHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) { ForwardedAddress += ((PIMAGE_NT_HEADERS64)Dll->FileHeader)->OptionalHeader.ImageBase; } else { ForwardedAddress += ((PIMAGE_NT_HEADERS32)Dll->FileHeader)->OptionalHeader.ImageBase; }
if (Parms->StatusRoutine) { if (Parms->Flags & BIND_REPORT_64BIT_VA) ((PIMAGEHLP_STATUS_ROUTINE64)(Parms->StatusRoutine)) (BindForwarder64, ImageName, ImportName, ForwardedAddress, (ULONG_PTR)ForwarderString ); else (Parms->StatusRoutine)( BindForwarder, ImageName, ImportName, (ULONG_PTR)ForwardedAddress, (ULONG_PTR)ForwarderString ); }
//
// Calculate the inmemory export table for this dll to see if the forwarded
// address we have is inside the new export table. TRUE is passed for MappedAsImage
// parm to ImageDirectoryEntryToData so we can get a real VA.
//
ExportBase = (ULONG64)ImageDirectoryEntryToData(Dll->MappedAddress, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &ExportSize);
//
// Convert mapped virtual address to real virtual address.
//
ExportBase -= (ULONG64) Dll->MappedAddress;
if (Dll->FileHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) { ExportBase += ((PIMAGE_NT_HEADERS64)Dll->FileHeader)->OptionalHeader.ImageBase; } else { ExportBase += ((PIMAGE_NT_HEADERS32)Dll->FileHeader)->OptionalHeader.ImageBase; }
if ((ForwardedAddress >= ExportBase) && (ForwardedAddress < (ExportBase + ExportSize))) {
// Address is inside the export table - convert to string and try again.
ForwarderString = (PUCHAR) BindpRvaToVa(Parms, FunctionTableBase[OrdinalNumber],Dll); goto BindAnotherForwarder; } else { *BoundForwarder = TRUE; break; } } while (0);
return ForwardedAddress; }
PIMAGE_BOUND_IMPORT_DESCRIPTOR BindpCreateNewImportSection( PBINDP_PARAMETERS Parms, PIMPORT_DESCRIPTOR *NewImportDescriptor, PULONG NewImportsSize ) { ULONG cbString, cbStruct; PIMPORT_DESCRIPTOR p, *pp; PBOUND_FORWARDER_REFS p1, *pp1; LPSTR CapturedStrings; PIMAGE_BOUND_IMPORT_DESCRIPTOR NewImports, NewImport; PIMAGE_BOUND_FORWARDER_REF NewForwarder;
*NewImportsSize = 0; cbString = 0; cbStruct = 0; pp = NewImportDescriptor; while (p = *pp) { cbStruct += sizeof( IMAGE_BOUND_IMPORT_DESCRIPTOR ); pp1 = &p->Forwarders; while (p1 = *pp1) { cbStruct += sizeof( IMAGE_BOUND_FORWARDER_REF ); pp1 = &p1->Next; }
pp = &p->Next; } if (cbStruct == 0) { BindpEndCapturedModuleNames = NULL; return NULL; } cbStruct += sizeof(IMAGE_BOUND_IMPORT_DESCRIPTOR); // Room for terminating zero entry
cbString = (ULONG) (BindpEndCapturedModuleNames - (LPSTR) BindpCapturedModuleNames); BindpEndCapturedModuleNames = NULL; *NewImportsSize = cbStruct+((cbString + sizeof(ULONG) - 1) & ~(sizeof(ULONG)-1)); #ifdef STANDALONE_BIND
NewImports = (PIMAGE_BOUND_IMPORT_DESCRIPTOR) calloc( *NewImportsSize, 1 ); #else
NewImports = (PIMAGE_BOUND_IMPORT_DESCRIPTOR) MemAlloc( *NewImportsSize ); #endif
if (NewImports != NULL) { CapturedStrings = (LPSTR)NewImports + cbStruct; memcpy(CapturedStrings, BindpCapturedModuleNames, cbString);
NewImport = NewImports; pp = NewImportDescriptor; while (p = *pp) { NewImport->TimeDateStamp = p->TimeDateStamp; NewImport->OffsetModuleName = (USHORT)(cbStruct + (p->ModuleName - (LPSTR) BindpCapturedModuleNames)); NewImport->NumberOfModuleForwarderRefs = p->NumberOfModuleForwarderRefs;
NewForwarder = (PIMAGE_BOUND_FORWARDER_REF)(NewImport+1); pp1 = &p->Forwarders; while (p1 = *pp1) { NewForwarder->TimeDateStamp = p1->TimeDateStamp; NewForwarder->OffsetModuleName = (USHORT)(cbStruct + (p1->ModuleName - (LPSTR) BindpCapturedModuleNames)); NewForwarder += 1; pp1 = &p1->Next; } NewImport = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)NewForwarder;
pp = &p->Next; } } else if (Parms->StatusRoutine != NULL) { if (Parms->Flags & BIND_REPORT_64BIT_VA) ((PIMAGEHLP_STATUS_ROUTINE64)(Parms->StatusRoutine)) ( BindOutOfMemory, NULL, NULL, 0, *NewImportsSize ); else (Parms->StatusRoutine)( BindOutOfMemory, NULL, NULL, 0, *NewImportsSize ); }
pp = NewImportDescriptor; while ((p = *pp) != NULL) { *pp = p->Next; pp1 = &p->Forwarders; while ((p1 = *pp1) != NULL) { *pp1 = p1->Next; #ifdef STANDALONE_BIND
free(p1); #else
MemFree(p1); #endif
}
#ifdef STANDALONE_BIND
free(p); #else
MemFree(p); #endif
}
return NewImports; }
BOOL BindpExpandImageFileHeaders( PBINDP_PARAMETERS Parms, PLOADED_IMAGE Dll, ULONG NewSizeOfHeaders ) { HANDLE hMappedFile; LPVOID lpMappedAddress; DWORD dwFileSizeLow, dwOldFileSize; DWORD dwFileSizeHigh; DWORD dwSizeDelta; PIMAGE_SECTION_HEADER Section; ULONG SectionNumber; PIMAGE_DEBUG_DIRECTORY DebugDirectories; ULONG DebugDirectoriesSize; ULONG OldSizeOfHeaders; PIMAGE_FILE_HEADER FileHeader;
dwFileSizeLow = GetFileSize( Dll->hFile, &dwFileSizeHigh ); if (dwFileSizeLow == 0xFFFFFFFF || dwFileSizeHigh != 0) { return FALSE; }
FileHeader = &((PIMAGE_NT_HEADERS32)Dll->FileHeader)->FileHeader;
OldSizeOfHeaders = Dll->FileHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC ? ((PIMAGE_NT_HEADERS64)Dll->FileHeader)->OptionalHeader.SizeOfHeaders : ((PIMAGE_NT_HEADERS32)Dll->FileHeader)->OptionalHeader.SizeOfHeaders; dwOldFileSize = dwFileSizeLow; dwSizeDelta = NewSizeOfHeaders - OldSizeOfHeaders; dwFileSizeLow += dwSizeDelta;
hMappedFile = CreateFileMapping(Dll->hFile, NULL, PAGE_READWRITE, dwFileSizeHigh, dwFileSizeLow, NULL ); if (!hMappedFile) { return FALSE; }
FlushViewOfFile(Dll->MappedAddress, Dll->SizeOfImage); UnmapViewOfFile(Dll->MappedAddress); lpMappedAddress = MapViewOfFileEx(hMappedFile, FILE_MAP_WRITE, 0, 0, 0, Dll->MappedAddress ); if (!lpMappedAddress) { lpMappedAddress = MapViewOfFileEx(hMappedFile, FILE_MAP_WRITE, 0, 0, 0, 0 ); }
CloseHandle(hMappedFile);
if (lpMappedAddress != Dll->MappedAddress) { Dll->MappedAddress = (PUCHAR) lpMappedAddress; CalculateImagePtrs(Dll); FileHeader = &((PIMAGE_NT_HEADERS32)Dll->FileHeader)->FileHeader; }
if (Dll->SizeOfImage != dwFileSizeLow) { Dll->SizeOfImage = dwFileSizeLow; }
DebugDirectories = (PIMAGE_DEBUG_DIRECTORY)ImageDirectoryEntryToData( (PVOID)Dll->MappedAddress, FALSE, IMAGE_DIRECTORY_ENTRY_DEBUG, &DebugDirectoriesSize );
if (DebugDirectoryIsUseful(DebugDirectories, DebugDirectoriesSize)) { while (DebugDirectoriesSize != 0) { DebugDirectories->PointerToRawData += dwSizeDelta; DebugDirectories += 1; DebugDirectoriesSize -= sizeof( *DebugDirectories ); } }
if (Dll->FileHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) { ((PIMAGE_NT_HEADERS64)Dll->FileHeader)->OptionalHeader.SizeOfHeaders = NewSizeOfHeaders; } else { ((PIMAGE_NT_HEADERS32)Dll->FileHeader)->OptionalHeader.SizeOfHeaders = NewSizeOfHeaders; } if (FileHeader->PointerToSymbolTable != 0) { // Only adjust if it's already set
FileHeader->PointerToSymbolTable += dwSizeDelta; } Section = Dll->Sections; for (SectionNumber=0; SectionNumber<FileHeader->NumberOfSections; SectionNumber++) { if (Section->PointerToRawData != 0) { Section->PointerToRawData += dwSizeDelta; } if (Section->PointerToRelocations != 0) { Section->PointerToRelocations += dwSizeDelta; } if (Section->PointerToLinenumbers != 0) { Section->PointerToLinenumbers += dwSizeDelta; } Section += 1; }
memmove((LPSTR)lpMappedAddress + NewSizeOfHeaders, (LPSTR)lpMappedAddress + OldSizeOfHeaders, dwOldFileSize - OldSizeOfHeaders );
if (Parms->StatusRoutine != NULL) { if (Parms->Flags & BIND_REPORT_64BIT_VA) ((PIMAGEHLP_STATUS_ROUTINE64)(Parms->StatusRoutine)) ( BindExpandFileHeaders, Dll->ModuleName, NULL, 0, NewSizeOfHeaders); else (Parms->StatusRoutine)( BindExpandFileHeaders, Dll->ModuleName, NULL, 0, NewSizeOfHeaders ); }
return TRUE; }
BOOL BindImageEx( IN DWORD Flags, IN LPSTR ImageName, IN LPSTR DllPath, IN LPSTR SymbolPath, IN PIMAGEHLP_STATUS_ROUTINE StatusRoutine ) { BINDP_PARAMETERS Parms; LOADED_IMAGE LoadedImageBuffer; PLOADED_IMAGE LoadedImage; ULONG CheckSum; ULONG HeaderSum; BOOL fSymbolsAlreadySplit, fRC; SYSTEMTIME SystemTime; FILETIME LastWriteTime; BOOL ImageModified; DWORD OldChecksum; CHAR DebugFileName[ MAX_PATH + 1 ]; CHAR DebugFilePath[ MAX_PATH ]; PIMAGE_OPTIONAL_HEADER32 OptionalHeader32 = NULL; PIMAGE_OPTIONAL_HEADER64 OptionalHeader64 = NULL; PIMAGE_FILE_HEADER FileHeader;
Parms.Flags = Flags; if (Flags & BIND_NO_BOUND_IMPORTS) { Parms.fNewImports = FALSE; } else { Parms.fNewImports = TRUE; } if (Flags & BIND_NO_UPDATE) { Parms.fNoUpdate = TRUE; } else { Parms.fNoUpdate = FALSE; } Parms.ImageName = ImageName; Parms.DllPath = DllPath; Parms.SymbolPath = SymbolPath; Parms.StatusRoutine = StatusRoutine;
fRC = FALSE; // Assume we'll fail to bind
__try {
// Map and load the image
LoadedImage = &LoadedImageBuffer; memset( LoadedImage, 0, sizeof( *LoadedImage ) ); if (MapAndLoad( ImageName, DllPath, LoadedImage, TRUE, Parms.fNoUpdate )) { LoadedImage->ModuleName = ImageName;
//
// Now locate and walk through and process the images imports
//
if (LoadedImage->FileHeader != NULL && ((Flags & BIND_ALL_IMAGES) || (!LoadedImage->fSystemImage)) ) {
FileHeader = &((PIMAGE_NT_HEADERS32)LoadedImage->FileHeader)->FileHeader; OptionalHeadersFromNtHeaders((PIMAGE_NT_HEADERS32)LoadedImage->FileHeader, &OptionalHeader32, &OptionalHeader64);
if (OPTIONALHEADER(DllCharacteristics) & IMAGE_DLLCHARACTERISTICS_NO_BIND) { goto NoBind; }
{ DWORD dwDataSize; PVOID pData = ImageDirectoryEntryToData( LoadedImage->MappedAddress, FALSE, IMAGE_DIRECTORY_ENTRY_SECURITY, &dwDataSize );
if (pData || dwDataSize) { // Signed - can't bind it.
goto NoBind; }
pData = ImageDirectoryEntryToData( LoadedImage->MappedAddress, FALSE, IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR, &dwDataSize ); if (pData || dwDataSize) { // COR header found - see if it's strong signed or contains IL only
if ((((IMAGE_COR20_HEADER *)pData)->Flags & COMIMAGE_FLAGS_STRONGNAMESIGNED) || (((IMAGE_COR20_HEADER *)pData)->Flags & COMIMAGE_FLAGS_ILONLY)) { goto NoBind; } } }
BindpWalkAndProcessImports( &Parms, LoadedImage, DllPath, &ImageModified );
//
// If the file is being updated, then recompute the checksum.
// and update image and possibly stripped symbol file.
//
if (!Parms.fNoUpdate && ImageModified && (LoadedImage->hFile != INVALID_HANDLE_VALUE)) { // The image may have been moved as part of the growing it to add space for the
// bound imports. Recalculate the file and optional headers.
FileHeader = &((PIMAGE_NT_HEADERS32)LoadedImage->FileHeader)->FileHeader; OptionalHeadersFromNtHeaders((PIMAGE_NT_HEADERS32)LoadedImage->FileHeader, &OptionalHeader32, &OptionalHeader64); if ( (FileHeader->Characteristics & IMAGE_FILE_DEBUG_STRIPPED) && (SymbolPath != NULL) ) { PIMAGE_DEBUG_DIRECTORY DebugDirectories; ULONG DebugDirectoriesSize; PIMAGE_DEBUG_MISC MiscDebug;
fSymbolsAlreadySplit = TRUE; StringCchCopy( DebugFileName, MAX_PATH, ImageName ); DebugDirectories = (PIMAGE_DEBUG_DIRECTORY)ImageDirectoryEntryToData( LoadedImage->MappedAddress, FALSE, IMAGE_DIRECTORY_ENTRY_DEBUG, &DebugDirectoriesSize ); if (DebugDirectoryIsUseful(DebugDirectories, DebugDirectoriesSize)) { while (DebugDirectoriesSize != 0) { if (DebugDirectories->Type == IMAGE_DEBUG_TYPE_MISC) { MiscDebug = (PIMAGE_DEBUG_MISC) ((PCHAR)LoadedImage->MappedAddress + DebugDirectories->PointerToRawData ); StringCchCopy( DebugFileName, MAX_PATH, (PCHAR) MiscDebug->Data ); break; } else { DebugDirectories += 1; DebugDirectoriesSize -= sizeof( *DebugDirectories ); } } } } else { fSymbolsAlreadySplit = FALSE; }
OldChecksum = OPTIONALHEADER(CheckSum); CheckSumMappedFile( (PVOID)LoadedImage->MappedAddress, GetFileSize(LoadedImage->hFile, NULL), &HeaderSum, &CheckSum );
OPTIONALHEADER_LV(CheckSum) = CheckSum; FlushViewOfFile(LoadedImage->MappedAddress, LoadedImage->SizeOfImage);
if (fSymbolsAlreadySplit) { if ( UpdateDebugInfoFileEx(ImageName, SymbolPath, DebugFilePath, (PIMAGE_NT_HEADERS32)(LoadedImage->FileHeader), OldChecksum)) { if (GetLastError() == ERROR_INVALID_DATA) { if (Parms.StatusRoutine != NULL) { if (Parms.Flags & BIND_REPORT_64BIT_VA) ((PIMAGEHLP_STATUS_ROUTINE64)(Parms.StatusRoutine)) ( BindMismatchedSymbols, LoadedImage->ModuleName, NULL, 0, (ULONG_PTR)DebugFileName ); else (Parms.StatusRoutine)( BindMismatchedSymbols, LoadedImage->ModuleName, NULL, 0, (ULONG_PTR)DebugFileName ); } } } else { if (Parms.StatusRoutine != NULL) { if (Parms.Flags & BIND_REPORT_64BIT_VA) ((PIMAGEHLP_STATUS_ROUTINE64)(Parms.StatusRoutine)) ( BindSymbolsNotUpdated, LoadedImage->ModuleName, NULL, 0, (ULONG_PTR)DebugFileName ); else (Parms.StatusRoutine)( BindSymbolsNotUpdated, LoadedImage->ModuleName, NULL, 0, (ULONG_PTR)DebugFileName ); } } }
GetSystemTime(&SystemTime); if (SystemTimeToFileTime( &SystemTime, &LastWriteTime )) { SetFileTime( LoadedImage->hFile, NULL, NULL, &LastWriteTime ); } } }
NoBind: fRC = TRUE; } } __except (EXCEPTION_EXECUTE_HANDLER) { // Nothing to do...
}
if (LoadedImage->MappedAddress) { UnmapViewOfFile( LoadedImage->MappedAddress ); } if (LoadedImage->hFile != INVALID_HANDLE_VALUE) { CloseHandle( LoadedImage->hFile ); }
if (!(Flags & BIND_CACHE_IMPORT_DLLS)) { UnloadAllImages(); }
return (fRC); }
BOOL BindpLookupThunk64( PBINDP_PARAMETERS Parms, PIMAGE_THUNK_DATA64 ThunkName, PLOADED_IMAGE Image, PIMAGE_THUNK_DATA64 SnappedThunks, PIMAGE_THUNK_DATA64 FunctionAddress, PLOADED_IMAGE Dll, PIMAGE_EXPORT_DIRECTORY Exports, PIMPORT_DESCRIPTOR NewImport, LPSTR DllPath, PULONG *ForwarderChain ) { BOOL Ordinal; USHORT OrdinalNumber; PULONG NameTableBase; PUSHORT NameOrdinalTableBase; PULONG FunctionTableBase; PIMAGE_IMPORT_BY_NAME ImportName; USHORT HintIndex; LPSTR NameTableName; ULONG64 ExportsBase; ULONG ExportSize; UCHAR NameBuffer[ 32 ]; PIMAGE_OPTIONAL_HEADER64 OptionalHeader = NULL; PIMAGE_OPTIONAL_HEADER64 DllOptionalHeader = NULL;
NameTableBase = (PULONG) BindpRvaToVa( Parms, Exports->AddressOfNames, Dll ); NameOrdinalTableBase = (PUSHORT) BindpRvaToVa( Parms, Exports->AddressOfNameOrdinals, Dll ); FunctionTableBase = (PULONG) BindpRvaToVa( Parms, Exports->AddressOfFunctions, Dll );
if (!FunctionTableBase) { return FALSE; }
OptionalHeader = &((PIMAGE_NT_HEADERS64)Image->FileHeader)->OptionalHeader;
DllOptionalHeader = &((PIMAGE_NT_HEADERS64)Dll->FileHeader)->OptionalHeader;
//
// Determine if snap is by name, or by ordinal
//
Ordinal = (BOOL)IMAGE_SNAP_BY_ORDINAL64(ThunkName->u1.Ordinal);
if (Ordinal) { UCHAR szOrdinal[8]; OrdinalNumber = (USHORT)(IMAGE_ORDINAL64(ThunkName->u1.Ordinal) - Exports->Base); if ( (ULONG)OrdinalNumber >= Exports->NumberOfFunctions ) { return FALSE; } ImportName = (PIMAGE_IMPORT_BY_NAME)NameBuffer; StringCchCopy((PCHAR) ImportName->Name, 31, "Ordinal"); StringCchCat((PCHAR) ImportName->Name, 31, _ultoa((ULONG) OrdinalNumber, (LPSTR) szOrdinal, 16)); } else { ImportName = (PIMAGE_IMPORT_BY_NAME)BindpRvaToVa( Parms, (ULONG)(ULONG64)(ThunkName->u1.AddressOfData), Image ); if (!ImportName || !NameTableBase) { return FALSE; } //
// now check to see if the hint index is in range. If it
// is, then check to see if it matches the function at
// the hint. If all of this is true, then we can snap
// by hint. Otherwise need to scan the name ordinal table
//
OrdinalNumber = (USHORT)(Exports->NumberOfFunctions+1); HintIndex = ImportName->Hint; if ((ULONG)HintIndex < Exports->NumberOfNames ) { NameTableName = (LPSTR) BindpRvaToVa( Parms, NameTableBase[HintIndex], Dll ); if ( NameTableName ) { if ( !strcmp((PCHAR)ImportName->Name, NameTableName) ) { OrdinalNumber = NameOrdinalTableBase[HintIndex]; } } }
if ((ULONG)OrdinalNumber >= Exports->NumberOfFunctions) { for (HintIndex = 0; HintIndex < Exports->NumberOfNames; HintIndex++) { NameTableName = (LPSTR) BindpRvaToVa( Parms, NameTableBase[HintIndex], Dll ); if (NameTableName) { if (!strcmp( (PCHAR)ImportName->Name, NameTableName )) { OrdinalNumber = NameOrdinalTableBase[HintIndex]; break; } } }
if ((ULONG)OrdinalNumber >= Exports->NumberOfFunctions) { return FALSE; } } }
FunctionAddress->u1.Function = (ULONGLONG)(FunctionTableBase[OrdinalNumber] + DllOptionalHeader->ImageBase);
ExportsBase = (ULONG64)((ULONG_PTR)ImageDirectoryEntryToData(Dll->MappedAddress, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &ExportSize) - (ULONG_PTR)Dll->MappedAddress);
ExportsBase += DllOptionalHeader->ImageBase;
if ((FunctionAddress->u1.Function > ExportsBase) && (FunctionAddress->u1.Function < (ExportsBase + ExportSize))) { BOOL BoundForwarder;
BoundForwarder = FALSE; if (NewImport != NULL) { FunctionAddress->u1.ForwarderString = BindpAddForwarderReference(Parms, Image->ModuleName, (LPSTR) ImportName->Name, NewImport, DllPath, (PUCHAR) BindpRvaToVa( Parms, FunctionTableBase[OrdinalNumber], Dll ), &BoundForwarder ); }
if (!BoundForwarder) { **ForwarderChain = (ULONG) (FunctionAddress - SnappedThunks); *ForwarderChain = (ULONG *)&FunctionAddress->u1.Ordinal;
if (Parms->StatusRoutine != NULL) { if (Parms->Flags & BIND_REPORT_64BIT_VA) ((PIMAGEHLP_STATUS_ROUTINE64)(Parms->StatusRoutine)) ( BindForwarderNOT64, Image->ModuleName, Dll->ModuleName, (ULONG64)FunctionAddress->u1.Function, (ULONG_PTR)(ImportName->Name)); else (Parms->StatusRoutine)( BindForwarderNOT, Image->ModuleName, Dll->ModuleName, (ULONG_PTR)FunctionAddress->u1.Function, (ULONG_PTR)(ImportName->Name) ); } } } else { if (Parms->StatusRoutine != NULL) { if (Parms->Flags & BIND_REPORT_64BIT_VA) ((PIMAGEHLP_STATUS_ROUTINE64)(Parms->StatusRoutine)) ( BindImportProcedure64, Image->ModuleName, Dll->ModuleName, (ULONG64)FunctionAddress->u1.Function, (ULONG_PTR)(ImportName->Name) ); else (Parms->StatusRoutine)( BindImportProcedure, Image->ModuleName, Dll->ModuleName, (ULONG_PTR)FunctionAddress->u1.Function, (ULONG_PTR)(ImportName->Name) ); } }
return TRUE; } // BindpLookupThunk64
BOOL BindpLookupThunk32( PBINDP_PARAMETERS Parms, PIMAGE_THUNK_DATA32 ThunkName, PLOADED_IMAGE Image, PIMAGE_THUNK_DATA32 SnappedThunks, PIMAGE_THUNK_DATA32 FunctionAddress, PLOADED_IMAGE Dll, PIMAGE_EXPORT_DIRECTORY Exports, PIMPORT_DESCRIPTOR NewImport, LPSTR DllPath, PULONG *ForwarderChain ) { BOOL Ordinal; USHORT OrdinalNumber; PULONG NameTableBase; PUSHORT NameOrdinalTableBase; PULONG FunctionTableBase; PIMAGE_IMPORT_BY_NAME ImportName; USHORT HintIndex; LPSTR NameTableName; ULONG ExportsBase; ULONG ExportSize; UCHAR NameBuffer[ 32 ]; PIMAGE_OPTIONAL_HEADER32 OptionalHeader = NULL; PIMAGE_OPTIONAL_HEADER32 DllOptionalHeader = NULL;
NameTableBase = (PULONG) BindpRvaToVa( Parms, Exports->AddressOfNames, Dll ); NameOrdinalTableBase = (PUSHORT) BindpRvaToVa( Parms, Exports->AddressOfNameOrdinals, Dll ); FunctionTableBase = (PULONG) BindpRvaToVa( Parms, Exports->AddressOfFunctions, Dll );
if (!FunctionTableBase) { return FALSE; } OptionalHeader = &((PIMAGE_NT_HEADERS32)Image->FileHeader)->OptionalHeader;
DllOptionalHeader = &((PIMAGE_NT_HEADERS32)Dll->FileHeader)->OptionalHeader;
//
// Determine if snap is by name, or by ordinal
//
Ordinal = (BOOL)IMAGE_SNAP_BY_ORDINAL32(ThunkName->u1.Ordinal);
if (Ordinal) { UCHAR szOrdinal[8]; OrdinalNumber = (USHORT)(IMAGE_ORDINAL32(ThunkName->u1.Ordinal) - Exports->Base); if ( (ULONG)OrdinalNumber >= Exports->NumberOfFunctions ) { return FALSE; } ImportName = (PIMAGE_IMPORT_BY_NAME)NameBuffer; StringCchCopy((PCHAR) ImportName->Name, 31, "Ordinal"); StringCchCat((PCHAR) ImportName->Name, 31, _ultoa((ULONG) OrdinalNumber, (LPSTR) szOrdinal, 16)); } else { ImportName = (PIMAGE_IMPORT_BY_NAME)BindpRvaToVa( Parms, ThunkName->u1.AddressOfData, Image ); if (!ImportName || !NameTableBase) { return FALSE; }
//
// now check to see if the hint index is in range. If it
// is, then check to see if it matches the function at
// the hint. If all of this is true, then we can snap
// by hint. Otherwise need to scan the name ordinal table
//
OrdinalNumber = (USHORT)(Exports->NumberOfFunctions+1); HintIndex = ImportName->Hint; if ((ULONG)HintIndex < Exports->NumberOfNames ) { NameTableName = (LPSTR) BindpRvaToVa( Parms, NameTableBase[HintIndex], Dll ); if ( NameTableName ) { if ( !strcmp((PCHAR)ImportName->Name, NameTableName) ) { OrdinalNumber = NameOrdinalTableBase[HintIndex]; } } }
if ((ULONG)OrdinalNumber >= Exports->NumberOfFunctions) { for (HintIndex = 0; HintIndex < Exports->NumberOfNames; HintIndex++) { NameTableName = (LPSTR) BindpRvaToVa( Parms, NameTableBase[HintIndex], Dll ); if (NameTableName) { if (!strcmp( (PCHAR)ImportName->Name, NameTableName )) { OrdinalNumber = NameOrdinalTableBase[HintIndex]; break; } } }
if ((ULONG)OrdinalNumber >= Exports->NumberOfFunctions) { return FALSE; } } }
FunctionAddress->u1.Function = FunctionTableBase[OrdinalNumber] + DllOptionalHeader->ImageBase;
ExportsBase = (ULONG)((ULONG_PTR)ImageDirectoryEntryToData(Dll->MappedAddress, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &ExportSize) - (ULONG_PTR)Dll->MappedAddress);
ExportsBase += DllOptionalHeader->ImageBase;
if ((FunctionAddress->u1.Function > ExportsBase) && (FunctionAddress->u1.Function < (ExportsBase + ExportSize))) { BOOL BoundForwarder;
BoundForwarder = FALSE; if (NewImport != NULL) { FunctionAddress->u1.ForwarderString = (ULONG)BindpAddForwarderReference(Parms, Image->ModuleName, (LPSTR) ImportName->Name, NewImport, DllPath, (PUCHAR) BindpRvaToVa( Parms, FunctionTableBase[OrdinalNumber], Dll ), &BoundForwarder ); }
if (!BoundForwarder) { **ForwarderChain = (ULONG) (FunctionAddress - SnappedThunks); *ForwarderChain = (ULONG *)&FunctionAddress->u1.Ordinal;
if (Parms->StatusRoutine != NULL) { if (Parms->Flags & BIND_REPORT_64BIT_VA) ((PIMAGEHLP_STATUS_ROUTINE64)(Parms->StatusRoutine)) ( BindForwarderNOT64, Image->ModuleName, Dll->ModuleName, (ULONG64)FunctionAddress->u1.Function, (ULONG_PTR)(ImportName->Name)); else (Parms->StatusRoutine)( BindForwarderNOT, Image->ModuleName, Dll->ModuleName, (ULONG_PTR)FunctionAddress->u1.Function, (ULONG_PTR)(ImportName->Name) ); } } } else { if (Parms->StatusRoutine != NULL) { if (Parms->Flags & BIND_REPORT_64BIT_VA) ((PIMAGEHLP_STATUS_ROUTINE64)(Parms->StatusRoutine)) ( BindImportProcedure64, Image->ModuleName, Dll->ModuleName, (ULONG64)FunctionAddress->u1.Function, (ULONG_PTR)(ImportName->Name) ); else (Parms->StatusRoutine)( BindImportProcedure, Image->ModuleName, Dll->ModuleName, (ULONG_PTR)FunctionAddress->u1.Function, (ULONG_PTR)(ImportName->Name) ); } }
return TRUE; } // BindpLookupThunk32
PVOID BindpRvaToVa( PBINDP_PARAMETERS Parms, ULONG Rva, PLOADED_IMAGE Image ) { PVOID Va;
Va = ImageRvaToVa( Image->FileHeader, Image->MappedAddress, Rva, &Image->LastRvaSection ); if (!Va && Parms->StatusRoutine != NULL) { if (Parms->Flags & BIND_REPORT_64BIT_VA) ((PIMAGEHLP_STATUS_ROUTINE64)(Parms->StatusRoutine)) ( BindRvaToVaFailed, Image->ModuleName, NULL, (ULONG64)Rva, 0 ); else (Parms->StatusRoutine)( BindRvaToVaFailed, Image->ModuleName, NULL, (ULONG)Rva, 0 ); }
return Va; }
VOID SetIdataToRo( PLOADED_IMAGE Image ) { PIMAGE_SECTION_HEADER Section; ULONG i;
for(Section = Image->Sections,i=0; i<Image->NumberOfSections; i++,Section++) { if (!_stricmp((PCHAR) Section->Name, ".idata")) { if (Section->Characteristics & IMAGE_SCN_MEM_WRITE) { Section->Characteristics &= ~IMAGE_SCN_MEM_WRITE; Section->Characteristics |= IMAGE_SCN_MEM_READ; }
break; } } }
VOID BindpWalkAndProcessImports( PBINDP_PARAMETERS Parms, PLOADED_IMAGE Image, LPSTR DllPath, PBOOL ImageModified ) { ULONG ForwarderChainHead; PULONG ForwarderChain; ULONG ImportSize; ULONG ExportSize; PIMPORT_DESCRIPTOR NewImportDescriptorHead, NewImportDescriptor; PIMAGE_BOUND_IMPORT_DESCRIPTOR PrevNewImports, NewImports; ULONG PrevNewImportsSize, NewImportsSize; PIMAGE_IMPORT_DESCRIPTOR Imports; PIMAGE_EXPORT_DIRECTORY Exports; LPSTR ImportModule; PLOADED_IMAGE Dll; PIMAGE_THUNK_DATA32 tname32,tsnap32; PIMAGE_THUNK_DATA64 tname64,tsnap64; PIMAGE_THUNK_DATA32 ThunkNames32; PIMAGE_THUNK_DATA64 ThunkNames64; PIMAGE_THUNK_DATA32 SnappedThunks32; PIMAGE_THUNK_DATA64 SnappedThunks64; PIMAGE_IMPORT_BY_NAME ImportName; ULONG NumberOfThunks; ULONG i, cb; BOOL Ordinal, BindThunkFailed, NoErrors; USHORT OrdinalNumber; UCHAR NameBuffer[ 32 ]; BOOL fWin64Image = FALSE; PIMAGE_FILE_HEADER FileHeader; NoErrors = FALSE; *ImageModified = FALSE;
//
// Locate the import array for this image/dll
//
NewImportDescriptorHead = NULL; Imports = (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(Image->MappedAddress, FALSE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ImportSize); if (Imports == NULL) { //
// Nothing to bind if no imports
//
return; }
FileHeader = &((PIMAGE_NT_HEADERS32)Image->FileHeader)->FileHeader; fWin64Image = Image->FileHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC;
PrevNewImports = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(Image->MappedAddress, FALSE, IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT, &PrevNewImportsSize);
// If the user asked for an old style bind and there are new style bind records
// already in the image, zero them out first. This is the fix the problem where
// you bind on NT (creating new import descriptors), boot Win95 and bind there
// (creating old bind format), and then reboot to NT (the loader will only check
// the BOUND_IMPORT array.
if (PrevNewImports && (Parms->fNewImports == FALSE) && (Parms->fNoUpdate == FALSE )) { if (fWin64Image) { ((PIMAGE_NT_HEADERS64)Image->FileHeader)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT ].VirtualAddress = 0; ((PIMAGE_NT_HEADERS64)Image->FileHeader)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT ].Size = 0; } else { ((PIMAGE_NT_HEADERS32)Image->FileHeader)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT ].VirtualAddress = 0; ((PIMAGE_NT_HEADERS32)Image->FileHeader)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT ].Size = 0; } PrevNewImports = 0; PrevNewImportsSize = 0; *ImageModified = TRUE; }
//
// For each import record
//
for(;Imports;Imports++) { if ( !Imports->Name ) { break; }
//
// Locate the module being imported and load the dll
//
ImportModule = (LPSTR)BindpRvaToVa( Parms, Imports->Name, Image );
if (ImportModule) { Dll = ImageLoad( ImportModule, DllPath ); if (!Dll) { if (Parms->StatusRoutine != NULL) { if (Parms->Flags & BIND_REPORT_64BIT_VA) ((PIMAGEHLP_STATUS_ROUTINE64)(Parms->StatusRoutine)) (BindImportModuleFailed, Image->ModuleName, ImportModule, 0, 0 ); else (Parms->StatusRoutine)( BindImportModuleFailed, Image->ModuleName, ImportModule, 0, 0 ); } //
// Unless specifically told not to, generate the new style
// import descriptor.
//
BindpAddImportDescriptor(Parms, &NewImportDescriptorHead, Imports, ImportModule, Dll ); continue; }
if (Parms->StatusRoutine != NULL) { if (Parms->Flags & BIND_REPORT_64BIT_VA) ((PIMAGEHLP_STATUS_ROUTINE64)(Parms->StatusRoutine)) ( BindImportModule, Image->ModuleName, ImportModule, 0, 0 ); else (Parms->StatusRoutine)( BindImportModule, Image->ModuleName, ImportModule, 0, 0 ); } //
// If we can load the DLL, locate the export section and
// start snapping the thunks
//
Exports = (PIMAGE_EXPORT_DIRECTORY)ImageDirectoryEntryToData(Dll->MappedAddress, FALSE, IMAGE_DIRECTORY_ENTRY_EXPORT, &ExportSize); if ( !Exports ) { continue; }
//
// For old style bind, bypass the bind if it's already bound.
// New style binds s/b looked up in PrevNewImport.
//
if ( (Parms->fNewImports == FALSE) && Imports->TimeDateStamp && (Imports->TimeDateStamp == FileHeader->TimeDateStamp)) { continue; }
//
// Now we need to size our thunk table and
// allocate a buffer to hold snapped thunks. This is
// done instead of writting to the mapped view so that
// thunks are only updated if we find all the entry points
//
ThunkNames32 = (PIMAGE_THUNK_DATA32) BindpRvaToVa( Parms, Imports->OriginalFirstThunk, Image ); ThunkNames64 = (PIMAGE_THUNK_DATA64) ThunkNames32;
if (!ThunkNames32) { //
// Skip this one if no thunks
//
continue; }
if (fWin64Image ? !ThunkNames64->u1.Function : !ThunkNames32->u1.Function) { continue; }
//
// Unless specifically told not to, generate the new style
// import descriptor.
//
NewImportDescriptor = BindpAddImportDescriptor(Parms, &NewImportDescriptorHead, Imports, ImportModule, Dll );
NumberOfThunks = 0; if (fWin64Image) { tname64 = ThunkNames64; while (tname64->u1.AddressOfData) { NumberOfThunks++; tname64++; } #ifdef STANDALONE_BIND
SnappedThunks64 = (PIMAGE_THUNK_DATA64) calloc( NumberOfThunks*sizeof(*SnappedThunks64), 1 ); #else
SnappedThunks64 = (PIMAGE_THUNK_DATA64) MemAlloc( NumberOfThunks*sizeof(*SnappedThunks64) ); #endif
if ( !SnappedThunks64 ) { continue; }
tname64 = ThunkNames64; tsnap64 = SnappedThunks64; } else { tname32 = ThunkNames32; while (tname32->u1.AddressOfData) { NumberOfThunks++; tname32++; } #ifdef STANDALONE_BIND
SnappedThunks32 = (PIMAGE_THUNK_DATA32) calloc( NumberOfThunks*sizeof(*SnappedThunks32), 1 ); #else
SnappedThunks32 = (PIMAGE_THUNK_DATA32) MemAlloc( NumberOfThunks*sizeof(*SnappedThunks32) ); #endif
if ( !SnappedThunks32 ) { continue; }
tname32 = ThunkNames32; tsnap32 = SnappedThunks32; }
NoErrors = TRUE; ForwarderChainHead = (ULONG)-1; ForwarderChain = &ForwarderChainHead; for(i=0;i<NumberOfThunks;i++) { BindThunkFailed = FALSE; __try { if (fWin64Image) { if (!BindpLookupThunk64( Parms, tname64, Image, SnappedThunks64, tsnap64, Dll, Exports, NewImportDescriptor, DllPath, &ForwarderChain )) { BindThunkFailed = TRUE; } } else { if (!BindpLookupThunk32( Parms, tname32, Image, SnappedThunks32, tsnap32, Dll, Exports, NewImportDescriptor, DllPath, &ForwarderChain )) { BindThunkFailed = TRUE; } } } __except ( EXCEPTION_EXECUTE_HANDLER ) { BindThunkFailed = TRUE; }
if (BindThunkFailed) { if (NewImportDescriptor != NULL) { NewImportDescriptor->TimeDateStamp = 0; }
if (Parms->StatusRoutine != NULL) { Ordinal = fWin64Image ? (BOOL)IMAGE_SNAP_BY_ORDINAL64(tname64->u1.Ordinal) : (BOOL)IMAGE_SNAP_BY_ORDINAL32(tname32->u1.Ordinal); if (Ordinal) { UCHAR szOrdinal[8];
OrdinalNumber = (USHORT)(IMAGE_ORDINAL(fWin64Image ? tname64->u1.Ordinal : tname32->u1.Ordinal) - Exports->Base);
ImportName = (PIMAGE_IMPORT_BY_NAME)NameBuffer; // Can't use sprintf w/o dragging in more CRT support than we want... Must run on Win95.
StringCchCopy((PCHAR) ImportName->Name, 31, "Ordinal"); StringCchCat((PCHAR) ImportName->Name, 31, _ultoa((ULONG) OrdinalNumber, (LPSTR)szOrdinal, 16)); } else { ImportName = (PIMAGE_IMPORT_BY_NAME)BindpRvaToVa( Parms, (ULONG)(ULONG_PTR)( fWin64Image ? (tname64->u1.AddressOfData) : (tname32->u1.AddressOfData)), Image ); }
if (Parms->Flags & BIND_REPORT_64BIT_VA) ((PIMAGEHLP_STATUS_ROUTINE64)(Parms->StatusRoutine)) ( BindImportProcedureFailed, Image->ModuleName, Dll->ModuleName, (ULONG64) fWin64Image ? tsnap64->u1.Function : tsnap32->u1.Function, (ULONG_PTR)(ImportName->Name) ); else (Parms->StatusRoutine)( BindImportProcedureFailed, Image->ModuleName, Dll->ModuleName, (ULONG_PTR) (fWin64Image ? tsnap64->u1.Function : tsnap32->u1.Function), (ULONG_PTR)(ImportName->Name) ); }
break; }
if (fWin64Image) { tname64++; tsnap64++; } else { tname32++; tsnap32++; } }
tname32 = (PIMAGE_THUNK_DATA32) BindpRvaToVa( Parms, Imports->FirstThunk, Image ); tname64 = (PIMAGE_THUNK_DATA64) tname32;
if ( !tname32 ) { NoErrors = FALSE; }
//
// If we were able to locate all of the entrypoints in the
// target dll, then copy the snapped thunks into the image,
// update the time and date stamp, and flush the image to
// disk
//
if ( NoErrors && Parms->fNoUpdate == FALSE ) { if (ForwarderChainHead != -1) { *ImageModified = TRUE; *ForwarderChain = -1; } if (Imports->ForwarderChain != ForwarderChainHead) { Imports->ForwarderChain = ForwarderChainHead; *ImageModified = TRUE; } if (fWin64Image) { cb = NumberOfThunks*sizeof(*SnappedThunks64); if (memcmp(tname64,SnappedThunks64,cb)) { MoveMemory(tname64,SnappedThunks64,cb); *ImageModified = TRUE; } } else { cb = NumberOfThunks*sizeof(*SnappedThunks32); if (memcmp(tname32,SnappedThunks32,cb)) { MoveMemory(tname32,SnappedThunks32,cb); *ImageModified = TRUE; } } if (NewImportDescriptorHead == NULL) { if (Imports->TimeDateStamp != FileHeader->TimeDateStamp) { Imports->TimeDateStamp = FileHeader->TimeDateStamp; *ImageModified = TRUE; } } else if (Imports->TimeDateStamp != 0xFFFFFFFF) { Imports->TimeDateStamp = 0xFFFFFFFF; *ImageModified = TRUE; } }
#ifdef STANDALONE_BIND
fWin64Image ? free(SnappedThunks64) : free(SnappedThunks32); #else
fWin64Image ? MemFree(SnappedThunks64) : MemFree(SnappedThunks32); #endif
} }
NewImports = BindpCreateNewImportSection(Parms, &NewImportDescriptorHead, &NewImportsSize); if ((PrevNewImportsSize != NewImportsSize) || memcmp( PrevNewImports, NewImports, NewImportsSize)) { *ImageModified = TRUE; }
if (!*ImageModified) { return; }
if (Parms->StatusRoutine != NULL) { if (Parms->Flags & BIND_REPORT_64BIT_VA) ((PIMAGEHLP_STATUS_ROUTINE64)(Parms->StatusRoutine)) ( BindImageModified, Image->ModuleName, NULL, 0, 0 ); else (Parms->StatusRoutine)( BindImageModified, Image->ModuleName, NULL, 0, 0 ); }
if (NewImports != NULL) { ULONG cbFreeFile, cbFreeHeaders, OffsetHeaderFreeSpace, cbFreeSpaceOnDisk;
if (NoErrors && Parms->fNoUpdate == FALSE) { if (fWin64Image) { ((PIMAGE_NT_HEADERS64)Image->FileHeader)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT ].VirtualAddress = 0; ((PIMAGE_NT_HEADERS64)Image->FileHeader)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT ].Size = 0; } else { ((PIMAGE_NT_HEADERS32)Image->FileHeader)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT ].VirtualAddress = 0; ((PIMAGE_NT_HEADERS32)Image->FileHeader)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT ].Size = 0; } } OffsetHeaderFreeSpace = GetImageUnusedHeaderBytes( Image, &cbFreeFile ); cbFreeHeaders = Image->Sections->VirtualAddress - (fWin64Image ? ((PIMAGE_NT_HEADERS64)Image->FileHeader)->OptionalHeader.SizeOfHeaders : ((PIMAGE_NT_HEADERS32)Image->FileHeader)->OptionalHeader.SizeOfHeaders) + cbFreeFile;
// FreeSpace on Disk may be larger that FreeHeaders in the headers (the linker
// can start the first section on a page boundary already)
cbFreeSpaceOnDisk = Image->Sections->PointerToRawData - (fWin64Image ? ((PIMAGE_NT_HEADERS64)Image->FileHeader)->OptionalHeader.SizeOfHeaders : ((PIMAGE_NT_HEADERS32)Image->FileHeader)->OptionalHeader.SizeOfHeaders) + cbFreeFile;
if (NewImportsSize > cbFreeFile) { if (NewImportsSize > cbFreeHeaders) { if (Parms->StatusRoutine != NULL) { if (Parms->Flags & BIND_REPORT_64BIT_VA) ((PIMAGEHLP_STATUS_ROUTINE64)(Parms->StatusRoutine)) ( BindNoRoomInImage, Image->ModuleName, NULL, 0, 0 ); else (Parms->StatusRoutine)( BindNoRoomInImage, Image->ModuleName, NULL, 0, 0 ); } NoErrors = FALSE; } else if (NoErrors && (Parms->fNoUpdate == FALSE)) { if (NewImportsSize <= cbFreeSpaceOnDisk) {
// There's already space on disk. Just adjust the header size.
if (fWin64Image) { ((PIMAGE_NT_HEADERS64)Image->FileHeader)->OptionalHeader.SizeOfHeaders = (((PIMAGE_NT_HEADERS64)Image->FileHeader)->OptionalHeader.SizeOfHeaders - cbFreeFile + NewImportsSize + ((PIMAGE_NT_HEADERS64)Image->FileHeader)->OptionalHeader.FileAlignment - 1) & ~(((PIMAGE_NT_HEADERS64)Image->FileHeader)->OptionalHeader.FileAlignment - 1); } else { ((PIMAGE_NT_HEADERS32)Image->FileHeader)->OptionalHeader.SizeOfHeaders = (((PIMAGE_NT_HEADERS32)Image->FileHeader)->OptionalHeader.SizeOfHeaders - cbFreeFile + NewImportsSize + ((PIMAGE_NT_HEADERS32)Image->FileHeader)->OptionalHeader.FileAlignment - 1) & ~(((PIMAGE_NT_HEADERS32)Image->FileHeader)->OptionalHeader.FileAlignment - 1); }
} else {
NoErrors = BindpExpandImageFileHeaders( Parms, Image, ((fWin64Image ? ((PIMAGE_NT_HEADERS64)Image->FileHeader)->OptionalHeader.SizeOfHeaders : ((PIMAGE_NT_HEADERS32)Image->FileHeader)->OptionalHeader.SizeOfHeaders) - cbFreeFile + NewImportsSize + (fWin64Image ? ((PIMAGE_NT_HEADERS64)Image->FileHeader)->OptionalHeader.FileAlignment - 1 : ((PIMAGE_NT_HEADERS32)Image->FileHeader)->OptionalHeader.FileAlignment - 1) ) & ~( fWin64Image ? ((PIMAGE_NT_HEADERS64)Image->FileHeader)->OptionalHeader.FileAlignment - 1 : ((PIMAGE_NT_HEADERS32)Image->FileHeader)->OptionalHeader.FileAlignment - 1 ) ); // Expand may have remapped the image. Recalc the header ptrs.
FileHeader = &((PIMAGE_NT_HEADERS32)Image->FileHeader)->FileHeader; } } }
if (Parms->StatusRoutine != NULL) { if (Parms->Flags & BIND_REPORT_64BIT_VA) ((PIMAGEHLP_STATUS_ROUTINE64)(Parms->StatusRoutine)) ( BindImageComplete, Image->ModuleName, NULL, (ULONG64)NewImports, NoErrors ); else (Parms->StatusRoutine)( BindImageComplete, Image->ModuleName, NULL, (ULONG_PTR)NewImports, NoErrors ); }
if (NoErrors && Parms->fNoUpdate == FALSE) { if (fWin64Image) { ((PIMAGE_NT_HEADERS64)Image->FileHeader)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT ].VirtualAddress = OffsetHeaderFreeSpace; ((PIMAGE_NT_HEADERS64)Image->FileHeader)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT ].Size = NewImportsSize; } else { ((PIMAGE_NT_HEADERS32)Image->FileHeader)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT ].VirtualAddress = OffsetHeaderFreeSpace; ((PIMAGE_NT_HEADERS32)Image->FileHeader)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT ].Size = NewImportsSize; } memcpy( (LPSTR)(Image->MappedAddress) + OffsetHeaderFreeSpace, NewImports, NewImportsSize ); }
#ifdef STANDALONE_BIND
free(NewImports); #else
MemFree(NewImports); #endif
}
if (NoErrors && Parms->fNoUpdate == FALSE) { SetIdataToRo( Image ); } }
DWORD GetImageUnusedHeaderBytes( PLOADED_IMAGE LoadedImage, LPDWORD SizeUnusedHeaderBytes ) { DWORD OffsetFirstUnusedHeaderByte; DWORD i; DWORD OffsetHeader; PIMAGE_NT_HEADERS NtHeaders = LoadedImage->FileHeader;
//
// this calculates an offset, not an address, so DWORD is correct
//
OffsetFirstUnusedHeaderByte = (DWORD) (((LPSTR)NtHeaders - (LPSTR)LoadedImage->MappedAddress) + (FIELD_OFFSET( IMAGE_NT_HEADERS, OptionalHeader ) + NtHeaders->FileHeader.SizeOfOptionalHeader + (NtHeaders->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER) ) ) );
if (LoadedImage->FileHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) { PIMAGE_OPTIONAL_HEADER64 OptionalHeader = (PIMAGE_OPTIONAL_HEADER64)&LoadedImage->FileHeader->OptionalHeader; for ( i=0; i < OptionalHeader->NumberOfRvaAndSizes; i++ ) { OffsetHeader = OptionalHeader->DataDirectory[i].VirtualAddress; if (OffsetHeader < OptionalHeader->SizeOfHeaders) { if (OffsetHeader >= OffsetFirstUnusedHeaderByte) { if (i == IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG) { PIMAGE_LOAD_CONFIG_DIRECTORY pd = (PIMAGE_LOAD_CONFIG_DIRECTORY)((ULONG_PTR)LoadedImage->FileHeader + OffsetHeader); if (pd->Size) { OffsetFirstUnusedHeaderByte = OffsetHeader + pd->Size; } else { OffsetFirstUnusedHeaderByte = OffsetHeader + OptionalHeader->DataDirectory[i].Size; } } else { OffsetFirstUnusedHeaderByte = OffsetHeader + OptionalHeader->DataDirectory[i].Size; } } } } *SizeUnusedHeaderBytes = OptionalHeader->SizeOfHeaders - OffsetFirstUnusedHeaderByte; } else { PIMAGE_OPTIONAL_HEADER32 OptionalHeader = (PIMAGE_OPTIONAL_HEADER32)&LoadedImage->FileHeader->OptionalHeader; for ( i=0; i < OptionalHeader->NumberOfRvaAndSizes; i++ ) { OffsetHeader = OptionalHeader->DataDirectory[i].VirtualAddress; if (OffsetHeader < OptionalHeader->SizeOfHeaders) { if (OffsetHeader >= OffsetFirstUnusedHeaderByte) { if (i == IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG) { PIMAGE_LOAD_CONFIG_DIRECTORY pd = (PIMAGE_LOAD_CONFIG_DIRECTORY)((ULONG_PTR)LoadedImage->FileHeader + OffsetHeader); if (pd->Size) { OffsetFirstUnusedHeaderByte = OffsetHeader + pd->Size; } else { OffsetFirstUnusedHeaderByte = OffsetHeader + OptionalHeader->DataDirectory[i].Size; } } else { OffsetFirstUnusedHeaderByte = OffsetHeader + OptionalHeader->DataDirectory[i].Size; } } } } *SizeUnusedHeaderBytes = OptionalHeader->SizeOfHeaders - OffsetFirstUnusedHeaderByte; }
return OffsetFirstUnusedHeaderByte; }
|