From 880c9c8f4cd964a8b5eaffb824703367303a3d11 Mon Sep 17 00:00:00 2001 From: n0p <0x90@n0p.cc> Date: Sun, 4 Aug 2013 23:11:21 +0200 Subject: Added correct output file for example main. --- SectionDoubleP_output.txt | 444 ++++++++++++++++------------------------------ 1 file changed, 151 insertions(+), 293 deletions(-) diff --git a/SectionDoubleP_output.txt b/SectionDoubleP_output.txt index 5a0e48d..5599fd8 100644 --- a/SectionDoubleP_output.txt +++ b/SectionDoubleP_output.txt @@ -1,294 +1,152 @@ -""" Tested with pefile 1.2.10. - - An implementation to push or pop a section header to the section table of a PE file. - For further information refer to the docstrings of pop_back/push_back. - - by n0p -""" +Information on every section after two sections have been added: +[IMAGE_SECTION_HEADER] +0x1F8 0x0 Name: .text +0x200 0x8 Misc: 0x53371 +0x200 0x8 Misc_PhysicalAddress: 0x53371 +0x200 0x8 Misc_VirtualSize: 0x53371 +0x204 0xC VirtualAddress: 0x1000 +0x208 0x10 SizeOfRawData: 0x54000 +0x20C 0x14 PointerToRawData: 0x1000 +0x210 0x18 PointerToRelocations: 0x0 +0x214 0x1C PointerToLinenumbers: 0x0 +0x218 0x20 NumberOfRelocations: 0x0 +0x21A 0x22 NumberOfLinenumbers: 0x0 +0x21C 0x24 Characteristics: 0x60000020 +[IMAGE_SECTION_HEADER] +0x220 0x0 Name: .rdata +0x228 0x8 Misc: 0x1B23E +0x228 0x8 Misc_PhysicalAddress: 0x1B23E +0x228 0x8 Misc_VirtualSize: 0x1B23E +0x22C 0xC VirtualAddress: 0x55000 +0x230 0x10 SizeOfRawData: 0x1C000 +0x234 0x14 PointerToRawData: 0x55000 +0x238 0x18 PointerToRelocations: 0x0 +0x23C 0x1C PointerToLinenumbers: 0x0 +0x240 0x20 NumberOfRelocations: 0x0 +0x242 0x22 NumberOfLinenumbers: 0x0 +0x244 0x24 Characteristics: 0x40000040 +[IMAGE_SECTION_HEADER] +0x248 0x0 Name: .data +0x250 0x8 Misc: 0x7E04 +0x250 0x8 Misc_PhysicalAddress: 0x7E04 +0x250 0x8 Misc_VirtualSize: 0x7E04 +0x254 0xC VirtualAddress: 0x71000 +0x258 0x10 SizeOfRawData: 0x1000 +0x25C 0x14 PointerToRawData: 0x71000 +0x260 0x18 PointerToRelocations: 0x0 +0x264 0x1C PointerToLinenumbers: 0x0 +0x268 0x20 NumberOfRelocations: 0x0 +0x26A 0x22 NumberOfLinenumbers: 0x0 +0x26C 0x24 Characteristics: 0xC0000040 +[IMAGE_SECTION_HEADER] +0x270 0x0 Name: .rsrc +0x278 0x8 Misc: 0x3B90 +0x278 0x8 Misc_PhysicalAddress: 0x3B90 +0x278 0x8 Misc_VirtualSize: 0x3B90 +0x27C 0xC VirtualAddress: 0x79000 +0x280 0x10 SizeOfRawData: 0x4000 +0x284 0x14 PointerToRawData: 0x72000 +0x288 0x18 PointerToRelocations: 0x0 +0x28C 0x1C PointerToLinenumbers: 0x0 +0x290 0x20 NumberOfRelocations: 0x0 +0x292 0x22 NumberOfLinenumbers: 0x0 +0x294 0x24 Characteristics: 0x40000040 +[IMAGE_SECTION_HEADER] +0x298 0x0 Name: .NewSec +0x2A0 0x8 Misc: 0x6 +0x2A0 0x8 Misc_PhysicalAddress: 0x6 +0x2A0 0x8 Misc_VirtualSize: 0x6 +0x2A4 0xC VirtualAddress: 0x7D000 +0x2A8 0x10 SizeOfRawData: 0x1000 +0x2AC 0x14 PointerToRawData: 0x76000 +0x2B0 0x18 PointerToRelocations: 0x0 +0x2B4 0x1C PointerToLinenumbers: 0x0 +0x2B8 0x20 NumberOfRelocations: 0x0 +0x2BA 0x22 NumberOfLinenumbers: 0x0 +0x2BC 0x24 Characteristics: 0x60000020 +[IMAGE_SECTION_HEADER] +0x2C0 0x0 Name: .NewSec +0x2C8 0x8 Misc: 0x6 +0x2C8 0x8 Misc_PhysicalAddress: 0x6 +0x2C8 0x8 Misc_VirtualSize: 0x6 +0x2CC 0xC VirtualAddress: 0x7E000 +0x2D0 0x10 SizeOfRawData: 0x1000 +0x2D4 0x14 PointerToRawData: 0x77000 +0x2D8 0x18 PointerToRelocations: 0x0 +0x2DC 0x1C PointerToLinenumbers: 0x0 +0x2E0 0x20 NumberOfRelocations: 0x0 +0x2E2 0x22 NumberOfLinenumbers: 0x0 +0x2E4 0x24 Characteristics: 0x60000020 +The instructions at the beginning of the last section: +jmp 0x44d4df +nop -import pefile, pydasm, sys - -class SectionDoublePError(Exception): - pass - -class SectionDoubleP: - def __init__(self, pe): - self.pe = pe - - def __adjust_optional_header(self): - """ Recalculates the SizeOfImage, SizeOfCode, SizeOfInitializedData and - SizeOfUninitializedData of the optional header. - """ - - # SizeOfImage = ((VirtualAddress + VirtualSize) of the new last section) - self.pe.OPTIONAL_HEADER.SizeOfImage = (self.pe.sections[-1].VirtualAddress + - self.pe.sections[-1].Misc_VirtualSize) - - self.pe.OPTIONAL_HEADER.SizeOfCode = 0 - self.pe.OPTIONAL_HEADER.SizeOfInitializedData = 0 - self.pe.OPTIONAL_HEADER.SizeOfUninitializedData = 0 - - # Recalculating the sizes by iterating over every section and checking if - # the appropriate characteristics are set. - for section in self.pe.sections: - if section.Characteristics & 0x00000020: - # Section contains code. - self.pe.OPTIONAL_HEADER.SizeOfCode += section.SizeOfRawData - if section.Characteristics & 0x00000040: - # Section contains initialized data. - self.pe.OPTIONAL_HEADER.SizeOfInitializedData += section.SizeOfRawData - if section.Characteristics & 0x00000080: - # Section contains uninitialized data. - self.pe.OPTIONAL_HEADER.SizeOfUninitializedData += section.SizeOfRawData - - def __add_header_space(self): - """ To make space for a new section header a buffer filled with nulls is added at the - end of the headers. The buffer has the size of one file alignment. - The data between the last section header and the end of the headers is copied to - the new space (everything moved by the size of one file alignment). If any data - directory entry points to the moved data the pointer is adjusted. - """ - - FileAlignment = self.pe.OPTIONAL_HEADER.FileAlignment - SizeOfHeaders = self.pe.OPTIONAL_HEADER.SizeOfHeaders - - data = '\x00' * FileAlignment - - # Adding the null buffer. - self.pe.__data__ = (self.pe.__data__[:SizeOfHeaders] + data + - self.pe.__data__[SizeOfHeaders + len(data):]) - - section_table_offset = (self.pe.DOS_HEADER.e_lfanew + 4 + - self.pe.FILE_HEADER.sizeof() + self.pe.FILE_HEADER.SizeOfOptionalHeader) - - # Copying the data between the last section header and SizeOfHeaders to the newly allocated - # space. - offset_new_section = section_table_offset + self.pe.FILE_HEADER.NumberOfSections*0x28 - size = SizeOfHeaders - offset_new_section - data = self.pe.get_data(offset_new_section, size) - self.pe.set_bytes_at_offset(offset_new_section + FileAlignment, data) - - # Checking data directories if anything points to the space between the last section header - # and the former SizeOfHeaders. If that's the case the pointer is increased by FileAlignment. - for dir in self.pe.OPTIONAL_HEADER.DATA_DIRECTORY: - if offset_new_section < dir.VirtualAddress and dir.VirtualAddress < SizeOfHeaders: - dir.VirtualAddress += FileAlignment - - self.pe.OPTIONAL_HEADER.SizeOfHeaders += FileAlignment - - # The raw addresses of the sections are adjusted. - section_raw_address = section_table_offset + 0x14 - for section in self.pe.sections: - self.pe.set_dword_at_offset(section_raw_address, section.PointerToRawData+FileAlignment) - section_raw_address += 0x28 - - self.pe.parse_sections(section_table_offset) - - def __is_null_data(self, data): - """ Checks if the given data contains just null bytes. - """ - - for char in data: - if char != '\x00': - return False - return True - - def pop_back(self): - """ Removes the last section of the section table. - Deletes the section header in the section table, the data of the section in the file, - pops the last section in the sections list of pefile and adjusts the sizes in the - optional header. - """ - - # Checking if there are any sections to pop. - if ( self.pe.FILE_HEADER.NumberOfSections > 0 - and self.pe.FILE_HEADER.NumberOfSections == len(self.pe.sections)): - - # Stripping the data of the section from the file. - if self.pe.sections[-1].SizeOfRawData != 0: - self.pe.__data__ = self.pe.__data__[:-self.pe.sections[-1].SizeOfRawData] - - # Overwriting the section header in the binary with nulls. - # Getting the address of the section table and manually overwriting - # the header with nulls unfortunally didn't work out. - self.pe.sections[-1].Name = '\x00'*8 - self.pe.sections[-1].Misc_VirtualSize = 0x00000000 - self.pe.sections[-1].VirtualAddress = 0x00000000 - self.pe.sections[-1].SizeOfRawData = 0x00000000 - self.pe.sections[-1].PointerToRawData = 0x00000000 - self.pe.sections[-1].PointerToRelocations = 0x00000000 - self.pe.sections[-1].PointerToLinenumbers = 0x00000000 - self.pe.sections[-1].NumberOfRelocations = 0x0000 - self.pe.sections[-1].NumberOfLinenumbers = 0x0000 - self.pe.sections[-1].Characteristics = 0x00000000 - - self.pe.sections.pop() - - self.pe.FILE_HEADER.NumberOfSections -=1 - - self.__adjust_optional_header() - else: - raise SectionDoublePError("There's no section to pop.") - - def push_back(self, Name=".NewSec", VirtualSize=0x00000000, VirtualAddress=0x00000000, - RawSize=0x00000000, RawAddress=0x00000000, RelocAddress=0x00000000, - Linenumbers=0x00000000, RelocationsNumber=0x0000, LinenumbersNumber=0x0000, - Characteristics=0xE00000E0, Data=""): - """ Adds the section, specified by the functions parameters, at the end of the section - table. - If the space to add an additional section header is insufficient, a buffer is inserted - after SizeOfHeaders. Data between the last section header and the end of SizeOfHeaders - is copied to +1 FileAlignment. Data directory entries pointing to this data are fixed. - - A call with no parameters creates the same section header as LordPE does. But for the - binary to be executable without errors a VirtualSize > 0 has to be set. - - If a RawSize > 0 is set or Data is given the data gets aligned to the FileAlignment and - is attached at the end of the file. - """ - - if self.pe.FILE_HEADER.NumberOfSections == len(self.pe.sections): - - FileAlignment = self.pe.OPTIONAL_HEADER.FileAlignment - SectionAlignment = self.pe.OPTIONAL_HEADER.SectionAlignment - - if len(Name) > 8: - raise SectionDoublePError("The name is too long for a section.") - - if ( VirtualAddress < (self.pe.sections[-1].Misc_VirtualSize + - self.pe.sections[-1].VirtualAddress) - or VirtualAddress % SectionAlignment != 0): - - if (self.pe.sections[-1].Misc_VirtualSize % SectionAlignment) != 0: - VirtualAddress = \ - (self.pe.sections[-1].VirtualAddress + self.pe.sections[-1].Misc_VirtualSize - - (self.pe.sections[-1].Misc_VirtualSize % SectionAlignment) + SectionAlignment) - else: - VirtualAddress = \ - (self.pe.sections[-1].VirtualAddress + self.pe.sections[-1].Misc_VirtualSize) - - if VirtualSize < len(Data): - VirtualSize = len(Data) - - if (len(Data) % FileAlignment) != 0: - # Padding the data of the section. - Data += '\x00' * (FileAlignment - (len(Data) % FileAlignment)) - - if RawSize != len(Data): - if ( RawSize > len(Data) - and (RawSize % FileAlignment) == 0): - Data += '\x00' * (RawSize - (len(Data) % RawSize)) - else: - RawSize = len(Data) - - - section_table_offset = (self.pe.DOS_HEADER.e_lfanew + 4 + - self.pe.FILE_HEADER.sizeof() + self.pe.FILE_HEADER.SizeOfOptionalHeader) - - # If the new section header exceeds the SizeOfHeaders there won't be enough space - # for an additional section header. Besides that it's checked if the 0x28 bytes - # (size of one section header) after the last current section header are filled - # with nulls/ are free to use. - if ( self.pe.OPTIONAL_HEADER.SizeOfHeaders < - section_table_offset + (self.pe.FILE_HEADER.NumberOfSections+1)*0x28 - or not self.__is_null_data(self.pe.get_data(section_table_offset + - (self.pe.FILE_HEADER.NumberOfSections)*0x28, 0x28))): - - # Checking if more space can be added. - if self.pe.OPTIONAL_HEADER.SizeOfHeaders < 0x1000: - - self.__add_header_space() - print "Additional space to add a new section header was allocated." - else: - raise SectionDoublePError("No more space can be added for the section header.") - - - # The validity check of RawAddress is done after space for a new section header may - # have been added because if space had been added the PointerToRawData of the previous - # section would have changed. - if (RawAddress != (self.pe.sections[-1].PointerToRawData + - self.pe.sections[-1].SizeOfRawData)): - RawAddress = \ - (self.pe.sections[-1].PointerToRawData + self.pe.sections[-1].SizeOfRawData) - - - # Appending the data of the new section to the file. - if len(Data) > 0: - self.pe.__data__ = self.pe.__data__[:] + Data - - section_offset = section_table_offset + self.pe.FILE_HEADER.NumberOfSections*0x28 - - # Manually writing the data of the section header to the file. - self.pe.set_bytes_at_offset(section_offset, Name) - self.pe.set_dword_at_offset(section_offset+0x08, VirtualSize) - self.pe.set_dword_at_offset(section_offset+0x0C, VirtualAddress) - self.pe.set_dword_at_offset(section_offset+0x10, RawSize) - self.pe.set_dword_at_offset(section_offset+0x14, RawAddress) - self.pe.set_dword_at_offset(section_offset+0x18, RelocAddress) - self.pe.set_dword_at_offset(section_offset+0x1C, Linenumbers) - self.pe.set_word_at_offset(section_offset+0x20, RelocationsNumber) - self.pe.set_word_at_offset(section_offset+0x22, LinenumbersNumber) - self.pe.set_dword_at_offset(section_offset+0x24, Characteristics) - - self.pe.FILE_HEADER.NumberOfSections +=1 - - # Parsing the section table of the file again to add the new section to the sections - # list of pefile. - self.pe.parse_sections(section_table_offset) - - self.__adjust_optional_header() - else: - raise SectionDoublePError("The NumberOfSections specified in the file header and the " + - "size of the sections list of pefile don't match.") - -def print_section_info(pe): - for section in pe.sections: - print section - - # If you don't have pydasm installed comment the rest of the function out. - print "The instructions at the beginning of the last section:" - - ep = pe.sections[-1].VirtualAddress - ep_ava = ep+pe.OPTIONAL_HEADER.ImageBase - data = pe.get_memory_mapped_image()[ep:ep+6] - offset = 0 - while offset < len(data): - i = pydasm.get_instruction(data[offset:], pydasm.MODE_32) - print pydasm.get_instruction_string(i, pydasm.FORMAT_INTEL, ep_ava+offset) - offset += i.length - -def main(argv): - pe = pefile.PE("putty.exe") - - sections = SectionDoubleP(pe) - - # JMP 0044C4DF - # NOP - # 0x0044C4DF is the entry point of putty.exe (at least of my version) when it's mapped at - # 0x00400000. - data="\xE9\xDA\xF4\xFC\xFF\x90" - - try: - # Characteristics: Executable as code, Readable, Contains executable code - sections.push_back(Characteristics=0x60000020, Data=data) - sections.push_back(Characteristics=0x60000020, Data=data) - except SectionDoublePError as e: - print e - - print "Information on every section after two sections have been added:" - print_section_info(pe) - - try: - sections.pop_back() - except SectionDoublePError as e: - print e - - print "\nInformation on every section after one of the added sections has been removed:" - print_section_info(pe) - - pe.OPTIONAL_HEADER.AddressOfEntryPoint = pe.sections[-1].VirtualAddress - - pe.write(filename="putty - modded.exe") - -if __name__ == '__main__': - main(sys.argv[1:]) +Information on every section after one of the added sections has been removed: +[IMAGE_SECTION_HEADER] +0x1F8 0x0 Name: .text +0x200 0x8 Misc: 0x53371 +0x200 0x8 Misc_PhysicalAddress: 0x53371 +0x200 0x8 Misc_VirtualSize: 0x53371 +0x204 0xC VirtualAddress: 0x1000 +0x208 0x10 SizeOfRawData: 0x54000 +0x20C 0x14 PointerToRawData: 0x1000 +0x210 0x18 PointerToRelocations: 0x0 +0x214 0x1C PointerToLinenumbers: 0x0 +0x218 0x20 NumberOfRelocations: 0x0 +0x21A 0x22 NumberOfLinenumbers: 0x0 +0x21C 0x24 Characteristics: 0x60000020 +[IMAGE_SECTION_HEADER] +0x220 0x0 Name: .rdata +0x228 0x8 Misc: 0x1B23E +0x228 0x8 Misc_PhysicalAddress: 0x1B23E +0x228 0x8 Misc_VirtualSize: 0x1B23E +0x22C 0xC VirtualAddress: 0x55000 +0x230 0x10 SizeOfRawData: 0x1C000 +0x234 0x14 PointerToRawData: 0x55000 +0x238 0x18 PointerToRelocations: 0x0 +0x23C 0x1C PointerToLinenumbers: 0x0 +0x240 0x20 NumberOfRelocations: 0x0 +0x242 0x22 NumberOfLinenumbers: 0x0 +0x244 0x24 Characteristics: 0x40000040 +[IMAGE_SECTION_HEADER] +0x248 0x0 Name: .data +0x250 0x8 Misc: 0x7E04 +0x250 0x8 Misc_PhysicalAddress: 0x7E04 +0x250 0x8 Misc_VirtualSize: 0x7E04 +0x254 0xC VirtualAddress: 0x71000 +0x258 0x10 SizeOfRawData: 0x1000 +0x25C 0x14 PointerToRawData: 0x71000 +0x260 0x18 PointerToRelocations: 0x0 +0x264 0x1C PointerToLinenumbers: 0x0 +0x268 0x20 NumberOfRelocations: 0x0 +0x26A 0x22 NumberOfLinenumbers: 0x0 +0x26C 0x24 Characteristics: 0xC0000040 +[IMAGE_SECTION_HEADER] +0x270 0x0 Name: .rsrc +0x278 0x8 Misc: 0x3B90 +0x278 0x8 Misc_PhysicalAddress: 0x3B90 +0x278 0x8 Misc_VirtualSize: 0x3B90 +0x27C 0xC VirtualAddress: 0x79000 +0x280 0x10 SizeOfRawData: 0x4000 +0x284 0x14 PointerToRawData: 0x72000 +0x288 0x18 PointerToRelocations: 0x0 +0x28C 0x1C PointerToLinenumbers: 0x0 +0x290 0x20 NumberOfRelocations: 0x0 +0x292 0x22 NumberOfLinenumbers: 0x0 +0x294 0x24 Characteristics: 0x40000040 +[IMAGE_SECTION_HEADER] +0x298 0x0 Name: .NewSec +0x2A0 0x8 Misc: 0x6 +0x2A0 0x8 Misc_PhysicalAddress: 0x6 +0x2A0 0x8 Misc_VirtualSize: 0x6 +0x2A4 0xC VirtualAddress: 0x7D000 +0x2A8 0x10 SizeOfRawData: 0x1000 +0x2AC 0x14 PointerToRawData: 0x76000 +0x2B0 0x18 PointerToRelocations: 0x0 +0x2B4 0x1C PointerToLinenumbers: 0x0 +0x2B8 0x20 NumberOfRelocations: 0x0 +0x2BA 0x22 NumberOfLinenumbers: 0x0 +0x2BC 0x24 Characteristics: 0x60000020 +The instructions at the beginning of the last section: +jmp 0x44c4df +nop \ No newline at end of file -- cgit v1.2.3