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 diff --git a/src/main/java/com/bai/util/Utils.java b/src/main/java/com/bai/util/Utils.java index 920f0b1..b090532 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; @@ -330,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()) @@ -343,7 +357,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 +385,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."); }