{"id":18835944,"url":"https://github.com/nscuro/usd-hackertage-2018-challenge","last_synced_at":"2026-04-19T15:02:44.430Z","repository":{"id":102805747,"uuid":"129631014","full_name":"nscuro/usd-hackertage-2018-challenge","owner":"nscuro","description":"Mini-Writeup zur Challenge für die usd Hackertage 2018","archived":false,"fork":false,"pushed_at":"2018-04-16T17:06:15.000Z","size":13363,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-23T13:45:42.606Z","etag":null,"topics":["challenge","csharp","dnspy","hackertage","unity","usd"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nscuro.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2018-04-15T16:52:52.000Z","updated_at":"2018-05-07T14:45:35.000Z","dependencies_parsed_at":null,"dependency_job_id":"55b9edb9-f84e-41ab-a30a-7db12e73150b","html_url":"https://github.com/nscuro/usd-hackertage-2018-challenge","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/nscuro/usd-hackertage-2018-challenge","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nscuro%2Fusd-hackertage-2018-challenge","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nscuro%2Fusd-hackertage-2018-challenge/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nscuro%2Fusd-hackertage-2018-challenge/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nscuro%2Fusd-hackertage-2018-challenge/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nscuro","download_url":"https://codeload.github.com/nscuro/usd-hackertage-2018-challenge/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nscuro%2Fusd-hackertage-2018-challenge/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32010958,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-18T20:23:30.271Z","status":"online","status_checked_at":"2026-04-19T02:00:07.110Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["challenge","csharp","dnspy","hackertage","unity","usd"],"created_at":"2024-11-08T02:17:39.626Z","updated_at":"2026-04-19T15:02:44.168Z","avatar_url":"https://github.com/nscuro.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# usd Hackertage 2018 - Challenge\n\nIn der diesjährigen (2018) Challenge galt es, Tokens in dem Format `usd{[a-z0-9]{32}}` in einem Unity Game zu finden. Mindestens eines musste gefunden werden, um sich für eine Anmeldung an den [Hackertagen](https://www.usd.de/usd-hackertage/) 2018 qualifizieren zu können - maximal 6 gab es zu holen.\n\nDies war meine erste Teilnahme an einer Challenge von [usd](https://www.usd.de/). Der folgende Aufschrieb dient hauptsächlich der persönlichen Archivierung.  \n\nZum nachträglichen Nachvollziehen der Lösung kann hier die Challenge heruntergeladen werden: [Awareness.zip](./Awareness.zip)\n\n## Token \\#1 - app.info\nDas erste Token \"versteckt\" sich in der `app.info` Datei:\n\n![Token 1 in der app.info Datei](.images/token_01_appinfo.png)\n\nDasselbe Token ließe sich alternativ auch unter `C:\\Users\\User\\AppData\\LocalLow` finden:\n\n![Token 1 im AppData Verzeichnis](.images/token_01_appdata.png) \n\n## Token \\#2 - Asset\nStupides Suchen nach Strings mit einem Text- bzw. Hex-Editor in den Ressourcen-Dateien des Spiels brachte (natürlich) keine weiteren Erkenntnisse.\n\n![Offensichtliche Ressourcen-Dateien](.images/game-files.png)\n\nAuf der Suche nach Software, die in der Lage ist Unity-Assets zu betrachten, bin ich auf [DevXUnity-Unpacker Magic Tools](http://devxdevelopment.com/UnityUnpacker) gestoßen. Gibt eine kostenlose Demoversion - top. \nFix runtergeladen und den Ordner `Awareness_Data` damit geöffnet.  \n\nUnter `Shared-Assets` findet sich nun ein Bild mit dem Namen `token`:\n\n![Token 2 - Bild in Shared-Assets](.images/token_02_asset.png)\n\n## Zwischenschritt\nDer Unity-Unpacker kann zwar auch den Quellcode des Spiels dekompilieren, aber nicht editieren oder gar debuggen. Nach kurzer Recherche habe ich dann das Tool [dnSpy](https://github.com/0xd4d/dnSpy) entdeckt. Kann dekompilieren, kann Code in .NET Assemblies editieren, kann .NET Binaries debuggen... Oh und es gibt sogar eine [Anleitung](https://github.com/0xd4d/dnSpy/wiki/Debugging-Unity-Games) wie man Unity Games debuggen kann!  \n\nIn meinem Fall musste ich tatsächlich der *[Turning a release build into a debug build](https://github.com/0xd4d/dnSpy/wiki/Debugging-Unity-Games#turning-a-release-build-into-a-debug-build)*-Anleitung folgen, bis ich mich erfolgreich an einen laufenden `Awareness.exe`-Prozess anhängen konnte.  \n\nBesonders interessant für uns sind die Assemblies `Awareness_Data/Managed/Api.dll` und `Awareness_Data/Managed/Assembly-CSharp.dll` - scheinbar ist letztere das Kompilat der Unity C\\#-Skripte des Entwicklers.\n\n## Token \\#3 - License Key\nBeim Starten des Spiels ist der Menüpunkt \"*New Game*\" ausgegraut, wir können lediglich \"*Enter License*\" oder \"*Exit*\" wählen.\n\n![Spielmenü beim ersten Start](.images/game_first-launch.png)\n\nWir durchstöbern den Quellcode und stoßen in `Assembly-CSharp.dll` auf die Klasse `RestrictedButton`. Dort wird in der Methode `Check()` festgelegt, ob der Button \"aktiv\" bzw. \"interactable\" ist. Wir setzen einen Breakpoint an genau dieser Stelle, wählen \"*Enter License*\" im Menü und geben eine beliebige Zeichenkette ein. Der Breakpoint wird getriggert und wir sehen den Wert, mit dem unsere Eingabe verglichen wird:\n\n![Token 3 - Lizenzschlüssel](.images/token_03_license.png)\n\nGibt man das Token dann als Lizenz ein, wird der Menüpunkt \"*New Game*\" freigeschaltet.\n\n## Token \\#4 - Highscore\nIn der Klasse `HttpApi` setzen wir einen Breakpoint in der `Start()` Methode und wählen im Menü \"*New Game*\". Der Breakpoint wird getriggert und wir können die Klassenfelder `endpoint` und `key` auslesen.\n\n![HTTP API Endpoint und Key](.images/token_04_httpapi-endpoint-and-key.png)\n\nWir entnehmen den restlichen Methoden der Klasse, dass es die API Endpoints `/players` und `/highscore` zu geben scheint. Ein Aufruf von `/players` gibt einen einfachen Integer zurück - angeblich die Anzahl der Spieler.  \n\nWesentlich interessanter sind da die Methoden `PostHighScore` und `SecureMessage`:\n\n![Methoden der HttpApi Klasse](.images/token_04_httpapi-methods.png)\n\nKurz: Um einen Highscore einstellen zu können, müssen wir den entsprechenden Score zusammen mit einem HMAC bestehend aus dem Score als Nachricht und dem zuvor identifizierten API key als Secret and den `/highscore` Endpoint posten. Wie deutlich im Code zu sehen muss SHA256 zum hashen verwendet werden.\n\n![Token 5 - Response auf das Posten eines Highscores](.images/token_04_highscore.png)\n\nFür die schnelle Erzeugung des HMAC habe ich [diese](https://www.freeformatter.com/hmac-generator.html) Seite verwendet. \n\n## Token \\#5 - HTTP API Secret\nWir schauen uns die Klasse `ApiSecret` aus dem `Api.dll` Assembly an.\n\n![ApiSecret Code](.images/token_05_code.png)\n\nOk - `GetString` sieht schonmal gruselig aus. Aber wir sehen, dass scheinbar je nachdem von welcher Methode aus `GetSecret` aufgerufen wird, wir ein anderes Secret bekommen.  \n\nSeltsamerweise wird `GetSecret` aber nie getriggert, kein Breakpoint greift. Wir behelfen uns, indem wir die Methode manuell von einer Stelle aus aufrufen, von der wir wissen, dass sie garantiert beim Starten des Spiels aufgerufen wird: `HttpApi.Start()`:\n\n![Die Modifizierte Methode](.images/token_05_modified-method.png)\n\nNun setzen wir einen Breakpoint in `ApiSecret`, Zeile `29`. Wir wählen wieder \"*New Game*\" und unser Breakpoint wird getriggert. Wir überspringen diese Zeile und editieren dann die Variable `flag`, sodass diese nun `false` statt `true` beinhaltet. Jetzt steppen wir im Debugger bis zum Ende der Methode und erhalten unser Token.\n\n![Token 5 - Das alternative API secret](.images/token_05_alternative-secret.png)\n\n## Token \\#6 - Screenshot\nBeim Betrachten der Klasse `ScreenshotUtil` fällt uns auf, dass Irgendwas komisches mit dem Bild gemacht wird, bevor es gespeichert wird:\n\n![Code der ScreenshotUtil Klasse](.images/token_06_code.png)\n\nEin Overlay wird über das Bild gelegt - bei den betroffenen Pixeln wird der Red-Channel um `0.01` inkrementiert - für das bloße Auge eine nicht zu erkennende Änderung.\n\nIch habe viel zu viel Zeit damit verbracht, irgendwie nachzuvollziehen, was genau da passiert und wie wohl das Resultat aussehen könnte, bis ic darauf kam, das Inkrement einfach auf eine höhere Zahl zu erhöhen, z.B. `1.0`.  \n\nDas war dann auch schon die Lösung. Code editiert, kompiliert, Assembly gespeichert, Spiel gestartet, mit `F12` einen Screenshot erstellt, die neue Datei `capture.png` im Hauptverzeichnis des Spiels geöffnet...  \n\nAm linken unteren Bildschirmrand war ein vertikal gespiegeltes Token. Also Bild um 180° gedreht und horizontal gespiegelt:\n\n![Token 6 - Der Screenshot](.images/token_06_screenshot.png)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnscuro%2Fusd-hackertage-2018-challenge","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnscuro%2Fusd-hackertage-2018-challenge","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnscuro%2Fusd-hackertage-2018-challenge/lists"}