How to play basketball like a pro

Do you know what I hate most? People who brags their achievements on Facebook. I can chew a gum and walk at the same time. I never bragged about it on Facebook though. Anyway, recently I saw lots of people posting screenshots of FaceBook Messenger’s basketball game scores. (If you don’t know, you can activate the game by sending basketball emoji 🏀 to yourself) I tried to play that game by myself, and found out that this game is pretty hard for me. I am competitive and I like challenges. How about fixing this game so that no matter what, everything will be perfect basket?

Preparation

In order to experiment with iOS binaries you must be jailbroken. Otherwise you will be limited to static analysis and you will have a hard time to do anything useful. In order to follow this tutorial, you must be jailbroken and able to SSH to your device. You can use this short tutorial to enable SSH access. If you are on Windows, use Putty to SSH to your phone. First thing is dumping class methods of Messenger’s binary. You can get the tools from iPhone Dev Wiki

I class dumped the binaries and found following interesting methods

-[MNBballScene setRimXVelocityMagnitude:]
-[MNBballScene setRimYVelocityMagnitude:]
-[MNBballScene readyBall]
-[MNBballScene readyBallAtRandomPosition]
-[MNBballScene _readyBallAtPosition:]
-[MNBballScene flingBallWithXVelocity:yVelocity:]
-[MNBballScene ballX]
-[MNBballScene ballY]
-[MNBballScene rimX]
-[MNBballScene rimY]
-[MNBballScene rimXVelocity]
-[MNBballScene rimYVelocity]
-[MNBballView bballGameBallIsReady:]
-[MNBballView bballGameBallHitRim:]
-[MNBballView bballGameMissedShot:]
-[MNBballView bballGameScored:]

Method names are pretty self explanatory. When you flick your finger, ballVelocityX and ballVelocityY are calculated. Around 0,65 seconds later you either hit the rim or score. Motion of the ball looks like a projectile motion. However, I found out that it is basically an illusion due to animation. In order to find out the logic of the game and possibly exploit it, we need access to raw data for successful hits.

We need a tool to live debug the app. There are basically two tools with scripting capabilities for these purposes. Frida and Cycript. I personally like Frida more but due to some bugs related to iOS, I used Cycript for this experiment. Cycript is a tool to inject javascript code in to live iOS process. It is created by saurik, I guess he doesn’t need an introduction. First of all, open Cydia and install Cycript. In order to test, SSH to your iPhone and type cycript. If you see cy# you are ready for the next step.

What makes basket a good basket?

I wanted to see what makes a good shot without touching the rim. Because when you hit the rim, your score is based on luck. I wanted to eliminate any luck factor.

Create a file named stats.cy with below contents and upload to your iPhone (/var/root)

What is the explanation of this file?

First we hook the function named -[MNBballScene flingBallWithXVelocity:yVelocity:] . In order to hook a function with Mobile Substrate you use following notation

var old_method_pointer = {};
MS.hookMessage(CLASSNAME, @selector(METHODNAME:), function(arguments) {
return old_method_pointer->call(this,arg0);
},old_method_pointer)

As you can see from the signature of this function, it takes two parameters(count colons) so our hook function becomes

MS.hookMessage(MNBballScene, @selector(flingBallWithXVelocity:yVelocity:),
//rest of the function body

In this function, we have all properties of the class. We get crucial properties of this class by using this syntax. Open Messenger, activate basketball game and switch back to your SSH session..If you are on cycript session, quit the session by typing :q. If you uploaded stats.cy to your device, type this commands one by one

cycript -p Messenger stats.cy
cycript -p Messenger

So when I fling the ball, I record every parameter of the shot.  If ball hits the rim, I increase hitRimCounter. I only log the record set, when we score without hitting the rim. Since when you hit the rim, result depends on luck. I played the game for a while and tried to score. It was pretty hard since I suck at games. My highest score was 26 I guess😀 After I played for a while, I switched back to my terminal. My cycript session was on. I typed log to see the contents of statistics. I quit cycript session by typing :q on console.  I first thought to use neural networks to tackle this problem. Due to nature of this data, it needed to be normalized, must be trained well etc. So I changed my mind and exported this data to spreadsheet file and tried to find some relations between input and output.

First attempt

From the data it is obvious that BallVelocityY doesn’t play much role on the success rate. What ever the distance, same BallVelocityY can be used for the fling. Therefore instead of finding both BallVelocityX and BallVelocityY, I fixed BallVelocityY as -900. I then realized that when you divide BallVelocityX to BallVelocityY, you get a result which is very close to the position of ball. Let’s test our idea. If you have cycript session, type :q to exit the session, which will also shutdowns the Messenger process.Create step1.cy with below content and upload to /var/root again

Again open the Messenger, activate the game and load step1.cy to Messenger process.

cycript -p Messenger step1.cy
cycript -p Messenger

Fling the ball. Wow! Much amazed! You will always score no matter how you fling the shot. When you pass 10, rim starts to move in X axis and after 30 it moves in both.

Getting a high score

If you just want a high score, we can prevent Rim to move in any direction so our script will work always. Just like previous one quit session, load step2.cy and play the game.

cycript -p Messenger step2.cy
cycript -p Messenger

By hooking setRimXVelocityMagnitude and setRimYVelocityMagnitude, this script always sets the speed of rim to 0. Therefore, rim will not move at all regardless of your score.

Perfecting the script

I wanted more because just showing off high score was not enough. People must see how it is done live. If you check my recorded log, RimVelocityX tells the magnitude and direction of the movement and rimX tells the position of rim. So we must also use RimVelocityX and rimX after we pass 10. I wish I could tell you how I came up with those numbers and throw you some fancy graphics. However, it was just basic try and error until I reached below script. Again, just like above, quit Cycript session, activate step3.cy and play the game.

cycript -p Messenger step3.cy
cycript -p Messenger

After 30 it gets harder because rim moves both in X and Y axis. However, script magically handles this. Since BallVelocityY doesn’t have much affect. It is there just for an illusion. Script of course doesn’t handle edge cases. Pun intended. You must try to fling the ball when it is not near the edge of screen. Because when backboard hits the edge of screen, direction of rim changes which invalidates the calculation. So if you are careful, you can easily score without missing a shot. When I was testing I reached 101 and then I stopped because I got bored.

Look Ma, no hands

Then I thought, maybe I should let the game play itself. -[MNBballScene rimX]  is a getter function which is used to get position of rim on X axis. Next script hooks this function and checks whether rimX is in safe range for a shot. When everything is right, shot is fired.

cycript -p Messenger step4.cy
cycript -p Messenger

Again shutdown your cycript session and activate step4.cy as before and just fling the ball once and watch the game play itself😀 It is pretty amazing to see that in action. So I recorded that part for your entertainment.

I guess that is all folks. If you find any error, or have improvements for the code, please comment below.

 

9 thoughts on “How to play basketball like a pro

  1. Hi there!, Nice write-up!, I am getting a segfault when running cycript -p Messenger stats.cy, have you come across that?

    • I got segfault as well but scripts were injected successfully. If scripts were injected you can reach your variables such as log etc. from the console. I wrote this article with iOS 9.0.1 so I don’t know what happens with other iOS versions.

      • Ok good to know. By the way have you been able to disable cert pinning for this specific app?, I am curious on how the MQTT traffic looks like before they deploy the Signal protocol on production. I am starting to learn cycript and the like and it’s awesome!

      • I didn’t dealt with cert pinning with this because it doesn’t need for my purpose. I generally use a SSL Kill Switch tweak from cydia. Most of the time it worked. I don’t know whether it will work for this app.

      • IIRC, I generally got segfault when I stop cycript session. I really don’t know the reason really. You may try to ask to helpful guys at #cycript channel at irc.saurik.com

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s