Skip to content

macOS 11 boot kext collection fails to import because ntools is set to 0 in LC_BUILD_VERSION #2192

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
zhuowei opened this issue Aug 8, 2020 · 0 comments
Assignees
Milestone

Comments

@zhuowei
Copy link

zhuowei commented Aug 8, 2020

Describe the bug
Ghidra 9.1.2 fails to import the boot kext cache from macOS 11 beta 3, because its Mach-O file contains a LC_BUILD_VERSION header with ntools set to 0.

To Reproduce
Steps to reproduce the behavior:

  1. Try to import /System/Library/KernelCollections/BootKernelExtensions.kc from macOS 11 beta 3

Expected behavior
The kernel cache is imported.

Actual behaviour

This error is shown:

Error importing file:
java.io.IOException
	at ghidra.app.util.opinion.MachoLoader.load(MachoLoader.java:98)
	at ghidra.app.util.opinion.AbstractLibrarySupportLoader.doLoad(AbstractLibrarySupportLoader.java:346)
	at ghidra.app.util.opinion.AbstractLibrarySupportLoader.loadProgram(AbstractLibrarySupportLoader.java:83)
	at ghidra.app.util.opinion.AbstractProgramLoader.load(AbstractProgramLoader.java:112)
	at ghidra.plugin.importer.ImporterUtilities.importSingleFile(ImporterUtilities.java:401)
	at ghidra.plugin.importer.ImporterDialog.lambda$okCallback$7(ImporterDialog.java:351)
	at ghidra.util.task.TaskLauncher$1.run(TaskLauncher.java:90)
	at ghidra.util.task.Task.monitoredRun(Task.java:126)
	at ghidra.util.task.TaskRunner.lambda$startTaskThread$1(TaskRunner.java:94)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at java.base/java.lang.Thread.run(Thread.java:834)

---------------------------------------------------
Build Date: 2020-Feb-12 1149 EST
Ghidra Version: 9.1.2
Java Home: /Library/Java/JavaVirtualMachines/amazon-corretto-11.jdk/Contents/Home
JVM Version: Amazon.com Inc. 11.0.4
OS: Mac OS X 10.15.6 x86_64

After looking for the root cause of this, it appears that this is caused by BuildVersionCommand.toDataType() passing the ntools field from the load command directly to ArrayDataType, which throws if the number of items is 0.

Unlike other MachO executables, the kext collection sets ntool to 0:

Load command 1
      cmd LC_BUILD_VERSION
  cmdsize 24
 platform 0
    minos 0.0
      sdk n/a
   ntools 0

This appears to still be a valid MachO, and indeed Ghidra does handle .o files with ntools=0 just fine; it only fails to handle this case for executables such as the kext collection.

Environment (please complete the following information):

  • OS: macOS 10.15.6
  • Java Version: 11.0.4
  • Ghidra Version: 9.1.2

Appendix: tracking down the root cause

The top level IOException wraps a NullPointerException:

java.lang.NullPointerException
	at ghidra.program.model.data.DataUtilities.createData(DataUtilities.java:138)
	at ghidra.app.util.opinion.MachoProgramBuilder.markupHeaders(MachoProgramBuilder.java:751)
	at ghidra.app.util.opinion.MachoProgramBuilder.build(MachoProgramBuilder.java:133)
	at ghidra.app.util.opinion.MachoProgramBuilder.buildProgram(MachoProgramBuilder.java:102)
	at ghidra.app.util.opinion.MachoLoader.load(MachoLoader.java:94)
	at ghidra.app.util.opinion.AbstractLibrarySupportLoader.doLoad(AbstractLibrarySupportLoader.java:346)
	at ghidra.app.util.opinion.AbstractLibrarySupportLoader.loadProgram(AbstractLibrarySupportLoader.java:83)
	at ghidra.app.util.opinion.AbstractProgramLoader.load(AbstractProgramLoader.java:112)
	at ghidra.plugin.importer.ImporterUtilities.importSingleFile(ImporterUtilities.java:401)
	at ghidra.plugin.importer.ImporterDialog.lambda$okCallback$7(ImporterDialog.java:351)
	at ghidra.util.task.TaskLauncher$1.run(TaskLauncher.java:90)
	at ghidra.util.task.Task.monitoredRun(Task.java:126)
	at ghidra.util.task.TaskRunner.lambda$startTaskThread$1(TaskRunner.java:94)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at java.base/java.lang.Thread.run(Thread.java:834)

This shows that the loadCommandDataType is set to null:

newDataType = newDataType.clone(program.getDataTypeManager());

DataUtilities.createData(program, loadCommandAddr, loadCommandDataType, -1, false,

> 
Breakpoint hit: "thread=Task - Import File", ghidra.app.util.opinion.MachoProgramBuilder.markupHeaders(), line=751 bci=104

Task - Import File[1] locals
Method arguments:
header = instance of ghidra.app.util.bin.format.macho.MachHeader$$EnhancerByCGLIB$$f0aa4076(id=9950)
headerAddr = instance of ghidra.program.model.address.GenericAddress(id=9951)
Local variables:
loadCommand = instance of ghidra.app.util.bin.format.macho.commands.BuildVersionCommand$$EnhancerByCGLIB$$b005e22d(id=9955)
loadCommandAddr = instance of ghidra.program.model.address.GenericAddress(id=9956)
loadCommandDataType = null
Task - Import File[1] print loadCommand.toDataType()
 loadCommand.toDataType() = null

loadCommand.toDataType() is returning null because the ContinuesInterceptor caught an IllegalArgumentException:

Step completed: "thread=Task - Import File", generic.continues.ContinuesInterceptor.intercept(), line=42 bci=38

Task - Import File[1] locals
Method arguments:
obj = instance of ghidra.app.util.bin.format.macho.commands.BuildVersionCommand$$EnhancerByCGLIB$$b005e22d(id=9955)
method = instance of java.lang.reflect.Method(id=9976)
args = instance of java.lang.Object[0] (id=9974)
proxy = instance of net.sf.cglib.proxy.MethodProxy(id=9977)
Local variables:
retValFromSuper = null
e = instance of java.lang.IllegalArgumentException(id=9978)
Task - Import File[1] print e
Internal exception during operation:
    Unexpected JDWP Error: 502

The original IllegalArgumentException is:

Exception occurred: java.lang.IllegalArgumentException (to be caught at: ghidra.app.util.bin.format.macho.commands.BuildVersionCommand$$EnhancerByCGLIB$$b005e22d$$FastClassByCGLIB$$2ec3d351.invoke(), line=-1 bci=774)"thread=Task - Import File", ghidra.program.model.data.ArrayDataType.<init>(), line=64 bci=85

shows that ArrayDataType throws the IllegalArgumentException if the number of items is <= 0

struct.add(new ArrayDataType(buildToolVersionDataType, ntools,
shows that ArrayDataType would be called based on ntools from the header

@ryanmkurtz ryanmkurtz self-assigned this Feb 9, 2021
@ryanmkurtz ryanmkurtz added this to the 9.2.3 milestone Feb 22, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants