Guest User

Untitled

a guest
Mar 9th, 2018
123
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.45 KB | None | 0 0
  1. #!/usr/bin/env python3
  2.  
  3. import sys
  4. import calendar
  5.  
  6. CONSOLE_TYPES = {
  7. 0xff: 'DS',
  8. 0x20: 'DS Lite',
  9. 0x57: 'DSi (or 3DS)',
  10. 0x43: 'iQue DS',
  11. 0x63: 'iQue DS Lite'
  12. }
  13.  
  14. COLOURS = {
  15. 1: 'Gray',
  16. 2: 'Brown',
  17. 3: 'Red',
  18. 4: 'Light Pink',
  19. 5: 'Orange',
  20. 6: 'Yellow',
  21. 7: 'Light Green',
  22. 8: 'Green',
  23. 9: 'Dark Green',
  24. 10: 'Teal',
  25. 11: 'Blue',
  26. 12: 'Dark Blue',
  27. 13: 'Dark Purple',
  28. 14: 'Purple',
  29. 15: 'Pink',
  30. }
  31.  
  32. WIFI_STATUSES = {
  33. 0: 'Normal',
  34. 1: 'AOSS',
  35. 16: 'WPA/WPA2',
  36. 255: 'Unconfigured'
  37. }
  38.  
  39. WPA_TYPES = {
  40. 0: 'None/WEP',
  41. 4: 'WPA-TKIP',
  42. 5: 'WPA2-TKIP',
  43. 6: 'WPA-AES',
  44. 7: 'WPA2-AES',
  45. }
  46.  
  47. LANGUAGES = {
  48. 0: 'Japanese',
  49. 1: 'English',
  50. 2: 'French',
  51. 3: 'German',
  52. 4: 'Italian',
  53. 5: 'Spanish',
  54. 6: 'Chinese',
  55. 7: 'Reserved',
  56. }
  57.  
  58. def format_ip_address(b):
  59. #Apparently I can't just use str.join for this thanks I hate it
  60. return '{0}.{1}.{2}.{3}'.format(*b)
  61.  
  62. def is_null_ip_address(b):
  63. return b[0] == 0 and b[1] == 0 and b[2] == 0 and b[3] == 0
  64.  
  65. def read_wifi_config(f, offset, slot_number):
  66. f.seek(offset + 0xe7)
  67. status = f.read(1)[0]
  68. if status == 0xff:
  69. return
  70.  
  71. print('Wifi %d status: %s' % (slot_number, WIFI_STATUSES.get(status, 'Unknown 0x{0:02X}'.format(status))))
  72.  
  73. f.seek(offset + 0x40)
  74.  
  75. ssid = f.read(32).decode('ascii', errors='backslashreplace').rstrip('\0')
  76. print('Wifi %d SSID: %s' % (slot_number, ssid))
  77. ssid_aoss = f.read(32).decode('ascii', errors='backslashreplace').rstrip('\0')
  78. print('Wifi %d SSID for AOSS: %s' % (slot_number, ssid_aoss))
  79.  
  80. f.seek(offset + 0xe6)
  81. wep_mode = f.read(1)[0]
  82. #0: None, 1 = 5 hex, 2 = 13 hex, 3 = 16 hex, 5 = 5 ascii, 6 = 13 byte, 7 = 16 byte
  83. print('Wifi %d WEP mode: %d' % (slot_number, wep_mode))
  84.  
  85. f.seek(offset + 0xea)
  86. #DSi only
  87. mtu = f.read(1)[0] | (f.read(1)[0] << 8)
  88. print('Wifi %d MTU: %d' % (slot_number, mtu))
  89.  
  90. f.seek(offset + 0xc0)
  91. ip_address = f.read(4)
  92. if is_null_ip_address(ip_address):
  93. print('Wifi %d IP address: DHCP' % slot_number)
  94. else:
  95. print('Wifi %d IP address: %s' % (slot_number, format_ip_address(ip_address)))
  96. gateway = f.read(4)
  97. print('Wifi %d gateway: %s' % (slot_number, format_ip_address(gateway)))
  98. primary_dns = f.read(4)
  99. print('Wifi %d primary: %s' % (slot_number, format_ip_address(primary_dns)))
  100. secondary_dns = f.read(4)
  101. print('Wifi %d secondary: %s' % (slot_number, format_ip_address(secondary_dns)))
  102. subnet_mask = f.read(1)[0]
  103. print('Wifi %d subnet mask: /%d' % (slot_number, subnet_mask))
  104.  
  105. if wep_mode > 0:
  106. f.seek(offset + 0x80)
  107. wep_keys = [None] * 4
  108. for i in range(4):
  109. wep_keys[i] = f.read(16)
  110. if wep_mode == 5:
  111. wep_keys[i] = wep_keys[i].decode('ascii', errors='backslashreplace')[:5]
  112. if wep_mode == 6:
  113. wep_keys[i] = wep_keys[i].decode('ascii', errors='backslashreplace')[:13]
  114. if wep_mode == 7:
  115. wep_keys[i] = wep_keys[i].decode('ascii', errors='backslashreplace')[:16]
  116. #TODO Format properly when WEP mode is hex
  117. print('Wifi %d WEP keys: %s' % (slot_number, list(wep_keys)))
  118.  
  119. def read_dsi_wifi_config(f, offset, slot_number):
  120. f.seek(offset + 0xe7)
  121. status = f.read(1)[0]
  122. if status == 0xff:
  123. return
  124.  
  125. print('Wifi %d status: %s' % (slot_number, WIFI_STATUSES.get(status, 'Unknown 0x{0:02X}'.format(status))))
  126.  
  127. ssid_length = f.read(1)[0]
  128. f.seek(offset + 0x40)
  129. ssid = f.read(ssid_length).decode('ascii', errors='backslashreplace')
  130. print('Wifi %d SSID: %s' % (slot_number, ssid))
  131.  
  132. f.seek(offset + 0xe6)
  133. wep_type = f.read(1)[0]
  134. if wep_type != 0:
  135. print('Wifi %d WEP type: %s' % (slot_number, wep_type))
  136.  
  137. f.seek(offset + 0x182)
  138. proxy_enabled = f.read(1)[0] > 0
  139. if proxy_enabled:
  140. proxy_uses_auth = f.read(1)[0] > 0
  141. proxy_name = f.read(100).decode('ascii', errors='backslashreplace').rstrip('\0')
  142. print('Wifi %d proxy name: %s' % (slot_number, proxy_name))
  143. proxy_port = f.read(1)[0] | (f.read(1)[0] << 8)
  144. print('Wifi %d proxy port: %s' % (slot_number, proxy_port))
  145.  
  146. if proxy_uses_auth:
  147. f.seek(offset)
  148. proxy_auth_username = f.read(32).decode('ascii', errors='backslashreplace').rstrip('\0')
  149. proxy_auth_password = f.read(32).decode('ascii', errors='backslashreplace').rstrip('\0')
  150. print('Wifi %d proxy authentication: username %s password %s' % (slot_number, proxy_auth_username, proxy_auth_password))
  151.  
  152.  
  153. f.seek(offset + 0xc0)
  154. ip_address = f.read(4)
  155. if is_null_ip_address(ip_address):
  156. print('Wifi %d IP address: DHCP' % slot_number)
  157. else:
  158. print('Wifi %d IP address: %s' % (slot_number, format_ip_address(ip_address)))
  159. gateway = f.read(4)
  160. print('Wifi %d gateway: %s' % (slot_number, format_ip_address(gateway)))
  161. primary_dns = f.read(4)
  162. print('Wifi %d primary: %s' % (slot_number, format_ip_address(primary_dns)))
  163. secondary_dns = f.read(4)
  164. print('Wifi %d secondary: %s' % (slot_number, format_ip_address(secondary_dns)))
  165. subnet_mask = f.read(1)[0]
  166. print('Wifi %d subnet mask: /%d' % (slot_number, subnet_mask))
  167.  
  168. if status == 16:
  169. f.seek(offset + 0x120)
  170. wpa_key = f.read(64).decode('ascii', errors='backslashreplace').rstrip('\0')
  171. #GBATEK says this is only 16 bytes, but that is clearly wrong as WPA keys can be longer than that
  172. print('Wifi %d WPA/WPA2 key: %s' % (slot_number, wpa_key))
  173. f.seek(offset + 0x181)
  174. wpa_type = f.read(1)[0]
  175. print('Wifi %d WPA type: %s' % (slot_number, WPA_TYPES.get(wpa_type, 'Unknown 0x{0:02X}'.format(wpa_type))))
  176.  
  177.  
  178. with open(sys.argv[1], 'rb') as f:
  179.  
  180. f.seek(8)
  181. firmware_id = f.read(4)
  182. print('Firmware ID: %s' % list(firmware_id))
  183.  
  184. f.seek(0x18)
  185. firmware_version = f.read(5)
  186. #BCD minute hour day month year
  187. #TODO Convert this
  188. #TODO Can we get the fat DS firmware version from this?
  189. print('Firmware build date: %s' % list(firmware_version))
  190.  
  191. console_type = f.read(1)[0]
  192. print('Console type: %s' % CONSOLE_TYPES.get(console_type, 'Unknown 0x{0:02X}'.format(console_type)))
  193.  
  194. f.seek(32)
  195. user_settings_offset = f.read(2)
  196. offset = ((user_settings_offset[1] << 8) | user_settings_offset[0]) * 8
  197. f.seek(offset) #I guess?
  198.  
  199. #It's always 5, unless something goes wrong
  200. user_settings_version = f.read(2)
  201. print('User settings version: %s' % list(user_settings_version))
  202.  
  203. favourite_colour = f.read(1)[0]
  204. print('Favourite colour: %s' % COLOURS.get(favourite_colour, 'Unknown 0x{0:02X}'.format(favourite_colour)))
  205.  
  206. birthday_month = f.read(1)[0]
  207. birthday_year = f.read(1)[0]
  208. print('Birthday: {0} {1}'.format(calendar.month_name[birthday_month], birthday_year))
  209.  
  210. unused = f.read(1)[0]
  211. print('Secret unused user setting: %s' % unused)
  212.  
  213. name = f.read(20).decode('utf-16le', errors='backslashreplace')
  214. name_length = f.read(1)[0] | (f.read(1)[0] << 8)
  215. print('Name: %s' % name[:name_length])
  216.  
  217. message = f.read(52).decode('utf-16le', errors='backslashreplace')
  218. message_length = f.read(1)[0] | (f.read(1)[0] << 8)
  219. print('Message: %s' % message[:message_length])
  220.  
  221. alarm_hour = f.read(1)[0]
  222. alarm_minute = f.read(1)[0]
  223. print('Alarm time: {0}:{1}'.format(alarm_hour, alarm_minute))
  224.  
  225. #TODO Touch calibration and whatnot
  226. f.seek(offset + 0x64)
  227. flags = f.read(2)
  228.  
  229. language = flags[0] & 7
  230. print('Language: %s' % LANGUAGES.get(language))
  231. gba_screen = flags[0] & 8
  232. print('GBA screen: %s' % 'Upper' if gba_screen == 0 else 'Lower')
  233. backlight_level = (flags[0] & 48) >> 4 #0 if not DS Lite
  234. print('Backlight level: %d' % backlight_level)
  235. #TODO other flags (cbf tbh m8)
  236.  
  237. f.seek(0x2f)
  238. wifi_version = f.read(1)[0]
  239. print('Wifi version: %d' % wifi_version)
  240.  
  241. read_wifi_config(f, offset - 0x400, 1)
  242. read_wifi_config(f, offset - 0x300, 2)
  243. read_wifi_config(f, offset - 0x200, 3)
  244.  
  245. if console_type == 0x57:
  246. read_dsi_wifi_config(f, offset - 0xa00, 4)
  247. read_dsi_wifi_config(f, offset - 0x800, 5)
  248. read_dsi_wifi_config(f, offset - 0x600, 6)
Add Comment
Please, Sign In to add comment