Crushing candies

King company, developers of Candy Crush Saga video game, seems to be proud of their willful evil attitude (1, 2, 3, …). It seems they are trying to grab an all time classic video game pretending to be the original creators.

But we have to accept Candy Crush is a crazy social phenomena with 46 million average monthly users. It is installed on almost every smartphone, tablet, or electronic device.

I, personally, lost the interest on it when I realize that all the levels where just the same with random difficulty. Most of the time I had the impression that it was not possible to accomplish the level if you didn’t play a minimum number of lifes.

That’s why I started looking into the application and tried to figure out how it works, that’s what I have found:

There are many applications to cheat, most of them give you infinite lives or boosters. But what about beating a level without even playing it?

Charles Web Debugging Proxy its a very powerful application that allows you to motorize internet connections. You can even use breakpoints to change the requests and the response allowing to do MITM attacks in a very simple way. The interface is awesome. With this application I started looking inside candy crush communication with king server. Most of the communication is done in HTTP, and they only use HTTPS for a few options.

Charles

The API function to communicate king server when you have finished a level (gameEnd2) is sent though HTTP, so I use this weakness to have some fun.
As the seed is sent at the initialization command the only annoying parameter of the request is “cs”, obviously a checksum. To find out how to generate the checksum, it is enough to decompile flash facebook aplication and search for “gameEnd2”:

api

Before calling the function, the program generates a MD5 hash. Mhhh tasty.

MD5

To get the checksum it is enough using the 6 first characters of the MD5 hash of the formula above. Following the path it is not difficult to get the secretForHash:

treasure

With this information I started playing with python and I wrote the following lines to beat all unlocked levels:

 

import requests
import json
import hashlib
import sys

session = sys.argv[1]

logo = """
   ______                __      ______      __           
  / ____/___ _____  ____/ /_  __/ ____/___ _/ /____  _____
/ /   / __ `/ __ \/ __  / / / / __/ / __ `/ __/ _ \/ ___/
/ /___/ /_/ / / / / /_/ / /_/ / /___/ /_/ / /_/  __/ /    
\____/\__,_/_/ /_/\__,_/\__, /_____/\__,_/\__/\___/_/     
                       /____/                             

"""
print logo

secretForHash = "BuFu6gBFv79BH9hk"
episode = "0"
level = "0"
candyURL = "http://candycrush.king.com/api/"

# Llamamos la funcion gameInit para sacar la informacion de la session:
args = {"_session": session}
sessionInfo = requests.get(candyURL + "gameInit", params=args)
userID = sessionInfo.json()["currentUser"]["userId"]
print "You are CCS user number: " + str(userID)

userUniverse= sessionInfo.json()["userUniverse"]
episode = 0
level = 0
while "score" in userUniverse["episodes"][episode]["levels"][level]:
    level = level +1
    if level >= len(sessionInfo.json()["userUniverse"]["episodes"][episode]["levels"]):
        level = 0
        episode = episode + 1
        
print "Current state: episode {0} level {1}".format(episode,level)

try:
    while True:
        score = sessionInfo.json()["universeDescription"]["episodeDescriptions"][episode]["levelDescriptions"][level]["starProgressions"][2]["points"] + 123
               
        args = {"_session": session, "arg0": episode + 1, "arg1": level + 1}
        seed = requests.get(candyURL + "gameStart", params=args).json()["seed"]
        
        # {"score":26240,"levelId":3,"seed":1396556308705,"timeLeftPercent":-1,"variant":0,"reason":0,"episodeId":1,"cs":"38fb4a"}
        arg0 = {"score": score, "levelId": level + 1, "seed": seed, "timeLeftPercent": -1, "variant": 0, "reason": 0, "episodeId": episode + 1}
    
        # MD5.hash(param1 + ":" + param2 + ":" + param3 + ":" + param4 + ":" + _loc_8 + ":" + this._seed + ":" + this._secretForHash);
        str2Hash = str(arg0["episodeId"]) + ":" + str(arg0["levelId"]) + ":" + str(arg0["score"]) + ":" + str(arg0["timeLeftPercent"]) + ":" + str(userID) + ":" + str(arg0["seed"]) + ":" + secretForHash 
        checksum = hashlib.md5(str2Hash).hexdigest()
        
        arg0["cs"] = checksum[0:6]
        args = {"_session": session, "arg0": json.dumps(arg0)}
        
        print("Unlocking episode {} level {} - score {} and seed {}".format(episode, level, score, seed)) 
        response = requests.get(candyURL + "gameEnd", params=args)
        
        # Next level:
        level = level +1
        if level >= len(sessionInfo.json()["universeDescription"]["episodeDescriptions"][episode]["levelDescriptions"]):
            level = 0
            episode = episode + 1
            
except:
    # print sys.exc_info()[0]
    # print sys.exc_info()[1]
    # print sys.exc_info()[2]
    print "Done"

 

And that’s how it works, the input parameter is your session hash. You can get it with Charles or wireshark or however you prefer.

termianl

And that’s the result:

Advertisements


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