Hoe ik de #kamergotchi app heb geautomatiseerd

En hoe de makers dit hadden kunnen voorkomen

Auteur: Tim van Dalen

Naar aanleiding van de aankomende verkiezingen op 15 maart, lanceerde het satirisch televisieprogramma Zondag met Lubach de app Kamergotchi. Met dit spelletje kun je de aan jou toegewezen lijsttrekker in leven houden of juist laten sterven. Als je je Kamergotchi goed verzorgt, word je beloond met punten. Inmiddels is ook bekend dat Jesse Klaver (GroenLinks) de best verzorgde lijsttrekker in het spel is.

Ruim 750.000 mensen hebben de app gedownload. Tijd om te kijken hoe de achterkant van Kamergotchi in elkaar steekt, vonden wij. Na wat graafwerk kwamen we er achter dat het niet zo moeilijk is om de app te automatiseren.

Op maandagochtend 20 februari, de ochtend na de aankondiging van Kamergotchi, hebben we drie accounts tegelijk automatisch aangezet. Dinsdag hadden we positie 1, 2 en 3 in de dag top 50 te pakken, en klommen alle drie de accounts in de totale top 50.

In dit artikel leg ik uit hoe het reverse engineeren van een app in zijn werk gaat, hoe je zo’n app vervolgens automatiseert en wat de makers van de Kamergotchi app hadden kunnen doen (en nog steeds zouden kunnen doen) om mij tegen te houden.


Hoe je een app reverse engineert

Voordat je de functionaliteit van een app kunt automatiseren, moet je eerst precies in kaart brengen wat deze doet. Voor veel applicaties is het een kwestie van uitzoeken van wat voor communicatie de app met de buitenwereld heeft. Dit contact gaat bijna altijd via internet. Wat we dus eigenlijk willen weten, is welke websites de app bezoekt wanneer jij op een knop drukt.

De makkelijkste manier om hier achter te komen, is door al het netwerkverkeer van je telefoon via een proxy te sturen. Dat is een programma dat namens een gebruiker (in dit geval je telefoon) verzoeken doet naar het internet. Als je de proxy zo instelt om bij te houden wat voor netwerkverzoeken worden gedaan, kun je uitlezen wat je telefoon allemaal doet.

Charles proxy met Kamergotchi verzoeken

Een voorbeeld van een proxy programma dat dat kan is Charles. Je kunt het programma op je desktop of laptop aanzetten. Vervolgens zet je in de netwerkinstellingen van je telefoon (bij zowel Android als iOS onder WiFi instellingen) dat hij je desktop/laptop moet gebruiken als proxy. Vanaf dat moment zie je elk verzoek dat je telefoon naar buiten toe maakt over internet verschijnen in het scherm.

Ik raad je aan dit experiment eens te doen met een aantal van je favoriete apps. Let er eens op hoeveel van deze apps data over het internet sturen terwijl je niets doet. Zie bijvoorbeeld de verzoeken van Kamergotchi naar Facebook in het screenshot hier boven.

De volgende stap is: Kamergotchi spelen! Nu we alles zo hebben ingesteld dat we kunnen zien wat de applicatie doet, willen we weten wat elke knop in de app precies doet.

Voordat we daar mee beginnen, eerst even een kort intermezzo over het internet. Alle verzoeken die we doen op het web (denk aan een website laden, een bericht plaatsen op social media, bestanden uploaden) hebben een werkwoord. Het internet heeft een aantal werkwoorden, maar voor nu beperken we ons tot twee daarvan: GET en POST. We gebruiken GET over het algemeen wanneer we een webpagina willen opvragen, POST wanneer we data willen versturen (zoals bijvoorbeeld het invullen van een formulier).

Als we de app Kamergotchi openen is het eerste dat we zien een verzoek naar GET https://api.kamergotchi.nl/game. Dit verzoek wordt vervolgens iedere seconde herhaald. Aan de inhoud van de pagina te zien is dit de game state. Deze pagina geeft de app informatie over hoe het spel op dat moment loopt. Interessante onderdelen daarvan zijn voor ons bijvoorbeeld careLeft en careResetcareLeft lijkt aan te geven hoe vaak we onze Kamergotchi nog eten, kennis en aandacht kunnen geven voordat deze wilt schorsen. careReset is de tijd waarop we, nadat careLeft op is, weer verder kunnen spelen. De tijd achter claimReset lijkt aan te geven over hoeveel tijd we weer op de claim knop kunnen klikken in het spel (die eens in de 2 uur een bonus geeft).

 

Wanneer we op één van de verzorg knoppen klikken in de app, zien we een verzoek naar POST https://api.kamergotchi.nl/game/care. Met deze link kunnen we onze Kamergotchi dus verzorgen. Met het verzoek wordt (zoals bij een web formulier) meegegeven wat voor type verzorging we willen geven.

Als we op de claim knop drukken, zien we een verzoek naar POST https://api.kamergotchi.nl/game/claim, zonder extra data.


Hoe je een app automatiseert

Nu we weten wat de Kamergotchi app precies doet, kunnen we een eigen appmaken die op dezelfde manier met de Kamergotchi website praat.

Het belangrijke verschil met de officiële Kamergotchi app is dat je in onze versie niet zelf hoeft te klikken om jouw lijsttrekker te verzorgen. Wanneer ik hier app zeg moet je niet denken aan een polished geheel met een mooie grafische voorkant zoals de officiële app dat is. Omdat het ons alleen gaat om punten scoren hebben we dat niet nodig. We kunnen onze voortgang altijd volgen via de echte Kamergotchi app.

Om zo snel mogelijk punten te verzamelen gaan we onze versie van de Kamergotchi app als volgt laten werken: wanneer we starten vragen we de huidige status van het spel op (met GET /game) en zien we hoe vaak we nog mogen verzorgen. Standaard is dit 8 keer tot de volgende reset. Dan doen we zo snel mogelijk dat aantal verzoeken naar POST /game/care, waarbij we elke keer de categorie (food, attention, knowledge) kiezen die op dat moment de laagste score heeft. Zo zorgen we er voor dat de tevredenheid van onze lijsttrekker gelijkmatig oploopt.

Nadat we deze ronde verzorging hebben gedaan, wachten we aan de hand van de waarde careReset een aantal minuten (standaard 7 minuten), en beginnen we weer helemaal opnieuw. Op die manier halen we dus elke 7 minuten het maximaal aantal punten.

Elke twee uur (wanneer de claimReset bereikt is) doen we een verzoek naar POST /game/claim om de bonuspunten te claimen.

Mocht je na deze uitleg benieuwd zijn hoe dit automatiseren nu precies in zijn werk gaat, kun je mijn volledige script hier vinden.

De resultaten bleken vrij snel zichtbaar te zijn. Ondanks dat onze accounts een aardige achterstand hadden op de mensen die zondagavond al begonnen waren met spelen (met name omdat de claim bonus afhankelijk is van het aantal dagen dat je Kamergotchi in leven is), waren we dinsdagochtend al nummer 2, 3 en 4 in de ranglijst. Hoewel niet gelijk duidelijk, hoort het account Wouter ook bij ons (je had er bij moeten zijn).

 

Wat later op de dag waren we zelfs nummer 1, 2 en 3, maar in de opwinding ben ik vergeten daar een screenshot van te nemen :). Ons code-orange.nlaccount met Tunahan Kuzu (als eerste gestart) haalde inmiddels ook al de top 20 van de totale ranglijst en klom uiteindelijk tot in de top 10.

Onze domeinnaam in de ranglijst begon ook op Twitter op te vallen.

View image on Twitter

Overigens waren we zeker niet de enigen die met een automatisch script mee deden aan Kamergotchi. Aan de hoge scores in de dag top 50 te zien, waren er veel meer mensen die dit deden. Aan onze top positie in de dag top 50 te zien, was ons script net iets beter in punten verzamelen en groeide onze score dus harder.


De shutdown

Maar, aan alles komt een eind. We hebben nooit geprobeerd om Kamergotchi voor de gek te houden en te doen alsof we wel echte spelers waren (sterker nog, in elk verzoek naar de Kamergotchi website had ik mijn naam en e-mailadres staan).

Dinsdagavond, bijna twee volle dagen na het uitkomen van onze Kamergotchi’s, kwam deze notificatie:

De notificatie met de ban

Op dat moment kon ik de app nog gebruiken, maar werden mijn verzoeken naar POST /game/care geweigerd door de Kamergotchi server. Niet veel later werden mijn verzoeken naar GET /game ook geweigerd en kon mijn app dus ook de game state niet meer ophalen. Sindsdien ziet de Kamergotchi app er voor mij zo uit:

 
De app na de ban

Na het blokkeren van onze accounts hebben we niet meer geprobeerd om de blokkade te omzeilen — de lol was er af.

Wel heb ik nog een email gestuurd naar block@kamergotchi.nl met mijn ideeën over het tegengaan van automatisering.


Hoe je automatiseren ontmoedigt

Vóór de lancering van de app hadden de makers een aantal maatregelen kunnen nemen om automatisering te ontmoedigen. Zo hadden ze bijvoorbeeld elk verzoek naar de server kunnen signen met een digitale sleutel en de huidige tijd. Op die manier wordt het veel moeilijker om automatisch de verzoeken te doen, omdat je dan eerst de sleutel uit de app moet zien te krijgen. Met die extra moeilijkheidsgraad haken mensen zoals ik veel sneller af — als Kamergotchi signed verzoeken had gebruikt had ik niet de moeite gedaan om het te automatiseren, het is maar een spelletje.

Na de lancering van de app heb je echter niets aan dat advies. Om deze functionaliteit toe te voegen aan de server moet namelijk iedereen ook over naar een nieuwe versie van de app, voordat je de oude (onbeveiligde) versie offline haalt. Anders werkt de app niet meer bij mensen die niet ge-update hebben. Het probleem daarmee is dat voordat je een update kan doen op iOS, Apple je update eerst moet goedkeuren. Dat proces is vrij onvoorspelbaar en kan soms wel meer dan twee weken duren. Niet heel handig voor een app die minder dan een maand te gebruiken is.

Om zonder update toch automatisering tegen te gaan, moet je dus een manier verzinnen die werkt binnen het huidige protocol (de manier waarop de website en de app communiceren).

Gelukkig is het Kamergotchi protocol daar best voor geschikt. De ‘schorsingstijd’ tussen twee rondes van verzorgen ligt namelijk niet vast, maar wordt elke keer door de website terug gegeven wanneer we een verzoek doen naar GET /game. Door deze tijd langer te maken bij mensen die je verdenkt van automatisering, zorg je ervoor dat deze spelers minder punten kunnen scoren, omdat ze langer moeten wachten.

Dit wordt ook wel exponential backoff genoemd in de informatica. Wanneer een speler direct na de “schorsingstijd” binnen 1 seconde 8 keer zijn Kamergotchi verzorgt, vermenigvuldig je de standaard 7 minuten wachttijd met een bepaalde factor, zeg 1,5. Die speler moet dan de volgende keer 10,5 minuut wachten totdat er weer verzorgd kan worden. Wordt er dan weer gelijk 8 keer te eten gegeven, dan wordt de tijd nogmaals met die factor vermenigvuldigd. Dan zit die speler dus al op 15.75 minuten.

De factor laat je afhangen van hoe erg een speler geautomatiseerd lijkt te zijn (door dus bijvoorbeeld te kijken naar hoe lang er tussen mogen verzorgen en de eerste verzorging zit). Daardoor moeten geautomatiseerde spelers veel langer wachten tot ze weer kunnen spelen en hebben echte spelers geen last van de maatregelen.

Natuurlijk kun je, als je echt wilt, dit ook omzeilen, door je script aan te passen om ‘menselijker’ voor te komen. Je kunt als app-bouwer nooit helemaal voorkomen dat iemand je app automatiseert. Aan het einde van de dag wil je namelijk dat je app gebruikt kan worden. Het kernwoord is dan ook ontmoedigen. Door het de zogenaamde valsspelers moeilijker te maken, hoop je dat niemand het probeert.

Helaas heb ik geen reactie gekregen op mijn mail naar Kamergotchi.