In the late-2000’s, I spent more time than I care to admit playing Halo online. During this time I was exposed to (but did not participate in) the small but unavoidable modding community within the game. People who had found ways to cheat, or alter the game to either win or sometimes just to implement fun new features. One of the techniques used was “Standby” cheating, which was when software was used to block the internet connections of the players on the opposing team, send large amounts of information to their connections, and force them to drop out of the game. If you were playing a 4v4 matchmaking game 3 of your teammates could be dropped from the game and the opposing team would just wait around to either kill you or run the clock for the win.
What does this have to do with Zoom? In order for “Standby” cheating to work, you would needed to be the “host” of the game. In Halo, host was usually given to whichever player had the fastest internet connection, and if you were able to slow down all other player connections, you could force yourself to become host. When I first started using Zoom, I saw the “claim host” button and was taken back to the times spent playing Halo. After all, Zoom is basically just a visual version of the game lobby — sans profanity (nsfw). In this article we are going to crack the Zoom host code, in a way that is functional but not practical.
Note: The following code is inefficient and may crash when run, especially when generating 8–10 digit numbers. Please be cautious if copying and pasting code, you can also use the command line version of this script., which has some built-in safeguards to prevent unwanted behavior.
First, we will need to download and import pyperclip, pyautogui, and pynput. Pyperclip will be used to save each host key we generate to our clipboard, and pyautogui will allow out program to interact with the Zoom user interface. I will be using a Mac connected to a 4K monitor for this project (this will be important to consider later, as pyautogui uses screenshots to locate items on the screen). Pynput will be used to click the input box bordered in blue seen in the below screenshot.
Analyzing the problem.
How do we know what the Zoom host code might be? Well, they tell us:
Part of my interest in this code is that it presents itself as a real-world version of a word problem that you may see on a test. What we want to find are all possible 6 digit, 7 digit, 8 digit, 9 digit, and 10 digit numbers. Because order matters, we are looking for all permutations of 6–10 digit numbers with repetition. We can find the number of possible codes with the following formula: nr, where n is the number of possible digit values for each ‘space’ in the key (0–9), and r is the number of digits in the key (r=10 for a 10 digit code). For a 10 digit code, we would have 10 billion possible numbers (10¹⁰).
We’ve figured out how many possible host keys there will be, but how do we find each possible host key? We use the cartesian product.
In python we can use itertools.product() to generate all of the possible host keys for a given digit length (6 digit code, 7 digit code etc.).
Above, we have a function that:
- Generates all of the possible n digit codes.
- Casts the resulting numbers as a list of lists of digits.
- Appending each resulting code to the master_key list.
- Turn the master_key list into an iterable, this way we can call next() to receive the next code in the list.
Interacting with Zoom via pyautogui/pyperclip.
Now that we can generate lists of all possible codes (more on this later), we need to interact with the Zoom interface in order to input those codes. For this we will use pyperclip, which allows us to save a list element as a string to the clipboard, and pyautogui which allows us to search for and interact with elements on the screen.
By passing the file path of a screenshot of a visual element on the screen, locateOnScreen() will search the screen and return the coordinates of the item if it is found. We can then use click(x,y) to click on the screen position. Because I am using a 4K display, I need to cut the resolution in half by multiplying each coordinate by .5.
In the above code, we perform the following tasks:
- Locate the ‘Claim Host’ button.
- Finding the coordinates of the center of the button on the screen.
- Clicking the button.
After the ‘Claim Host’ button is clicked the following input box appears center screen:
Lastly, after a number is entered, a blue ‘Claim Host’ button appears next to the input box:
We can automate the host key input by placing out mouse and keyboard movements at the appropriate position within script. We will break the tasks of copying/pasting/clicking into functions, then at the end of the script call the functions in the order we need them to execute. Then we are going to call that driver function at the end of the script recursively, so it will run until either the programs crashes or the master_key generator is consumed. We will use Pyperclip to copy each key from the master_key list to the clipboard, at each loop iteration. Let’s look at the code.
As we can see from the above gif, this code works — but not well. We can look at a rough estimate of how long each loop takes to complete.
After 100 iterations of the loop, it took our driver function and average of 2.6690 seconds to complete the necessary processes. Using a 2016 Macbook Pro with 2.7 GHz Quad-Core Intel Core i7 processor it will take on average:
- 4.413 weeks to crack, if we needed the last 6 digit host code.
- 44.130 weeks to crack, , if we needed the last 7 digit host code.
- 8.463 years to crack, if we needed the last 8 digit host code.
- 84.663 years to crack, if we needed the last 9 digit code.
- If we were unlucky, and the key we needed was the last 10 digit number in the master key list, 9999999999, it would take approximately 846.334 years to obtain the correct host code.
In the future, it would be interesting to revisit this project, dig deep into the nitty gritty of the operations taking place within the script, and see how performance could be improved. I should also make the necessary changes to deal with a correct guess, so in 800 years maybe i’ll receive a nice ‘success’ message. Check my github repository to see if I was able to make any progress, or share suggestions below!