NationalSecurityAgency / ghidra

Ghidra is a software reverse engineering (SRE) framework
https://www.nsa.gov/ghidra
Apache License 2.0
49.06k stars 5.65k forks source link

Ghidra file import crashes due to corrupted section header table #6673

Open mucoze opened 3 days ago

mucoze commented 3 days ago

Ghidra importing fails when the binary has a corrupted section header table.

The sample is ARM:LE:32:v8:default

Error output:

Cannot invoke "ghidra.program.model.address.Address.hasSameAddressSpace(ghidra.program.model.address.Address)" because "addr" is null
java.lang.NullPointerException: Cannot invoke "ghidra.program.model.address.Address.hasSameAddressSpace(ghidra.program.model.address.Address)" because "addr" is null
    at ghidra.program.database.mem.MemoryBlockDB.contains(MemoryBlockDB.java:131)
    at ghidra.program.database.mem.MemoryMapDB.getBlockDB(MemoryMapDB.java:502)
    at ghidra.program.database.mem.MemoryMapDB.getBlock(MemoryMapDB.java:473)
    at ghidra.app.util.bin.format.elf.relocation.ARM_ElfRelocationHandler.relocate(ARM_ElfRelocationHandler.java:266)
    at ghidra.app.util.bin.format.elf.relocation.ARM_ElfRelocationHandler.relocate(ARM_ElfRelocationHandler.java:28)
    at ghidra.app.util.bin.format.elf.relocation.AbstractElfRelocationHandler.relocate(AbstractElfRelocationHandler.java:119)
    at ghidra.app.util.bin.format.elf.relocation.ElfRelocationContext.processRelocation(ElfRelocationContext.java:146)
    at ghidra.app.util.bin.format.elf.relocation.ElfRelocationContext.processRelocation(ElfRelocationContext.java:121)
    at ghidra.app.util.opinion.ElfProgramBuilder.processRelocationTableEntries(ElfProgramBuilder.java:1054)
    at ghidra.app.util.opinion.ElfProgramBuilder.processRelocationTable(ElfProgramBuilder.java:951)
    at ghidra.app.util.opinion.ElfProgramBuilder.processRelocations(ElfProgramBuilder.java:886)
    at ghidra.app.util.opinion.ElfProgramBuilder.load(ElfProgramBuilder.java:174)
    at ghidra.app.util.opinion.ElfProgramBuilder.loadElf(ElfProgramBuilder.java:111)
    at ghidra.app.util.opinion.ElfLoader.load(ElfLoader.java:147)
    at ghidra.app.util.opinion.AbstractLibrarySupportLoader.doLoad(AbstractLibrarySupportLoader.java:864)
    at ghidra.app.util.opinion.AbstractLibrarySupportLoader.loadProgram(AbstractLibrarySupportLoader.java:98)
    at ghidra.app.util.opinion.AbstractProgramLoader.load(AbstractProgramLoader.java:131)
    at ghidra.plugin.importer.ImporterUtilities.importSingleFile(ImporterUtilities.java:395)
    at ghidra.plugin.importer.ImporterDialog.lambda$okCallback$7(ImporterDialog.java:338)
    at ghidra.util.task.TaskBuilder$TaskBuilderTask.run(TaskBuilder.java:306)
    at ghidra.util.task.Task.monitoredRun(Task.java:134)
    at ghidra.util.task.TaskRunner.lambda$startTaskThread$0(TaskRunner.java:106)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
    at java.base/java.lang.Thread.run(Thread.java:840)

---------------------------------------------------
Build Date: 2024-Jun-14 1025 EDT
Ghidra Version: 11.1.1
Java Home: /usr/lib/jvm/java-17-openjdk-amd64
JVM Version: Ubuntu 17.0.11
OS: Linux 5.15.0-107-generic amd64

readelf output

readelf --section-headers sample.so  
There are 25 section headers, starting at offset 0x1676c:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0] <no-strings>      NULL            00000000 000000 000000 00      0   0  0
  [ 1] <no-strings>      NULL            00000000 000000 000000 00      0   0  0
  [ 2] <no-strings>      NULL            00000000 000000 000000 00      0   0  0
  [ 3] <no-strings>      NULL            00000000 000000 000000 00      0   0  0
  [ 4] <no-strings>      NULL            00000000 000000 000000 00      0   0  0
  [ 5] <no-strings>      NULL            00000000 000000 000000 00      0   0  0
  [ 6] <no-strings>      NULL            00000000 000000 000000 00      0   0  0
  [ 7] <no-strings>      NULL            00000000 000000 000000 00      0   0  0
  [ 8] <no-strings>      NULL            00000000 000000 000000 00      0   0  0
  [ 9] <no-strings>      NULL            00000000 000000 000000 00      0   0  0
  [10] <no-strings>      NULL            00000000 000000 000000 00      0   0  0
  [11] <no-strings>      NULL            00000000 000000 000000 00      0   0  0
  [12] <no-strings>      NULL            00000000 000000 000000 00      0   0  0
  [13] <no-strings>      NULL            00000000 000000 000000 00      0   0  0
  [14] <no-strings>      NULL            00000000 000000 000000 00      0   0  0
  [15] <no-strings>      NULL            00000000 000000 000000 00      0   0  0
  [16] <no-strings>      NULL            00000000 000000 000000 00      0   0  0
  [17] <no-strings>      NULL            00000000 000000 000000 00      0   0  0
  [18] <no-strings>      NULL            00000000 000000 000000 00      0   0  0
  [19] <no-strings>      NULL            00000000 000000 000000 00      0   0  0
  [20] <no-strings>      NULL            00000000 000000 000000 00      0   0  0
  [21] <no-strings>      NULL            00000000 000000 000000 00      0   0  0
  [22] <no-strings>      NULL            00000000 000000 000000 00      0   0  0
  [23] <no-strings>      NULL            00000000 000000 000000 00      0   0  0
  [24] <no-strings>      NULL            00000000 000000 000000 00      0   0  0
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  y (purecode), p (processor specific)
readelf: Error: no .dynamic section in the dynamic segment

Expected behavior If possible, Ghidra can force import of binaries that have a corrupted section header table. Otherwise, it may just refuse to import with a warning, instead of being fail.

Screenshots image

Environment:

ghidra1 commented 2 days ago

There are many many ways a file could be in a non-compliant form and we cannot check for all cases. If you attach a sample file I can take a look at handling the case better. I can certainly handle the null case identified by the stack trace above, although I would like to understand how such a binary would handle its dynamic relocations properly.

ghidra1 commented 1 day ago

@mucoze Could you please attach a file which exhibits this behavior. I have been unable to reproduce.

mucoze commented 23 hours ago

@ghidra1 Hi, I have crafted a sample binary that you can use to reproduce the error.

In the zip archive, you can find the one with corrupted Section Header Table and also the original file. sample_library.zip