Commands for MacOS which gives similar information as "lsappinfo" and "system_profiler SPApplicationsDataType" for other Mach-O binaries

Hello,

I am currently researching for ways to get the versions of all of the Mach-O executables and dylibs installed on my MacOS machine.

Based on my initial research, I am able to get the information of installed applications from commands like "lsappinfo" and "system_profiler SPApplicationsDataType".

However, the above commands only give me information about applications installed in my machine, not all the Mach-O binaries and dylibs.

I also saw otool -L output is not very reliable as some dylibs don't show the current version.

Are there any alternate commands I can try to get this information? Can this be achievable through any frameworks on MacOS? Any pointers will help me a lot.

Answered by DTS Engineer in 866394022

From the perspective of a security product:

  • You can’t trust lsappinfo or any API layered on top of Launch Services. It’s possible for apps to be on the system that are not known to LS.
  • Given an app bundle, you can’t find all the Mach-O images within that bundle other than by walking the file system hierarchy.

That second point warrants further explanation. While Apple has clear guidelines about where to put code within a bundle — see Placing content in a bundle — many (many many) third-party apps bend those guidelines. For example, it’s very common to see entire Java runtimes placed within Contents/Resources. APIs like NSBundle assume that the bundle is structured correctly, and thus won’t be useful in a security product that can’t trust the bundle’s structure.


Finally, there’s your question about dynamic library versions. There are no good APIs for that, but the Mach-O on-disk image structure is reasonably well defined [1] and thus you can open the file and read the info you need:

  1. Identify a relevant file by looking for the Mach-O and universal binary magic numbers. If it’s a universal binary, process each Mach-O image within that separately.
  2. Look at the filetype field of the Mach-O header to tell whether it’s a dynamic library or not.
  3. If it’s a dynamic library, parse the load commands look for a LC_ID_DYLIB command. That includes current_version and compatibility_version fields.
  4. You should also look for the LC_BUILD_VERSION command (and the older LC_VERSION_MIN_xyz commands) to confirm whether this code is actually built for macOS or not. Keep in mind that:
  • DriverKit is a separate platform than macOS.
  • macOS supports the iOS Apps on Mac feature.
  • On a Mac used by a developer, you will likely encounter Mach-O images built for the simulator platform.

I have a bunch of links to Mach-O docs and resources in An Apple Library Primer.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] That “reasonably” is important. The general structure of a Mach-O file is quite stable. Once you start digging into the details, that story starts to change. For example, a Mach-O file will likely container a code signature, and we only support folks creating that with Apple tools.

I am currently researching for ways to get the versions of all of the Mach-O executables and dylibs

To what end?

Your ultimate goal here matters, because that affects what path you follow. For example, if you’re just messing around with shell scripts, then lsappinfo is a reasonable enough choice. However, if you’re trying to build a product that you ship to a wide range of users, you wouldn’t want to rely on lsappinfo because it’s output is intended to be read by humans, not by programs. OTOH, there are APIs that let you get similar information.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I am looking at performing this check on file system paths which I can consume as an input to my product. I understand lsappinfo is not scalable, can you please suggest which APIs can get me this similar information?

I have looked at using NSBundle, however, this would work if the CFBundleShortVersionString is added to the Info.plist. This would still not let me fetch the versions of dylibs linked to the executable.

I am looking at performing this check on file system paths which I can consume as an input to my product.

OK. But I’d like more info about your goal. Is this a security product? Or a developer tool? Or something else?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Yes, it is for a security product.

Accepted Answer

From the perspective of a security product:

  • You can’t trust lsappinfo or any API layered on top of Launch Services. It’s possible for apps to be on the system that are not known to LS.
  • Given an app bundle, you can’t find all the Mach-O images within that bundle other than by walking the file system hierarchy.

That second point warrants further explanation. While Apple has clear guidelines about where to put code within a bundle — see Placing content in a bundle — many (many many) third-party apps bend those guidelines. For example, it’s very common to see entire Java runtimes placed within Contents/Resources. APIs like NSBundle assume that the bundle is structured correctly, and thus won’t be useful in a security product that can’t trust the bundle’s structure.


Finally, there’s your question about dynamic library versions. There are no good APIs for that, but the Mach-O on-disk image structure is reasonably well defined [1] and thus you can open the file and read the info you need:

  1. Identify a relevant file by looking for the Mach-O and universal binary magic numbers. If it’s a universal binary, process each Mach-O image within that separately.
  2. Look at the filetype field of the Mach-O header to tell whether it’s a dynamic library or not.
  3. If it’s a dynamic library, parse the load commands look for a LC_ID_DYLIB command. That includes current_version and compatibility_version fields.
  4. You should also look for the LC_BUILD_VERSION command (and the older LC_VERSION_MIN_xyz commands) to confirm whether this code is actually built for macOS or not. Keep in mind that:
  • DriverKit is a separate platform than macOS.
  • macOS supports the iOS Apps on Mac feature.
  • On a Mac used by a developer, you will likely encounter Mach-O images built for the simulator platform.

I have a bunch of links to Mach-O docs and resources in An Apple Library Primer.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] That “reasonably” is important. The general structure of a Mach-O file is quite stable. Once you start digging into the details, that story starts to change. For example, a Mach-O file will likely container a code signature, and we only support folks creating that with Apple tools.

Commands for MacOS which gives similar information as "lsappinfo" and "system_profiler SPApplicationsDataType" for other Mach-O binaries
 
 
Q