internal byte[] GetResource(int[] Index) { UInt32 PEPointer = ByteOperations.ReadUInt32(Buffer, 0x3C); UInt16 OptionalHeaderSize = ByteOperations.ReadUInt16(Buffer, PEPointer + 0x14); UInt32 SectionTablePointer = PEPointer + 0x18 + OptionalHeaderSize; UInt16 SectionCount = ByteOperations.ReadUInt16(Buffer, PEPointer + 0x06); UInt32?ResourceSectionEntryPointer = null; for (int i = 0; i < SectionCount; i++) { string SectionName = ByteOperations.ReadAsciiString(Buffer, (UInt32)(SectionTablePointer + (i * 0x28)), 8); int e = SectionName.IndexOf('\0'); if (e >= 0) { SectionName = SectionName.Substring(0, e); } if (SectionName == ".rsrc") { ResourceSectionEntryPointer = (UInt32)(SectionTablePointer + (i * 0x28)); break; } } if (ResourceSectionEntryPointer == null) { throw new Exception("Resource-section not found"); } UInt32 ResourceRawSize = ByteOperations.ReadUInt32(Buffer, (UInt32)ResourceSectionEntryPointer + 0x10); UInt32 ResourceRawPointer = ByteOperations.ReadUInt32(Buffer, (UInt32)ResourceSectionEntryPointer + 0x14); UInt32 ResourceVirtualPointer = ByteOperations.ReadUInt32(Buffer, (UInt32)ResourceSectionEntryPointer + 0x0C); UInt32 p = ResourceRawPointer; for (int i = 0; i < Index.Length; i++) { UInt16 ResourceNamedEntryCount = ByteOperations.ReadUInt16(Buffer, p + 0x0c); UInt16 ResourceIdEntryCount = ByteOperations.ReadUInt16(Buffer, p + 0x0e); for (int j = ResourceNamedEntryCount; j < ResourceNamedEntryCount + ResourceIdEntryCount; j++) { UInt32 ResourceID = ByteOperations.ReadUInt32(Buffer, (UInt32)(p + 0x10 + (j * 8))); UInt32 NextPointer = ByteOperations.ReadUInt32(Buffer, (UInt32)(p + 0x10 + (j * 8) + 4)); if (ResourceID == (UInt32)Index[i]) { // Check high bit if (((NextPointer & 0x80000000) == 0) != (i == (Index.Length - 1))) { throw new Exception("Bad resource path"); } p = ResourceRawPointer + (NextPointer & 0x7fffffff); break; } } } UInt32 ResourceValuePointer = ByteOperations.ReadUInt32(Buffer, p) - ResourceVirtualPointer + ResourceRawPointer; UInt32 ResourceValueSize = ByteOperations.ReadUInt32(Buffer, p + 4); byte[] ResourceValue = new byte[ResourceValueSize]; Array.Copy(Buffer, ResourceValuePointer, ResourceValue, 0, ResourceValueSize); return(ResourceValue); }
public UInt32 GetChecksumOffset() { return(ByteOperations.ReadUInt32(Buffer, 0x3C) + +0x58); }
// TargetFilePath is relative to the root of the PatchDefinition // OutputFilePath can be null public static void AddPatch(string InputFilePath, string OutputFilePath, string PatchDefinitionName, string TargetVersionDescription, string TargetFilePath, string PathToVisualStudioWithWP8SDK, UInt32 VirtualAddress, CodeType CodeType, string ArmCodeFragment, string PatchDefintionsXmlPath) { SHA1Managed SHA = new SHA1Managed(); // Compile ARM code byte[] CompiledCode = null; if (VirtualAddress != 0) { CompiledCode = ArmCompiler.Compile(PathToVisualStudioWithWP8SDK, VirtualAddress, CodeType, ArmCodeFragment); } // Read original binary byte[] Binary = File.ReadAllBytes(InputFilePath); // Backup original checksum UInt32 ChecksumOffset = GetChecksumOffset(Binary); UInt32 OriginalChecksum = ByteOperations.ReadUInt32(Binary, ChecksumOffset); // Determine Raw Offset PeFile PeFile = new PeFile(Binary); UInt32 RawOffset = 0; if (VirtualAddress != 0) { RawOffset = PeFile.ConvertVirtualAddressToRawOffset(VirtualAddress); } // Add or replace patch string PatchDefintionsXml = File.ReadAllText(PatchDefintionsXmlPath); PatchEngine PatchEngine = new PatchEngine(PatchDefintionsXml); PatchDefinition PatchDefinition = PatchEngine.PatchDefinitions.Where(d => (string.Compare(d.Name, PatchDefinitionName, true) == 0)).FirstOrDefault(); if (PatchDefinition == null) { PatchDefinition = new PatchDefinition(); PatchDefinition.Name = PatchDefinitionName; PatchEngine.PatchDefinitions.Add(PatchDefinition); } TargetVersion TargetVersion = PatchDefinition.TargetVersions.Where(v => (string.Compare(v.Description, TargetVersionDescription, true) == 0)).FirstOrDefault(); if (TargetVersion == null) { TargetVersion = new TargetVersion(); TargetVersion.Description = TargetVersionDescription; PatchDefinition.TargetVersions.Add(TargetVersion); } TargetFile TargetFile = TargetVersion.TargetFiles.Where(f => ((f.Path != null) && (string.Compare(f.Path.TrimStart(new char[] { '\\' }), TargetFilePath.TrimStart(new char[] { '\\' }), true) == 0))).FirstOrDefault(); if (TargetFile == null) { TargetFile = new TargetFile(); TargetVersion.TargetFiles.Add(TargetFile); } TargetFile.Path = TargetFilePath; TargetFile.HashOriginal = SHA.ComputeHash(Binary); Patch Patch; if (VirtualAddress != 0) { Patch = TargetFile.Patches.Where(p => p.Address == RawOffset).FirstOrDefault(); if (Patch == null) { Patch = new Patch(); Patch.Address = RawOffset; TargetFile.Patches.Add(Patch); } Patch.OriginalBytes = new byte[CompiledCode.Length]; Buffer.BlockCopy(Binary, (int)RawOffset, Patch.OriginalBytes, 0, CompiledCode.Length); Patch.PatchedBytes = CompiledCode; } // Apply all patches foreach (Patch CurrentPatch in TargetFile.Patches) { Buffer.BlockCopy(CurrentPatch.PatchedBytes, 0, Binary, (int)CurrentPatch.Address, CurrentPatch.PatchedBytes.Length); } // Calculate checksum // This also modifies the binary // Original checksum is already backed up UInt32 Checksum = CalculateChecksum(Binary); // Add or replace checksum patch Patch = TargetFile.Patches.Where(p => p.Address == ChecksumOffset).FirstOrDefault(); if (Patch == null) { Patch = new Patch(); Patch.Address = ChecksumOffset; TargetFile.Patches.Add(Patch); } Patch.OriginalBytes = new byte[4]; ByteOperations.WriteUInt32(Patch.OriginalBytes, 0, OriginalChecksum); Patch.PatchedBytes = new byte[4]; ByteOperations.WriteUInt32(Patch.PatchedBytes, 0, Checksum); // Calculate hash for patched target file TargetFile.HashPatched = SHA.ComputeHash(Binary); // Write patched file if (OutputFilePath != null) { File.WriteAllBytes(OutputFilePath, Binary); } // Write PatchDefintions PatchEngine.WriteDefinitions(PatchDefintionsXmlPath); }
public PeFile(byte[] Buffer) { int P = 0; this.Buffer = Buffer; // Read MS-DOS header section DosHeader = MarshalBytesTo <IMAGE_DOS_HEADER>(Buffer, P); // MS-DOS magic number should read 'MZ' if (DosHeader.e_magic != 0x5a4d) { throw new InvalidOperationException("File is not a portable executable."); } // Read NT Headers P = (int)DosHeader.e_lfanew; NtHeaders.Signature = MarshalBytesTo <UInt32>(Buffer, P); // Make sure we have 'PE' in the pe signature if (NtHeaders.Signature != 0x4550) { throw new InvalidOperationException("Invalid portable executable signature in NT header."); } P += sizeof(UInt32); NtHeaders.FileHeader = MarshalBytesTo <IMAGE_FILE_HEADER>(Buffer, P); // Read optional headers P += Marshal.SizeOf(typeof(IMAGE_FILE_HEADER)); if (Is32bitAssembly()) { Load32bitOptionalHeaders(Buffer, P); ImageBase = NtHeaders.OptionalHeader32.ImageBase; EntryPoint = NtHeaders.OptionalHeader32.AddressOfEntryPoint; ExportDirectoryVirtualOffset = NtHeaders.OptionalHeader32.DataDirectory[0].VirtualAddress; ImportDirectoryVirtualOffset = NtHeaders.OptionalHeader32.DataDirectory[1].VirtualAddress; RuntimeDirectoryVirtualOffset = NtHeaders.OptionalHeader32.DataDirectory[3].VirtualAddress; RuntimeDirectorySize = NtHeaders.OptionalHeader32.DataDirectory[3].Size; } else { Load64bitOptionalHeaders(Buffer, P); ImageBase = NtHeaders.OptionalHeader64.ImageBase; EntryPoint = NtHeaders.OptionalHeader64.AddressOfEntryPoint; ExportDirectoryVirtualOffset = NtHeaders.OptionalHeader64.DataDirectory[0].VirtualAddress; ImportDirectoryVirtualOffset = NtHeaders.OptionalHeader64.DataDirectory[1].VirtualAddress; RuntimeDirectoryVirtualOffset = NtHeaders.OptionalHeader64.DataDirectory[3].VirtualAddress; RuntimeDirectorySize = NtHeaders.OptionalHeader64.DataDirectory[3].Size; } // Read Sections _sectionHeaders.ToList().ForEach(s => { byte[] RawCode = new byte[s.SizeOfRawData]; System.Buffer.BlockCopy(Buffer, (int)s.PointerToRawData, RawCode, 0, (int)s.SizeOfRawData); Sections.Add(new Section { Header = s, Buffer = RawCode, VirtualAddress = s.VirtualAddress + (UInt32)ImageBase, VirtualSize = s.Misc.VirtualSize, IsCode = ((s.Characteristics & (uint)Constants.SectionFlags.IMAGE_SCN_CNT_CODE) != 0) }); }); // Read Exports // TODO: Proper support for 64-bit files if (ExportDirectoryVirtualOffset != 0) { IMAGE_EXPORT_DIRECTORY ExportDirectory = MarshalBytesTo <IMAGE_EXPORT_DIRECTORY>(Buffer, (int)ConvertVirtualOffsetToRawOffset((uint)(ExportDirectoryVirtualOffset))); if (ExportDirectory.AddressOfNames != 0) { Section ExportsSection = GetSectionForVirtualAddress((uint)(ImageBase + ExportDirectory.AddressOfNames)); UInt32 OffsetNames = (UInt32)(ImageBase + ExportDirectory.AddressOfNames - ExportsSection.VirtualAddress); UInt32 OffsetOrdinals = (UInt32)(ImageBase + ExportDirectory.AddressOfNameOrdinals - ExportsSection.VirtualAddress); UInt32 OffsetFunctions = (UInt32)(ImageBase + ExportDirectory.AddressOfFunctions - ExportsSection.VirtualAddress); string[] ExportNames = new string[ExportDirectory.NumberOfNames]; UInt16[] Ordinals = new UInt16[ExportDirectory.NumberOfNames]; UInt32[] VirtualAddresses = new UInt32[ExportDirectory.NumberOfFunctions]; for (int i = 0; i < ExportDirectory.NumberOfNames; i++) { UInt32 NamesRVA = ByteOperations.ReadUInt32(ExportsSection.Buffer, (UInt32)(OffsetNames + (i * sizeof(UInt32)))); UInt32 NameOffset = (UInt32)(NamesRVA + ImageBase - ExportsSection.VirtualAddress); ExportNames[i] = ByteOperations.ReadAsciiString(ExportsSection.Buffer, NameOffset); Ordinals[i] = ByteOperations.ReadUInt16(ExportsSection.Buffer, (UInt32)(OffsetOrdinals + (i * sizeof(UInt16)))); } for (int i = 0; i < ExportDirectory.NumberOfFunctions; i++) { VirtualAddresses[i] = ByteOperations.ReadUInt32(ExportsSection.Buffer, (UInt32)(OffsetFunctions + (i * sizeof(UInt32)))); VirtualAddresses[i] -= (VirtualAddresses[i] % 2); // Round down for Thumb2 } for (int i = 0; i < ExportDirectory.NumberOfNames; i++) { Exports.Add(new FunctionDescriptor() { Name = ExportNames[i], VirtualAddress = (UInt32)(ImageBase + VirtualAddresses[Ordinals[i]]) }); } } } // Read Imports // TODO: Proper support for 64-bit files if (ImportDirectoryVirtualOffset != 0) { Section ImportsSection = GetSectionForVirtualAddress((uint)(ImageBase + ImportDirectoryVirtualOffset)); IMAGE_IMPORT_DESCRIPTOR ImportDirectory; do { ImportDirectory = MarshalBytesTo <IMAGE_IMPORT_DESCRIPTOR>(ImportsSection.Buffer, (int)(ImportDirectoryVirtualOffset - (ImportsSection.VirtualAddress - ImageBase))); if (ImportDirectory.OriginalFirstThunk != 0) { // ImportDirectory.OriginalFirstThunk is the VirtualOffset to an array of VirtualOffsets. They point to a struct with a word-value, followed by a zero-terminated ascii-string, which is the name of the import. // ImportDirectory.FirstThunk points to an array pointers which is the actual import table. UInt32 NameArrayOffset = ImportDirectory.OriginalFirstThunk - (ImportsSection.VirtualAddress - (UInt32)ImageBase); UInt32 NameOffset; int i = 0; do { NameOffset = ByteOperations.ReadUInt32(ImportsSection.Buffer, NameArrayOffset); if ((NameOffset < (ImportsSection.VirtualAddress - ImageBase)) || (NameOffset >= (ImportsSection.VirtualAddress + ImportsSection.VirtualSize - ImageBase))) { NameOffset = 0; // ImportDirectory.OriginalFirstThunk seems to contain Characteristics, not an offset to an array. } NameArrayOffset += sizeof(UInt32); if (NameOffset != 0) { string Name = ByteOperations.ReadAsciiString(ImportsSection.Buffer, NameOffset + 2 - (ImportsSection.VirtualAddress - (UInt32)ImageBase)); Imports.Add(new FunctionDescriptor() { Name = Name, VirtualAddress = ImportDirectory.FirstThunk + (UInt32)ImageBase + (UInt32)(i * sizeof(UInt32)) }); i++; } }while (NameOffset != 0); ImportDirectoryVirtualOffset += (UInt64)Marshal.SizeOf(typeof(IMAGE_IMPORT_DESCRIPTOR)); } }while (ImportDirectory.OriginalFirstThunk != 0); } // Read Runtime functions // TODO: Proper support for 64-bit files if (RuntimeDirectoryVirtualOffset != 0) { Section RuntimeSection = GetSectionForVirtualAddress((uint)(ImageBase + RuntimeDirectoryVirtualOffset)); RUNTIME_FUNCTION_32 RuntimeFunction; for (int i = 0; i < (RuntimeDirectorySize / Marshal.SizeOf(typeof(RUNTIME_FUNCTION_32))); i++) { RuntimeFunction = MarshalBytesTo <RUNTIME_FUNCTION_32>(RuntimeSection.Buffer, (int)(RuntimeDirectoryVirtualOffset - (RuntimeSection.VirtualAddress - ImageBase)) + (i * Marshal.SizeOf(typeof(RUNTIME_FUNCTION_32)))); RuntimeFunctions.Add(new FunctionDescriptor() { Name = null, VirtualAddress = (UInt32)(RuntimeFunction.RVAofBeginAddress + ImageBase) }); } } }
private static UInt32 GetChecksumOffset(byte[] PEFile) { return(ByteOperations.ReadUInt32(PEFile, 0x3C) + +0x58); }