1 #include <pspsdk.h>
2 #include <pspkernel.h>
3 #include <pspdebug.h>
4 #include <pspmoduleinfo.h>
5 #include <pspctrl.h>
6 #include <pspchnnlsv.h>
7 #include <psputility.h>
8 #include "kernelcall/kernelcall.h"
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include "encrypt.h"
13 #include "decrypt.h"
14 #include "psf.h"
15
16 #define printf pspDebugScreenPrintf
17
18 /* Define the module info section */
19 PSP_MODULE_INFO("ppssppsavetool", 0, 1, 0);
20 PSP_MAIN_THREAD_ATTR(PSP_THREAD_ATTR_USER);
21 PSP_HEAP_SIZE_KB(-64);
22
23 #define ENCRYPT_FILE_VERSION 1
24
25
26 int currentMenu = 0;
27 int selectedOption = 0;
28 int basePath = 0;
29 int workDir = 0;
30
31 char *menuList0[] = {"Encrypt","Decrypt", "Exit", NULL};
32 char *menuList1[] = {"ms0:/PSP/SAVEDATAPPSSPP/","host0:/","host1:/", "host2:/", "Back", NULL};
33 char *menuList2[] = {"Back", NULL};
34
GetSDKMainVersion(int sdkVersion)35 int GetSDKMainVersion(int sdkVersion)
36 {
37 if(sdkVersion > 0x307FFFF)
38 return 6;
39 if(sdkVersion > 0x300FFFF)
40 return 5;
41 if(sdkVersion > 0x206FFFF)
42 return 4;
43 if(sdkVersion > 0x205FFFF)
44 return 3;
45 if(sdkVersion >= 0x2000000)
46 return 2;
47 if(sdkVersion >= 0x1000000)
48 return 1;
49 return 0;
50 };
51
ProcessInput(int maxOption,int * selectedOption)52 int ProcessInput(int maxOption, int *selectedOption)
53 {
54 SceCtrlData pad, oldpad;
55 sceCtrlReadBufferPositive(&oldpad, 1);
56 while(1)
57 {
58 sceCtrlReadBufferPositive(&pad, 1);
59
60 if (pad.Buttons != 0)
61 {
62 if (!(oldpad.Buttons & PSP_CTRL_CROSS) && pad.Buttons & PSP_CTRL_CROSS)
63 {
64 return *selectedOption;
65 }
66 else if (!(oldpad.Buttons & PSP_CTRL_UP) && pad.Buttons & PSP_CTRL_UP && *selectedOption > 0)
67 {
68 *selectedOption = *selectedOption-1;
69 return -1;
70 }
71 else if (!(oldpad.Buttons & PSP_CTRL_DOWN) && pad.Buttons & PSP_CTRL_DOWN && *selectedOption < maxOption-1)
72 {
73 *selectedOption = *selectedOption + 1;
74 return -1;
75 }
76 }
77 oldpad = pad;
78 }
79 }
80
81 typedef struct
82 {
83 char name[30];
84 char saveFile[30];
85 int errorId;
86 } DirInfo;
87
88 typedef struct
89 {
90 int fileVersion;
91 u8 key[16];
92 int sdkVersion;
93 } EncryptFileInfo;
94
95 DirInfo dirList[128];
96 int numDirList;
97 DirInfo invalidDirList[128];
98 int numInvalidDirList;
99
FileExist(char * basePath,char * dirPath,char * fileName)100 int FileExist(char* basePath, char* dirPath, char* fileName)
101 {
102 SceIoStat fileStat;
103 char path[1024];
104 sprintf(path,"%s%s/%s",basePath, dirPath, fileName);
105 if(sceIoGetstat(path, &fileStat) < 0) // no file
106 return 0;
107 return 1;
108 }
109
FileRead(char * basePath,char * dirPath,char * fileName,u8 * dataout,int size)110 int FileRead(char* basePath, char* dirPath, char* fileName, u8* dataout, int size)
111 {
112 char path[1024];
113 sprintf(path,"%s%s/%s",basePath, dirPath, fileName);
114 SceUID fileId = sceIoOpen(path, PSP_O_RDONLY, 0777);
115 if(fileId < 0)
116 return -1;
117 sceIoRead(fileId, dataout, size);
118 sceIoClose(fileId);
119 return 0;
120 }
121
AddErrorDir(char * dirName,int error)122 void AddErrorDir(char* dirName, int error)
123 {
124 if(numInvalidDirList >= 128)
125 return;
126 DirInfo *inf = &invalidDirList[numInvalidDirList];
127 strcpy(inf->name,dirName);
128 inf->errorId = error;
129 numInvalidDirList++;
130 }
131
UpdateValidDir(int isEncrypt)132 int UpdateValidDir(int isEncrypt)
133 {
134 numDirList = 0;
135 numInvalidDirList = 0;
136
137 const char* pspPath = "ms0:/PSP/SAVEDATA/";
138
139 char* pathSrc;
140 char* pathDst;
141 if(isEncrypt)
142 {
143 pathSrc = menuList1[basePath];
144 pathDst = pspPath;
145 }
146 else
147 {
148 pathSrc = pspPath;
149 pathDst = menuList1[basePath];
150 }
151
152 int dfd;
153 dfd = sceIoDopen(menuList1[basePath]);
154 if(dfd >= 0)
155 {
156 SceIoDirent data;
157 while(sceIoDread(dfd, &data) > 0 && numDirList < 128)
158 {
159 if(!(data.d_stat.st_attr & 0x10)) // is not a directory
160 {
161 continue;
162 }
163
164 if(data.d_name[0] == '.') // ignore "." and ".."
165 continue;
166
167 if(FileExist(menuList1[basePath], data.d_name, "ENCRYPT_INFO.BIN") < 0)
168 {
169 AddErrorDir(data.d_name,1);
170 continue;
171 }
172
173 EncryptFileInfo encryptInfo;
174 if(FileRead(menuList1[basePath], data.d_name, "ENCRYPT_INFO.BIN",(u8*)&encryptInfo,sizeof(encryptInfo)) < 0)
175 {
176 AddErrorDir(data.d_name,2);
177 continue;
178 }
179
180 if(encryptInfo.fileVersion != ENCRYPT_FILE_VERSION) // Not good version
181 {
182 AddErrorDir(data.d_name,3);
183 continue;
184 }
185
186 if(FileExist(pathSrc, data.d_name, "PARAM.SFO") < 0)
187 {
188 AddErrorDir(data.d_name,4);
189 continue;
190 }
191
192 u8 paramsfo[0x1330];
193 if(FileRead(pathSrc, data.d_name, "PARAM.SFO",(u8*)¶msfo,0x1330) < 0)
194 {
195 AddErrorDir(data.d_name,5);
196 continue;
197 }
198
199 u8 *datafile;
200 int listLen;
201 if (find_psf_section("SAVEDATA_FILE_LIST", paramsfo, 0x1330,
202 &datafile, &listLen) < 0)
203 {
204 AddErrorDir(data.d_name,6);
205 continue;
206 }
207 if(datafile[0] == 0)
208 {
209 AddErrorDir(data.d_name,7);
210 continue;
211 }
212
213 char filename[32];
214 strcpy(filename, (char*)datafile);
215
216 if(FileExist(pathSrc, data.d_name, filename) < 0)
217 {
218 AddErrorDir(data.d_name,8);
219 continue;
220 }
221
222 DirInfo *inf = &dirList[numDirList];
223 inf->errorId = 0;
224 strcpy(inf->name, data.d_name);
225 strcpy(inf->saveFile, filename);
226
227 numDirList++;
228
229 }
230 sceIoDclose(dfd);
231 if(numDirList == 0)
232 {
233 return -1;
234 }
235 }
236 else
237 {
238 return -2;
239 }
240 return 0;
241 }
242
FileCopy(char * srcPath,char * destPath,char * fileName)243 int FileCopy(char* srcPath, char* destPath, char* fileName)
244 {
245 SceIoStat fileStat;
246 char path[258];
247 sprintf(path,"%s/%s",srcPath, fileName);
248
249 if(sceIoGetstat(path, &fileStat) < 0)
250 return -1;
251 u8* data = malloc(fileStat.st_size);
252
253 SceUID fileId = sceIoOpen(path, PSP_O_RDONLY, 0777);
254 if(fileId < 0)
255 {
256 printf("Fail opening %s\n",path);
257 free(data);
258 return -1;
259 }
260 sceIoRead(fileId, data, fileStat.st_size);
261 sceIoClose(fileId);
262
263 sprintf(path,"%s/%s",destPath, fileName);
264
265 fileId = sceIoOpen(path, PSP_O_WRONLY | PSP_O_CREAT, 0777);
266 if(fileId < 0)
267 {
268 printf("Fail opening %s\n",path);
269 return -1;
270 }
271 sceIoWrite(fileId, data, fileStat.st_size);
272 sceIoClose(fileId);
273
274 free(data);
275 return 0;
276 }
277
main(int argc,char * argv[])278 int main(int argc, char *argv[])
279 {
280 int i;
281 pspDebugScreenInit();
282
283 SceUID mod = pspSdkLoadStartModule ("flash0:/kd/chnnlsv.prx",PSP_MEMORY_PARTITION_KERNEL);
284 if (mod < 0) {
285 printf("Error 0x%08X loading/starting chnnlsv.prx.\n", mod);
286 }
287
288 mod = pspSdkLoadStartModule ("kernelcall.prx",PSP_MEMORY_PARTITION_KERNEL);
289 if (mod < 0) {
290 printf("Error 0x%08X loading/starting kernelcall.prx.\n", mod);
291 }
292
293 sceCtrlSetSamplingCycle(0);
294 sceCtrlSetSamplingMode(PSP_CTRL_MODE_ANALOG);
295 for(;;)
296 {
297 printf("====================================================================");
298 printf("PPSSPP Save Tool\n");
299 printf("====================================================================\n\n\n");
300
301 switch(currentMenu)
302 {
303
304 case 0:
305 {
306 int maxOption = 0;
307 for(i = 0; menuList0[i]; i++)
308 {
309 if(i == selectedOption)
310 printf(" > %s\n",menuList0[i]);
311 else
312 printf(" %s\n",menuList0[i]);
313 maxOption++;
314 }
315
316 int input = ProcessInput(maxOption, &selectedOption);
317 if(input == 0)
318 {
319 currentMenu = 1;
320 selectedOption = 0;
321 }
322 else if(input == 1)
323 {
324 currentMenu = 4;
325 selectedOption = 0;
326 }
327 else if(input == 2)
328 {
329 sceKernelExitGame();
330 }
331 }
332 break;
333 case 4:
334 case 1:
335 {
336 int maxOption = 0;
337 printf("PPSSPP Decrypted Save Directory : \n");
338 for(i = 0; menuList1[i]; i++)
339 {
340 if(i == selectedOption)
341 printf(" > %s\n",menuList1[i]);
342 else
343 printf(" %s\n",menuList1[i]);
344 maxOption++;
345 }
346
347 int input = ProcessInput(maxOption, &selectedOption);
348 if(input == maxOption-1)
349 {
350 if(currentMenu == 1)
351 selectedOption = 0;
352 else
353 selectedOption = 1;
354 currentMenu = 0;
355 }
356 else if(input >= 0)
357 {
358 basePath = selectedOption;
359 if(currentMenu == 1)
360 {
361 currentMenu = 2;
362 UpdateValidDir(1);
363 }
364 else
365 {
366 currentMenu = 5;
367 UpdateValidDir(0);
368 }
369 selectedOption = 0;
370 }
371 }
372 break;
373 case 5:
374 case 2:
375 {
376 int maxOption = 0;
377 if(currentMenu == 2)
378 printf("Save to encrypt : \n");
379 else
380 printf("Save to decrypt : \n");
381
382 if(numDirList == 0)
383 {
384 printf("No compatible data, see README for help on use\n");
385 }
386 for(i = 0; i < numDirList; i++)
387 {
388 if(i == selectedOption)
389 printf(" > %s\n",dirList[i].name);
390 else
391 printf(" %s\n",dirList[i].name);
392 maxOption++;
393 }
394
395 for(i = 0; menuList2[i]; i++)
396 {
397 if((i+numDirList) == selectedOption)
398 printf(" > %s\n",menuList2[i]);
399 else
400 printf(" %s\n",menuList2[i]);
401 maxOption++;
402 }
403
404 printf("\n Invalid path : \n");
405 for(i = 0; i < numInvalidDirList && i < (22-numDirList); i++)
406 {
407 switch(invalidDirList[i].errorId)
408 {
409 case 1:
410 printf(" %s : ENCRYPT_INFO.BIN not found\n",invalidDirList[i].name);
411 break;
412 case 2:
413 printf(" %s : ENCRYPT_INFO.BIN read error\n",invalidDirList[i].name);
414 break;
415 case 3:
416 printf(" %s : ENCRYPT_INFO.BIN wrong version\n",invalidDirList[i].name);
417 break;
418 case 4:
419 printf(" %s : PARAM.SFO not found\n",invalidDirList[i].name);
420 break;
421 case 5:
422 printf(" %s : PARAM.SFO read error\n",invalidDirList[i].name);
423 break;
424 case 6:
425 printf(" %s : SAVEDATA_FILE_LIST not found in PARAM.SFO\n",invalidDirList[i].name);
426 break;
427 case 7:
428 printf(" %s : no save name in SAVEDATA_FILE_LIST\n",invalidDirList[i].name);
429 break;
430 case 8:
431 printf(" %s : no save found\n",invalidDirList[i].name);
432 break;
433 default:
434 break;
435 }
436 }
437
438 int input = ProcessInput(maxOption, &selectedOption);
439 if(input == numDirList)
440 {
441 if(currentMenu == 2)
442 currentMenu = 1;
443 else
444 currentMenu = 4;
445 selectedOption = basePath;
446 }
447 else if(input >= 0)
448 {
449 if(currentMenu == 2)
450 currentMenu = 3;
451 else
452 currentMenu = 6;
453 workDir = input;
454 selectedOption = 0;
455 }
456 }
457 break;
458 case 6:
459 case 3:
460 {
461
462 EncryptFileInfo encryptInfo;
463 if(FileRead(menuList1[basePath], dirList[workDir].name, "ENCRYPT_INFO.BIN",(u8*)&encryptInfo,sizeof(encryptInfo)) < 0)
464 {
465 printf("Can't read encrypt file\n");
466 }
467 else
468 {
469 printf("Key : ");
470 for(i = 0; i < 16; i++)
471 printf(" %02x",(u8)encryptInfo.key[i]);
472 printf("\n");
473 printf("SDK Version : 0x%x\n",encryptInfo.sdkVersion);
474
475 char srcPath[128];
476 char dstPath[128];
477 if(currentMenu == 3)
478 {
479 sprintf(srcPath,"%s%s",menuList1[basePath], dirList[workDir].name);
480 sprintf(dstPath,"ms0:/PSP/SAVEDATA/%s",dirList[workDir].name);
481 sceIoMkdir(dstPath,0777);
482 }
483 else
484 {
485 sprintf(srcPath,"ms0:/PSP/SAVEDATA/%s",dirList[workDir].name);
486 sprintf(dstPath,"%s%s",menuList1[basePath], dirList[workDir].name);
487 }
488
489 int dfd;
490 dfd = sceIoDopen(srcPath);
491 if(dfd >= 0)
492 {
493 SceIoDirent dirinfo;
494 while(sceIoDread(dfd, &dirinfo) > 0)
495 {
496
497 if(!(dirinfo.d_stat.st_mode & 0x2000)) // is not a file
498 continue;
499
500 if(strcmp(dirinfo.d_name,"ENCRYPT_INFO.BIN") == 0) // don't copy encrypt info
501 continue;
502
503 FileCopy(srcPath, dstPath, dirinfo.d_name);
504
505 }
506 sceIoDclose(dfd);
507 }
508
509 if(currentMenu == 3)
510 {
511
512 char decryptedFile[258], encryptedFile[258], srcSFO[258], dstSFO[258];
513 sprintf(decryptedFile,"%s/%s",srcPath ,dirList[workDir].saveFile);
514 sprintf(srcSFO,"%s/PARAM.SFO",srcPath);
515
516 sprintf(encryptedFile,"%s/%s",dstPath ,dirList[workDir].saveFile);
517 sprintf(dstSFO,"%s/PARAM.SFO",dstPath);
518
519 printf("Encoding %s into %s\n",decryptedFile, encryptedFile);
520
521 int ret = encrypt_file(decryptedFile,
522 encryptedFile,
523 dirList[workDir].saveFile,
524 srcSFO,
525 dstSFO,
526 encryptInfo.key[0] != 0 ? encryptInfo.key : NULL,
527 GetSDKMainVersion(encryptInfo.sdkVersion)
528 );
529
530 if(ret < 0) {
531 printf("Error: encrypt_file() returned %d\n\n", ret);
532 } else {
533 printf("Successfully wrote %d bytes to\n", ret);
534 printf(" %s\n", encryptedFile);
535 printf("and updated hashes in\n");
536 printf(" %s\n\n", dstSFO);
537 }
538 }
539 else
540 {
541 char decryptedFile[258], encryptedFile[258];
542 sprintf(encryptedFile,"%s/%s",srcPath ,dirList[workDir].saveFile);
543 sprintf(decryptedFile,"%s/%s",dstPath ,dirList[workDir].saveFile);
544
545 printf("Decoding %s into %s\n",encryptedFile, decryptedFile);
546
547 int ret = decrypt_file(decryptedFile, encryptedFile, encryptInfo.key[0] != 0 ? encryptInfo.key : NULL, GetSDKMainVersion(encryptInfo.sdkVersion));
548
549 if(ret < 0) {
550 printf("Error: decrypt_file() returned %d\n\n", ret);
551 } else {
552 printf("Successfully wrote %d bytes to\n", ret);
553 printf(" %s\n", decryptedFile);
554 }
555 }
556 printf(" > Back\n");
557
558 int input = ProcessInput(1, &selectedOption);
559 if(input >= 0)
560 {
561 if(currentMenu == 3)
562 currentMenu = 2;
563 else
564 currentMenu = 5;
565 selectedOption = 0;
566 }
567 }
568 }
569 break;
570 default:
571 sceKernelExitGame();
572 break;
573 }
574
575 pspDebugScreenClear();
576 sceDisplayWaitVblankStart();
577 sceGuSwapBuffers();
578 }
579 return 0;
580 }
581