Vincent Gable’s Blog

April 29, 2010

What Am I About To Call?

Filed under: Cocoa,iPhone,MacOSX,Objective-C,Programming,Reverse Engineering,Tips | , ,
― Vincent Gable on April 29, 2010

Say you’re in gdb, and about to execute a call instruction for dyld_stub_objc_msgSend, how do you know what’s about to happen?

On i386

(gdb) x/s *(SEL*)($esp+4)

tells you the message that’s about to be sent.

(gdb) po *(id*)$esp

tells you the target object that’s about to get the message.

July 9, 2009


Filed under: Reverse Engineering,Uncategorized | , , , , ,
― Vincent Gable on July 9, 2009

When I was in my early teens, I played a lot of Marathon — the classic Macintosh first-person shooter by Bungie.

There’s a detail about Marathon ∞ that I haven’t seen documented anywhere, but I thought was very cool.

If you tried to use MacsBug on a PowerPC machine to inspect (disassemble) M∞, none of the functions had names, except for one: HeyPervertStopLookingAtMyPEF.

(PEF stands for Preferred Executable Format, the way Mac OS applications stored PowerPC code).

Today, you can still play Marathon 2: Durandal on XBox Live for a price, or play any of the trilogy for free on a computer. Sadly though, I don’t think the game has aged as well as Escape Velocity, which is still a blast today.

February 5, 2009

Reverse Engineering Inter-Process Communication

Filed under: Interface Builder,MacOSX,Reverse Engineering | ,
― Vincent Gable on February 5, 2009

Matt Gallagher tells how he reverse engineered the link between Xcode and Interface Builder. Very interesting, I learned a lot. I’ve done essentially the same thing with iChat. (And in retrospect it might have been a bad idea, because it’s broken on Snow Leopard).

December 19, 2008

Undocumented Automator.framework Goodness: Actions Library

In Leopard, Apple introduced AMWorkflowView and AMWorkflowController, which let you easily add automator-editing capabilities to your application (modulo bugs!)

Obviously, for editing a workflow to be useful, you need to be able to add actions to it. And to do that, you need to be able to browse and search actions. But the current Automator.framework has no official support for doing this.

But there are undocumented private APIs, which (link launches it) uses…

How to Find Them

class-dump is an amazingly useful command-line tool that lets you generate headers from a compiled Objective-C binary. Download it, and point it at /System/Library/Frameworks/Automator.framework/Automator, to see everything Automator.framework really lets you do.

Instant Library Panel

The most useful definition I found was,
@interface NSApplication (AMLibraryPanel)
- (void)orderFrontAutomatorLibraryPanel:(id)sender;

Calling [NSApp orderFrontAutomatorLibraryPanel:nil]; will show a panel with the same action-library view Automator has.

This is what I’m using right now in IMLocation to let people find actions for workflows. I don’t like the idea of using private APIs. But I like the idea of implementing my own AMLibraryView replacement even less. It would be a lot of work to make it as good as the real thing. Any differences give users a fractured experience — one way to do something in Automator, another in my program. And I would get dismal ROI, because I expect Apple to expose this functionality in the (near) future.

(I also wouldn’t be so bullish on using private APIs if I didn’t have workarounds in place right now. The only way orderFrontAutomatorLibraryPanel: gets called is if a user presses a “Show Actions” button on the toolbar. That same toolbar has an “Open in Automator” button that opens the worklfow in Automator, where they can edit it without bugs. So even if orderFrontAutomatorLibraryPanel: stopped working tomorrow, users could still do everything they could before — albeit less elegantly).

Looking Just Like Automator

I don’t recommend doing this, but I’ve been able to embed an AMLibraryView in an NSSplitView next to an AMWorkflowView, to get a more appearance.

Here’s how I did it, given the IBOutlets workflowViewAndLibrarySplitView which is an NSSplit view with an AMWorkflowView in one side, and the other side’s view connected to the outlet workflowLibraryView,

[workflowViewAndLibrarySplitView replaceSubview:workflowLibraryView with:[[AMLibraryPanel sharedLibraryPanel] _libraryView]];

Will put the library view inside your split view.

Of course this screws up orderFrontAutomatorLibraryPanel:. And I would not expect it to work in two windows. And it’s using an underscore-private method of an already private and undocumented API. That’s just to too risky for me; so I stick with the panel. It gets the job done with one line of code, and that’s good enough for me.

December 2, 2008

Bug In The Machine

Filed under: Announcement,Programming,Reverse Engineering | , , ,
― Vincent Gable on December 2, 2008

I was going through some old (OS 9 old at youngest!) backups, and found this dump from a MacsBug session. You can actually see a bug sitting in memory! To me it looks like the bug is inside an old television, with distortion sweeping across the screen, so some of the bug’s left side is wrapped around to the right.

 Displaying memory from 1D9F8CB0
  1D9F8CB0  •???•???•???•???•???•???•???•???•???•???•???•???•???•???•???•???
  1D9F8CF0  •???•???•???•???•???•???•???•???•???•???•???•???•???•???•???•???
  1D9F8D30  •???•???•???•???•???•???•???•???•???•???•???•???•???•???•???•???
  1D9F8D70  •???•???•???•???•üÖ`´••••••P•••Ñ•y•pÄ@•••••Ä•@•••••••••H•••H••••
  1D9F8DB0  •••••••••••É9ÿ•••••••••••••••••••üçÄ´••••• •••‚ 0000000000000000
  1D9F8DF0  0000000000000000000000000000000000000000000000000000000000000000
  1D9F8E30  0000000000000000000000000000000000000000000000000000000000000000
  1D9F8E70  0000000000000000000000000000000000000000000000000000000000000000
  1D9F8EB0  0000000000000000000000000000000000000000000000000000000000000000
  1D9F8EF0  0000000000000000000000000000000000000000000000000000000000000000
  1D9F8F30  0000000000000000000000000000000000000000000000000000000000000000
  1D9F8F70  0000000000000000000000000000000000000000000000000000000%***$*#**
  1D9F8FB0  #*$$*$*#*#**$$*00*$*$*$$**#*#*#*#*#*#**#%00000000000000*•!#•!!!!
  1D9F8FF0  !!!•!!!!!!!!!!!0%!!!!#!!!!!!!!!!!!!!!!!!*00000000000000*!"!•!!!!
  1D9F9030  !!••!!!!!!!!!!!0.!!••!!!!!!!!!!•!•!!•!!!#00000000000000*!!!(•!!!
  1D9F9070  !!!(•!!!!!!!!!!0%!!((!!!!!!!!•!!!!!!!!!!*00000000000000#!!! ••! 
  1D9F90B0  •••••••••••••••0*••!•••••••••••••••••••••00000000000000*!!!•••00
  1D9F90F0  •••••••••••••••0#••!•••••••••••!00•••••••00000000000000#!!!••#0/
  1D9F9130  0&••••••••••••••!••! •••••••••+0$0.••••••00000000000000#!!!•!0••
  1D9F9170  !00#••••••••!000000$!•••••••!00!••,••••• 00000000000000*!!!•0%••
  1D9F91B0  ••%0%••••••%00000000/••••••,0.••••%0•••••00000000000000$!••00•••
  1D9F91F0  ••!*00••••000000000000••••00!••••••00#•••00000000000000*!!/0••••
  1D9F9230  ••!••/0$•00000000000000••0$••••••••*0%!•!00000000000000#•#0$••••
  1D9F9270  •!•••!$•*00000000000000%•!•••••••!(•*0*• 00000000000000*•00••••!
  1D9F92B0  (•••••••0000000000000000•••••••!* •••%0•!00000000000000*00••••!0
  1D9F92F0  &!•••••/00000000000000000!•••'$00!••••00*00000000000000*•*!•••00
  1D9F9330  000••••000000000000000000•!•*00/%0••••••*00000000000000$!•!••$0•
  1D9F9370  ••%00•!000000000000000000*$00%!••0#••••••00000000000000$!••••0.•
  1D9F93B0  ••••$•%0000000000000000000•%!•••••0!••••!00000000000000*!•(•00••
  1D9F93F0  •••(••00000000000000000000!! •••••/0"••••00000000000000#!!!$0•••
  1D9F9430  ••!!••00000000000000000000•!!••••!#0%!•••00000000000000*!!*0*•••
  1D9F9470  ••!•••00000000000000000000*!•••("!••0#•••00000000000000*!!0,••••
  1D9F94B0  •! •••00000000000000000000#!•!•!••••/0•• 00000000000000#!%0!••••
  1D9F94F0  ••••••00000000000000000000#•*••••••••0%!!00000000000000*!•$•••%0
  1D9F9530  0000#•00000000000000000000#%00000%•••!•!•00000000000000*!!!••!0%
  1D9F9570  *•! ••00000000000000000000*#*$!!•0!•••••*00000000000000*!(!••00!
  1D9F95B0  ••••••00000000000000000000••!!•••/0•••••#00000000000000#!!!•$0••
  1D9F95F0  ••••••%0000000000000000000!(!!••••0%•••••00000000000000*!!!(0*••
  1D9F9630  ••!!!!.000000000000000000.!!!••!!!%0-!••!00000000000000*!(•0,•••
  1D9F9670  ••!•!•!000000000000000000•#*•••••••,0••••00000000000000$!!$0••••
  1D9F96B0  •!•$00•/00000000000000000•00/*••••••0.!•!00000000000000*!!!!••••
  1D9F96F0  #000•••!0000000000000000$(•.00%••••• •!!•00000000000000*!!••••••
  1D9F9730  00!•••••/000000000000000!!(!!*00•••••• !•00000000000000$!!(••••$
  1D9F9770  0•••••••!00000000000000*!!!!!•!0!••••••!$00000000000000#(!!••••0
  1D9F97B0  ,••••••!!$000000000000$!!!!!!•!00•••••••$00000000000000*!!!••••0
  1D9F97F0   ••••!••••!0000000000$(!!!!!••••0*••••••!00000000000000#!!!•••,/
  1D9F9830  ••••!!!•••••00000000*!!!!"!!••••/0••••••!00000000000000*!!!•••0!
  1D9F9870  ••••••••••••••$%%%•!!!!!!!!••••• 0)••••••00000000000000#!!!••/0•
  1D9F98B0  •••!!•••••••••.,/•(•!!!!!!•••••••0,!!••••00000000000000*!!!••0!•
  1D9F98F0  •••••••••••••00000•!!!!!!••••••••!0!!••••00000000000000#!!!•••••
  1D9F9930  ••!!••••••••.000000!!!!!••••••••••••!!••!00000000000000$••!•••••
  1D9F9970  ••!•••••••••0000000!• •••••••••••••••!•••00000000000000*!•!•••••
  1D9F99B0  •!!•••••••••0000000$!••••••••••••••••!!•!00000000000000#!!!•••••
  1D9F99F0  •!•••••••••!0000000*!"••••••••••••••••!• 00000000000000#!!••••••
  1D9F9A30  ••••••••••••0000000#!!••••••••••••••••••!00000000000000#!!!•••••
  1D9F9A70  ••••••••••••0000000•!!!••••••••••••••••••00000000000000$!"••••••
  1D9F9AB0  •••••••••••••000000!!!••••••••••••••••••!00000000000000*!!!•••••
  1D9F9AF0  •••••••••••••/0000•(!!!••••••••••••••••• 00000000000000#!•!•••••
  1D9F9B30  ••••••••••••••!*$•!!!!!••••••••••••••••••00000000000000#!!••••••
  1D9F9B70  ••••••••••••••••!!!"!!!••••••••••••••••••00000000000000*!!!•••••
  1D9F9BB0  •••••••••••••••••!!!!!•••••••••••••••••••00000000000000%$#*!!•! 
  1D9F9BF0  •!!!•• ! •! • • !#*$*#!!!•! !! !•• ! • !*00000000000000000000000
  1D9F9C30  0000000000000000000000000000000000000000000000000000000000000000
  1D9F9C70  0000000000000000000000000000000000000000000000000000000000000000
  1D9F9CB0  0000000000000000000000000000000000000000000000000000000000000000
  1D9F9CF0  0000000000000000000000000000000000000000000000000000000000000000
  1D9F9D30  0000000000000000000000000000000000000000000000000000000000000000
  1D9F9D70  0000000000000000000000000000000000000000000000000000000000000000
  1D9F9DB0  0000000000000000000000000000000000000000000000000000000000000000
  1D9F9DF0  0000000000000000000000000000000000000000000000000000000000000000
  1D9F9E30  0000000000000000000000000000000000000000000000000000000000000000
  1D9F9E70  0000000000000000000000000000000000000000000000000000000000000000
 Unrecognized symbol 'prinf'
 Closing log

I swear this is a real memory dump of a sold-for-money application that I didn’t have any part in writing. Unfortunately I don’t remember some specifics, like which application it was.

September 18, 2008

I Would Rather Have a Runtime Error Than a Compile Error

Filed under: Programming,Quotes,Reverse Engineering | , , ,
― Vincent Gable on September 18, 2008

And the weird thing is, I realized early in my career that I would actually rather have a runtime error than a compile error. [(some laughs)] Because at that time… now this is way contrary to popular opinion. Everybody wants early error detection. Oh God, not a runtime error, right? But the debugger gives you this ability to start poking and prodding, especially in a more dynamic language, where you can start simulating things, you can back it up… You’ve got your time-machine debuggers like the OCaml one, that can actually save the states and back up.

You’ve got amazing tools at your disposal (in the debugger)… Whereas if the compiler gives you an error that says “expected expression angle-bracket”, you don’t have a “compiler-debugger” that you can shell into…

So, you know, in some sense, your runtime errors are actually kind of nicer.

— An excerpt from one of Steve Yegge’s (long!) talks.

I think there is a real nugget of truth in this. At runtime, you can examine your program’s state, but there is absolutely no way to do that at compile time. Without a debugger, you can’t just look at some nontrivial code and know what the value of x is when there’s an error reading y. (Adding "print x", recompiling, and trying again, would work of course, but that’s just using your compiler as an inefficient debugger!)

Similarly, Strong Typing vs. Strong Testing , essentially argues that some tests can only be made at runtime. (If you read any links on this page, read it, it’s much shorter and to the point).

July 14, 2008

Crash Reporter Prefs

Filed under: MacOSX,Reverse Engineering,Tips |
― Vincent Gable on July 14, 2008

/Developer/Applications/Utilities/ can make crash reports much more useful. It will show crash-reports for background processes, and stack-trace in the notification dialog.

Crash report-files are stored in ~/Library/Logs/CrashReporter/

Unfortunately, crash reports are not sent back to third-party developers, even when you send them to Apple.

EDITED TO ADD: This still works in Snow Leopard (Mac OS X 10.5.6)

July 7, 2008

Getting OS X Icons

Filed under: Design,MacOSX,Programming,Reverse Engineering,Usability | ,
― Vincent Gable on July 7, 2008

This is what the Apple HIG has to say about icons. You should read it if you ever use icons. Even if you are not drawing your own icons, you need to understand how they should be used. (eg: icons in a toolbar should have a flat “head on” perspective, not the three-demensional look they have in the Dock.) You’ll find the icons you need faster if you know what they should look like.

Websites with icons you can use freely: IconDrawer, Iconfactory,

SystemIconViewer (source included) by Noodlesoft is a useful tool. It lets you browse over 100 standard OS X icons that are available programatically.

For getting paths to private OS X icons, try poking around inside — A commercial program that lets you customize just about any icon on your system. As of v2.6.1 / contains information on where icons are located. Icon locations do change completely between releases of OS X, even if the icon itself does not! I found CandyBar to be a better source of up-to-date icon locations then google. IconData.plist is pretty big and dense, but you can search it for keywords if you open it in Xcode, which helped me a lot.

(Although I haven’t used any of them personally, these are some design firms Apple recommends, if you have the cash.)

Powered by WordPress