Skip to content

Instantly share code, notes, and snippets.

@andriitishchenko
Created December 16, 2022 22:26
Show Gist options
  • Save andriitishchenko/5e2cdec7bc30164f91c62557b63dcc73 to your computer and use it in GitHub Desktop.
Save andriitishchenko/5e2cdec7bc30164f91c62557b63dcc73 to your computer and use it in GitHub Desktop.
Mach-O analysis

Mac OS X executable (Malware) Analysis

some calc theory

(12345)₁₀ = (3039)₁₆

  • When 12345 is divided by 16, the quotient is 771 and the remainder is 9.
  • When 771 is divided by 16, the quotient is 48 and the remainder is 3.
  • When 48 is divided by 16, the quotient is 3 and the remainder is 0.
  • When 3 is divided by 16, the quotient is 0 and the remainder is 3.
  • Write the remainders from bottom to top.
(3039)₁₆ = (3 × 16³) + (0 × 16²) + (3 × 16¹) + (9 × 16⁰) = (12345)₁₀

The 0x prefix must be added explicitly

# dec to hex
$ printf '0x%x\n' 12345
0x3039

# hex to dec
$ printf '%d\n' 0x3039
12345

# shell math, note the result is always dec
$ echo $(( 1+17 ))   
18

$ echo $(( 0x1+17 ))
18

$ echo $(( 0x1 + 0x11 ))
18

some tools

check the architecture you have

$ uname -m
x86_64

chech type of file

$ file alert.app/Contents/MacOS/alert
alert.app/Contents/MacOS/alert: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit executable x86_64] [arm64:Mach-O 64-bit executable arm64]
alert.app/Contents/MacOS/alert (for architecture x86_64):	Mach-O 64-bit executable x86_64
alert.app/Contents/MacOS/alert (for architecture arm64):	Mach-O 64-bit executable arm64

So it is a fat binary what contains several architectures - x86_64 and arm64

$ otool -fh alert.app/Contents/MacOS/alert
Fat headers
fat_magic 0xcafebabe
nfat_arch 2
architecture 0
    cputype 16777223
    cpusubtype 3
    capabilities 0x0
    offset 16384
    size 58720
    align 2^14 (16384)
architecture 1
    cputype 16777228
    cpusubtype 0
    capabilities 0x0
    offset 81920
    size 73072
    align 2^14 (16384)
alert.app/Contents/MacOS/alert:
Mach header
      magic  cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
 0xfeedfacf 16777223          3  0x00           2    37       4216 0x00200085
$ size alert.app/Contents/MacOS/alert
__TEXT	__DATA	__OBJC	others	dec	hex
16384	16384	0	4295000064	4295032832	100010000

display the load commands:

$ otool -l alert.app/Contents/MacOS/alert
...long output...

print shared libraries used

$ otool -L alert.app/Contents/MacOS/alert
alert.app/Contents/MacOS/alert:
	/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (compatibility version 300.0.0, current version 1775.118.101)
	/usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1292.100.5)
	/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (compatibility version 45.0.0, current version 2022.44.149)
	@rpath/libswiftAppKit.dylib (compatibility version 1.0.0, current version 104.0.0)
    ...

list symbols from object files

$ nm alert.app/Contents/MacOS/alert 
...long output...

Check disassembly

# limited to first 10 lines
$ otool -tVj -arch x86_64 -function_offsets alert | head -10
alert:
(__TEXT,__text) section
    +0 0000000100001920	55              	pushq	%rbp
    +1 0000000100001921	4889e5          	movq	%rsp, %rbp
    +4 0000000100001924	53              	pushq	%rbx
    +5 0000000100001925	50              	pushq	%rax
    +6 0000000100001926	488b3d5b2d0000  	movq	0x2d5b(%rip), %rdi              ## Objc class ref: _OBJC_CLASS_$_NSApplication
   +13 000000010000192d	e8ca160000      	callq	0x100002ffc                     ## symbol stub for: _swift_getInitializedObjCClass
   +18 0000000100001932	488b35ff2c0000  	movq	0x2cff(%rip), %rsi              ## Objc selector ref: sharedApplication
   +25 0000000100001939	4889c7          	movq	%rax, %rdi
...

hex it!

# print bytes form position 0 to 0+120 by 16 bytes in a row
$ xxd -s 0  -l 120 -c 16 alert 
00000000: cafe babe 0000 0002 0100 0007 0000 0003  ................
00000010: 0000 4000 0000 e560 0000 000e 0100 000c  ..@....`........
00000020: 0000 0000 0001 4000 0001 1d70 0000 000e  [email protected]....
00000030: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000040: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000050: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000060: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000070: 0000 0000 0000 0000                      ........

Note, 00000000: cafe babe means Universal fat Binary archive - Big Endian.

 cefaedfe: Mach-O Little Endian (32-bit)
 cffaedfe: Mach-O Little Endian (64-bit)
 feedface: Mach-O Big Endian (32-bit)
 feedfacf: Mach-O Big Endian (64-bit)

let's get hexdecimal of the exact line +6 0000000100001926 488b3d5b2d0000 movq 0x2d5b(%rip), %rdi

offset = address - segment.address + segment.offset + fat_arch.offset

First get architecture offset

$ lipo -detailed_info alert
Fat header in: alert
fat_magic 0xcafebabe
nfat_arch 2
architecture x86_64
    cputype CPU_TYPE_X86_64
    cpusubtype CPU_SUBTYPE_X86_64_ALL
    capabilities 0x0
    offset 16384           < = = = = = = same as otool -fh 
    size 58720
    align 2^14 (16384)
architecture arm64
    cputype CPU_TYPE_ARM64
    cpusubtype CPU_SUBTYPE_ARM64_ALL
    capabilities 0x0
    offset 81920
    size 73072
    align 2^14 (16384)

as example for Non-fat:

$ lipo -detailed_info skype
input file skype is not a fat file
Non-fat file: skype is architecture: x86_64

Get section info

$ otool -l -arch x86_64 alert | grep __text -A 5
  sectname __text
   segname __TEXT
      addr 0x0000000100001920
      size 0x000000000000160a
    offset 6432
     align 2^4 (16)
  • address = 0000000100001926
  • segment.address = 0x0000000100001920 (addr)
  • segment.offset = 6432
  • fat_arch.offset = 16384

offset = 0x5926

$ printf '0x%x\n' $(( 0x0000000100001926 - 0x0000000100001920 + 6432 + 16384)) 
0x5926
$ xxd -s 0x5926  -l 120 -c 16 alert
00005926: 488b 3d5b 2d00 00e8 ca16 0000 488b 35ff  H.=[-.......H.5.
00005936: 2c00 0048 89c7 e861 1600 0048 89c7 e865  ,..H...a...H...e
00005946: 1600 0048 8905 7836 0000 31ff e8b9 0100  ...H..x6..1.....
00005956: 0048 89c7 e831 1600 0048 8b35 da2c 0000  .H...1...H.5.,..
00005966: 4889 c7e8 3416 0000 4889 055b 3600 0048  H...4...H..[6..H
00005976: 8b3d 4c36 0000 488b 35c5 2c00 0048 89c2  .=L6..H.5.,..H..
00005986: e817 1600 00e8 b815 0000 89c3 e8ab 1500  ................
00005996: 0089 df48 89c6 e895                      ...H....

Same for the other arch, but be aware that the bytes can be reversed LE<->BE

otool: +12 0000000100002c94 d503201f nop ; d503201f => 1f 20 03 d5

xxd: 00016c94: 1f20 03d5 80c2 0258 0d01 0094 1f20 03d5 . .....X..... ..

Dump method names from Obj-C section otool -oV alert

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment