Advertisement
pippoo9

Tutorial zum Dekompilieren/Decompile von Wherigo Cartridges

Jun 6th, 2013
9,472
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.65 KB | None | 0 0
  1. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2. #
  3. # Tutorial zum Dekompilieren von Wherigo-Cartridges / How to decompile Wherigo-Cartridges
  4. # 06.06.2013 pippo
  5. #
  6. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  7.  
  8. Zunächst wird die entsprechende Cartridge von http://www.wherigo.com/ heruntergeladen und zwar die Version für PC.
  9. Mit einem Hexeditor, z.B. von http://hexedit.nextsoft.de/ wird die Cartridge geöffnet.
  10.  
  11. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  12.  
  13. ** Aufbau einer Cartridge **
  14.  
  15. Der Aufbau einer Cartridge ist wie folgt dokumentiert:
  16.  
  17. @0000:
  18. ; Signature:
  19. BYTE 0x02
  20. BYTE 0x0a
  21. BYTE "CART", 0x00
  22.  
  23. @0007:
  24. ; Number of objects ("media files") in cartridge:
  25. USHORT number_of_objects
  26.  
  27. @0009:
  28. ; references to individual objects in cartridge.
  29. ; there is exactly [number_of_objects] blocks like this:
  30. repeat <number_of_objects> times {
  31. USHORT object_id ; distinct ID for each object, duplicates are forbidden
  32. LONG address ; address of object in GWC file
  33. }
  34.  
  35. @xxxx:
  36. LONG header_length ; length of information header (following block):
  37. struct {
  38. DOUBLE Latitude ; N+/S-
  39. DOUBLE Longitude ; E+/W-
  40.  
  41. LONG unknown0
  42. LONG unknown1
  43. LONG unknown2
  44. LONG unknown3
  45.  
  46. ; media-ID of icon and splashscreen:
  47. SHORT ID_of_splashscreen ; -1 = without splashscreen/poster
  48. SHORT ID_of_small_icon ; -1 = without icon
  49.  
  50. ASCIIZ type_of_cartridge ; "Tour guide", "Wherigo cache", etc.
  51. ASCIIZ PlayerName ; name of player who downloaded this cartridge
  52.  
  53. LONG unknown6
  54. LONG unknown7
  55.  
  56. ASCIIZ CartridgeName ; "Name of this cartridge"
  57. ASCIIZ CartridgeGUID
  58. ASCIIZ CartridgeDescription ; "this is a sample cartridge"
  59. ASCIIZ StartingLocationDescription ; "nice parking"
  60. ASCIIZ Version ; "1.2"
  61. ASCIIZ Author
  62. ASCIIZ Company
  63. ASCIIZ RecommendedDevice ; "Garmin Colorado", "Windows PPC", etc.
  64.  
  65. LONG unknown8
  66.  
  67. ASCIIZ CompletionCode } header
  68.  
  69. @xxxx + header_length + 4:
  70. ; here should be first object, but it is not important, as all objects have
  71. ; it's address (offset in .gwc file) known, including the first one:
  72.  
  73.  
  74. @address_of_FIRST_object (with ID=0):
  75. ; always Lua bytecode
  76. LONG length
  77. ;
  78. BYTE[length] content_of_object ; Lua bytecode
  79.  
  80. @address_of_ALL_OTHER_objects (with ID > 0):
  81. BYTE valid_object
  82. if (valid_object == 0) {
  83. ; when valid_object == 0, it means that object is DELETED and does not exist in cartridge.
  84. ; nothing else follows.
  85. } else {
  86. LONG object_type ; 1=bmp, (2=png?), 3=jpg, 4=gif, 17=wav, 18=mp3, 19=fdl, other values have unknown meaning
  87. LONG length
  88. BYTE[length] content_of_object
  89. }
  90. ; ============================================================================
  91. ; And that is all.
  92. ; ============================================================================
  93.  
  94. BYTE = unsigned char (1 byte)
  95. SHORT = signed short (2 bytes)
  96. USHORT = unsigned short (2 bytes)
  97. LONG = signed long (4 bytes)
  98. ULONG = unsigned long (4 bytes)
  99. DOUBLE = double-precision floating point number (8 bytes)
  100. ASCIIZ = zero-terminated string ("hello world!", 0x00)
  101.  
  102. Source: http://ati.land.cz/gps/wherigo/gwc.htm
  103.  
  104. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  105.  
  106. ** Manuelles Extrahieren von Elementen **
  107.  
  108. D.h. wir können anhand dieser Beschreibung den Code und alle Elemente der Cartridge extrahieren.
  109.  
  110. 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.
  111.  
  112. 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.
  113.  
  114. 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.
  115.  
  116. Wir markieren den Code von Anfang bis Ende und kopieren ihn in eine neue Datei (z.B. cartridge.new).
  117.  
  118. Mit Hilfe von unluac.jar (Quelle: http://sourceforge.net/projects/unluac/) können wir jetzt diesen Code in eine lesbare Form bringen:
  119. java -jar unluac.jar cartridge.new
  120.  
  121. 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!
  122.  
  123. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  124.  
  125. ** Lesen des Quelltextes **
  126.  
  127. Finalkoordinaten sind entweder als Zone hinterlegt mit entsprechender Beschreibung oder als Klartext im Quelltext in einem Text.
  128.  
  129. Teilweise sind Texte und Namen gecrypted, diese entschlüsseln wir etwas später im Tutorial.
  130.  
  131. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  132.  
  133. ** Verwendung von Hashwerten für Fragen und Eingaben **
  134.  
  135. 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:
  136.  
  137. Vorher muss man die Variablen a und b aus dem lua-Quelltext herausfinden und dann dem PHP-Skript übergeben:
  138.  
  139. lua-Quelltext:
  140.  
  141. function _Urwigo.Hash(str)
  142. ---> hier wird a definiert: local b = 378551 <---
  143. ---> hier wird b definiert: local a = 63689 <---
  144. local hash = 0
  145. for i = 1, str do
  146. hash = hash * a + string.byte(str, i)
  147. hash = math.fmod(hash, 65535)
  148. a = a * b
  149. a = math.fmod(a, 65535)
  150. end
  151. return hash
  152. end
  153.  
  154. PHP-Quelltext zum Brute-Forcen (break_hash.php):
  155.  
  156. <?php
  157.  
  158. if ($_SERVER[argv][1] == "" || $_SERVER[argv][2] == "" || $_SERVER[argv][3] == "" || $_SERVER[argv][4] == "")
  159. {
  160. echo "Bitte a,b,Hashwert und maximale Textlaenge angeben!\n";
  161. die;
  162. }
  163.  
  164. // this is the hash we are trying to crack
  165. define('HASH', $_SERVER[argv][3]);
  166.  
  167. // available characters to try for password
  168. // uncomment additional charsets for more complex passwords
  169. $charset = 'abcdefghijklmnopqrstuvwxyz';
  170. $charset .= '0123456789';
  171. $charset .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
  172. //$charset .= '~`!@#$%^&*()-_\/\'";:,.+=<>? ';
  173. #########################################################
  174. $charset_length = strlen($charset);
  175.  
  176. brute($charset, $_SERVER[argv][4]);
  177.  
  178. echo "Execution complete.\n";
  179.  
  180. function brute($chars,$maxLen=2,$string="")
  181. {
  182. for ($i=0;$i<strlen($chars);++$i)
  183. {
  184. // Action
  185. //echo $string.$chars[$i]."\n";
  186.  
  187. if (_Hash($string.$chars[$i]) == HASH)
  188. {
  189. echo 'FOUND MATCH, text: '.$string.$chars[$i]."\n";
  190. }
  191.  
  192. if(strlen($string)<$maxLen-1){
  193. brute($chars,$maxLen,$string.$chars[$i]);
  194. }
  195. }
  196. }
  197.  
  198. function _Hash($string)
  199. {
  200. global $_SERVER;
  201.  
  202. // echo "String-Laenge: ".strlen($string)."\n";
  203.  
  204. $b = $_SERVER[argv][1];
  205. $a = $_SERVER[argv][2];
  206.  
  207. $hash = 0;
  208.  
  209. for ($i = 0; $i < strlen($string); $i++)
  210. {
  211. // echo ">> ".ord(substr($string, $i, 1))."\n";
  212.  
  213. $hash = $hash * $a + ord(substr($string, $i, 1));
  214. $hash = fmod($hash, 65535);
  215. $a = $a * $b;
  216. $a = fmod($a, 65535);
  217. }
  218. return $hash;
  219. }
  220.  
  221. ?>
  222.  
  223. Aufrufparameter:
  224. php -f break_hash.php [a] [b] [Hash] [Max. Anzahl Zeichen]
  225.  
  226. Beispiel:
  227. php -f break_hash.php 378551 63689 31978 4
  228.  
  229. Ergebnis:
  230. FOUND MATCH, text: azVJ
  231. FOUND MATCH, text: aJKj
  232. FOUND MATCH, text: aNHY
  233. FOUND MATCH, text: aREH
  234. FOUND MATCH, text: aVB7
  235.  
  236. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  237.  
  238. ** Gecryptete Strings **
  239.  
  240. Teilweise sind die Strings innerhalb einer Cartridge mit einer internen Funktion verschlüsselt.
  241. Diese Funktion befindet sich am Anfang des dekompilierten Lua-Codes und sieht ungefähr wie folgt aus:
  242.  
  243. function _VVn3(str)
  244. local res = ""
  245. local dtable = [[
  246. gkc Yq1(i3@
  247. G-bLr] \!Xp6`BvsEt"^/{e%~aK<S2wUDA*ZPW =&?|lV}9.'N7R[n45Jh)+$TCM,jHo 8#Oy;u
  248. x>_mzf0d:IFQ]]
  249. for i = 1, #str do
  250. local b = str:byte(i)
  251. if b > 0 and b <= 127 then
  252. res = res .. string.char(dtable:byte(b))
  253. else
  254. res = res .. string.char(b)
  255. end
  256. end
  257. return res
  258. end
  259.  
  260. Innerhalb des Lua-Codes findet man dann die Verweise auf diese Funktion:
  261.  
  262. _lF_wF.Name = _VVn3("g33\025&*\0253&&0")
  263.  
  264. Nun kann mit einem einfachen Code dieser String wieder in lesbaren Text verwandelt werden.
  265. Es handelt sich um einen Lua-Code, der online ausgeführt werden kann, z.B. unter http://www.lua.org/cgi-bin/demo
  266.  
  267. Dort einfach die Funktion eintragen und darunter ein Echo mit dem kodierten String:
  268.  
  269. print(_VVn3(":3\avp&&\a\014\006\\\a8h\\J\aVh\006\\v3J\a\0020V3p0\025\a\002p\006\0050VN"))
  270.  
  271. Dann das Programm ausführen und der Text wird im Klartext erscheinen.
  272.  
  273. 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.
  274.  
  275. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  276.  
  277. ** Dateien innerhalb der Cartridge **
  278.  
  279. 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.
  280.  
  281. Folgendes PHP-Skript exportiert automatisch alle Dateien in einen tmp-Ordner (Ordner bitte selber anlegen!):
  282.  
  283. <?php
  284. /*
  285.  
  286. lua_export_all.php
  287.  
  288. */
  289. $dateinummer="0";
  290.  
  291. $fd=fopen($_SERVER[argv][1], r);
  292. while ($fd && !feof($fd))
  293. {
  294. $c=fread($fd,1);
  295. $hex[]=bin2hex($c);
  296. }
  297. fclose($fd);
  298.  
  299. $number_of_objects=hexdec($hex[8].$hex[7]);
  300. echo "$number_of_objects Objekte gefunden.\n";
  301.  
  302. for ($a=9; $a<10000; $a+=6)
  303. {
  304. // Wo befindet sich Element $a ?
  305. //
  306. $dateinummer=$hex[$a].$hex[$a+1];
  307. echo $dateinummer."\n";
  308.  
  309. $sprungmarke_anfang=hexdec($hex[$a+5].$hex[$a+4].$hex[$a+3].$hex[$a+2]);
  310.  
  311. if ($a == 9)
  312. {
  313. $laenge=hexdec($hex[$sprungmarke_anfang+3].$hex[$sprungmarke_anfang+2].$hex[$sprungmarke_anfang+1].$hex[$sprungmarke_anfang+0]);
  314. }
  315. else
  316. {
  317. $laenge=hexdec($hex[$sprungmarke_anfang+8].$hex[$sprungmarke_anfang+7].$hex[$sprungmarke_anfang+6].$hex[$sprungmarke_anfang+5]);
  318. }
  319.  
  320.  
  321. // Ich lese diese Datei bis zum Ende
  322. //
  323. if ($a==9) { $sprungmarke_anfang+=4; } else { $sprungmarke_anfang+=9; }
  324.  
  325. echo $dateinummer."\n";
  326. echo $sprungmarke_anfang."\n";
  327. echo $laenge."\n\n";
  328.  
  329. $fw=fopen("tmp/$dateinummer.jpg", w);
  330. for ($b=$sprungmarke_anfang; $b<$sprungmarke_anfang+$laenge; $b++)
  331. {
  332. //echo $hex[$b]." ";
  333. fwrite($fw, hextobin($hex[$b]));
  334. }
  335. fclose($fw);
  336.  
  337. $n++;
  338. if ($n>$number_of_objects) { die; }
  339.  
  340. echo "\n";
  341. }
  342.  
  343. function hextobin($hexstr)
  344. {
  345. $n = strlen($hexstr);
  346. $sbin="";
  347. $i=0;
  348. while($i<$n)
  349. {
  350. $a =substr($hexstr,$i,2);
  351. $c = pack("H*",$a);
  352. if ($i==0){$sbin=$c;}
  353. else {$sbin.=$c;}
  354. $i+=2;
  355. }
  356. return $sbin;
  357. }
  358. ?>
  359.  
  360. Ausführung mit:
  361. php -f lua_export_all.php cartridge.new
  362.  
  363. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  364.  
  365.  
  366.  
  367. ** ENDE **
  368.  
  369. Stichworte:
  370. 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