6

I'm trying to decompress a Mach-O binary which has been compressed using one of the compression algorithms in Mac 10.10's HFS+ implementation. Basically the file has the "com.apple.decmpfs" attribute on it, which says that it is compression type 8. Then the compressed contents of the file are stored in the file's resource fork.

It doesn't seem to have any identifiable header on it. Does anyone recognize it, or have any ideas what it might be? Below is a dump of the first 0x200 bytes of the compressed version of /bin/bash, and the first 0x200 bytes of the same file as viewed under Mac OS.

The Mach-O header (CF FA ED FE) and some executable's strings (e.g. __PAGEZERO) can be seem in the compressed version.

Compressed (first 0x200 bytes of /bin/bash):

Offset(h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 

00000000  E0 01 CF FA ED FE 07 00 00 01 03 00 00 80 02 00  à.Ïúíþ.......€.. 
00000010  00 00 12 00 04 E8 E8 06 00 00 85 00 20 00 08 01  .....èè...…. ... 
00000020  40 04 19 46 48 EB 5F 5F 50 41 47 45 5A 45 52 4F  @..FHë__PAGEZERO 
00000030  00 38 01 F7 9E 01 00 F0 0C 08 48 8E 28 02 E5 54  .8.÷ž..ð..HŽ(.åT 
00000040  45 58 54 00 38 01 F3 10 40 9E 60 08 F8 20 10 46  EXT.8.ó.@ž`.ø .F 
00000050  07 46 05 48 0D 06 10 88 E5 74 65 78 74 00 30 01  .F.H...ˆåtext.0. 
00000060  38 50 F6 9E EC 0B C8 10 5F 1C 07 F5 50 0A 02 20  8Pöžì.È._..õP.. 
00000070  01 E4 04 00 80 00 FA F1 E8 5F 5F 73 74 75 62 73  .ä..€.úñè__stubs 
00000080  00 F8 38 50 F6 CE 4C 28 07 F1 CE 62 04 00 F1 28  .ø8PöÎL(.ñÎb..ñ( 
00000090  10 28 01 60 50 08 6E 06 F5 E7 5F 68 65 6C 70 65  .(.`P.n.õç_helpe 
000000A0  72 FA F9 9E B0 2C 9E 5E 07 08 10 38 A0 F0 04 E7  rúùž°,ž^...8 ð.ç 
000000B0  63 73 74 72 69 6E 67 FA FD 9E 0E 34 9E 61 F8 08  cstringúýž.4žaø. 
000000C0  10 38 01 F2 38 5C F3 18 50 C9 41 6F 6E 73 F6 38  .8.ò8\ó.PÉAonsö8 
000000D0  50 F6 CE 70 2C 08 F1 9E F0 21 08 10 20 FB 38 01  PöÎp,.ñžð!.. û8. 
000000E0  FB ED 5F 5F 75 6E 77 69 6E 64 5F 69 6E 66 6F 38  ûí__unwind_info8 
000000F0  50 F9 9E 60 4E 9E 94 11 08 10 38 94 F6 38 01 F2  Pùž`Nž”...8”ö8.ò 
00000100  0A 28 56 78 E4 44 41 54 41 FA F1 58 48 60 9E 00  .(VxäDATAúñXH`ž. 
00000110  E0 32 30 5E B0 08 F6 60 08 03 08 01 E4 5F 5F 67  à20^°.ö`....ä__g 
00000120  6F 3A 27 F1 38 50 FF 9E 38 01 F4 58 0A 03 10 01  o:'ñ8Pÿž8.ôX.... 
00000130  09 D0 98 01 BB 00 F4 EF 5F 5F 6E 6C 5F 73 79 6D  .И.».ôï__nl_sym 
00000140  62 6F 6C 5F 70 74 72 38 50 F7 9E 38 61 9E 10 00  bol_ptr8P÷ž8až.. 
00000150  08 10 38 50 F6 6E E2 F5 9E 6C 61 F0 06 66 48 9E  ..8Pönâõžlað.fHž 
00000160  D8 05 6E 48 F7 08 E8 98 01 E4 00 F4 39 D8 F8 38  Ø.nH÷.è˜.ä.ô9Øø8 
00000170  50 F4 9E 20 67 9E 88 26 08 10 39 D8 F0 04 E5 64  Pôž gžˆ&..9Øð.åd 
00000180  61 74 61 00 30 01 38 50 F6 9E B0 8D 9E 04 79 08  ata.0.8Pöž°.ž.y. 
00000190  10 38 50 F0 04 E6 63 6F 6D 6D 6F 6E FA FE CE C0  .8Pð.æcommonúþÎÀ 
000001A0  06 09 F1 C8 01 68 0E 00 F5 38 50 F2 6E 01 F9 9B  ..ñÈ.h..õ8Pòn.ù› 
000001B0  B6 62 73 F4 38 50 F8 9E 30 15 9E 10 21 F0 10 3C  ¶bsô8Pøž0.ž.!ð.< 
000001C0  E8 E7 4C 49 4E 4B 45 44 49 2A C4 58 48 40 9E 00  èçLINKEDI*ÄXH@ž. 
000001D0  A0 F1 90 07 10 09 96 A0 87 11 88 38 4C F2 45 48   ñ....– ‡.ˆ8LòEH 
000001E0  22 48 09 30 00 28 41 B1 50 C8 3B 50 13 09 F5 08  "H.0.(A±PÈ;P..õ. 
000001F0  01 40 10 F0 EA 08 0C 00 00 F8 1F 09 00 F8 33 1B  .@.ðê....ø...ø3. 

Uncompressed (first 0x200 bytes of /bin/bash):

Offset(h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 

00000000  CF FA ED FE 07 00 00 01 03 00 00 80 02 00 00 00  Ïúíþ.......€.... 
00000010  12 00 00 00 E8 06 00 00 85 00 20 00 00 00 00 00  ....è...…. ..... 
00000020  19 00 00 00 48 00 00 00 5F 5F 50 41 47 45 5A 45  ....H...__PAGEZE 
00000030  52 4F 00 00 00 00 00 00 00 00 00 00 00 00 00 00  RO.............. 
00000040  00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00  ................ 
00000050  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................ 
00000060  00 00 00 00 00 00 00 00 19 00 00 00 28 02 00 00  ............(... 
00000070  5F 5F 54 45 58 54 00 00 00 00 00 00 00 00 00 00  __TEXT.......... 
00000080  00 00 00 00 01 00 00 00 00 60 08 00 00 00 00 00  .........`...... 
00000090  00 00 00 00 00 00 00 00 00 60 08 00 00 00 00 00  .........`...... 
000000A0  07 00 00 00 05 00 00 00 06 00 00 00 00 00 00 00  ................ 
000000B0  5F 5F 74 65 78 74 00 00 00 00 00 00 00 00 00 00  __text.......... 
000000C0  5F 5F 54 45 58 54 00 00 00 00 00 00 00 00 00 00  __TEXT.......... 
000000D0  EC 0B 00 00 01 00 00 00 5F 1C 07 00 00 00 00 00  ì......._....... 
000000E0  EC 0B 00 00 02 00 00 00 00 00 00 00 00 00 00 00  ì............... 
000000F0  00 04 00 80 00 00 00 00 00 00 00 00 00 00 00 00  ...€............ 
00000100  5F 5F 73 74 75 62 73 00 00 00 00 00 00 00 00 00  __stubs......... 
00000110  5F 5F 54 45 58 54 00 00 00 00 00 00 00 00 00 00  __TEXT.......... 
00000120  4C 28 07 00 01 00 00 00 62 04 00 00 00 00 00 00  L(......b....... 
00000130  4C 28 07 00 01 00 00 00 00 00 00 00 00 00 00 00  L(.............. 
00000140  08 04 00 80 00 00 00 00 06 00 00 00 00 00 00 00  ...€............ 
00000150  5F 5F 73 74 75 62 5F 68 65 6C 70 65 72 00 00 00  __stub_helper... 
00000160  5F 5F 54 45 58 54 00 00 00 00 00 00 00 00 00 00  __TEXT.......... 
00000170  B0 2C 07 00 01 00 00 00 5E 07 00 00 00 00 00 00  °,......^....... 
00000180  B0 2C 07 00 02 00 00 00 00 00 00 00 00 00 00 00  °,.............. 
00000190  00 04 00 80 00 00 00 00 00 00 00 00 00 00 00 00  ...€............ 
000001A0  5F 5F 63 73 74 72 69 6E 67 00 00 00 00 00 00 00  __cstring....... 
000001B0  5F 5F 54 45 58 54 00 00 00 00 00 00 00 00 00 00  __TEXT.......... 
000001C0  0E 34 07 00 01 00 00 00 61 F8 00 00 00 00 00 00  .4......aø...... 
000001D0  0E 34 07 00 00 00 00 00 00 00 00 00 00 00 00 00  .4.............. 
000001E0  02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................ 
000001F0  5F 5F 63 6F 6E 73 74 00 00 00 00 00 00 00 00 00  __const......... 
00000200  5F 5F 54 45 58 54 00 00 00 00 00 00 00 00 00 00  __TEXT.......... 

Thanks in advance!

2
  • 1
    This smells like an older LZ/LZW compression. Unlike modern implementations, which use bits, this compresses per byte. That's why you can identify fragments of the original text inside the compressed data.
    – Jongware
    Feb 12 '15 at 10:48
  • @Jongware those were my thoughts too. I haven't had any luck pinning it down to a particular algorithm though. Feb 13 '15 at 8:49
5

OK... it seems to be LZVN compression. Following on from Igor's suggestions I ran kextstat on my Mac, however that only listed:

  • com.apple.AppleFSCompression.AppleFSCompressionTypeZlib
  • com.apple.AppleFSCompression.AppleFSCompressionTypeDataless

Looking at the strings inside the 'dataless' compression it turned out to be type 5: AppleFSCompressionTypeDataless.kext. Searching for the same string with type 8, I found this log:

com_apple_AppleFSCompression_AppleFSCompressionTypeLZVN  <class com_apple_AppleFSCompression_AppleFSCompressionTypeLZVN, id 0x10000025d, !registered, !matched, active, busy 0, retain 4>
      |   {
      |     "IOProbeScore" = 0x0
      |     "CFBundleIdentifier" = "com.apple.AppleFSCompression.AppleFSCompressionTypeLZVN"
      |     "IOMatchCategory" = "com_apple_AppleFSCompression_AppleFSCompressionTypeLZVN"
      |     "IOClass" = "com_apple_AppleFSCompression_AppleFSCompressionTypeLZVN"
      |     "IOProviderClass" = "IOResources"
      |     "com.apple.AppleFSCompression.providesType10" = Yes
      |     "com.apple.AppleFSCompression.providesType9" = Yes
      |     "com.apple.AppleFSCompression.providesType8" = Yes
      |     "IOResourceMatch" = "IOBSD"
      |     "com.apple.AppleFSCompression.providesType7" = Yes
      |   }

Which seems to be something the Chameleon guys already worked out: trunk/CHANGES

Edit: Apple has just released an open source implementation: https://github.com/lzfse/lzfse

2
3

according to this post, you can use afscexpand tool to decompress such files.if you prefer the hard way, xnu source code may be of help.

2
  • Hi Igor, unfortunately that article doesn't go into the details of the compression algorithm. You can see in the decompfs.c source that they support registering many types of compression algorithms. Type 1 is no compression, type 4 uses zlib. This data is marked as type 8 and seems to be lacking any header which I know of. Feb 13 '15 at 8:46
  • then i guess you need to find all calls to register_decmpfs_decompressor and find the one that registers type 8. i'm guessing it will be one of the kexts.
    – Igor Skochinsky
    Feb 13 '15 at 10:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.