Coinmaster
4 minute read
Coinmaster is the name of a popular mobile game that allows players to build their own village and attack other players' villages. The game is free to play, but players can purchase virtual coins and spins to speed up their progress. It is almost purely luck based, with the only skill being in how you spend your coins and spins. I wanted to see if I could create a bot that could play the game for me.
Tools Used
- Python: The primary programming language.
- Fiddler: For capturing and analyzing HTTP traffic.
- Android Emulator: For running the game on a computer.
- ADB: For interacting with the emulator.
- Frida: For SSL pinning bypass.
- Jadx: For decompiling and reverse engineering the game.
Method
Creating the Bot
The game was available in the browser via facebook initially, which made it easy to capture the traffic and reverse engineer the API with fiddler. I then created a python bot that could play the game, which was quite straigt forward. The bot played a strategy where it would only spin when the spinns were full, or when it had atleast one missing shield. This strategy was quite effective (although nothing extraordinary), and the bot was able to play the game for me for a long time.
Here is the result of letting the bot play for a few days:
Here is the main loop of the bot, which would run indefinitely until I stopped it manually:
while 1:
CoinMaster.update_offers()
CoinMaster.click_offers()
CoinMaster.update_login_bonus()
CoinMaster.update_balance()
# Check if login bonus is unclaimed
if not CoinMaster.login_bonus["claimed"]:
# Collect the login bonus
CoinMaster.collect_login_bonus()
# Check is daily bonus is available
if CoinMaster.time_to_daily_bonus == 0:
# Collect the daily bonus
CoinMaster.collect_daily_bonus()
# Claim all chests from generic rewards
for reward in CoinMaster.generic_rewards:
reward_UID = reward['id']
chest_type = reward['subType']
# Claim the reward from the server
CoinMaster.claim_generic_reward(reward_UID)
logging.info(f'Opened {chest_type}')
# Log all rewards received from chest
for prize in reward['content']:
# Prize reward amount is number if int, else the length of all contents in list
reward_amount = prize['value'] if isinstance(
prize['value'], int) else len(prize['value'])
reward_type = prize['type']
logging.info(f'{reward_amount} {reward_type} claimed')
# Claim all free coins from offers
for message in CoinMaster.messages:
if (
"data" in message
and "reward" in message["data"]
):
if "VQ_ENTRY_REWARD" in message["data"]["collectUrl"]:
if 'viking_quest' not in CoinMaster.active_events:
continue
CoinMaster.claim_reward(message["data"]["rewardId"])
CoinMaster.reset_colored_statistics(terminal_width)
for reward_type in message["data"]["reward"]:
logger.info(
f'Used offer for {human_format(message["data"]["reward"][reward_type])} {reward_type}'
)
CoinMaster.print_colored_statistics()
break
# Check if upgrade/fix is buyable
CoinMaster.auto_upgrade()
As you see its quite simple, although I would add more features as I went along. The bot would claim all free coins and spins, and would also claim all chests from the generic rewards. It would also claim the daily bonus and the login bonus, and would automatically upgrade the village when possible. The bot would also attack other players when possible, and would buy shields when needed.
I tracked the progress of the bot by logging all actions. I also recorded the amount of coins and spins I had, as well as the amount of stars I had. I would then plot this data to see how the bot was doing for later analysis, in the hopes of finding better strategies.
Generic Reward Bug
After having the bot play for almost a year, the bot suddenly started generating enourmous amounts of spinns. As it turned out, there was a discrepancy between how my bot claimed the generic rewards, and how the game client did it. The bot would try to reclaim the rewards in an infinite loop, which would generate far more spinns than should be possible.
It quickly got out of control, and soon I had to slow the bot down to prevent if from generating too many spinns. I was able to generate millions of spinns in a day, and quickly rose to the top of the leaderboard. I believe I had the most spinns out of all players in the game, peaking at a bit over 100 million spinns. For reference, this would be arund $3,000,000 worth of spinns if you were to buy them from the in-game store.
At the end of this graph, you can see how the village level rises quickly, before largely stopping and coins increasing instead. This is because the bots strategy would change from upgrading the village as soon as it could (which made me fly up the global leaderboard), to hoarding cash instead in an attempt to avoid getting noticed.
As a side note: In total, my account spun a bit over 300 thousand times. It would take an incredibly long time to spin 100 million times more. Even if you were to spin 10 times a second, it would take you well over 3 months of continuous 24/7 spinning to reach that number.
Shadow Ban
Sadly, the game developers patched the bug after a few days. My account became shadow banned, meaning I couldn't interact with other players, and although I was able to keep the spinns they were almost useless as they stopped generating coins. I contacted support for information on what had happened, and offered to provide insight on how the bot worked, but my message was disregarded and would never reach the developer team. This concluded my time with Coinmaster.
A New Hope?
As I logged in to the game when writing this article, I noticed that I was not shadow banned anymore. I was able to interact with other players, and my spinns were generating coins again.
The game has changed a lot since I last played, and I am not sure if the bot would work anymore. If I ever decide to spend the time, I might go back to this project and see if I can make the bot work again. Unless the developers have added some kind of anti-bot measures, I think it should be possible to make the bot work quite easily again.