Exemple #1
0
        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);
        }
Exemple #2
0
 public UInt32 GetChecksumOffset()
 {
     return(ByteOperations.ReadUInt32(Buffer, 0x3C) + +0x58);
 }
Exemple #3
0
        // 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);
        }
Exemple #4
0
        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)
                    });
                }
            }
        }
Exemple #5
0
 private static UInt32 GetChecksumOffset(byte[] PEFile)
 {
     return(ByteOperations.ReadUInt32(PEFile, 0x3C) + +0x58);
 }