Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- #
- # Tutorial zum Dekompilieren von Wherigo-Cartridges / How to decompile Wherigo-Cartridges
- # 06.06.2013 pippo
- #
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Zunächst wird die entsprechende Cartridge von http://www.wherigo.com/ heruntergeladen und zwar die Version für PC.
- Mit einem Hexeditor, z.B. von http://hexedit.nextsoft.de/ wird die Cartridge geöffnet.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ** Aufbau einer Cartridge **
- Der Aufbau einer Cartridge ist wie folgt dokumentiert:
- @0000:
- ; Signature:
- BYTE 0x02
- BYTE 0x0a
- BYTE "CART", 0x00
- @0007:
- ; Number of objects ("media files") in cartridge:
- USHORT number_of_objects
- @0009:
- ; references to individual objects in cartridge.
- ; there is exactly [number_of_objects] blocks like this:
- repeat <number_of_objects> times {
- USHORT object_id ; distinct ID for each object, duplicates are forbidden
- LONG address ; address of object in GWC file
- }
- @xxxx:
- LONG header_length ; length of information header (following block):
- struct {
- DOUBLE Latitude ; N+/S-
- DOUBLE Longitude ; E+/W-
- LONG unknown0
- LONG unknown1
- LONG unknown2
- LONG unknown3
- ; media-ID of icon and splashscreen:
- SHORT ID_of_splashscreen ; -1 = without splashscreen/poster
- SHORT ID_of_small_icon ; -1 = without icon
- ASCIIZ type_of_cartridge ; "Tour guide", "Wherigo cache", etc.
- ASCIIZ PlayerName ; name of player who downloaded this cartridge
- LONG unknown6
- LONG unknown7
- ASCIIZ CartridgeName ; "Name of this cartridge"
- ASCIIZ CartridgeGUID
- ASCIIZ CartridgeDescription ; "this is a sample cartridge"
- ASCIIZ StartingLocationDescription ; "nice parking"
- ASCIIZ Version ; "1.2"
- ASCIIZ Author
- ASCIIZ Company
- ASCIIZ RecommendedDevice ; "Garmin Colorado", "Windows PPC", etc.
- LONG unknown8
- ASCIIZ CompletionCode } header
- @xxxx + header_length + 4:
- ; here should be first object, but it is not important, as all objects have
- ; it's address (offset in .gwc file) known, including the first one:
- @address_of_FIRST_object (with ID=0):
- ; always Lua bytecode
- LONG length
- ;
- BYTE[length] content_of_object ; Lua bytecode
- @address_of_ALL_OTHER_objects (with ID > 0):
- BYTE valid_object
- if (valid_object == 0) {
- ; when valid_object == 0, it means that object is DELETED and does not exist in cartridge.
- ; nothing else follows.
- } else {
- LONG object_type ; 1=bmp, (2=png?), 3=jpg, 4=gif, 17=wav, 18=mp3, 19=fdl, other values have unknown meaning
- LONG length
- BYTE[length] content_of_object
- }
- ; ============================================================================
- ; And that is all.
- ; ============================================================================
- BYTE = unsigned char (1 byte)
- SHORT = signed short (2 bytes)
- USHORT = unsigned short (2 bytes)
- LONG = signed long (4 bytes)
- ULONG = unsigned long (4 bytes)
- DOUBLE = double-precision floating point number (8 bytes)
- ASCIIZ = zero-terminated string ("hello world!", 0x00)
- Source: http://ati.land.cz/gps/wherigo/gwc.htm
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ** Manuelles Extrahieren von Elementen **
- D.h. wir können anhand dieser Beschreibung den Code und alle Elemente der Cartridge extrahieren.
- Zuerst gehen wir an das 9. Byte der Datei, denn ab dort stehen in den nächsten 2 Byte die Nummer der ersten Datei (00 00) und in den folgenden 4 Byte die Adresse der Datei innerhalb der Cartridge. Dabei ist die Datei 00 00 immer der Lua-Code.
- Wir gehen davon aus, dass hinter 00 00 die Bytefolge C6 02 00 00 steht. Daraus folgt, dass der Lua-Code ab 02 C6 00 00 beginnt; denn die Sprungmarke ist rückwärts zu lesen. Wenn wir an die Stelle 02 C6 schauen, dann ist beim Lua-Code (Datei 00 00) zuerst die Länge in 4 Bytes angegeben und danach der eigentliche Code.
- Wir gehen davon aus, dass die Länge als 2A B9 01 00 angegeben ist, das ergibt rückwärts: 00 01 B9 2A. Wir nehmen jetzt den Windows-Taschenrechner und rechnen einfach mit der Hex-Addition 02 C6 + 04 + 01 B9 2A. Das ergibt 1 BB F4 und dort ist das letzte Byte des Lua-Codes zu finden.
- Wir markieren den Code von Anfang bis Ende und kopieren ihn in eine neue Datei (z.B. cartridge.new).
- Mit Hilfe von unluac.jar (Quelle: http://sourceforge.net/projects/unluac/) können wir jetzt diesen Code in eine lesbare Form bringen:
- java -jar unluac.jar cartridge.new
- Am Ende dieses Tutorials steht ein PHP-Code mit dem man den lua-Binärcode und alle anderen Dateien automatisch aus der Cartridge extrahieren kann!
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ** Lesen des Quelltextes **
- Finalkoordinaten sind entweder als Zone hinterlegt mit entsprechender Beschreibung oder als Klartext im Quelltext in einem Text.
- Teilweise sind Texte und Namen gecrypted, diese entschlüsseln wir etwas später im Tutorial.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ** Verwendung von Hashwerten für Fragen und Eingaben **
- Manchmal stehen die erwarteten Antworten zu einer Frage nicht direkt im Quelltext, sondern werden gegen einen Hashwert geprüft. Der Hash ist allerdings kein md5 oder ähnlich eindeutiges, sondern irgendwas anders vermurkstes. Mit einem kleinen Bruteforce kann man problemlos eine der richtigen/gültigen Antworten herausfinden:
- Vorher muss man die Variablen a und b aus dem lua-Quelltext herausfinden und dann dem PHP-Skript übergeben:
- lua-Quelltext:
- function _Urwigo.Hash(str)
- ---> hier wird a definiert: local b = 378551 <---
- ---> hier wird b definiert: local a = 63689 <---
- local hash = 0
- for i = 1, str do
- hash = hash * a + string.byte(str, i)
- hash = math.fmod(hash, 65535)
- a = a * b
- a = math.fmod(a, 65535)
- end
- return hash
- end
- PHP-Quelltext zum Brute-Forcen (break_hash.php):
- <?php
- if ($_SERVER[argv][1] == "" || $_SERVER[argv][2] == "" || $_SERVER[argv][3] == "" || $_SERVER[argv][4] == "")
- {
- echo "Bitte a,b,Hashwert und maximale Textlaenge angeben!\n";
- die;
- }
- // this is the hash we are trying to crack
- define('HASH', $_SERVER[argv][3]);
- // available characters to try for password
- // uncomment additional charsets for more complex passwords
- $charset = 'abcdefghijklmnopqrstuvwxyz';
- $charset .= '0123456789';
- $charset .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
- //$charset .= '~`!@#$%^&*()-_\/\'";:,.+=<>? ';
- #########################################################
- $charset_length = strlen($charset);
- brute($charset, $_SERVER[argv][4]);
- echo "Execution complete.\n";
- function brute($chars,$maxLen=2,$string="")
- {
- for ($i=0;$i<strlen($chars);++$i)
- {
- // Action
- //echo $string.$chars[$i]."\n";
- if (_Hash($string.$chars[$i]) == HASH)
- {
- echo 'FOUND MATCH, text: '.$string.$chars[$i]."\n";
- }
- if(strlen($string)<$maxLen-1){
- brute($chars,$maxLen,$string.$chars[$i]);
- }
- }
- }
- function _Hash($string)
- {
- global $_SERVER;
- // echo "String-Laenge: ".strlen($string)."\n";
- $b = $_SERVER[argv][1];
- $a = $_SERVER[argv][2];
- $hash = 0;
- for ($i = 0; $i < strlen($string); $i++)
- {
- // echo ">> ".ord(substr($string, $i, 1))."\n";
- $hash = $hash * $a + ord(substr($string, $i, 1));
- $hash = fmod($hash, 65535);
- $a = $a * $b;
- $a = fmod($a, 65535);
- }
- return $hash;
- }
- ?>
- Aufrufparameter:
- php -f break_hash.php [a] [b] [Hash] [Max. Anzahl Zeichen]
- Beispiel:
- php -f break_hash.php 378551 63689 31978 4
- Ergebnis:
- FOUND MATCH, text: azVJ
- FOUND MATCH, text: aJKj
- FOUND MATCH, text: aNHY
- FOUND MATCH, text: aREH
- FOUND MATCH, text: aVB7
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ** Gecryptete Strings **
- Teilweise sind die Strings innerhalb einer Cartridge mit einer internen Funktion verschlüsselt.
- Diese Funktion befindet sich am Anfang des dekompilierten Lua-Codes und sieht ungefähr wie folgt aus:
- function _VVn3(str)
- local res = ""
- local dtable = [[
- gkc Yq1(i3@
- G-bLr]\!Xp6`BvsEt"^/{e%~aK<S2wUDA*ZPW =&?|lV}9.'N7R[n45Jh)+$TCM,jHo 8#Oy;u
- x>_mzf0d:IFQ]]
- for i = 1, #str do
- local b = str:byte(i)
- if b > 0 and b <= 127 then
- res = res .. string.char(dtable:byte(b))
- else
- res = res .. string.char(b)
- end
- end
- return res
- end
- Innerhalb des Lua-Codes findet man dann die Verweise auf diese Funktion:
- _lF_wF.Name = _VVn3("g33\025&*\0253&&0")
- Nun kann mit einem einfachen Code dieser String wieder in lesbaren Text verwandelt werden.
- Es handelt sich um einen Lua-Code, der online ausgeführt werden kann, z.B. unter http://www.lua.org/cgi-bin/demo
- Dort einfach die Funktion eintragen und darunter ein Echo mit dem kodierten String:
- print(_VVn3(":3\avp&&\a\014\006\\\a8h\\J\aVh\006\\v3J\a\0020V3p0\025\a\002p\006\0050VN"))
- Dann das Programm ausführen und der Text wird im Klartext erscheinen.
- Durch Binärzeichen kann das Einfügen in den Browser u.U. nicht möglich sein, dann bitte den dekompilierten Quelltext einfach mit dem >> vi << verändern und direkt von der Konsole mit >> lua << ausführen.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ** Dateien innerhalb der Cartridge **
- Innerhalb einer Cartridge können Dateien (lua-Binärcode, jpg, wav, mp3 usw.) abgelegt werden. Die Anzahl der Dateien und deren Position ist wieder in der Cartridge an bestimmten Stellen hinterlegt. Die Vorgehensweise ist die gleiche wie beim Lua-Code, allerdings ist an der entsprechenden Sprungmarke der Aufbau der Informationen ein wenig ergänzt und zwar um ein Feld ob die Datei wirklich in der Cartridge enthalten ist, den Dateityp und dann die Länge. D.h. Man muss nicht 4 Byte auf Startadresse und Endadresse addieren, sondern 9 Byte.
- Folgendes PHP-Skript exportiert automatisch alle Dateien in einen tmp-Ordner (Ordner bitte selber anlegen!):
- <?php
- /*
- lua_export_all.php
- */
- $dateinummer="0";
- $fd=fopen($_SERVER[argv][1], r);
- while ($fd && !feof($fd))
- {
- $c=fread($fd,1);
- $hex[]=bin2hex($c);
- }
- fclose($fd);
- $number_of_objects=hexdec($hex[8].$hex[7]);
- echo "$number_of_objects Objekte gefunden.\n";
- for ($a=9; $a<10000; $a+=6)
- {
- // Wo befindet sich Element $a ?
- //
- $dateinummer=$hex[$a].$hex[$a+1];
- echo $dateinummer."\n";
- $sprungmarke_anfang=hexdec($hex[$a+5].$hex[$a+4].$hex[$a+3].$hex[$a+2]);
- if ($a == 9)
- {
- $laenge=hexdec($hex[$sprungmarke_anfang+3].$hex[$sprungmarke_anfang+2].$hex[$sprungmarke_anfang+1].$hex[$sprungmarke_anfang+0]);
- }
- else
- {
- $laenge=hexdec($hex[$sprungmarke_anfang+8].$hex[$sprungmarke_anfang+7].$hex[$sprungmarke_anfang+6].$hex[$sprungmarke_anfang+5]);
- }
- // Ich lese diese Datei bis zum Ende
- //
- if ($a==9) { $sprungmarke_anfang+=4; } else { $sprungmarke_anfang+=9; }
- echo $dateinummer."\n";
- echo $sprungmarke_anfang."\n";
- echo $laenge."\n\n";
- $fw=fopen("tmp/$dateinummer.jpg", w);
- for ($b=$sprungmarke_anfang; $b<$sprungmarke_anfang+$laenge; $b++)
- {
- //echo $hex[$b]." ";
- fwrite($fw, hextobin($hex[$b]));
- }
- fclose($fw);
- $n++;
- if ($n>$number_of_objects) { die; }
- echo "\n";
- }
- function hextobin($hexstr)
- {
- $n = strlen($hexstr);
- $sbin="";
- $i=0;
- while($i<$n)
- {
- $a =substr($hexstr,$i,2);
- $c = pack("H*",$a);
- if ($i==0){$sbin=$c;}
- else {$sbin.=$c;}
- $i+=2;
- }
- return $sbin;
- }
- ?>
- Ausführung mit:
- php -f lua_export_all.php cartridge.new
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ** ENDE **
- Stichworte:
- wherigo knacken betrügen schummeln geocaching dekompilieren dechiffrieren lösung auslesen decompile crack final koordinaten mogeln bilder extrahieren hack how to coords reveal get
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement