diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..3a4fd09
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,104 @@
+cmake_minimum_required(VERSION 2.8)
+
+if(NOT DEFINED CMAKE_TOOLCHAIN_FILE)
+ if(DEFINED ENV{VITASDK})
+ set(CMAKE_TOOLCHAIN_FILE "$ENV{VITASDK}/share/vita.toolchain.cmake" CACHE PATH "toolchain file")
+ else()
+ message(FATAL_ERROR "Please define VITASDK to point to your SDK path!")
+ endif()
+endif()
+
+project(FasterARK)
+
+include("${VITASDK}/share/vita.cmake" REQUIRED)
+
+set(VITA_APP_NAME "FasterARK")
+set(VITA_TITLEID "FASTERARK")
+
+set(VITA_VERSION "01.00")
+
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,-q -Wall -fno-lto")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+
+set(VITA_MKSFOEX_FLAGS "${VITA_MKSFOEX_FLAGS} -s CATEGORY=gdb")
+set(VITA_MAKE_FSELF_FLAGS "${VITA_MAKE_FSELF_FLAGS}")
+
+include_directories(
+)
+
+link_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+)
+
+add_executable(${PROJECT_NAME}
+ src/main.c
+ src/ui.c
+ src/install.c
+ src/io.c
+ src/promote.c
+ src/pbp.c
+ src/sha256
+)
+
+target_link_libraries(${PROJECT_NAME}
+
+ vita2d
+ z
+ c
+ m
+ png
+ jpeg
+ SceGxm_stub
+ SceSysmodule_stub
+ ScePgf_stub
+ ScePvf_stub
+ SceCtrl_stub
+ SceCommonDialog_stub
+
+ SceLibKernel_stub
+ SceIofilemgr_stub
+ SceAppMgr_stub
+ SceDisplay_stub
+ SceVshBridge_stub
+ ScePromoterUtil_stub
+ taihen_stub
+)
+
+vita_create_self(eboot.bin ${PROJECT_NAME} UNSAFE)
+
+vita_create_vpk(${PROJECT_NAME}.vpk ${VITA_TITLEID} eboot.bin
+ VERSION ${VITA_VERSION}
+ NAME ${VITA_APP_NAME}
+
+ FILE sce_sys/icon0.png sce_sys/icon0.png
+ FILE sce_sys/livearea/contents/bg.png sce_sys/livearea/contents/bg.png
+ FILE sce_sys/livearea/contents/template.xml sce_sys/livearea/contents/template.xml
+
+ FILE res/rif/game.rif rif/game.rif
+ FILE res/psp/EBOOT.PBP psp/EBOOT.PBP
+ FILE res/psp/PBOOT.PBP psp/PBOOT.PBP
+ FILE res/save/ARK_01234/ARK.BIN save/ARK_01234/ARK.BIN
+ FILE res/save/ARK_01234/ARK4.BIN save/ARK_01234/ARK4.BIN
+ FILE res/save/ARK_01234/ARKX.BIN save/ARK_01234/ARKX.BIN
+ FILE res/save/ARK_01234/FLASH0.ARK save/ARK_01234/FLASH0.ARK
+ FILE res/save/ARK_01234/H.BIN save/ARK_01234/H.BIN
+ FILE res/save/ARK_01234/ICON0.PNG save/ARK_01234/ICON0.PNG
+ FILE res/save/ARK_01234/IDSREG.PRX save/ARK_01234/IDSREG.PRX
+ FILE res/save/ARK_01234/K.BIN save/ARK_01234/K.BIN
+ FILE res/save/ARK_01234/LANG.ARK save/ARK_01234/LANG.ARK
+ FILE res/save/ARK_01234/MEDIASYN.PRX save/ARK_01234/MEDIASYN.PRX
+ FILE res/save/ARK_01234/PARAM.SFO save/ARK_01234/PARAM.SFO
+ FILE res/save/ARK_01234/POPS.PRX save/ARK_01234/POPS.PRX
+ FILE res/save/ARK_01234/POPSMAN.PRX save/ARK_01234/POPSMAN.PRX
+ FILE res/save/ARK_01234/PS1SPU.PRX save/ARK_01234/PS1SPU.PRX
+ FILE res/save/ARK_01234/RECOVERY.PBP save/ARK_01234/RECOVERY.PBP
+ FILE res/save/ARK_01234/RECOVERY.PRX save/ARK_01234/RECOVERY.PRX
+ FILE res/save/ARK_01234/SAVEDATA.BIN save/ARK_01234/SAVEDATA.BIN
+ FILE res/save/ARK_01234/THEME.ARK save/ARK_01234/THEME.ARK
+ FILE res/save/ARK_01234/UPDATER.TXT save/ARK_01234/UPDATER.TXT
+ FILE res/save/ARK_01234/USBDEV.PRX save/ARK_01234/USBDEV.PRX
+ FILE res/save/ARK_01234/VBOOT.PBP save/ARK_01234/VBOOT.PBP
+ FILE res/save/ARK_01234/VSHMENU.PRX save/ARK_01234/VSHMENU.PRX
+ FILE res/save/ARK_01234/XBOOT.PBP save/ARK_01234/XBOOT.PBP
+ FILE res/save/ARK_01234/XMBCTRL.PRX save/ARK_01234/XMBCTRL.PRX
+)
diff --git a/res/psp/EBOOT.PBP b/res/psp/EBOOT.PBP
new file mode 100644
index 0000000..d3a66b4
Binary files /dev/null and b/res/psp/EBOOT.PBP differ
diff --git a/res/psp/PBOOT.PBP b/res/psp/PBOOT.PBP
new file mode 100644
index 0000000..5ca9ee0
Binary files /dev/null and b/res/psp/PBOOT.PBP differ
diff --git a/res/save/ARK_01234/ARK.BIN b/res/save/ARK_01234/ARK.BIN
new file mode 100644
index 0000000..2f40c9d
Binary files /dev/null and b/res/save/ARK_01234/ARK.BIN differ
diff --git a/res/save/ARK_01234/ARK4.BIN b/res/save/ARK_01234/ARK4.BIN
new file mode 100644
index 0000000..93401e0
Binary files /dev/null and b/res/save/ARK_01234/ARK4.BIN differ
diff --git a/res/save/ARK_01234/ARKX.BIN b/res/save/ARK_01234/ARKX.BIN
new file mode 100644
index 0000000..0de574f
Binary files /dev/null and b/res/save/ARK_01234/ARKX.BIN differ
diff --git a/res/save/ARK_01234/FLASH0.ARK b/res/save/ARK_01234/FLASH0.ARK
new file mode 100644
index 0000000..be8d11e
Binary files /dev/null and b/res/save/ARK_01234/FLASH0.ARK differ
diff --git a/res/save/ARK_01234/H.BIN b/res/save/ARK_01234/H.BIN
new file mode 100644
index 0000000..c84ba02
Binary files /dev/null and b/res/save/ARK_01234/H.BIN differ
diff --git a/res/save/ARK_01234/ICON0.PNG b/res/save/ARK_01234/ICON0.PNG
new file mode 100644
index 0000000..5561931
Binary files /dev/null and b/res/save/ARK_01234/ICON0.PNG differ
diff --git a/res/save/ARK_01234/IDSREG.PRX b/res/save/ARK_01234/IDSREG.PRX
new file mode 100644
index 0000000..ed1ee73
Binary files /dev/null and b/res/save/ARK_01234/IDSREG.PRX differ
diff --git a/res/save/ARK_01234/K.BIN b/res/save/ARK_01234/K.BIN
new file mode 100644
index 0000000..0382f6b
Binary files /dev/null and b/res/save/ARK_01234/K.BIN differ
diff --git a/res/save/ARK_01234/LANG.ARK b/res/save/ARK_01234/LANG.ARK
new file mode 100644
index 0000000..9a328f1
Binary files /dev/null and b/res/save/ARK_01234/LANG.ARK differ
diff --git a/res/save/ARK_01234/MEDIASYN.PRX b/res/save/ARK_01234/MEDIASYN.PRX
new file mode 100644
index 0000000..31a94da
Binary files /dev/null and b/res/save/ARK_01234/MEDIASYN.PRX differ
diff --git a/res/save/ARK_01234/PARAM.SFO b/res/save/ARK_01234/PARAM.SFO
new file mode 100644
index 0000000..a84c3db
Binary files /dev/null and b/res/save/ARK_01234/PARAM.SFO differ
diff --git a/res/save/ARK_01234/POPS.PRX b/res/save/ARK_01234/POPS.PRX
new file mode 100644
index 0000000..efa50d2
Binary files /dev/null and b/res/save/ARK_01234/POPS.PRX differ
diff --git a/res/save/ARK_01234/POPSMAN.PRX b/res/save/ARK_01234/POPSMAN.PRX
new file mode 100644
index 0000000..6394ee6
Binary files /dev/null and b/res/save/ARK_01234/POPSMAN.PRX differ
diff --git a/res/save/ARK_01234/PS1SPU.PRX b/res/save/ARK_01234/PS1SPU.PRX
new file mode 100644
index 0000000..1e1808c
Binary files /dev/null and b/res/save/ARK_01234/PS1SPU.PRX differ
diff --git a/res/save/ARK_01234/RECOVERY.PBP b/res/save/ARK_01234/RECOVERY.PBP
new file mode 100644
index 0000000..828540f
Binary files /dev/null and b/res/save/ARK_01234/RECOVERY.PBP differ
diff --git a/res/save/ARK_01234/RECOVERY.PRX b/res/save/ARK_01234/RECOVERY.PRX
new file mode 100644
index 0000000..25c34aa
Binary files /dev/null and b/res/save/ARK_01234/RECOVERY.PRX differ
diff --git a/res/save/ARK_01234/SAVEDATA.BIN b/res/save/ARK_01234/SAVEDATA.BIN
new file mode 100644
index 0000000..59e2a76
--- /dev/null
+++ b/res/save/ARK_01234/SAVEDATA.BIN
@@ -0,0 +1 @@
+tNYD9˭\P鲙
\ No newline at end of file
diff --git a/res/save/ARK_01234/THEME.ARK b/res/save/ARK_01234/THEME.ARK
new file mode 100644
index 0000000..5590cdc
Binary files /dev/null and b/res/save/ARK_01234/THEME.ARK differ
diff --git a/res/save/ARK_01234/UPDATER.TXT b/res/save/ARK_01234/UPDATER.TXT
new file mode 100644
index 0000000..8546897
--- /dev/null
+++ b/res/save/ARK_01234/UPDATER.TXT
@@ -0,0 +1 @@
+http://ark-4.ddns.net
\ No newline at end of file
diff --git a/res/save/ARK_01234/USBDEV.PRX b/res/save/ARK_01234/USBDEV.PRX
new file mode 100644
index 0000000..b1a20d9
Binary files /dev/null and b/res/save/ARK_01234/USBDEV.PRX differ
diff --git a/res/save/ARK_01234/VBOOT.PBP b/res/save/ARK_01234/VBOOT.PBP
new file mode 100644
index 0000000..f8e533e
Binary files /dev/null and b/res/save/ARK_01234/VBOOT.PBP differ
diff --git a/res/save/ARK_01234/VSHMENU.PRX b/res/save/ARK_01234/VSHMENU.PRX
new file mode 100644
index 0000000..917b144
Binary files /dev/null and b/res/save/ARK_01234/VSHMENU.PRX differ
diff --git a/res/save/ARK_01234/XBOOT.PBP b/res/save/ARK_01234/XBOOT.PBP
new file mode 100644
index 0000000..a178f3a
Binary files /dev/null and b/res/save/ARK_01234/XBOOT.PBP differ
diff --git a/res/save/ARK_01234/XMBCTRL.PRX b/res/save/ARK_01234/XMBCTRL.PRX
new file mode 100644
index 0000000..6ef81f8
Binary files /dev/null and b/res/save/ARK_01234/XMBCTRL.PRX differ
diff --git a/sce_sys/icon0.png b/sce_sys/icon0.png
new file mode 100644
index 0000000..91a94d6
Binary files /dev/null and b/sce_sys/icon0.png differ
diff --git a/sce_sys/livearea/contents/bg.png b/sce_sys/livearea/contents/bg.png
new file mode 100644
index 0000000..bb34622
Binary files /dev/null and b/sce_sys/livearea/contents/bg.png differ
diff --git a/sce_sys/livearea/contents/template.xml b/sce_sys/livearea/contents/template.xml
new file mode 100644
index 0000000..b8a559f
--- /dev/null
+++ b/sce_sys/livearea/contents/template.xml
@@ -0,0 +1,7 @@
+
+
+
+
+ bg.png
+
+
diff --git a/src/install.c b/src/install.c
new file mode 100644
index 0000000..23d9069
--- /dev/null
+++ b/src/install.c
@@ -0,0 +1,84 @@
+#include
+#include
+#include
+#include
+
+#include "io.h"
+#include "promote.h"
+#include "pbp.h"
+#include "install.h"
+#include "ui.h"
+
+
+void createPspEmuDirectories() {
+
+ CreateDirAndUpdateUi("ux0:pspemu");
+ CreateDirAndUpdateUi("ux0:pspemu/PSP");
+ CreateDirAndUpdateUi("ux0:pspemu/PSP/SAVEDATA");
+
+ CreateDirAndUpdateUi("ux0:pspemu/temp");
+ CreateDirAndUpdateUi("ux0:pspemu/temp/game");
+ CreateDirAndUpdateUi("ux0:pspemu/temp/game/PSP");
+ CreateDirAndUpdateUi("ux0:pspemu/temp/game/PSP/GAME");
+ CreateDirAndUpdateUi("ux0:pspemu/temp/game/PSP/LICENSE");
+}
+
+
+void genEbootSignature(char* ebootPath) {
+ char ebootSigFilePath[MAX_PATH];
+ char ebootSig[0x200];
+ unsigned char pbpHash[0x20];
+
+ int swVer = 0;
+
+ memset(ebootSig, 0x00, sizeof(ebootSig));
+ memset(pbpHash, 0x00, sizeof(pbpHash));
+
+ snprintf(ebootSigFilePath, MAX_PATH, "ux0:/pspemu/temp/game/PSP/GAME/%s/__sce_ebootpbp", TITLE_ID);
+
+ updateUi("Calculating EBOOT.PBP hash ...");
+ HashPbp(ebootPath, pbpHash);
+
+ updateUi("Generating EBOOT.PBP Signature ...");
+ int res = _vshNpDrmEbootSigGenPsp(ebootPath, pbpHash, ebootSig, &swVer);
+ if(res >= 0) {
+ WriteFile(ebootSigFilePath, ebootSig, sizeof(ebootSig));
+ }
+}
+
+void placePspGameData() {
+ char gameFolder[MAX_PATH];
+ char ebootFile[MAX_PATH];
+ char pbootFile[MAX_PATH];
+ char rifFile[MAX_PATH];
+
+ // create game folder .
+ snprintf(gameFolder, MAX_PATH, "ux0:/pspemu/temp/game/PSP/GAME/%s", TITLE_ID);
+ CreateDirAndUpdateUi(gameFolder);
+
+ // get path to EBOOT.PBP and PBOOT.PBP
+ snprintf(ebootFile, MAX_PATH, "ux0:/pspemu/temp/game/PSP/GAME/%s/EBOOT.PBP", TITLE_ID);
+ snprintf(pbootFile, MAX_PATH, "ux0:/pspemu/temp/game/PSP/GAME/%s/PBOOT.PBP", TITLE_ID);
+ snprintf(rifFile, MAX_PATH, "ux0:/pspemu/temp/game/PSP/LICENSE/%s.rif", CONTENT_ID);
+
+ CopyFileAndUpdateUi("app0:/psp/EBOOT.PBP", ebootFile);
+ CopyFileAndUpdateUi("app0:/psp/PBOOT.PBP", pbootFile);
+ CopyFileAndUpdateUi("app0:/rif/game.rif", rifFile);
+
+ genEbootSignature(ebootFile);
+}
+void createBubble() {
+ updateUi("Promoting ...");
+ promoteCma("ux0:/pspemu/temp/game", TITLE_ID, SCE_PKG_TYPE_PSP);
+}
+
+void copySaveFiles() {
+ CopyTree("app0:/save", "ux0:/pspemu/PSP/SAVEDATA");
+}
+
+void doInstall() {
+ createPspEmuDirectories();
+ placePspGameData();
+ createBubble();
+ copySaveFiles();
+}
\ No newline at end of file
diff --git a/src/install.h b/src/install.h
new file mode 100644
index 0000000..c7ae0e8
--- /dev/null
+++ b/src/install.h
@@ -0,0 +1,8 @@
+#define TITLE_ID "NPUZ01234"
+#define CONTENT_ID "IP9100-PCSI00011_00-PSMRUNTIME000000"
+
+void createPspEmuDirectories();
+void placePspGameData();
+void createBubble();
+void copySaveFiles();
+void doInstall();
\ No newline at end of file
diff --git a/src/io.c b/src/io.c
new file mode 100644
index 0000000..283bf54
--- /dev/null
+++ b/src/io.c
@@ -0,0 +1,103 @@
+#include
+#include
+#include
+#include
+#include "io.h"
+#include "ui.h"
+
+void CopyFileAndUpdateUi(char* src, char* dst) {
+ char msg[MAX_PATH+0x100];
+ snprintf(msg, sizeof(msg), "Copying %s ...", src);
+ updateUi(msg);
+
+ CopyFile(src, dst);
+}
+
+
+void CreateDirAndUpdateUi(char* dir) {
+ char msg[MAX_PATH+0x100];
+ snprintf(msg, sizeof(msg), "Creating directory %s ...", dir);
+ updateUi(msg);
+
+ sceIoMkdir(dir, 0006);
+}
+
+int WriteFile(const char *file, void *buf, int size) {
+ SceUID fd = sceIoOpen(file, SCE_O_WRONLY | SCE_O_CREAT , 0777);
+ if (fd < 0)
+ return fd;
+
+ int written = sceIoWrite(fd, buf, size);
+
+ sceIoClose(fd);
+ return written;
+}
+
+int ReadFile(const char *file, void *buf, int size) {
+ SceUID fd = sceIoOpen(file,SCE_O_RDONLY, 0777);
+ if (fd < 0)
+ return fd;
+
+ int read = sceIoRead(fd, buf, size);
+
+ sceIoClose(fd);
+ return read;
+}
+
+size_t GetFileSize(const char *file) {
+ SceIoStat stat;
+
+ int ret = sceIoGetstat(file, &stat);
+ if(ret < 0)
+ return ret;
+
+ return stat.st_size;
+}
+
+void CopyFile(const char *file, const char* dstfile) {
+ size_t sz = GetFileSize(file);
+
+ char* buf = malloc(sz);
+ if(buf != NULL) {
+ ReadFile(file, buf, sz);
+ WriteFile(dstfile, buf, sz);
+ free(buf);
+ }
+}
+
+void CopyTree(const char* src, const char* dst) {
+ SceUID dfd = sceIoDopen(src);
+ char* srcEnt = malloc(MAX_PATH);
+ memset(srcEnt, 0x00, MAX_PATH);
+
+ char* dstEnt = malloc(MAX_PATH);
+ memset(dstEnt, 0x00, MAX_PATH);
+
+ int dir_read_ret = 0;
+ SceIoDirent* dir = malloc(sizeof(SceIoDirent));
+ do{
+ memset(dir, 0x00, sizeof(SceIoDirent));
+
+ dir_read_ret = sceIoDread(dfd, dir);
+
+ snprintf(srcEnt, MAX_PATH, "%s/%s", src, dir->d_name);
+ snprintf(dstEnt, MAX_PATH, "%s/%s", dst, dir->d_name);
+
+ if(SCE_S_ISDIR(dir->d_stat.st_mode)) {
+ CreateDirAndUpdateUi(dstEnt);
+ CopyTree(srcEnt, dstEnt);
+ }
+ else{
+ CopyFileAndUpdateUi(srcEnt, dstEnt);
+ }
+
+
+ } while(dir_read_ret > 0);
+
+
+ free(dir);
+ sceIoDclose(dfd);
+
+ free(srcEnt);
+ free(dstEnt);
+}
\ No newline at end of file
diff --git a/src/io.h b/src/io.h
new file mode 100644
index 0000000..e96cdc9
--- /dev/null
+++ b/src/io.h
@@ -0,0 +1,10 @@
+#define MAX_PATH (0x1000)
+
+size_t GetFileSize(const char *file);
+void CopyFile(const char *file, const char* dstfile);
+void CopyTree(const char* src, const char* dst);
+int ReadFile(const char *file, void *buf, int size);
+int WriteFile(const char *file, void *buf, int size);
+
+void CopyFileAndUpdateUi(char* src, char* dst);
+void CreateDirAndUpdateUi(char* dir);
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..ee2a108
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,31 @@
+#include
+#include
+#include
+#include
+
+#include "install.h"
+#include "ui.h"
+
+void waitCross(){
+ SceCtrlData pad;
+ while(1){
+ memset(&pad, 0x00, sizeof(SceCtrlData));
+ sceCtrlPeekBufferPositive(0, &pad, 1);
+ if(pad.buttons == SCE_CTRL_CROSS)
+ break;
+ }
+}
+
+int main(int argc, const char *argv[]) {
+ uiInit();
+
+ displayMsg("Install?", "Press X to begin installation ...");
+ waitCross();
+
+ doInstall();
+
+ displayMsg("Install Complete!", "Press X to close this application ...");
+ waitCross();
+
+ return 0;
+}
\ No newline at end of file
diff --git a/src/pbp.c b/src/pbp.c
new file mode 100644
index 0000000..6032dac
--- /dev/null
+++ b/src/pbp.c
@@ -0,0 +1,52 @@
+#include
+#include
+#include
+#include
+#include "sha256.h"
+#include "pbp.h"
+
+int HashPbp(char* eboot_file, unsigned char* out_hash) {
+ unsigned char wbuf[0x7c0];
+
+ // open the pbp file
+ SceUID pbp_fd = sceIoOpen(eboot_file, SCE_O_RDONLY, 0);
+
+ // error check
+ if(pbp_fd < 0)
+ return pbp_fd;
+
+ // inital read
+ int read_sz = sceIoRead(pbp_fd, wbuf, sizeof(wbuf));
+ if(read_sz < sizeof(PbpHeader)) return read_sz;
+
+ // calculate data hash size
+ size_t hash_sz = (((PbpHeader*)wbuf)->data_psar_ptr + 0x1C0000);
+
+ // initalize hash
+ SHA256_CTX ctx;
+ sha256_init(&ctx);
+
+ // first hash
+ sha256_update(&ctx, wbuf, read_sz);
+ size_t total_hashed = read_sz;
+
+ do {
+ read_sz = sceIoRead(pbp_fd, wbuf, sizeof(wbuf));
+
+ if((total_hashed + read_sz) > hash_sz)
+ read_sz = (hash_sz - total_hashed); // calculate remaining
+
+ sha256_update(&ctx, wbuf, read_sz);
+ total_hashed += read_sz;
+
+ if(read_sz < sizeof(wbuf)) // treat EOF as complete
+ total_hashed = hash_sz;
+
+ } while(total_hashed < hash_sz);
+
+ sha256_final(&ctx, out_hash);
+
+ sceIoClose(pbp_fd);
+
+ return 1;
+}
diff --git a/src/pbp.h b/src/pbp.h
new file mode 100644
index 0000000..b6c5cce
--- /dev/null
+++ b/src/pbp.h
@@ -0,0 +1,79 @@
+typedef enum PbpType{
+ PBP_TYPE_NPUMDIMG = 0,
+ PBP_TYPE_PSISOIMG = 1,
+ PBP_TYPE_PSTITLEIMG = 2,
+ PBP_TYPE_UNKNOWN = 3
+} PbpType;
+
+// for PSISOIMG and PSTITLEIMG contents
+
+typedef struct DataPspHeader{
+ SceUInt8 magic[0x4];
+ SceUInt8 unk[0x7C];
+ SceUInt8 unk2[0x32];
+ SceUInt8 unk3[0xE];
+ SceUInt8 hash[0x14];
+ SceUInt8 reserved[0x58];
+ SceUInt8 unk4[0x434];
+ char content_id[0x30];
+} DataPspHeader;
+
+// for NPUMDIMG content
+typedef struct NpUmdImgBody {
+ SceUInt16 sector_size; // 0x0800
+ SceUInt16 unk_2; // 0xE000
+ SceUInt32 unk_4;
+ SceUInt32 unk_8;
+ SceUInt32 unk_12;
+ SceUInt32 unk_16;
+ SceUInt32 lba_start;
+ SceUInt32 unk_24;
+ SceUInt32 nsectors;
+ SceUInt32 unk_32;
+ SceUInt32 lba_end;
+ SceUInt32 unk_40;
+ SceUInt32 block_entry_offset;
+ char disc_id[0x10];
+ SceUInt32 header_start_offset;
+ SceUInt32 unk_68;
+ SceUInt8 unk_72;
+ SceUInt8 bbmac_param;
+ SceUInt8 unk_74;
+ SceUInt8 unk_75;
+ SceUInt32 unk_76;
+ SceUInt32 unk_80;
+ SceUInt32 unk_84;
+ SceUInt32 unk_88;
+ SceUInt32 unk_92;
+} NpUmdImgBody;
+
+typedef struct NpUmdImgHeader{
+ SceUInt8 magic[0x08]; // "NPUMDIMG"
+ SceUInt32 key_index; // usually 2, or 3.
+ SceUInt32 block_basis;
+ char content_id[0x30];
+ NpUmdImgBody body;
+ SceUInt8 header_key[0x10];
+ SceUInt8 data_key[0x10];
+ SceUInt8 header_hash[0x10];
+ SceUInt8 padding[0x8];
+ SceUInt8 ecdsa_sig[0x28];
+} NpUmdImgHeader;
+
+// generic eboot.pbp header
+
+typedef struct PbpHeader
+{
+ char magic[0x4];
+ SceUInt32 version;
+ SceUInt32 param_sfo_ptr;
+ SceUInt32 icon0_png_ptr;
+ SceUInt32 icon1_pmf_ptr;
+ SceUInt32 pic0_png_ptr;
+ SceUInt32 pic1_png_ptr;
+ SceUInt32 snd0_at3_ptr;
+ SceUInt32 data_psp_ptr;
+ SceUInt32 data_psar_ptr;
+} PbpHeader;
+
+int HashPbp(char* eboot_file, unsigned char* out_hash);
\ No newline at end of file
diff --git a/src/promote.c b/src/promote.c
new file mode 100644
index 0000000..a308600
--- /dev/null
+++ b/src/promote.c
@@ -0,0 +1,77 @@
+#include
+
+static int loadScePaf() {
+ static uint32_t argp[] = { 0x180000, -1, -1, 1, -1, -1 };
+
+ int result = -1;
+
+ uint32_t buf[4];
+ buf[0] = sizeof(buf);
+ buf[1] = (uint32_t)&result;
+ buf[2] = -1;
+ buf[3] = -1;
+
+ return sceSysmoduleLoadModuleInternalWithArg(SCE_SYSMODULE_INTERNAL_PAF, sizeof(argp), argp, buf);
+}
+
+static int unloadScePaf() {
+ uint32_t buf = 0;
+ return sceSysmoduleUnloadModuleInternalWithArg(SCE_SYSMODULE_INTERNAL_PAF, 0, NULL, &buf);
+}
+
+int promoteCma(const char *path, const char *titleid, int type) {
+ int res;
+
+ ScePromoterUtilityImportParams promoteArgs;
+ memset(&promoteArgs,0x00,sizeof(ScePromoterUtilityImportParams));
+ strncpy(promoteArgs.path,path,0x7F);
+ strncpy(promoteArgs.titleid,titleid,0xB);
+ promoteArgs.type = type;
+ promoteArgs.attribute = 0x1;
+
+ res = loadScePaf();
+ if (res < 0) {
+ sceClibPrintf("loadScePaf: %x\n", res);
+ return res;
+ }
+
+ res = sceSysmoduleLoadModuleInternal(SCE_SYSMODULE_INTERNAL_PROMOTER_UTIL);
+ if (res < 0) {
+ sceClibPrintf("sceSysmoduleLoadModuleInternal: %x\n", res);
+ return res;
+ }
+
+ res = scePromoterUtilityInit();
+ if (res < 0) {
+ sceClibPrintf("scePromoterUtilityInit: %x\n", res);
+ return res;
+ }
+
+ res = scePromoterUtilityPromoteImport(&promoteArgs);
+ if (res < 0) {
+ sceClibPrintf("scePromoterUtilityPromoteImport: %x\n", res);
+ return res;
+ }
+
+ res = scePromoterUtilityExit();
+ if (res < 0) {
+ sceClibPrintf("scePromoterUtilityExit: %x\n", res);
+ return res;
+ }
+
+ res = sceSysmoduleUnloadModuleInternal(SCE_SYSMODULE_INTERNAL_PROMOTER_UTIL);
+ if (res < 0) {
+ sceClibPrintf("sceSysmoduleUnloadModuleInternal: %x\n", res);
+ return res;
+ }
+
+
+ res = unloadScePaf();
+ if (res < 0)
+ if (res < 0) {
+ sceClibPrintf("unloadScePaf: %x\n", res);
+ return res;
+ }
+
+ return res;
+}
\ No newline at end of file
diff --git a/src/promote.h b/src/promote.h
new file mode 100644
index 0000000..6cfdd20
--- /dev/null
+++ b/src/promote.h
@@ -0,0 +1 @@
+int promoteCma(const char *path, const char *titleid, int type);
\ No newline at end of file
diff --git a/src/sha256.c b/src/sha256.c
new file mode 100644
index 0000000..eb9c5c0
--- /dev/null
+++ b/src/sha256.c
@@ -0,0 +1,158 @@
+/*********************************************************************
+* Filename: sha256.c
+* Author: Brad Conte (brad AT bradconte.com)
+* Copyright:
+* Disclaimer: This code is presented "as is" without any guarantees.
+* Details: Implementation of the SHA-256 hashing algorithm.
+ SHA-256 is one of the three algorithms in the SHA2
+ specification. The others, SHA-384 and SHA-512, are not
+ offered in this implementation.
+ Algorithm specification can be found here:
+ * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf
+ This implementation uses little endian byte order.
+*********************************************************************/
+
+/*************************** HEADER FILES ***************************/
+#include
+#include
+#include "sha256.h"
+
+/****************************** MACROS ******************************/
+#define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b))))
+#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b))))
+
+#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z)))
+#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
+#define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22))
+#define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25))
+#define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3))
+#define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10))
+
+/**************************** VARIABLES *****************************/
+static const WORD k[64] = {
+ 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
+ 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
+ 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
+ 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
+ 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
+ 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
+ 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
+ 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
+};
+
+/*********************** FUNCTION DEFINITIONS ***********************/
+void sha256_transform(SHA256_CTX *ctx, const BYTE data[])
+{
+ WORD a, b, c, d, e, f, g, h, i, j, t1, t2, m[64];
+
+ for (i = 0, j = 0; i < 16; ++i, j += 4)
+ m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]);
+ for ( ; i < 64; ++i)
+ m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16];
+
+ a = ctx->state[0];
+ b = ctx->state[1];
+ c = ctx->state[2];
+ d = ctx->state[3];
+ e = ctx->state[4];
+ f = ctx->state[5];
+ g = ctx->state[6];
+ h = ctx->state[7];
+
+ for (i = 0; i < 64; ++i) {
+ t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i];
+ t2 = EP0(a) + MAJ(a,b,c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + t1;
+ d = c;
+ c = b;
+ b = a;
+ a = t1 + t2;
+ }
+
+ ctx->state[0] += a;
+ ctx->state[1] += b;
+ ctx->state[2] += c;
+ ctx->state[3] += d;
+ ctx->state[4] += e;
+ ctx->state[5] += f;
+ ctx->state[6] += g;
+ ctx->state[7] += h;
+}
+
+void sha256_init(SHA256_CTX *ctx)
+{
+ ctx->datalen = 0;
+ ctx->bitlen = 0;
+ ctx->state[0] = 0x6a09e667;
+ ctx->state[1] = 0xbb67ae85;
+ ctx->state[2] = 0x3c6ef372;
+ ctx->state[3] = 0xa54ff53a;
+ ctx->state[4] = 0x510e527f;
+ ctx->state[5] = 0x9b05688c;
+ ctx->state[6] = 0x1f83d9ab;
+ ctx->state[7] = 0x5be0cd19;
+}
+
+void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len)
+{
+ WORD i;
+
+ for (i = 0; i < len; ++i) {
+ ctx->data[ctx->datalen] = data[i];
+ ctx->datalen++;
+ if (ctx->datalen == 64) {
+ sha256_transform(ctx, ctx->data);
+ ctx->bitlen += 512;
+ ctx->datalen = 0;
+ }
+ }
+}
+
+void sha256_final(SHA256_CTX *ctx, BYTE hash[])
+{
+ WORD i;
+
+ i = ctx->datalen;
+
+ // Pad whatever data is left in the buffer.
+ if (ctx->datalen < 56) {
+ ctx->data[i++] = 0x80;
+ while (i < 56)
+ ctx->data[i++] = 0x00;
+ }
+ else {
+ ctx->data[i++] = 0x80;
+ while (i < 64)
+ ctx->data[i++] = 0x00;
+ sha256_transform(ctx, ctx->data);
+ memset(ctx->data, 0, 56);
+ }
+
+ // Append to the padding the total message's length in bits and transform.
+ ctx->bitlen += ctx->datalen * 8;
+ ctx->data[63] = ctx->bitlen;
+ ctx->data[62] = ctx->bitlen >> 8;
+ ctx->data[61] = ctx->bitlen >> 16;
+ ctx->data[60] = ctx->bitlen >> 24;
+ ctx->data[59] = ctx->bitlen >> 32;
+ ctx->data[58] = ctx->bitlen >> 40;
+ ctx->data[57] = ctx->bitlen >> 48;
+ ctx->data[56] = ctx->bitlen >> 56;
+ sha256_transform(ctx, ctx->data);
+
+ // Since this implementation uses little endian byte ordering and SHA uses big endian,
+ // reverse all the bytes when copying the final state to the output hash.
+ for (i = 0; i < 4; ++i) {
+ hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff;
+ hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff;
+ hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff;
+ hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff;
+ hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff;
+ hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff;
+ hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff;
+ hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff;
+ }
+}
diff --git a/src/sha256.h b/src/sha256.h
new file mode 100644
index 0000000..7123a30
--- /dev/null
+++ b/src/sha256.h
@@ -0,0 +1,34 @@
+/*********************************************************************
+* Filename: sha256.h
+* Author: Brad Conte (brad AT bradconte.com)
+* Copyright:
+* Disclaimer: This code is presented "as is" without any guarantees.
+* Details: Defines the API for the corresponding SHA1 implementation.
+*********************************************************************/
+
+#ifndef SHA256_H
+#define SHA256_H
+
+/*************************** HEADER FILES ***************************/
+#include
+
+/****************************** MACROS ******************************/
+#define SHA256_BLOCK_SIZE 32 // SHA256 outputs a 32 byte digest
+
+/**************************** DATA TYPES ****************************/
+typedef unsigned char BYTE; // 8-bit byte
+typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines
+
+typedef struct {
+ BYTE data[64];
+ WORD datalen;
+ unsigned long long bitlen;
+ WORD state[8];
+} SHA256_CTX;
+
+/*********************** FUNCTION DECLARATIONS **********************/
+void sha256_init(SHA256_CTX *ctx);
+void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len);
+void sha256_final(SHA256_CTX *ctx, BYTE hash[]);
+
+#endif // SHA256_H
diff --git a/src/ui.c b/src/ui.c
new file mode 100644
index 0000000..430c059
--- /dev/null
+++ b/src/ui.c
@@ -0,0 +1,83 @@
+#include
+#include
+#include
+#include
+#include
+#include
+
+int progress = 0;
+const int totalProgress = 42; // this is like how many times updateUi is called ..
+
+vita2d_pgf *pgf;
+vita2d_pvf *pvf;
+
+void uiInit() {
+ vita2d_init();
+ vita2d_set_clear_color(RGBA8(0x00, 0x00, 0x00, 0xFF));
+ pgf = vita2d_load_default_pgf();
+ pvf = vita2d_load_default_pvf();
+}
+
+void drawTextCenter(int y, char* text) {
+ int width = 0;
+ int height = 0;
+
+ vita2d_pgf_text_dimensions(pgf, 1.0, text, &width, &height);
+
+ int x = ((960 / 2) - (width / 2));
+ vita2d_pgf_draw_text(pgf, x, y, RGBA8(255,255,255,255), 1.0f, text);
+}
+
+void drawProgress() {
+ int end = 900;
+ int start = 60;
+ int y = 300;
+ int percent = (int)floor(((float)progress / (float)totalProgress) * 840.0);
+ char percentText[0x100];
+
+ vita2d_draw_line(start, y, end, y, RGBA8(128,128,128,255));
+ vita2d_draw_line(start, y, start + percent, y, RGBA8(0,255,0,255));
+
+ snprintf(percentText, sizeof(percentText), "%i%%", progress);
+ drawTextCenter(320, percentText);
+}
+
+void endDraw() {
+ vita2d_end_drawing();
+ vita2d_swap_buffers();
+}
+
+void startDraw() {
+ vita2d_start_drawing();
+ vita2d_clear_screen();
+}
+
+void drawLines() {
+ vita2d_pgf_draw_text(pgf, 20, 30, RGBA8(255,255,255,255), 1.0f, "FasterARK");
+ vita2d_draw_line(0, 64, 960, 64, RGBA8(255,255,255,255));
+ vita2d_draw_line(0, 544-64, 960, 544-64, RGBA8(255,255,255,255));
+}
+
+
+void displayMsg(char* title, char* msg) {
+ startDraw();
+ drawLines();
+
+ drawTextCenter(190, title);
+ drawTextCenter(230, msg);
+
+ endDraw();
+}
+
+void updateUi(char* msg) {
+ progress++;
+
+ startDraw();
+ drawLines();
+
+ drawTextCenter(190, "Installing ...");
+ drawTextCenter(230, msg);
+ drawProgress();
+
+ endDraw();
+}
\ No newline at end of file
diff --git a/src/ui.h b/src/ui.h
new file mode 100644
index 0000000..50166b2
--- /dev/null
+++ b/src/ui.h
@@ -0,0 +1,3 @@
+void uiInit();
+void updateUi(char* msg);
+void displayMsg(char* title, char* msg);
\ No newline at end of file