private static UInt32 CalculateChecksum(byte[] PEFile) { UInt32 Checksum = 0; UInt32 Hi; // Clear file checksum ByteOperations.WriteUInt32(PEFile, GetChecksumOffset(PEFile), 0); for (UInt32 i = 0; i < ((UInt32)PEFile.Length & 0xfffffffe); i += 2) { Checksum += ByteOperations.ReadUInt16(PEFile, i); Hi = Checksum >> 16; if (Hi != 0) { Checksum = Hi + (Checksum & 0xFFFF); } } if ((PEFile.Length % 2) != 0) { Checksum += (UInt32)ByteOperations.ReadUInt8(PEFile, (UInt32)PEFile.Length - 1); Hi = Checksum >> 16; if (Hi != 0) { Checksum = Hi + (Checksum & 0xFFFF); } } Checksum += (UInt32)PEFile.Length; // Write file checksum ByteOperations.WriteUInt32(PEFile, GetChecksumOffset(PEFile), Checksum); return(Checksum); }
internal Version GetProductVersion() { byte[] version = GetResource(new int[] { (int)ResourceType.RT_VERSION, 1, 1033 }); // RT_VERSION format: // https://msdn.microsoft.com/en-us/library/windows/desktop/ms647001(v=vs.85).aspx // https://msdn.microsoft.com/en-us/library/windows/desktop/ms646997(v=vs.85).aspx UInt32 FixedFileInfoPointer = 0x28; UInt16 Major = ByteOperations.ReadUInt16(version, FixedFileInfoPointer + 0x12); UInt16 Minor = ByteOperations.ReadUInt16(version, FixedFileInfoPointer + 0x10); UInt16 Build = ByteOperations.ReadUInt16(version, FixedFileInfoPointer + 0x16); UInt16 Revision = ByteOperations.ReadUInt16(version, FixedFileInfoPointer + 0x14); return(new Version(Major, Minor, Build, Revision)); }
internal UInt32 CalculateChecksum() { UInt32 Checksum = 0; UInt32 Hi; // Clear file checksum // ByteOperations.WriteUInt32(PEFile, GetChecksumOffset(), 0); UInt32 ChecksumOffset = GetChecksumOffset(); for (UInt32 i = 0; i < ((UInt32)Buffer.Length & 0xfffffffe); i += 2) { if ((i < ChecksumOffset) || (i >= (ChecksumOffset + 4))) { Checksum += ByteOperations.ReadUInt16(Buffer, i); } Hi = Checksum >> 16; if (Hi != 0) { Checksum = Hi + (Checksum & 0xFFFF); } } if ((Buffer.Length % 2) != 0) { Checksum += (UInt32)ByteOperations.ReadUInt8(Buffer, (UInt32)Buffer.Length - 1); Hi = Checksum >> 16; if (Hi != 0) { Checksum = Hi + (Checksum & 0xFFFF); } } Checksum += (UInt32)Buffer.Length; // Write file checksum // ByteOperations.WriteUInt32(Buffer, GetChecksumOffset(), Checksum); return(Checksum); }
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 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) }); } } }