/// <summary> /// 重定位表的处理 /// </summary> /// <param name="pPEHeader"></param> private unsafe void ReLocation(IMAGE_NT_HEADERS *pPEHeader) { #if _WIN64 Int64 iDelta = (Int64)((Int64)this.mModuleHandle - (Int64)pPEHeader->OptionalHeader.ImageBase); #else Int32 iDelta = (Int32)this.mModuleHandle - (Int32)pPEHeader->OptionalHeader.ImageBase; #endif if (iDelta == 0) { return; } #if _WIN64 IMAGE_BASE_RELOCATION *pRelocation = (IMAGE_BASE_RELOCATION *)((IntPtr)((Int64)this.mModuleHandle + (Int64)pPEHeader->OptionalHeader.GetDirectory(IMAGE_DIRECTORY_ENTRY.IMAGE_DIRECTORY_ENTRY_BASERELOC).VirtualAddress)); while (pRelocation->VirtualAddress > 0 && pRelocation->SizeOfBlock > 0) { UInt16 *pLocData = (UInt16 *)((IntPtr)pRelocation + sizeof(IMAGE_BASE_RELOCATION)); var iNumberOfReloc = (pRelocation->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / 2; for (Int32 i = 0; i < iNumberOfReloc; i++) { if ((pLocData[i] & 0xFFFF) / 0x1000 == Win32API.IMAGE_REL_BASED_HIGHLOW) { UInt32 *lpPoint = (UInt32 *)((IntPtr)((Int64)this.mModuleHandle + (Int64)pRelocation->VirtualAddress + (pLocData[i] & 0xFFF))); * lpPoint += (UInt32)iDelta; } else if ((pLocData[i] & 0xFFFF) / 0x1000 == Win32API.IMAGE_REL_BASED_DIR64) { UInt64 *lpPoint = (UInt64 *)((IntPtr)((Int64)this.mModuleHandle + (Int64)pRelocation->VirtualAddress + (pLocData[i] & 0xFFF))); * lpPoint += (UInt64)iDelta; } } pRelocation = (IMAGE_BASE_RELOCATION *)((IntPtr)((Int64)((IntPtr)pRelocation) + (Int64)pRelocation->SizeOfBlock)); } #else IMAGE_BASE_RELOCATION *pRelocation = (IMAGE_BASE_RELOCATION *)(this.mModuleHandle + (Int32)pPEHeader->OptionalHeader.GetDirectory(IMAGE_DIRECTORY_ENTRY.IMAGE_DIRECTORY_ENTRY_BASERELOC).VirtualAddress); while (pRelocation->VirtualAddress > 0 && pRelocation->SizeOfBlock > 0) { UInt16 *pLocData = (UInt16 *)((IntPtr)pRelocation + sizeof(IMAGE_BASE_RELOCATION)); var iNumberOfReloc = (pRelocation->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / 2; for (Int32 i = 0; i < iNumberOfReloc; i++) { if ((pLocData[i] & 0xFFFF) / 0x1000 == Win32API.IMAGE_REL_BASED_HIGHLOW) { UInt32 *lpPoint = (UInt32 *)(this.mModuleHandle + (Int32)pRelocation->VirtualAddress + (pLocData[i] & 0xFFF)); * lpPoint += (UInt32)iDelta; } } pRelocation = (IMAGE_BASE_RELOCATION *)((IntPtr)pRelocation + (Int32)pRelocation->SizeOfBlock); } #endif }
private void PerformBaseRelocation(uint delta) { if (delta == 0) { return; } int imageSizeOfBaseRelocation = Marshal.SizeOf(typeof(IMAGE_BASE_RELOCATION)); IMAGE_DATA_DIRECTORY *directory = &this.headers->OptionalHeader.BaseRelocationTable; if (directory->Size > 0) { IMAGE_BASE_RELOCATION *relocation = (IMAGE_BASE_RELOCATION *)(this.codeBase + directory->VirtualAddress); while (relocation->VirtualAdress > 0) { byte * dest = this.codeBase + relocation->VirtualAdress; ushort *relInfo = (ushort *)((byte *)relocation + imageSizeOfBaseRelocation); for (int i = 0; i < ((relocation->SizeOfBlock - imageSizeOfBaseRelocation) / 2); i++, relInfo++) { uint *patchAddrHL; BasedRelocationType type; int offset; // the upper 4 bits define the type of relocation type = (BasedRelocationType)(*relInfo >> 12); // the lower 12 bits define the offset offset = *relInfo & 0xfff; switch (type) { case BasedRelocationType.IMAGE_REL_BASED_ABSOLUTE: break; case BasedRelocationType.IMAGE_REL_BASED_HIGHLOW: patchAddrHL = (uint *)(dest + offset); *patchAddrHL += delta; break; default: break; } } // advance to next relocation block relocation = (IMAGE_BASE_RELOCATION *)(((byte *)relocation) + relocation->SizeOfBlock); } } }
private void PerformBaseRelocation(Image image, long delta) { IMAGE_DATA_DIRECTORY directory = Environment.Is64BitProcess ? image.OptionalHeader64->BaseRelocationTable : image.OptionalHeader32->BaseRelocationTable; if (directory.Size == 0) { return; } IMAGE_BASE_RELOCATION *relocation = (IMAGE_BASE_RELOCATION *)(image.BasePtr + directory.VirtualAddress); while (relocation->VirtualAddress > 0) { ApplyRelocationBlock(image, delta, relocation); relocation = (IMAGE_BASE_RELOCATION *)((byte *)relocation + relocation->BlockSizeInclusive); } }
private void ApplyRelocationBlock(Image image, long delta, IMAGE_BASE_RELOCATION *relocation) { byte * dest = image.BasePtr + relocation->VirtualAddress; ushort *relocationInfo = (ushort *)((byte *)relocation + sizeof(IMAGE_BASE_RELOCATION)); for (int i = 0; i < (relocation->BlockSizeInclusive - sizeof(IMAGE_BASE_RELOCATION)) / 2; i++, relocationInfo++) { RelocationType type = (RelocationType)(*relocationInfo >> 12); int offset = *relocationInfo & 0xFFF; switch (type) { case RelocationType.Absolute: // Skip relocation; break; case RelocationType.HighLow: // Change complete 32-bit address. int *patchAddressHighLow = (int *)(dest + offset); if ((byte *)patchAddressHighLow < image.BasePtr || (byte *)patchAddressHighLow > image.BasePtr + image.Size) { throw new LoadFailedException("This DLL is damaged; relocation table references an illegal 32-bit offset."); } *patchAddressHighLow += (int)delta; break; case RelocationType.Dir64: // Change complete 64-bit address. long *patchAddress64 = (long *)(dest + offset); if ((byte *)patchAddress64 < image.BasePtr || (byte *)patchAddress64 > image.BasePtr + image.Size) { throw new LoadFailedException("This DLL is damaged; relocation table references an illegal 64-bit offset."); } *patchAddress64 += delta; break; default: throw new LoadFailedException(string.Format("This DLL requires unsupported address-relocation type {0} ({1})", type, (int)type)); } } }