예제 #1
0
        public PEReader(BinaryReader reader)
        {
            // Reset reader position, just in case
            reader.BaseStream.Seek(0, SeekOrigin.Begin);

            // Read MS-DOS header section
            _dosHeader = MarshalBytesTo <IMAGE_DOS_HEADER>(reader);

            // MS-DOS magic number should read 'MZ'
            if (_dosHeader.e_magic != 0x5a4d)
            {
                throw new InvalidOperationException("File is not a portable executable.");
            }

            // Skip MS-DOS stub and seek reader to NT Headers
            reader.BaseStream.Seek(_dosHeader.e_lfanew, SeekOrigin.Begin);

            // Read NT Headers
            _ntHeaders.Signature = MarshalBytesTo <UInt32>(reader);

            // Make sure we have 'PE' in the pe signature
            if (_ntHeaders.Signature != 0x4550)
            {
                throw new InvalidOperationException("Invalid portable executable signature in NT header.");
            }

            _ntHeaders.FileHeader = MarshalBytesTo <IMAGE_FILE_HEADER>(reader);

            // Read optional headers
            if (Is32bitAssembly())
            {
                Load32bitOptionalHeaders(reader);
            }
            else
            {
                Load64bitOptionalHeaders(reader);
            }

            // Read section data
            foreach (IMAGE_SECTION_HEADER header in _sectionHeaders)
            {
                // Skip to beginning of a section
                reader.BaseStream.Seek(header.PointerToRawData, SeekOrigin.Begin);

                // Read section data... and do something with it
                byte[] sectiondata = reader.ReadBytes((int)header.SizeOfRawData);
            }
        }
예제 #2
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)
                    });
                }
            }
        }