Chapters

Hide chapters

Advanced Apple Debugging & Reverse Engineering

Fourth Edition · iOS 16, macOS 13.3 · Swift 5.8, Python 3 · Xcode 14

Section I: Beginning LLDB Commands

Section 1: 10 chapters
Show chapters Hide chapters

Section IV: Custom LLDB Commands

Section 4: 8 chapters
Show chapters Hide chapters

18. Mach-O Fun
Written by Walter Tyree

Heads up... You're reading this book for free, with parts of this chapter shown beyond this point as scrambled text.

Hopefully you’re not too burnt out from dumping raw bytes and comparing them to structs in the previous chapter, because here comes the real fun!

To hammer in the different Mach-O section types, you’ll build a series of examples across this chapter. You’ll start with a “scanner” that looks for any insecure http: hardcoded strings loaded into the process. After that, you’ll learn how to cheat those silly, gambling or freemium games where you never win the loot.

Commence funtime meow.

Mach-O Refresher

Just so you know what’s expected of you, you’ll start with a brief refresher from the previous chapter.

Segments are groupings on disk and in memory that have the same memory protections. Segments can have zero or more sections found inside a grouping.

Sections are sub-components found in a segment. They serve a specific purpose to the program. For example, there’s a specific section for compiled code and a different section for hard-coded strings.

Sections and segments are dictated by the load commands, which are at the beginning of the executable, immediately following the Mach-O Header

You saw a couple of the important segments in the previous chapter, notably the __TEXT, __DATA, and __LINKEDIT segments.

The Mach-O Sections

Included in this chapter is an iOS project called MachOFun. Open it up and take a look around.

(lldb) image dump sections MachOFun
  0x00000001 code             [0x00000001006e0240-0x00000001006e8b34)  r-x  0x00004240 0x000088f4 0x80000400 MachOFun.__TEXT.__text
(lldb) image lookup -n "-[UIViewController viewDidLoad]"
1 match found in /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/PrivateFrameworks/UIKitCore.framework/UIKitCore:
        Address: UIKitCore[0x0000000000abb3f8] (UIKitCore.__TEXT.__text + 11243624)
        Summary: UIKitCore`-[UIViewController viewDidLoad]
0x00000006 data-cstr        [0x0000000109e6a320-0x0000000109e6b658)  r-x  0x0000c320 0x00001338 0x00000002 MachOFun.__TEXT.__cstring
(lldb) memory read -r -fC -c 0x00001338 0x0000000109e6a320

Finding HTTP Strings

Now that you know hardcoded UTF-8 strings are stored in the __TEXT.__cstring module, you’ll use that knowledge to search every module in the process to see if any string begins with the characters "http:"

import MachO
for i in 0..<_dyld_image_count() {
    let imagePath = _dyld_get_image_name(i)!
    let name = String(validatingUTF8: imagePath)!
    let basenameString = (name as NSString).lastPathComponent

    var module : InsecureHTTPRequestsData = (basenameString, [])
    var rawDataSize: UInt = 0
    guard let rawData =
      getsectdatafromFramework(basenameString,
                               "__TEXT",
                               "__cstring",
                               &rawDataSize) else {
      continue
    }

    print(
      "__TEXT.__cstring data: \(rawData), \(basenameString)")
}
__TEXT.cstring data: 0x0000000102bae5e0, libBacktraceRecording.dylib
__TEXT.cstring data: 0x0000000102b82688, libRPAC.dylib
__TEXT.cstring data: 0x0000000102bedf88, libViewDebuggerSupport.dylib
__TEXT.cstring data: 0x0000000102a6a0a0, MachOFun
...
(lldb) image lookup -a 0x0000000102bedf88
Address: libViewDebuggerSupport.dylib[0x000000000002df88] (libViewDebuggerSupport.dylib.__TEXT.__cstring + 0)
Summary: "numberOfSections"
(lldb) x/s 0x0000000102bedf88
0x102bedf88: "numberOfSections"
var index = 0
while index < rawDataSize {
  let cur = rawData.advanced(by: index)
  let length = strlen(cur)
  index = index + length + 1

  guard let str = String(utf8String: cur),
    length > 0 else {
      continue
  }

  if str.hasPrefix("http:") {
    module.strings.append(str)
  }
}

if module.strings.count > 0 {
  dataSource.append(module)
}
let _ = "https://www.google.com"
let _ = "http://www.altavista.com"

Sections in the __DATA Segment

Now that you’ve got your public insecure URL shaming out of the way, it’s time to shift the attention to the writeable __DATA segment and explore some interesting sections.

(lldb) image dump sections MachOFun
0x00000015 data-ptrs        [0x000000010213c7a8-0x000000010213c7c8)  rw-  0x000107a8 0x00000020 0x10000000 MachOFun.__DATA_CONST__objc_classlist
(lldb) x/4gx 0x0000010dcae8e0
0x10dcae8e0: 0x000000010dcb0580 0x000000010dcb0690
0x10dcae8f0: 0x000000010dcb0758 0x000000010dcb0800
(lldb) exp -l objc -O -- 0x000000010dcb0580
MachOFun.CasinoContainerView

(lldb) exp -l objc -O -- 0x000000010dcb0690
MachOFun.CasinoViewController

(lldb) exp -l objc -O -- 0x000000010dcb0758
MachOFun.InsecureNetworkRequestsTableViewController

(lldb) exp -l objc -O -- 0x000000010dcb0800
MachOFun.AppDelegate

The __bss, __common and __const Sections

Sometimes a module needs to keep references to data that lives past a function call. As you’ve learned earlier, if you were to declare a constant such as let v = UIView() inside of a function, the pointer v is stored on the stack which points to allocated memory on the heap. But as soon as the instruction pointer leaves the function, the reference to the v variable is long gone. That’s why there are several sections in the __DATA segment designed to store variables across the lifetime of a process.

Cheating Freemium Games

The __DATA segment not only stores references to data in the module, but it also provides references to external variables, classes, methods, and functions that are not defined within the module.

(lldb) exp -l objc -O -- [[NSBundle mainBundle] executablePath]
(lldb) platform shell dyld_info -fixups ${APP_PATH}
__DATA_CONST __got            0x1000102D0              bind  libSystem.B.dylib/_arc4random_uniform
(lldb) po (char *)_dyld_get_image_name(3)
/Users/virtualadmin/Library/Developer/CoreSimulator/Devices/53BD59A2-6863-444C-8B4A-6C2E8159D81F/data/Containers/Bundle/Application/D62A2699-1881-4BC5-BD11-ACAD2479D057/MachOFun.app/MachOFun
(lldb) p/x (intptr_t)_dyld_get_image_vmaddr_slide(3) + 0x1000102D0
(lldb) x/gx 0x00000001005ec2d0
0x1005ec2d0: 0x00000001800d8bc4
(lldb) image lookup -a 0x00000001800d8bc4
Address: libsystem_c.dylib[0x0000000000023bc4] (libsystem_c.dylib.__TEXT.__text + 141016)
Summary: libsystem_c.dylib`arc4random_uniform
(lldb) exp -l objc -p -- int lolzfunc()  { return 5; }
(lldb) p/x lolzfunc
(int (*)()) $0 = 0x00000001018209b0
(lldb) memory write -s8 0x00000001005ec2d0 0x00000001018209b0

Objective-C Swizzling vs Function Interposing

Unlike Objective-C method swizzling, lazy pointer loading occurs on a per-module basis. That means that the trick you just performed will only work when the MachOFun module calls out to arc4random_uniform. It wouldn’t work if, say, CFNetwork called out to arc4random_uniform.

Key Points

  • Use image dump sections to find all of the segments and sections for a module.
  • TEXT.__cstring holds hard coded utf8 strings in an executable. Where do you think the other strings are?
  • Explore the __DATA sections to find links to other modules as well as symbol names and metadata.
  • The terminal apps nm, otool and dyld_info can help you discover symbols in applications.

Where to Go From Here?

Oh my! There is so much more for you to learn about Mach-O, but the road ends here for now.

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2024 Kodeco Inc.

You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a Kodeco Personal Plan.

Unlock now