112

I submitted a binary file to Apple without any source code.

Apart from manually checking the source code how does Apple know what was used and what APIs you have called?

Tim Ferrell
  • 1,257
  • 16
  • 38
Tattat
  • 14,290
  • 32
  • 84
  • 135

10 Answers10

179

There are 3 ways I know. These are just some speculation, since I do not work in the Apple review team.

1. otool -L

This will list all libraries the app has linked to. Something clearly you should not use, like IOKit and WebKit can be detected by this.

2. nm -u

This will list all linked symbols. This can detect

  • Undocumented C functions such as _UIImageWithName;
  • Objective-C classes such as UIProgressHUD
  • Ivars such as UITouch._phase (which could be the cause of rejection of Three20-based apps last few months.)

3. Listing Objective-C selectors, or strings

Objective-C selectors are stored in a special region of the binary, and therefore Apple could extract the content from there, and check if you've used some undocumented Objective-C methods, such as -[UIDevice setOrientation:].

Since selectors are independent from the class you're messaging, even if your custom class defines -setOrientation: irrelevant to UIDevice, there will be a possibility of being rejected.


You could use Erica Sadun's APIKit to detect potential rejection due to (false alarms of) private APIs.


(If you really really really really want to workaround these checks, you could use runtime features such as

  • dlopen, dlsym
  • objc_getClass, sel_registerName, objc_msgSend
  • -valueForKey:; object_getInstanceVariable, object_getIvar, etc.

to get those private libraries, classes, methods and ivars. )

kennytm
  • 469,458
  • 94
  • 1,022
  • 977
  • Great answer. I'll just add that if your application is doing something that is extremely difficult to do without using a private API, I'm sure your app gets extra scrutiny. – Matthew Frederick Dec 14 '10 at 08:30
  • I'm curious about the workaround of calling private methods. I think the compiler will generate call to objc_msgSend(foo, @selector(privateMethod)) for [foo privateMethod], so if Apple can detect the direct call of privateMethod they can also detect the indirect call via objc_msgSend(or performSelector:). – an0 Feb 16 '11 at 03:45
  • I'm wondering why you say that you shouldn't link against IOKit and WebKit? – hjaltij Apr 13 '11 at 11:43
  • otool -ov just show the classes/selectors of the app it's self. Is there any way we can show the symbols it's linked to ? nm -u just show the objective c classes, i want show the objective-c selectors too. – jim.huang Feb 23 '12 at 03:13
  • 2
    What do you execute otool on? The .app file? – Rob Apr 23 '12 at 23:58
  • Couldn't apple just compile a version of iOS with guards and run your app on it ? – Eric Jun 01 '12 at 23:55
  • 1
    @Eric, they *could*, although such an instrumented version would probably impact performance. Regardless, seeing private APIs get through into the App Store repeatedly, it's clear that they **don't** do this, or at least don't do it all the time. – Nate Jan 28 '13 at 08:55
  • If someone is interested, Erica Sadun's tool is now expired. You can fake it by using libfaketime (`brew install libfaketime`), and calling `faketime '2008-12-12' ./apiscanner your.app` – Eric Feb 11 '13 at 13:10
  • You mentioned that `-valueForKey:` should be safe to use. Can you comment on setting the value of a private key. Is `-setValue:forKey:` safe in your opinion? – Daniel May 31 '13 at 03:48
  • @Daniel: Should be the same. – kennytm Jun 02 '13 at 11:02
  • Based on these post I created tool which check if library uses some specific/private API. You can find this script in the following location https://github.com/nomenas/APIChecker. Developers who will discover more MacOS private APIs are welcomed to update this list with APIs in this repository. – nomenas Jul 09 '13 at 22:10
26

You can list the selectors in a Mach-O program using the following one-liner in Terminal:

otool -s __TEXT __objc_methname "$1" |expand -8 | cut -c17- | sed -n '3,$p' | perl -n -e 'print join("\n",split(/\x00/,scalar reverse (reverse unpack("(a4)*",pack("(H8)*",split(/\s/,$_))))))'
Constantino Tsarouhas
  • 6,736
  • 6
  • 43
  • 54
Robert Diamond
  • 1,065
  • 1
  • 13
  • 10
  • +1, @Robert Diamond, Can you describe more for the same. I need to check Google analytic uses UDID call or not. Thanks – Mangesh May 13 '13 at 08:03
13

Let's say you want to use some private API; objective C allows you to construct any SEL from a string:

   SEL my_sel = NSSelectorFromString([NSString stringWithFormat:\
@"%@%@%@", "se","tOr","ientation:"]);
    [UIDevice performSelector:my_sel ...];

How could a robot or library scan catch this? They would have to catch this using some tool that monitors private accesses at runtime. Even if they constructed such a runtime tool, it is hard to catch because this call may be hidden in some rarely exercised path.

  • [user1203764](http://stackoverflow.com/users/1203764/user1203764) [comments](http://stackoverflow.com/suggested-edits/199528) that these kind of calls can actually be detected – Rup Feb 11 '12 at 13:43
  • @Rup want to put an opinion on my question here about using valueForKey, please? http://stackoverflow.com/questions/11923597/using-valueforkey-to-access-view-in-uibarbuttonitem-private-api-violation – Dan Rosenstark Aug 12 '12 at 16:23
  • 1
    @Yar interesting question! But I'm not enough of an expert to comment sorry. What Farcaller said seems reasonable to me – Rup Aug 12 '12 at 20:16
  • Thanks @Rup, no one apparently is enough of an expert in this field :) – Dan Rosenstark Aug 13 '12 at 12:59
  • Someone I know says he just got a call like this into the App Store. – bugloaf Mar 13 '14 at 16:27
  • Of course, the very use of NSSelectorFromString can raise suspicion on the Apple reviewer side, and if so - he can use other tools to reconstruct the original code (disassemble) and understand the original intent of the use. – Motti Shneor Jun 30 '16 at 12:20
7

I imagine they look at all symbols your binary's trying to import (info no doubt easily available to them in the symbol table thereof) and ding you if any of those symbols are found in their "private API list". Pretty easy to automate, in fact.

Alex Martelli
  • 762,786
  • 156
  • 1,160
  • 1,345
  • 1
    Actually, I can say with certainty that this is not the case (at least it's not **all** they do), based on private API usage that I know has gotten through. If this is all that was needed, private API usage wouldn't *slip* through. My experience suggests that KennyTM's answer is almost certainly correct. This is an area where Objective-C is fundamentally different than other languages, like C. – Nate Oct 04 '12 at 03:54
1

aside from symbol investigation...

apple could very easily have a version of the sdk that checks each of the private methods stacks when called to make sure it is entered from one of the designated methods.

Grady Player
  • 13,550
  • 2
  • 47
  • 75
  • That won't be enough, because program can only call this private call at an arbitrary time in the future, depending on other logic. To do this scrutiny Apple must actually block private APIs altogether, or have the frameworks report private API calls to Apple automatically - which significantly harms performance. – Motti Shneor Jul 03 '16 at 11:31
1

A executable isn't exactly a black box. If you call out to a library, it's an easy thing to find. This is why I lament the loss of the assembly languages in modern CS educations. =] Tools like ldd will tell you what you have linked in, though I don't remember what incarnation of ldd made it to the mac iPhone dev kit.

Sniggerfardimungus
  • 10,708
  • 10
  • 46
  • 91
  • 1
    I've frequently wondered: if you were to write your binary to self-modify, only generating the code to import a private API after some criteria had been met (say, after the publication date of your app) whether Apple would catch it. They certainly report back to us some interesting statistics, like the number of our games that are being run on jailbroken phones. – Sniggerfardimungus May 16 '10 at 02:21
  • @user30997, The privileged code can probably only be accessed through a system call; the executing thread switches into a higher privilege and checks if the previous privilege has permissions to execute the code or not. That's just an example though, there are other ways of doing it, but I _highly_ doubt the developers were naive enough to leave out a basic runtime privilege checking mechanism such as this, it would definately have been publicized by now. – L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳ May 16 '10 at 03:07
1
otool -L somebinary
dvenema
  • 495
  • 1
  • 4
  • 8
0

Even if you're statically linking, at worst, they could take samples of the code from the private APIs on their list, and search your binary against them (also relatively easy to automate).

Knowing Apple, I'd bet they have a comprehensive, automated system, and any uncertainty is probably either denied or reviewed manually.

End of the day, I think it's probably not worth the effort to try and fool Apple.

wash
  • 467
  • 4
  • 7
0

This desktop application, App Scanner, can scan .app files for private api usage by pulling apart the Mach-O Binary file. If it can, then Apple can too!

0x8badf00d
  • 6,331
  • 3
  • 33
  • 66
Andrew
  • 2,692
  • 21
  • 27
0

There are a lot of tools for reverse engineering that allows inspect a code

  • nm - lists the symbols from object files
  • objdump - display information from object files.
  • otool - view the content of Mach-O[About] executables
  • strings - this will get you all the strings.

You can find examples/representation of using these commands in gists for Objective-C and Swift

yoAlex5
  • 13,571
  • 5
  • 105
  • 98