From 92f57edde24ddfbc60935a5e425f1a38a7bfac87 Mon Sep 17 00:00:00 2001 From: dev747368 <48332326+dev747368@users.noreply.github.com> Date: Wed, 15 Dec 2021 17:13:06 -0500 Subject: [PATCH] GP-1592 Process symbols in .gnu_debugdata. .gnu_debugdata is a xz compressed ELF file that only contains a symtabthat has been stripped out of the main binary.If its present, decompress it and markup the symbols when loading the main binary. --- .../app/util/bin/format/elf/ElfHeader.java | 5 +- .../app/util/opinion/ElfProgramBuilder.java | 74 +++++++++++++++++-- Ghidra/Framework/Project/Module.manifest | 1 + Ghidra/Framework/Project/build.gradle | 1 + 4 files changed, 73 insertions(+), 8 deletions(-) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfHeader.java index e34edbdb8a..5ec0a7bcc9 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfHeader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfHeader.java @@ -15,9 +15,10 @@ */ package ghidra.app.util.bin.format.elf; +import java.util.*; + import java.io.IOException; import java.io.RandomAccessFile; -import java.util.*; import generic.continues.GenericFactory; import ghidra.app.util.bin.*; @@ -614,7 +615,7 @@ public class ElfHeader implements StructConverter, Writeable { // The p_offset may not refer to the start of the DYNAMIC table so we must use // p_vaddr to find it relative to a PT_LOAD segment long vaddr = dynamicHeaders[0].getVirtualAddress(); - if (vaddr == 0) { + if (vaddr == 0 || dynamicHeaders[0].getFileSize() == 0) { Msg.warn(this, "ELF Dynamic table appears to have been stripped from binary"); return; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfProgramBuilder.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfProgramBuilder.java index 1159e134ea..f331bf6991 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfProgramBuilder.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfProgramBuilder.java @@ -15,24 +15,28 @@ */ package ghidra.app.util.opinion; -import java.io.IOException; -import java.io.InputStream; -import java.math.BigInteger; -import java.text.NumberFormat; import java.util.*; +import java.io.*; +import java.math.BigInteger; +import java.nio.file.AccessMode; +import java.text.NumberFormat; + +import org.apache.commons.compress.compressors.xz.XZCompressorInputStream; import org.apache.commons.lang3.StringUtils; +import generic.continues.GenericFactory; import ghidra.app.cmd.label.SetLabelPrimaryCmd; import ghidra.app.util.MemoryBlockUtils; import ghidra.app.util.Option; -import ghidra.app.util.bin.ByteProvider; +import ghidra.app.util.bin.*; import ghidra.app.util.bin.format.MemoryLoadable; import ghidra.app.util.bin.format.elf.*; import ghidra.app.util.bin.format.elf.ElfDynamicType.ElfDynamicValueType; import ghidra.app.util.bin.format.elf.extend.ElfLoadAdapter; import ghidra.app.util.bin.format.elf.relocation.*; import ghidra.app.util.importer.MessageLog; +import ghidra.app.util.importer.MessageLogContinuesFactory; import ghidra.framework.options.Options; import ghidra.program.database.mem.FileBytes; import ghidra.program.database.register.AddressRangeObjectMap; @@ -53,6 +57,7 @@ import ghidra.util.*; import ghidra.util.datastruct.*; import ghidra.util.exception.*; import ghidra.util.task.TaskMonitor; +import utilities.util.FileUtilities; class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper { @@ -1319,7 +1324,10 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper { // Mapped data/object symbol addresses with specific sizes HashMap dataAllocationMap = new HashMap<>(); - ElfSymbolTable[] symbolTables = elf.getSymbolTables(); + List symbolTables = new ArrayList<>(); + symbolTables.addAll(List.of(elf.getSymbolTables())); + symbolTables.addAll(getGnuDebugDataSymbolTables(monitor)); + int totalCount = 0; for (ElfSymbolTable elfSymbolTable : symbolTables) { @@ -1357,6 +1365,60 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper { allocateUndefinedSymbolData(dataAllocationMap); } + /** + * Returns any symbol tables that are embedded in the ".gnu_debugdata" section. + *

+ * The ".gnu_debugdata" section contains a xz compressed minimal ELF file that has symbols that + * have been stripped from this binary. + * + * @param monitor checked for cancelation when copying data + * @return list of ElfSymbolTables, empty if not present + */ + private List getGnuDebugDataSymbolTables(TaskMonitor monitor) { + ElfSectionHeader debugDataSection = elf.getSection(".gnu_debugdata"); + Address debugDataAddr = findLoadAddress(debugDataSection, 0); + if (debugDataAddr != null) { + try { + File tmpFile = File.createTempFile("ghidra_gnu_debugdata", null); + try (ByteProviderWrapper compressedDebugDataBP = new ByteProviderWrapper( + new MemoryByteProvider(memory, debugDataAddr), 0, debugDataSection.getSize()); + XZCompressorInputStream xzIS = + new XZCompressorInputStream(compressedDebugDataBP.getInputStream(0)); + ObfuscatedOutputStream oos = + new ObfuscatedOutputStream(new FileOutputStream(tmpFile));) { + + FileUtilities.copyStreamToStream(xzIS, oos, monitor); + oos.close(); + + try (ByteProvider debugDataBP = + new ObfuscatedFileByteProvider(tmpFile, null, AccessMode.READ)) { + + GenericFactory factory = MessageLogContinuesFactory.create(log); + ElfHeader minidebugElf = ElfHeader.createElfHeader(factory, debugDataBP); + minidebugElf.parse(); + + ElfSymbolTable[] minidebugSymbolTables = minidebugElf.getSymbolTables(); + int debugSymbolsCount = 0; + for (ElfSymbolTable symTable : minidebugSymbolTables) { + debugSymbolsCount += symTable.getSymbols().length; + } + log(String.format("Found %d symbols in .gnu_debugdata", debugSymbolsCount)); + + return List.of(minidebugSymbolTables); + } + } + finally { + tmpFile.delete(); + } + } + catch (IOException | ElfException e) { + log("Error extracting .gnu_debugdata section embedded symbols."); + Msg.error(this, "Error extracting .gnu_debugdata section embedded symbols.", e); + } + } + return List.of(); + } + private void processSymbols(ElfSymbol[] symbols, HashMap dataAllocationMap, TaskMonitor monitor) throws CancelledException { for (ElfSymbol elfSymbol : symbols) { diff --git a/Ghidra/Framework/Project/Module.manifest b/Ghidra/Framework/Project/Module.manifest index 81ea432cb4..e150e4162e 100644 --- a/Ghidra/Framework/Project/Module.manifest +++ b/Ghidra/Framework/Project/Module.manifest @@ -1 +1,2 @@ MODULE FILE LICENSE: lib/commons-compress-1.19.jar Apache License 2.0 +MODULE FILE LICENSE: lib/xz-1.9.jar Public Domain diff --git a/Ghidra/Framework/Project/build.gradle b/Ghidra/Framework/Project/build.gradle index 2411541a76..0333ddf292 100644 --- a/Ghidra/Framework/Project/build.gradle +++ b/Ghidra/Framework/Project/build.gradle @@ -31,5 +31,6 @@ dependencies { testImplementation project(path: ':Generic', configuration: 'testArtifacts') api "org.apache.commons:commons-compress:1.19" + api "org.tukaani:xz:1.9" }