From da7d49e41f50ce810d1078ee009568e9a89da349 Mon Sep 17 00:00:00 2001 From: john0x1a Date: Thu, 5 Sep 2024 14:31:33 +0200 Subject: [PATCH 1/3] Add support for Mach-O headers in entrypoint getter --- src/main/java/com/bai/util/Utils.java | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/bai/util/Utils.java b/src/main/java/com/bai/util/Utils.java index 920f0b1..4b56ea8 100644 --- a/src/main/java/com/bai/util/Utils.java +++ b/src/main/java/com/bai/util/Utils.java @@ -12,10 +12,15 @@ import ghidra.app.util.bin.MemoryByteProvider; import ghidra.app.util.bin.format.elf.ElfException; import ghidra.app.util.bin.format.elf.ElfHeader; +import ghidra.app.util.bin.format.macho.commands.EntryPointCommand; +import ghidra.app.util.bin.format.macho.commands.LoadCommand; +import ghidra.app.util.bin.format.macho.commands.LoadCommandTypes; import ghidra.app.util.bin.format.pe.PortableExecutable; import ghidra.app.util.bin.format.pe.OptionalHeader; +import ghidra.app.util.bin.format.macho.MachHeader; import ghidra.app.util.opinion.ElfLoader; import ghidra.app.util.opinion.PeLoader; +import ghidra.app.util.opinion.MachoLoader; import ghidra.program.model.address.Address; import ghidra.program.model.data.FunctionDefinitionDataType; import ghidra.program.model.data.IntegerDataType; @@ -343,7 +348,7 @@ public static List getReferences(List symbolNames) { } /** - * Get the entry function of the ELF/PE executable. + * Get the entry function of the ELF/PE/MACH-O executable. * @return */ public static Function getEntryFunction() { @@ -371,7 +376,27 @@ public static Function getEntryFunction() { entryAddress = entryAddress.add(GlobalState.currentProgram.getImageBase().getOffset()); } break; + case MachoLoader.MACH_O_NAME: { + MachHeader header = new MachHeader(provider); + header.parse(); + if (!header.parseAndCheck(LoadCommandTypes.LC_MAIN)) { + throw new RuntimeException("Could not locate the entrypoint of the Mach-O binary executable."); + } + + Optional loadCommandOptional = header.getLoadCommands().stream() + .filter(loadCommand -> loadCommand.getCommandType() == LoadCommandTypes.LC_MAIN) + .findFirst(); + + if (loadCommandOptional.isEmpty()) { + throw new RuntimeException("Could not find the LC_MAIN load command in the Mach-O header."); + } + + entryAddress = (GlobalState.currentProgram.getImageBase()) + .add(((EntryPointCommand) loadCommandOptional.get()).getEntryOffset()); + + } + break; default: throw new Exception("Unsupported file format."); } From e3b8eb6f6e6bbae14d4bc7ed6ff1a849a23af598 Mon Sep 17 00:00:00 2001 From: john0x1a Date: Thu, 5 Sep 2024 14:36:57 +0200 Subject: [PATCH 2/3] Add mangled reference symbols for Mach-O binaries. --- src/main/java/com/bai/util/Utils.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/com/bai/util/Utils.java b/src/main/java/com/bai/util/Utils.java index 4b56ea8..b090532 100644 --- a/src/main/java/com/bai/util/Utils.java +++ b/src/main/java/com/bai/util/Utils.java @@ -335,6 +335,15 @@ public static List getReferences(List symbolNames) { Logging.error("Empty symbol table"); return new ArrayList<>(); } + + // OS X ABI for Mach-O format mangles C symbols by prepending an underscore (_) to symbols + if (GlobalState.currentProgram.getExecutableFormat().equals(MachoLoader.MACH_O_NAME)) { + List machOMangledNames = symbolNames.stream() + .map(name -> "_" + name) + .toList(); + symbolNames.addAll(machOMangledNames); + } + return Stream.generate(() -> null) .takeWhile(x -> symbolIterator.hasNext()) .map(n -> symbolIterator.next()) From 17e5c96fe539d64e8e534f5c2567de72eb586f04 Mon Sep 17 00:00:00 2001 From: john0x1a Date: Thu, 5 Sep 2024 14:45:44 +0200 Subject: [PATCH 3/3] Bump test ghidra version to 11.1.2 --- .github/workflows/integration_test.yml | 4 ++-- .github/workflows/unittest.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/integration_test.yml b/.github/workflows/integration_test.yml index 773cce5..c6bf800 100644 --- a/.github/workflows/integration_test.yml +++ b/.github/workflows/integration_test.yml @@ -27,7 +27,7 @@ jobs: uses: er28-0652/setup-ghidra@0.0.6 if: steps.cache.outputs.cache-hit != 'true' with: - version: '10.4' + version: '11.1.2' - name: Download Z3 uses: pavpanchekha/setup-z3@0.2.0 if: steps.cache.outputs.cache-hit != 'true' @@ -39,7 +39,7 @@ jobs: if: steps.cache.outputs.cache-hit == 'true' run: | echo "CPATH=/opt/hostedtoolcache/z3/4.8.15/x64/z3-4.8.15-x64-glibc-2.31/include" >> $GITHUB_ENV - echo "GHIDRA_INSTALL_DIR=/opt/hostedtoolcache/ghidra/10.4/x64" >> $GITHUB_ENV + echo "GHIDRA_INSTALL_DIR=/opt/hostedtoolcache/ghidra/11.1.2/x64" >> $GITHUB_ENV - name: Setup Z3 run: | cp $CPATH/../bin/com.microsoft.z3.jar $GITHUB_WORKSPACE/lib/com.microsoft.z3.jar diff --git a/.github/workflows/unittest.yml b/.github/workflows/unittest.yml index 0679b79..45c588a 100644 --- a/.github/workflows/unittest.yml +++ b/.github/workflows/unittest.yml @@ -27,7 +27,7 @@ jobs: uses: er28-0652/setup-ghidra@0.0.6 if: steps.cache.outputs.cache-hit != 'true' with: - version: '10.4' + version: '11.1.2' - name: Download Z3 uses: pavpanchekha/setup-z3@0.2.0 if: steps.cache.outputs.cache-hit != 'true' @@ -39,7 +39,7 @@ jobs: if: steps.cache.outputs.cache-hit == 'true' run: | echo "CPATH=/opt/hostedtoolcache/z3/4.8.15/x64/z3-4.8.15-x64-glibc-2.31/include" >> $GITHUB_ENV - echo "GHIDRA_INSTALL_DIR=/opt/hostedtoolcache/ghidra/10.4/x64" >> $GITHUB_ENV + echo "GHIDRA_INSTALL_DIR=/opt/hostedtoolcache/ghidra/11.1.2/x64" >> $GITHUB_ENV - name: Setup Z3 run: | cp $CPATH/../bin/com.microsoft.z3.jar $GITHUB_WORKSPACE/lib/com.microsoft.z3.jar