You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1799 lines
70 KiB
1799 lines
70 KiB
/*++
|
|
|
|
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;
|
|
}
|