diff --git a/tests/test_parse_pe.py b/tests/test_parse_pe.py index 853a891..91b1ed0 100644 --- a/tests/test_parse_pe.py +++ b/tests/test_parse_pe.py @@ -91,9 +91,6 @@ def test_pe_parsing_strange_optional_header_size(tmp_path, proc32): # Also check that section retrieval works (as its position is based on OptionalHeader Size) assert set(s.name for s in mod.pe.sections) == {".text", ".data", ".l1"} - - - # Make a test from current_process parsing ? def test_pe_parsing_dotnet32_process_64(proc64, pe_dotnet32): # .NET pe32 loadable in 64bit process -> rewrite of the OptionalHeader @@ -126,6 +123,27 @@ def test_pe_parsing_dotnet32_current_process_64(proc64, pe_dotnet32): assert imported_dlls == ['mscoree.dll'] assert ".text" in sections_names +# PE header of Syschpe32\ntdll.dll with a 8 chars sections .hexpthk that broke the parseur +# This PE as 8 bytes sections name + VirtualSize non aligned on 0x100 so there is a non-null non-ascii byte after the name +PE_SECTION_8CHARS = b""" +eJzzjZrAwMzAwMACxP//MzDsYIAABwbC4AMRagYbCHBlYPBhZEYRu8HAxMjNyMnAwMQAwSAgAMUK +II4DhA2UY4VKw2hwQLFAmBBTFSBqQYQAwig4MECyg4ogAGiuMRZxvQgIuMDIAPcDAxuqGgUGhgS9 +SAjQhgqA1XGgqnNgYDigFwUBYHmYX7gwzHtAmW9GwSgYBfQAnU8b3zAAy4aMr/+BQNTGwIGht0aF +IwMkF54BKg0yGBQcGAL+izoApTrfHJ4wvMAAB/+AA4/UnJx8hfL8opwUhbSi/FyFRIWAypKM/Dy3 +/KLwzLyU/PJihZLU4hIFUMU5CoYd0DBAsJuAbBsD7OpA7YsEIM4B4goD3GIMDO6pJcElKR6JeSk5 +qSB+eFFmSapbJpgTlJqYAmUyAFOXa0VqMkN2alFeao6xkV5KTg6NPDkKcAIAM7/CEw==""" + +def test_pe_parsing_section_8_chars(proc32, tmp_path): + pe_path = (tmp_path / "pe_parsing_8chars_section.exe") + pe_data = pe_data = zlib.decompress(b64decode(PE_SECTION_8CHARS)) + + with pe_path.open("wb") as f: + f.write(pe_data) + + mod = proc32.load_library(str(pe_path)) + # check that section retrieval works + assert set(s.name for s in mod.pe.sections) == {u".XXXXXXX", u".YYYYYYY", u".ZZZZZZZ"} + # A "Portable Executable 32 .NET Assembly" DLL # Result of compiling a simple hello-world # Can be loaded into a 64b process to witness 32 -> 64b PE conversion at load time diff --git a/windows/pe_parse.py b/windows/pe_parse.py index a19eb74..ec092a4 100644 --- a/windows/pe_parse.py +++ b/windows/pe_parse.py @@ -109,7 +109,7 @@ class PESection(IMAGE_SECTION_HEADER): if self.target is None: name = get_string(self.target, ctypes.addressof(self.Name))[:8] else: - name = get_string(self.target, self._base_addr)[:8] + name = self.target.read_memory(self._base_addr, 8).split(b"\x00", 1)[0].decode("ascii") # Decode as UTF-8 as the MS doc say ? return name @@ -451,4 +451,17 @@ class PEFile(object): iat_entry.name = str(name) if name else "" name = get_string(self.target, self.baseaddr + import_descriptor.Name) res.setdefault(name.lower(), []).extend(IAT) - return res \ No newline at end of file + return res + + @utils.fixedpropety + def binid(self): + """Return the hex-string {TimeStamp}{SizeOfCode} used by PDB to identify a PE. + + I do not know the official name of this value... + + :type: :class:`str` + """ + nth = self.get_NT_HEADER() + timestamp = nth.FileHeader.TimeDateStamp + image_size = nth.OptionalHeader.SizeOfImage + return "{timestamp:08x}{image_size:x}".format(timestamp=timestamp, image_size=image_size) \ No newline at end of file