Merge pull request #275 from Xele02/master

Save Update
This commit is contained in:
Henrik Rydgård 2012-12-28 05:30:19 -08:00
commit 5d303f1577
21 changed files with 1863 additions and 58 deletions

View file

@ -47,8 +47,8 @@ int PSPSaveDialog::Init(int paramAddr)
u32 retval = param.SetPspParam(&request);
DEBUG_LOG(HLE,"sceUtilitySavedataInitStart(%08x)", paramAddr);
DEBUG_LOG(HLE,"Mode: %i", param.GetPspParam()->mode);
INFO_LOG(HLE,"sceUtilitySavedataInitStart(%08x)", paramAddr);
INFO_LOG(HLE,"Mode: %i", param.GetPspParam()->mode);
switch(param.GetPspParam()->mode)
{
@ -665,7 +665,7 @@ int PSPSaveDialog::Update()
param.GetPspParam()->result = SCE_UTILITY_SAVEDATA_ERROR_SIZES_NO_DATA;
}
status = SCE_UTILITY_STATUS_FINISHED;
// TODO: intentional missing break?
break;
case SCE_UTILITY_SAVEDATA_TYPE_LIST:
param.GetList(param.GetPspParam());
param.GetPspParam()->result = 0;

View file

@ -68,6 +68,13 @@ namespace
return result != 0;
}
struct EncryptFileInfo
{
int fileVersion;
u8 key[16];
int sdkVersion;
};
}
SavedataParam::SavedataParam()
@ -184,8 +191,20 @@ bool SavedataParam::Save(SceUtilitySavedataParam* param, int saveId)
sfoFile.SetValue("PARENTAL_LEVEL",param->sfoParam.parentalLevel,4);
sfoFile.SetValue("CATEGORY","MS",4);
sfoFile.SetValue("SAVEDATA_DIRECTORY",GetSaveDir(param,saveId),64);
sfoFile.SetValue("SAVEDATA_FILE_LIST","",3168); // This need to be filed with the save filename and a hash
sfoFile.SetValue("SAVEDATA_PARAMS","",128); // This need to be filled with a hash of the save file encrypted.
// For each file, 32 bytes for filename, 32 bytes for file hash (0 in PPSSPP)
u8* tmpData = new u8[3168];
memset(tmpData, 0, 3168);
sprintf((char*)tmpData,"%s",GetFileName(param).c_str());
sfoFile.SetValue("SAVEDATA_FILE_LIST", tmpData, 3168, 3168);
delete[] tmpData;
// No crypted save, so fill with 0
tmpData = new u8[128];
memset(tmpData, 0, 128);
sfoFile.SetValue("SAVEDATA_PARAMS", tmpData, 128, 128);
delete[] tmpData;
u8 *sfoData;
size_t sfoSize;
sfoFile.WriteSFO(&sfoData,&sfoSize);
@ -222,6 +241,21 @@ bool SavedataParam::Save(SceUtilitySavedataParam* param, int saveId)
std::string snd0path = dirPath+"/"+snd0Name;
WritePSPFile(snd0path, data_, param->snd0FileData.bufSize);
}
// Save Encryption Data
{
EncryptFileInfo encryptInfo;
int dataSize = sizeof(encryptInfo); // version + key + sdkVersion
memset(&encryptInfo,0,dataSize);
encryptInfo.fileVersion = 1;
encryptInfo.sdkVersion = sceKernelGetCompiledSdkVersion();
if(param->size > 1500)
memcpy(encryptInfo.key,param->key,16);
std::string encryptInfoPath = dirPath+"/"+"ENCRYPT_INFO.BIN";
WritePSPFile(encryptInfoPath, (u8*)&encryptInfo, dataSize);
}
}
return true;
}
@ -293,6 +327,8 @@ bool SavedataParam::GetSizes(SceUtilitySavedataParam *param)
return false;
}
bool ret = true;
if (Memory::IsValidAddress(param->msFree))
{
Memory::Write_U32((u32)MemoryStick_SectorSize(),param->msFree); // cluster Size
@ -317,12 +353,13 @@ bool SavedataParam::GetSizes(SceUtilitySavedataParam *param)
}
else
{
Memory::Write_U32(1,param->msData+36);
Memory::Write_U32(0x20,param->msData+40);
Memory::Write_U32(0,param->msData+36);
Memory::Write_U32(0,param->msData+40);
Memory::Write_U8(0,param->msData+44);
Memory::Write_U32(0x20,param->msData+52);
Memory::Write_U32(0,param->msData+52);
Memory::Write_U8(0,param->msData+56);
//return false;
ret = false;
// this should return SCE_UTILITY_SAVEDATA_ERROR_SIZES_NO_DATA
}
}
if (Memory::IsValidAddress(param->utilityData))
@ -345,7 +382,7 @@ bool SavedataParam::GetSizes(SceUtilitySavedataParam *param)
Memory::Memset(param->utilityData+20,0,spaceTxt.size()+1);
Memory::Memcpy(param->utilityData+20,spaceTxt.c_str(),spaceTxt.size()); // save size in text
}
return true;
return ret;
}

View file

@ -46,23 +46,18 @@ void ParamSFOData::SetValue(std::string key, unsigned int value, int max_size)
}
void ParamSFOData::SetValue(std::string key, std::string value, int max_size)
{
if(key == "ACCOUNT_ID" ||
key == "PADDING" ||
key == "PARAMS" ||
key == "PARAMS2" ||
key == "SAVEDATA_FILE_LIST" ||
key == "SAVEDATA_PARAMS")
{
values[key].type = VT_UTF8_SPE;
}
else
{
values[key].type = VT_UTF8;
}
values[key].type = VT_UTF8;
values[key].s_value = value;
values[key].max_size = max_size;
}
void ParamSFOData::SetValue(std::string key, const u8* value, unsigned int size, int max_size)
{
values[key].type = VT_UTF8_SPE;
values[key].SetData(value,size);
values[key].max_size = max_size;
}
int ParamSFOData::GetValueInt(std::string key)
{
std::map<std::string,ValueData>::iterator it = values.find(key);
@ -73,10 +68,21 @@ int ParamSFOData::GetValueInt(std::string key)
std::string ParamSFOData::GetValueString(std::string key)
{
std::map<std::string,ValueData>::iterator it = values.find(key);
if(it == values.end() || (it->second.type != VT_UTF8 && it->second.type != VT_UTF8_SPE))
if(it == values.end() || (it->second.type != VT_UTF8))
return "";
return it->second.s_value;
}
u8* ParamSFOData::GetValueData(std::string key, unsigned int *size)
{
std::map<std::string,ValueData>::iterator it = values.find(key);
if(it == values.end() || (it->second.type != VT_UTF8_SPE))
return 0;
if(size)
{
*size = it->second.u_size;
}
return it->second.u_value;
}
// I'm so sorry Ced but this is highly endian unsafe :(
bool ParamSFOData::ReadSFO(const u8 *paramsfo, size_t size)
@ -108,9 +114,9 @@ bool ParamSFOData::ReadSFO(const u8 *paramsfo, size_t size)
case 0x0004:
// Special format UTF-8
{
const char *utfdata = (const char *)(data_start + indexTables[i].data_table_offset);
const u8 *utfdata = (const u8 *)(data_start + indexTables[i].data_table_offset);
DEBUG_LOG(LOADER, "%s %s", key, utfdata);
SetValue(key,std::string(utfdata,indexTables[i].param_len),indexTables[i].param_max_len);
SetValue(key, utfdata, indexTables[i].param_len, indexTables[i].param_max_len);
}
break;
case 0x0204:
@ -187,10 +193,10 @@ bool ParamSFOData::WriteSFO(u8 **paramsfo, size_t *size)
else if(it->second.type == VT_UTF8_SPE)
{
index_ptr->param_fmt = 0x0004;
index_ptr->param_len = it->second.s_value.size()+1;
index_ptr->param_len = it->second.u_size;
memcpy(data_ptr,it->second.s_value.c_str(),index_ptr->param_len);
data_ptr[index_ptr->param_len] = 0;
memset(data_ptr,0,index_ptr->param_max_len);
memcpy(data_ptr,it->second.u_value,index_ptr->param_len);
}
else if(it->second.type == VT_UTF8)
{

View file

@ -25,9 +25,11 @@ class ParamSFOData
public:
void SetValue(std::string key, unsigned int value, int max_size);
void SetValue(std::string key, std::string value, int max_size);
void SetValue(std::string key, const u8* value, unsigned int size, int max_size);
int GetValueInt(std::string key);
std::string GetValueString(std::string key);
u8* GetValueData(std::string key, unsigned int *size);
bool ReadSFO(const u8 *paramsfo, size_t size);
bool WriteSFO(u8 **paramsfo, size_t *size);
@ -37,14 +39,48 @@ private:
{
VT_INT,
VT_UTF8,
VT_UTF8_SPE
VT_UTF8_SPE // raw data in u8
};
struct ValueData
class ValueData
{
public:
ValueType type;
int max_size;
std::string s_value;
int i_value;
u8* u_value;
unsigned int u_size;
void SetData(const u8* data, int size)
{
if(u_value)
{
delete[] u_value;
u_value = 0;
}
if(size > 0)
{
u_value = new u8[size];
memcpy(u_value,data,size);
}
u_size = size;
}
ValueData()
{
u_value = 0;
u_size = 0;
type = VT_INT;
max_size = 0;
i_value = 0;
}
~ValueData()
{
if(u_value)
delete[] u_value;
}
};
std::map<std::string,ValueData> values;

View file

@ -32,6 +32,12 @@ BlockAllocator kernelMemory(256);
// STATE END
//////////////////////////////////////////////////////////////////////////
#define SCE_KERNEL_HASCOMPILEDSDKVERSION 0x1000
#define SCE_KERNEL_HASCOMPILERVERSION 0x2000
int flags_ = 0;
int sdkVersion_;
int compilerVersion_;
struct NativeFPL
{
@ -439,6 +445,154 @@ void sceKernelPrintf()
RETURN(0);
}
void sceKernelSetCompiledSdkVersion(int sdkVersion)
{
int sdkMainVersion = sdkVersion & 0xFFFF0000;
bool valiSDK = false;
switch(sdkMainVersion)
{
case 0x1000000:
case 0x1050000:
case 0x2000000:
case 0x2050000:
case 0x2060000:
case 0x2070000:
case 0x2080000:
case 0x3000000:
case 0x3010000:
case 0x3030000:
case 0x3040000:
case 0x3050000:
case 0x3060000:
valiSDK = true;
break;
default:
valiSDK = false;
break;
}
if(valiSDK)
{
sdkVersion_ = sdkVersion;
flags_ |= SCE_KERNEL_HASCOMPILEDSDKVERSION;
}
else
{
ERROR_LOG(HLE,"sceKernelSetCompiledSdkVersion unknown SDK : %x\n",sdkVersion);
}
return;
}
void sceKernelSetCompiledSdkVersion370(int sdkVersion)
{
int sdkMainVersion = sdkVersion & 0xFFFF0000;
if(sdkMainVersion == 0x3070000)
{
sdkVersion_ = sdkVersion;
flags_ |= SCE_KERNEL_HASCOMPILEDSDKVERSION;
}
else
{
ERROR_LOG(HLE,"sceKernelSetCompiledSdkVersion370 unknown SDK : %x\n",sdkVersion);
}
return;
}
void sceKernelSetCompiledSdkVersion380_390(int sdkVersion)
{
int sdkMainVersion = sdkVersion & 0xFFFF0000;
if(sdkMainVersion == 0x3080000 || sdkMainVersion == 0x3090000)
{
sdkVersion_ = sdkVersion;
flags_ |= SCE_KERNEL_HASCOMPILEDSDKVERSION;
}
else
{
ERROR_LOG(HLE,"sceKernelSetCompiledSdkVersion380_390 unknown SDK : %x\n",sdkVersion);
}
return;
}
void sceKernelSetCompiledSdkVersion395(int sdkVersion)
{
int sdkMainVersion = sdkVersion & 0xFFFFFF00;
if(sdkMainVersion == 0x4000000
|| sdkMainVersion == 0x4000100
|| sdkMainVersion == 0x4000500
|| sdkMainVersion == 0x3090500
|| sdkMainVersion == 0x3090600)
{
sdkVersion_ = sdkVersion;
flags_ |= SCE_KERNEL_HASCOMPILEDSDKVERSION;
}
else
{
ERROR_LOG(HLE,"sceKernelSetCompiledSdkVersion395 unknown SDK : %x\n",sdkVersion);
}
return;
}
void sceKernelSetCompiledSdkVersion600_602(int sdkVersion)
{
int sdkMainVersion = sdkVersion & 0xFFFF0000;
if(sdkMainVersion == 0x6010000
|| sdkMainVersion == 0x6000000
|| sdkMainVersion == 0x6020000)
{
sdkVersion_ = sdkVersion;
flags_ |= SCE_KERNEL_HASCOMPILEDSDKVERSION;
}
else
{
ERROR_LOG(HLE,"sceKernelSetCompiledSdkVersion600_602 unknown SDK : %x\n",sdkVersion);
}
return;
}
void sceKernelSetCompiledSdkVersion603_605(int sdkVersion)
{
int sdkMainVersion = sdkVersion & 0xFFFF0000;
if(sdkMainVersion == 0x6040000
|| sdkMainVersion == 0x6030000
|| sdkMainVersion == 0x6050000)
{
sdkVersion_ = sdkVersion;
flags_ |= SCE_KERNEL_HASCOMPILEDSDKVERSION;
}
else
{
ERROR_LOG(HLE,"sceKernelSetCompiledSdkVersion603_605 unknown SDK : %x\n",sdkVersion);
}
return;
}
void sceKernelSetCompiledSdkVersion606(int sdkVersion)
{
int sdkMainVersion = sdkVersion & 0xFFFF0000;
if(sdkMainVersion == 0x6060000)
{
sdkVersion_ = sdkVersion;
flags_ |= SCE_KERNEL_HASCOMPILEDSDKVERSION;
}
else
{
ERROR_LOG(HLE,"sceKernelSetCompiledSdkVersion606 unknown SDK : %x\n",sdkVersion);
}
return;
}
int sceKernelGetCompiledSdkVersion()
{
if(!(flags_ & SCE_KERNEL_HASCOMPILEDSDKVERSION))
return 0;
return sdkVersion_;
}
void sceKernelSetCompilerVersion(int version)
{
compilerVersion_ = version;
flags_ |= SCE_KERNEL_HASCOMPILERVERSION;
}
// VPL = variable length memory pool
@ -657,23 +811,6 @@ u32 GetMemoryBlockPtr(u32 uid, u32 addr) {
return 0;
}
u32 sceKernelSetCompiledSdkVersion(u32 param) {
// pretty sure this only takes one arg
ERROR_LOG(HLE,"UNIMPL sceKernelSetCompiledSdkVersion(%08x)", param);
return 0;
}
u32 sceKernelSetCompiledSdkVersion395(u32 param) {
// pretty sure this only takes one arg
ERROR_LOG(HLE,"UNIMPL sceKernelSetCompiledSdkVersion395(%08x)", param);
return 0;
}
u32 sceKernelSetCompilerVersion(u32 a, u32 b, u32 c, u32 d) {
ERROR_LOG(HLE,"UNIMPL sceKernelSetCompilerVersion(%08x, %08x, %08x, %08x)", a, b, c, d);
return 0;
}
const HLEFunction SysMemUserForUser[] = {
{0xA291F107,sceKernelMaxFreeMemSize, "sceKernelMaxFreeMemSize"},
{0xF919F628,sceKernelTotalFreeMemSize,"sceKernelTotalFreeMemSize"},
@ -682,16 +819,15 @@ const HLEFunction SysMemUserForUser[] = {
{0xB6D61D02,sceKernelFreePartitionMemory,"sceKernelFreePartitionMemory"}, //(void *ptr) ?
{0x9D9A5BA1,sceKernelGetBlockHeadAddr,"sceKernelGetBlockHeadAddr"}, //(void *ptr) ?
{0x13a5abef,sceKernelPrintf,"sceKernelPrintf 0x13a5abef"},
{0xf77d77cb,WrapU_UUUU<sceKernelSetCompilerVersion>,"sceKernelSetCompilerVersion"},
{0x7591c7db,WrapU_U<sceKernelSetCompiledSdkVersion>,"sceKernelSetCompiledSdkVersion"},
{0x342061E5,0,"sceKernelSetCompiledSdkVersion370"},
{0x315AD3A0,0,"sceKernelSetCompiledSdkVersion380_390"},
{0xEBD5C3E6,WrapU_U<sceKernelSetCompiledSdkVersion395>,"sceKernelSetCompiledSdkVersion395"},
{0x91DE343C,0,"sceKernelSetCompiledSdkVersion_500_505"},
{0x35669d4c,0,"sceKernelSetCompiledSdkVersion600_602"}, //??
{0x1b4217bc,0,"sceKernelSetCompiledSdkVersion603_605"},
{0x358ca1bb,0,"sceKernelSetCompiledSdkVersion606"},
{0x7591c7db,&WrapV_I<sceKernelSetCompiledSdkVersion>,"sceKernelSetCompiledSdkVersion"},
{0x342061E5,&WrapV_I<sceKernelSetCompiledSdkVersion370>,"sceKernelSetCompiledSdkVersion370"},
{0x315AD3A0,&WrapV_I<sceKernelSetCompiledSdkVersion380_390>,"sceKernelSetCompiledSdkVersion380_390"},
{0xEBD5C3E6,&WrapV_I<sceKernelSetCompiledSdkVersion395>,"sceKernelSetCompiledSdkVersion395"},
{0xf77d77cb,&WrapV_I<sceKernelSetCompilerVersion>,"sceKernelSetCompilerVersion"},
{0x35669d4c,&WrapV_I<sceKernelSetCompiledSdkVersion600_602>,"sceKernelSetCompiledSdkVersion600_602"}, //??
{0x1b4217bc,&WrapV_I<sceKernelSetCompiledSdkVersion603_605>,"sceKernelSetCompiledSdkVersion603_605"},
{0x358ca1bb,&WrapV_I<sceKernelSetCompiledSdkVersion606>,"sceKernelSetCompiledSdkVersion606"},
{0xfc114573,&WrapI_V<sceKernelGetCompiledSdkVersion>,"sceKernelGetCompiledSdkVersion"},
// Obscure raw block API
{0xDB83A952,WrapU_UU<GetMemoryBlockPtr>,"SysMemUserForUser_DB83A952"}, // GetMemoryBlockAddr
{0x50F61D8A,WrapU_U<FreeMemoryBlock>,"SysMemUserForUser_50F61D8A"}, // FreeMemoryBlock

View file

@ -49,5 +49,6 @@ void sceKernelFreeFpl();
void sceKernelCancelFpl();
void sceKernelReferFplStatus();
int sceKernelGetCompiledSdkVersion();
void Register_SysMemUserForUser();

44
Tools/SaveTool/Makefile Normal file
View file

@ -0,0 +1,44 @@
SUBDIRS = kernelcall
release:
@for i in $(SUBDIRS); do echo "make all in $$i..."; (cd $$i; $(MAKE) release; cp $$i.prx ..); done
make all
allclean:
make clean
@for i in $(SUBDIRS); do echo "Clearing in $$i..."; (cd $$i; $(MAKE) clean; rm -rf $$i.prx); done
TARGET = ppssppsavetool
OBJS = main.o decrypt.o encrypt.o hash.o psf.o $(KERNELCALL_OBJS)
BUILD_PRX=1
EXTRA_TARGETS = EBOOT.PBP
PSP_EBOOT_TITLE = PPSSPP Save Tool
PSP_FW_VERSION=350
INCDIR =
CFLAGS = -O0 -G0 -Wall -g
CXXFLAGS = $(CFLAGS) -fno-exceptions -fno-rtti
ASFLAGS = $(CFLAGS)
KERNELCALL_OBJS = kernelcall_0000.o \
kernelcall_0001.o \
kernelcall_0002.o \
kernelcall_0003.o \
kernelcall_0004.o \
kernelcall_0005.o \
kernelcall_0006.o \
kernelcall_0007.o
$(KERNELCALL_OBJS): kernelcall/kernelcall.S
psp-gcc $(CFLAGS) -DF_$* $< -c -o $@
LIBDIR =
LDFLAGS =
LIBS = -lpsputility -lpspgum -lpspgu -lm
PSPSDK=$(shell psp-config --pspsdk-path)
include $(PSPSDK)/lib/build.mak

77
Tools/SaveTool/README Normal file
View file

@ -0,0 +1,77 @@
PSP Tool for encoding save data from PPSSPP to read on PSP and decoding
PSP save to read on PPSSPP.
Alpha version. Was only tested on Project Dive Extend.
Build
=====
Require PSP Toolchain with PSP SDK
make release
This will build ppssppsavetool.prx and kernelcall.prx.
clean : make allclean
How to use
==========
Require PSP Toolchain with PRX Link and usb link, pspsh to work. Seems
there is limitation for directories listing when running directly the
tool from the PSP.
A) PREPARING DATA
=================
1) Play the game on PPSSPP until a game save is done. This will create
the file "ENCRYPT_INFO.BIN" in the save directory. It contain the
encoding key and sdk version of the game. This file is the same for all
save of the game, so you can use it on different save folder without
the need to make them all on PPSSPP.
2) Run usbhostfs_pc. Then mount .ppsspp/PSP/SAVEDATA directory :
mount 1 <path to .ppsspp/PSP/SAVEDATA>
If you enter "drives", you should see host1: mapped to the directory.
3) Run PRX Link on the psp, and pspsh on the PC.
B) ENCODING A SAVE FROM PPSSPP TO PSP
=====================================
1) From pspsh, run ppssppsavetool.prx.
2) In the menu, select "Encrypt", "host1:/". This will list the
directories in ppsspp save directory which can be encoded.
For a directory to appear, it must contain the ENCRYPT_INFO.BIN file,
and the files of a ppsspp save.
3) After selecting the directory to encode, it will be copied into
the PSP/SAVEGAME directory and encoded. Now you can play the save on
the PSP.
C) DECODING A SAVE FROM PSP TO PPSSPP
=====================================
1) You should have a directory in the PPSSPP save directory with the
same name that the PSP save you want to convert. And in it, the
"ENCRYPT_INFO.BIN" file.
Ex : You want to decrypt the save in ms0:/PSP/SAVEDATA/XXXXYYY/
You create .ppsspp/PSP/SAVEDATA/XXXXYYY/ if not existing, and put the
"ENCRYPT_INFO.BIN" generated before in it.
2) From pspsh, run ppssppsavetool.prx.
3) In the menu, select "decrypt", "host1:/". You should see your
directory in the list.
4) After selecting it, the game decode the save and save it into the
PPSSPP save directory. You can now launch your game in PPSSPP and load
the save.

164
Tools/SaveTool/decrypt.c Normal file
View file

@ -0,0 +1,164 @@
/*
* PSP Software Development Kit - http://www.pspdev.org
* -----------------------------------------------------------------------
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
*
* decrypt.c - Decryption routines using sceChnnlsv
*
* Copyright (c) 2005 Jim Paris <jim@jtan.com>
* Coypright (c) 2005 psp123
*
* $Id: decrypt.c 1562 2005-12-10 20:52:45Z jim $
*/
#include "decrypt.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <pspchnnlsv.h>
#include "kernelcall/kernelcall.h"
unsigned int align16(unsigned int v)
{
return ((v + 0xF) >> 4) << 4;
}
/* Read, decrypt, and write a savedata file. See main.c for example usage. */
int decrypt_file(const char *decrypted_filename,
const char *encrypted_filename,
const unsigned char *gamekey,
const int mainSdkVersion)
{
FILE *in, *out;
int len, aligned_len;
unsigned char *data, *cryptkey;
int retval;
/* Open file and get size */
if ((in = fopen(encrypted_filename, "r")) == NULL) {
retval = -1;
goto out;
}
fseek(in, 0, SEEK_END);
len = ftell(in);
fseek(in, 0, SEEK_SET);
if (len <= 0) {
retval = -2;
goto out1;
}
/* Allocate buffers */
aligned_len = align16(len);
if ((data = (unsigned char *) memalign(0x10, aligned_len)) == NULL) {
retval = -3;
goto out1;
}
if ((cryptkey = (unsigned char *) memalign(0x10, 0x10)) == NULL) {
retval = -4;
goto out2;
}
/* Fill buffers */
if (gamekey != NULL)
memcpy(cryptkey, gamekey, 0x10);
memset(data + len, 0, aligned_len - len);
if (fread(data, 1, len, in) != len) {
retval = -5;
goto out3;
}
/* Do the decryption */
if ((retval = decrypt_data( gamekey ? (mainSdkVersion >= 4 ? 5 : 3) : 1, // 5 for sdk >= 4, else 3
data, &len, &aligned_len,
gamekey ? cryptkey : NULL)) < 0) {
retval -= 100;
goto out3;
}
/* Write the data out. decrypt_data has set len correctly. */
if ((out = fopen(decrypted_filename, "w")) == NULL) {
retval = -6;
goto out3;
}
if (fwrite(data, 1, len, out) != len) {
retval = -7;
goto out4;
}
/* All done. Return file length. */
retval = len;
out4:
fclose(out);
out3:
free(cryptkey);
out2:
free(data);
out1:
fclose(in);
out:
return retval;
}
/* Do the actual hardware decryption.
mode is 3 for saves with a cryptkey, or 1 otherwise
data, dataLen, and cryptkey must be multiples of 0x10.
cryptkey is NULL if mode == 1.
*/
int decrypt_data(unsigned int mode,
unsigned char *data,
int *dataLen,
int *alignedLen,
unsigned char *cryptkey)
{
pspChnnlsvContext1 ctx1;
pspChnnlsvContext2 ctx2;
/* Need a 16-byte IV plus some data */
if (*alignedLen <= 0x10)
return -1;
*dataLen -= 0x10;
*alignedLen -= 0x10;
/* Set up buffers */
memset(&ctx1, 0, sizeof(pspChnnlsvContext1));
memset(&ctx2, 0, sizeof(pspChnnlsvContext2));
/* Perform the magic */
if (sceChnnlsv_E7833020_(&ctx1, mode) < 0)
return -2;
if (sceChnnlsv_ABFDFC8B_(&ctx2, mode, 2, data, cryptkey) < 0)
return -3;
if (sceChnnlsv_F21A1FCA_(&ctx1, data, 0x10) < 0)
return -4;
if (sceChnnlsv_F21A1FCA_(&ctx1, data + 0x10, *alignedLen) < 0)
return -5;
if (sceChnnlsv_850A7FA1_(&ctx2, data + 0x10, *alignedLen) < 0)
return -6;
/* Verify that it decrypted correctly */
if (sceChnnlsv_21BE78B4_(&ctx2) < 0)
return -7;
/* If desired, a new file hash from this PSP can be computed now:
if (sceChnnlsv_C4C494F8(ctx1, newhash, cryptkey) < 0)
return -8;
*/
/* The decrypted data starts at data + 0x10, so shift it back. */
memmove(data, data + 0x10, *dataLen);
/* All done */
return 0;
}

31
Tools/SaveTool/decrypt.h Normal file
View file

@ -0,0 +1,31 @@
/*
* PSP Software Development Kit - http://www.pspdev.org
* -----------------------------------------------------------------------
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
*
* decrypt.h - Declarations for functions in decrypt.c
*
* Copyright (c) 2005 Jim Paris <jim@jtan.com>
* Coypright (c) 2005 psp123
*
* $Id: decrypt.h 1562 2005-12-10 20:52:45Z jim $
*/
#include <pspchnnlsv.h>
/* Detect the samegame format and decrypt it. See main.c for an example. */
int decrypt_file(const char *decrypted_filename,
const char *encrypted_filename,
const unsigned char *gamekey,
const int mainSdkVersion);
/* Do the actual hardware decryption.
mode is 3 for saves with a cryptkey, or 1 otherwise.
data, alignedLen, and cryptkey must be multiples of 0x10.
cryptkey is NULL if mode == 1.
*/
int decrypt_data(unsigned int mode,
unsigned char *data,
int *dataLen,
int *alignedLen,
unsigned char *cryptkey);

233
Tools/SaveTool/encrypt.c Normal file
View file

@ -0,0 +1,233 @@
/*
* PSP Software Development Kit - http://www.pspdev.org
* -----------------------------------------------------------------------
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
*
* encrypt.c - Encryption routines using sceChnnlsv
*
* Copyright (c) 2005 Jim Paris <jim@jtan.com>
* Coypright (c) 2005 psp123
*
* $Id: encrypt.c 1560 2005-12-10 01:16:32Z jim $
*/
#include "encrypt.h"
#include "hash.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <pspchnnlsv.h>
#include "kernelcall/kernelcall.h"
static inline int align16(unsigned int v)
{
return ((v + 0xF) >> 4) << 4;
}
int fopen_getsize(const char *filename, FILE **fd, int *size)
{
if ((*fd = fopen(filename, "r")) == NULL)
return -1;
fseek(*fd, 0, SEEK_END);
*size = ftell(*fd);
fseek(*fd, 0, SEEK_SET);
if (*size <= 0) {
fclose(*fd);
return -2;
}
return 0;
}
/* Encrypt the given plaintext file, and update the message
authentication hashes in the param.sfo. The data_filename is
usually the final component of encrypted_filename, e.g. "DATA.BIN".
See main.c for an example of usage. */
int encrypt_file(const char *plaintext_filename,
const char *encrypted_filename,
const char *data_filename,
const char *paramsfo_filename,
const char *paramsfo_filename_out,
const unsigned char *gamekey,
const int mainSdkVersion)
{
FILE *in = NULL, *out = NULL, *sfo = NULL;
unsigned char *data = NULL, *cryptkey = NULL, *hash = NULL;
unsigned char paramsfo[0x1330];
int len, aligned_len, tmp;
int retval;
/* Open plaintext and param.sfo files and get size */
if (fopen_getsize(plaintext_filename, &in, &len) < 0) {
retval = -1;
goto out;
}
if (fopen_getsize(paramsfo_filename, &sfo, &tmp) < 0) {
retval = -2;
goto out;
}
/* Verify size of param.sfo; all known saves use this size */
if (tmp != 0x1330) {
retval = -3;
goto out;
}
/* Allocate buffers. data has 0x10 bytes extra for the IV. */
aligned_len = align16(len);
if ((data =
(unsigned char *) memalign(0x10, aligned_len + 0x10)) == NULL) {
retval = -4;
goto out;
}
if ((cryptkey = (unsigned char *) memalign(0x10, 0x10)) == NULL) {
retval = -5;
goto out;
}
if ((hash = (unsigned char *) memalign(0x10, 0x10)) == NULL) {
retval = -6;
goto out;
}
/* Fill buffers. */
memset(data + len, 0, aligned_len - len);
if (fread(data, 1, len, in) != len) {
retval = -7;
goto out;
}
if (fread(paramsfo, 1, 0x1330, sfo) != 0x1330) {
retval = -8;
goto out;
}
if (gamekey != NULL)
memcpy(cryptkey, gamekey, 0x10);
/* Do the encryption */
if ((retval = encrypt_data( gamekey ? (mainSdkVersion >= 4 ? 5 : 3) : 1, // 5 for sdk >= 4, 3 otherwise
data,
&len, &aligned_len,
hash,
gamekey ? cryptkey : NULL)) < 0) {
retval -= 1000;
goto out;
}
/* Update the param.sfo hashes */
if ((retval = update_hashes(paramsfo, 0x1330,
data_filename, hash,
gamekey ? 3 : 1)) < 0) {
retval -= 2000;
goto out;
}
/* Write the data to the file. encrypt_data has already set len. */
if ((out = fopen(encrypted_filename, "w")) == NULL) {
retval = -9;
goto out;
}
if (fwrite(data, 1, len, out) != len) {
retval = -10;
goto out;
}
/* Reopen param.sfo, and write the updated copy out. */
fclose(sfo);
if ((sfo = fopen(paramsfo_filename_out, "w")) == NULL) {
retval = -11;
goto out;
}
if (fwrite(paramsfo, 1, 0x1330, sfo) != 0x1330) {
retval = -12;
goto out;
}
/* All done. Return file length. */
retval = len;
out:
if(out) fclose(out);
if(hash) free(hash);
if(cryptkey) free(cryptkey);
if(data) free(data);
if(sfo) fclose(sfo);
if(in) fclose(in);
return retval;
}
/* Do the actual hardware encryption.
mode is 3 for saves with a cryptkey, or 1 otherwise
data, dataLen, and cryptkey must be multiples of 0x10.
cryptkey is NULL if mode == 1.
*/
int encrypt_data(unsigned int mode,
unsigned char *data,
int *dataLen,
int *alignedLen,
unsigned char *hash,
unsigned char *cryptkey)
{
pspChnnlsvContext1 ctx1;
pspChnnlsvContext2 ctx2;
/* Make room for the IV in front of the data. */
memmove(data + 0x10, data, *alignedLen);
/* Set up buffers */
memset(&ctx1, 0, sizeof(pspChnnlsvContext1));
memset(&ctx2, 0, sizeof(pspChnnlsvContext2));
memset(hash, 0, 0x10);
memset(data, 0, 0x10);
/* Build the 0x10-byte IV and setup encryption */
if (sceChnnlsv_ABFDFC8B_(&ctx2, mode, 1, data, cryptkey) < 0)
return -1;
if (sceChnnlsv_E7833020_(&ctx1, mode) < 0)
return -2;
if (sceChnnlsv_F21A1FCA_(&ctx1, data, 0x10) < 0)
return -3;
if (sceChnnlsv_850A7FA1_(&ctx2, data + 0x10, *alignedLen) < 0)
return -4;
/* Clear any extra bytes left from the previous steps */
memset(data + 0x10 + *dataLen, 0, *alignedLen - *dataLen);
/* Encrypt the data */
if (sceChnnlsv_F21A1FCA_(&ctx1, data + 0x10, *alignedLen) < 0)
return -5;
/* Verify encryption */
if (sceChnnlsv_21BE78B4_(&ctx2) < 0)
return -6;
/* Build the file hash from this PSP */
if (sceChnnlsv_C4C494F8_(&ctx1, hash, cryptkey) < 0)
return -7;
/* Adjust sizes to account for IV */
*alignedLen += 0x10;
*dataLen += 0x10;
/* All done */
return 0;
}

38
Tools/SaveTool/encrypt.h Normal file
View file

@ -0,0 +1,38 @@
/*
* PSP Software Development Kit - http://www.pspdev.org
* -----------------------------------------------------------------------
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
*
* encrypt.h - Declarations for functions in encrypt.c
*
* Copyright (c) 2005 Jim Paris <jim@jtan.com>
* Coypright (c) 2005 psp123
*
* $Id: encrypt.h 1559 2005-12-10 01:10:11Z jim $
*/
#include <pspchnnlsv.h>
/* Encrypt the given plaintext file, and update the message
authentication hashes in the param.sfo. The data_filename is
usually the final component of encrypted_filename, e.g. "DATA.BIN".
See main.c for an example of usage. */
int encrypt_file(const char *plaintext_filename,
const char *encrypted_filename,
const char *data_filename,
const char *paramsfo_filename,
const char *paramsfo_filename_out,
const unsigned char *gamekey,
const int mainSdkVersion);
/* Do the actual hardware encryption.
mode is 3 for saves with a cryptkey, or 1 otherwise.
data, alignedLen, cryptkey, and hash must be multiples of 0x10.
cryptkey is NULL if mode == 1.
*/
int encrypt_data(unsigned int mode,
unsigned char *data,
int *dataLen,
int *alignedLen,
unsigned char *hash,
unsigned char *cryptkey);

129
Tools/SaveTool/hash.c Normal file
View file

@ -0,0 +1,129 @@
/*
* PSP Software Development Kit - http://www.pspdev.org
* -----------------------------------------------------------------------
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
*
* hash.c - Hashing routines using sceChnnlsv
*
* Copyright (c) 2005 Jim Paris <jim@jtan.com>
* Coypright (c) 2005 psp123
*
* $Id: hash.c 1560 2005-12-10 01:16:32Z jim $
*/
#include "hash.h"
#include "psf.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <pspchnnlsv.h>
#include "kernelcall/kernelcall.h"
static inline int align16(unsigned int v)
{
return ((v + 0xF) >> 4) << 4;
}
/* Update the hashes in the param.sfo data, using
the given file hash, and by computing the param.sfo hashes.
filehash must be a multiple of 16 bytes, and is reused to
store other hashes. The filename is e.g. "DATA.BIN". */
int update_hashes(unsigned char *data,
int len,
const char *filename,
unsigned char *filehash,
int encryptmode)
{
int alignedLen = align16(len);
unsigned char *datafile, *savedata_params;
int listLen, paramsLen;
int ret;
/* Locate SAVEDATA_PARAM section in the param.sfo. */
if ((ret = find_psf_section("SAVEDATA_PARAMS", data, 0x1330,
&savedata_params, &paramsLen)) < 0) {
return ret - 100;
}
/* Locate the pointer for this DATA.BIN equivalent */
if ((ret = find_psf_section("SAVEDATA_FILE_LIST", data, 0x1330,
&datafile, &listLen)) < 0) {
return ret - 200;
}
if ((ret = find_psf_datafile(filename, datafile,
listLen, &datafile)) < 0) {
return ret - 300;
}
/* Check minimum sizes based on where we want to write */
if ((listLen < 0x20) || (paramsLen < 0x80)) {
return -1;
}
/* Clear params and insert file hash */
memset(savedata_params, 0, paramsLen);
memcpy(datafile + 0x0D, filehash, 0x10);
/* Compute 11D0 hash over entire file */
if ((ret = build_hash(filehash, data, len, alignedLen,
(encryptmode & 2) ? 4 : 2, NULL)) < 0) { // Not sure about "2"
return ret - 400;
}
/* Copy 11D0 hash to param.sfo and set flag indicating it's there */
memcpy(savedata_params + 0x20, filehash, 0x10);
*savedata_params |= 0x01;
/* If new encryption mode, compute and insert the 1220 hash. */
if (encryptmode & 2) {
/* Enable the hash bit first */
*savedata_params |= 0x20;
if ((ret = build_hash(filehash, data, len, alignedLen,
3, 0)) < 0) {
return ret - 500;
}
memcpy(savedata_params + 0x70, filehash, 0x10);
}
/* Compute and insert the 11C0 hash. */
if ((ret = build_hash(filehash, data, len, alignedLen, 1, 0)) < 0) {
return ret - 600;
}
memcpy(savedata_params + 0x10, filehash, 0x10);
/* All done. */
return 0;
}
/* Build a single hash using the given data and mode.
data and alignedLen must be multiples of 0x10.
cryptkey is NULL for savedata. */
int build_hash(unsigned char *output,
unsigned char *data,
unsigned int len,
unsigned int alignedLen,
int mode,
unsigned char *cryptkey)
{
pspChnnlsvContext1 ctx1;
/* Set up buffers */
memset(&ctx1, 0, sizeof(pspChnnlsvContext1));
memset(output, 0, 0x10);
memset(data + len, 0, alignedLen - len);
/* Perform the magic */
if (sceChnnlsv_E7833020_(&ctx1, mode & 0xFF) < 0)
return -1;
if (sceChnnlsv_F21A1FCA_(&ctx1, data, alignedLen) < 0)
return -2;
if (sceChnnlsv_C4C494F8_(&ctx1, output, cryptkey) < 0)
return -3;
/* All done. */
return 0;
}

34
Tools/SaveTool/hash.h Normal file
View file

@ -0,0 +1,34 @@
/*
* PSP Software Development Kit - http://www.pspdev.org
* -----------------------------------------------------------------------
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
*
* hash.h - Declarations for functions in hash.c
*
* Copyright (c) 2005 Jim Paris <jim@jtan.com>
* Coypright (c) 2005 psp123
*
* $Id: hash.h 1559 2005-12-10 01:10:11Z jim $
*/
#include <pspchnnlsv.h>
/* Update the hashes in the param.sfo data, using
the given file hash, and by computing the param.sfo hashes.
filehash must be a multiple of 16 bytes, and is reused to
store other hashes. The filename is e.g. "DATA.BIN". */
int update_hashes(unsigned char *data,
int len,
const char *filename,
unsigned char *filehash,
int encryptmode);
/* Build a single hash using the given data and mode.
data, and alignedLen must be multiples of 0x10.
cryptkey is NULL for savedata.*/
int build_hash(unsigned char *output,
unsigned char *data,
unsigned int len,
unsigned int alignedLen,
int mode,
unsigned char *cryptkey);

Binary file not shown.

View file

@ -0,0 +1,24 @@
release: all
psp-build-exports -k exports.exp
psp-build-exports -s -k -v exports.exp
TARGET = kernelcall
OBJS = kernelcall.o
BUILD_PRX=1
PRX_EXPORTS=exports.exp
USE_KERNEL_LIBS = 1
USE_KERNEL_LIBC = 1
INCDIR =
CFLAGS = -O0 -G0 -Wall -g
CXXFLAGS = $(CFLAGS) -fno-exceptions -fno-rtti
ASFLAGS = $(CFLAGS)
LIBDIR =
LDFLAGS = -mno-crt0 -nostartfiles
LIBS = -lpspchnnlsv
PSPSDK=$(shell psp-config --pspsdk-path)
include $(PSPSDK)/lib/build.mak

View file

@ -0,0 +1,84 @@
#include <pspsdk.h>
#include <pspkernel.h>
#include <pspidstorage.h>
#include <pspsysreg.h>
#include <string.h>
#include <pspchnnlsv.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
PSP_MODULE_INFO("kernelcall", 0x1006, 2, 0);
u64 sceSysreg_driver_4F46EEDE();
u64 GetFuseId()
{
u64 fuseId = sceSysreg_driver_4F46EEDE();
return fuseId;
}
int sceChnnlsv_E7833020_(pspChnnlsvContext1 *ctx, int mode)
{
int k1 = pspSdkSetK1(0);
int res = sceChnnlsv_E7833020(ctx,mode);
pspSdkSetK1(k1);
return res;
}
int sceChnnlsv_F21A1FCA_(pspChnnlsvContext1 *ctx, unsigned char *data, int len)
{
int k1 = pspSdkSetK1(0);
int res = sceChnnlsv_F21A1FCA(ctx,data,len);
pspSdkSetK1(k1);
return res;
}
int sceChnnlsv_C4C494F8_(pspChnnlsvContext1 *ctx,
unsigned char *hash, unsigned char *cryptkey)
{
int k1 = pspSdkSetK1(0);
int res = sceChnnlsv_C4C494F8(ctx,hash,cryptkey);
pspSdkSetK1(k1);
return res;
}
int sceChnnlsv_ABFDFC8B_(pspChnnlsvContext2 *ctx, int mode1, int mode2,
unsigned char *hashkey, unsigned char *cipherkey)
{
int k1 = pspSdkSetK1(0);
int res = sceChnnlsv_ABFDFC8B(ctx,mode1,mode2,hashkey,cipherkey);
pspSdkSetK1(k1);
return res;
}
int sceChnnlsv_850A7FA1_(pspChnnlsvContext2 *ctx, unsigned char *data, int len)
{
int k1 = pspSdkSetK1(0);
int res = sceChnnlsv_850A7FA1(ctx,data,len);
pspSdkSetK1(k1);
return res;
}
int sceChnnlsv_21BE78B4_(pspChnnlsvContext2 *ctx)
{
int k1 = pspSdkSetK1(0);
int res = sceChnnlsv_21BE78B4(ctx);
pspSdkSetK1(k1);
return res;
}
int module_start(SceSize args, void *argp)
{
return 0;
}
int module_stop()
{
return 0;
}

View file

@ -0,0 +1,9 @@
u64 GetFuseId();
int sceChnnlsv_E7833020_(pspChnnlsvContext1 *ctx, int mode);
int sceChnnlsv_F21A1FCA_(pspChnnlsvContext1 *ctx, unsigned char *data, int len);
int sceChnnlsv_C4C494F8_(pspChnnlsvContext1 *ctx,
unsigned char *hash, unsigned char *cryptkey);
int sceChnnlsv_ABFDFC8B_(pspChnnlsvContext2 *ctx, int mode1, int mode2,
unsigned char *hashkey, unsigned char *cipherkey);
int sceChnnlsv_850A7FA1_(pspChnnlsvContext2 *ctx, unsigned char *data, int len);
int sceChnnlsv_21BE78B4_(pspChnnlsvContext2 *ctx);

579
Tools/SaveTool/main.c Normal file
View file

@ -0,0 +1,579 @@
#include <pspsdk.h>
#include <pspkernel.h>
#include <pspdebug.h>
#include <pspmoduleinfo.h>
#include <pspctrl.h>
#include <pspchnnlsv.h>
#include <psputility.h>
#include "kernelcall/kernelcall.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "encrypt.h"
#include "decrypt.h"
#include "psf.h"
#define printf pspDebugScreenPrintf
/* Define the module info section */
PSP_MODULE_INFO("ppssppsavetool", 0, 1, 0);
PSP_MAIN_THREAD_ATTR(PSP_THREAD_ATTR_USER);
PSP_HEAP_SIZE_KB(-64);
#define ENCRYPT_FILE_VERSION 1
int currentMenu = 0;
int selectedOption = 0;
int basePath = 0;
int workDir = 0;
char *menuList0[] = {"Encrypt","Decrypt", "Exit", NULL};
char *menuList1[] = {"ms0:/PSP/SAVEDATAPPSSPP/","host0:/","host1:/", "host2:/", "Back", NULL};
char *menuList2[] = {"Back", NULL};
int GetSDKMainVersion(int sdkVersion)
{
if(sdkVersion > 0x307FFFF)
return 6;
if(sdkVersion > 0x300FFFF)
return 5;
if(sdkVersion > 0x206FFFF)
return 4;
if(sdkVersion > 0x205FFFF)
return 3;
if(sdkVersion >= 0x2000000)
return 2;
if(sdkVersion >= 0x1000000)
return 1;
return 0;
};
int ProcessInput(int maxOption, int *selectedOption)
{
SceCtrlData pad, oldpad;
sceCtrlReadBufferPositive(&oldpad, 1);
while(1)
{
sceCtrlReadBufferPositive(&pad, 1);
if (pad.Buttons != 0)
{
if (!(oldpad.Buttons & PSP_CTRL_CROSS) && pad.Buttons & PSP_CTRL_CROSS)
{
return *selectedOption;
}
else if (!(oldpad.Buttons & PSP_CTRL_UP) && pad.Buttons & PSP_CTRL_UP && *selectedOption > 0)
{
*selectedOption = *selectedOption-1;
return -1;
}
else if (!(oldpad.Buttons & PSP_CTRL_DOWN) && pad.Buttons & PSP_CTRL_DOWN && *selectedOption < maxOption-1)
{
*selectedOption = *selectedOption + 1;
return -1;
}
}
oldpad = pad;
}
}
typedef struct
{
char name[30];
char saveFile[30];
int errorId;
} DirInfo;
typedef struct
{
int fileVersion;
u8 key[16];
int sdkVersion;
} EncryptFileInfo;
DirInfo dirList[128];
int numDirList;
DirInfo invalidDirList[128];
int numInvalidDirList;
int FileExist(char* basePath, char* dirPath, char* fileName)
{
SceIoStat fileStat;
char path[1024];
sprintf(path,"%s%s/%s",basePath, dirPath, fileName);
if(sceIoGetstat(path, &fileStat) < 0) // no file
return 0;
return 1;
}
int FileRead(char* basePath, char* dirPath, char* fileName, u8* dataout, int size)
{
char path[1024];
sprintf(path,"%s%s/%s",basePath, dirPath, fileName);
SceUID fileId = sceIoOpen(path, PSP_O_RDONLY, 0777);
if(fileId < 0)
return -1;
sceIoRead(fileId, dataout, size);
sceIoClose(fileId);
return 0;
}
void AddErrorDir(char* dirName, int error)
{
if(numInvalidDirList >= 128)
return;
DirInfo *inf = &invalidDirList[numInvalidDirList];
strcpy(inf->name,dirName);
inf->errorId = error;
numInvalidDirList++;
}
int UpdateValidDir(int isEncrypt)
{
numDirList = 0;
numInvalidDirList = 0;
const char* pspPath = "ms0:/PSP/SAVEDATA/";
char* pathSrc;
char* pathDst;
if(isEncrypt)
{
pathSrc = menuList1[basePath];
pathDst = pspPath;
}
else
{
pathSrc = pspPath;
pathDst = menuList1[basePath];
}
int dfd;
dfd = sceIoDopen(menuList1[basePath]);
if(dfd >= 0)
{
SceIoDirent data;
while(sceIoDread(dfd, &data) > 0 && numDirList < 128)
{
if(!(data.d_stat.st_attr & 0x10)) // is not a directory
{
continue;
}
if(data.d_name[0] == '.') // ignore "." and ".."
continue;
if(FileExist(menuList1[basePath], data.d_name, "ENCRYPT_INFO.BIN") < 0)
{
AddErrorDir(data.d_name,1);
continue;
}
EncryptFileInfo encryptInfo;
if(FileRead(menuList1[basePath], data.d_name, "ENCRYPT_INFO.BIN",(u8*)&encryptInfo,sizeof(encryptInfo)) < 0)
{
AddErrorDir(data.d_name,2);
continue;
}
if(encryptInfo.fileVersion != ENCRYPT_FILE_VERSION) // Not good version
{
AddErrorDir(data.d_name,3);
continue;
}
if(FileExist(pathSrc, data.d_name, "PARAM.SFO") < 0)
{
AddErrorDir(data.d_name,4);
continue;
}
u8 paramsfo[0x1330];
if(FileRead(pathSrc, data.d_name, "PARAM.SFO",(u8*)&paramsfo,0x1330) < 0)
{
AddErrorDir(data.d_name,5);
continue;
}
u8 *datafile;
int listLen;
if (find_psf_section("SAVEDATA_FILE_LIST", paramsfo, 0x1330,
&datafile, &listLen) < 0)
{
AddErrorDir(data.d_name,6);
continue;
}
if(datafile[0] == 0)
{
AddErrorDir(data.d_name,7);
continue;
}
char filename[32];
strcpy(filename, (char*)datafile);
if(FileExist(pathSrc, data.d_name, filename) < 0)
{
AddErrorDir(data.d_name,8);
continue;
}
DirInfo *inf = &dirList[numDirList];
inf->errorId = 0;
strcpy(inf->name, data.d_name);
strcpy(inf->saveFile, filename);
numDirList++;
}
sceIoDclose(dfd);
if(numDirList == 0)
{
return -1;
}
}
else
{
return -2;
}
return 0;
}
int FileCopy(char* srcPath, char* destPath, char* fileName)
{
SceIoStat fileStat;
char path[258];
sprintf(path,"%s/%s",srcPath, fileName);
if(sceIoGetstat(path, &fileStat) < 0)
return -1;
u8* data = malloc(fileStat.st_size);
SceUID fileId = sceIoOpen(path, PSP_O_RDONLY, 0777);
if(fileId < 0)
{
printf("Fail opening %s\n",path);
return -1;
}
sceIoRead(fileId, data, fileStat.st_size);
sceIoClose(fileId);
sprintf(path,"%s/%s",destPath, fileName);
fileId = sceIoOpen(path, PSP_O_WRONLY | PSP_O_CREAT, 0777);
if(fileId < 0)
{
printf("Fail opening %s\n",path);
return -1;
}
sceIoWrite(fileId, data, fileStat.st_size);
sceIoClose(fileId);
free(data);
return 0;
}
int main(int argc, char *argv[])
{
int i;
pspDebugScreenInit();
SceUID mod = pspSdkLoadStartModule ("flash0:/kd/chnnlsv.prx",PSP_MEMORY_PARTITION_KERNEL);
if (mod < 0) {
printf("Error 0x%08X loading/starting chnnlsv.prx.\n", mod);
}
mod = pspSdkLoadStartModule ("kernelcall.prx",PSP_MEMORY_PARTITION_KERNEL);
if (mod < 0) {
printf("Error 0x%08X loading/starting kernelcall.prx.\n", mod);
}
sceCtrlSetSamplingCycle(0);
sceCtrlSetSamplingMode(PSP_CTRL_MODE_ANALOG);
for(;;)
{
printf("====================================================================");
printf("PPSSPP Save Tool\n");
printf("====================================================================\n\n\n");
switch(currentMenu)
{
case 0:
{
int maxOption = 0;
for(i = 0; menuList0[i]; i++)
{
if(i == selectedOption)
printf(" > %s\n",menuList0[i]);
else
printf(" %s\n",menuList0[i]);
maxOption++;
}
int input = ProcessInput(maxOption, &selectedOption);
if(input == 0)
{
currentMenu = 1;
selectedOption = 0;
}
else if(input == 1)
{
currentMenu = 4;
selectedOption = 0;
}
else if(input == 2)
{
sceKernelExitGame();
}
}
break;
case 4:
case 1:
{
int maxOption = 0;
printf("PPSSPP Decrypted Save Directory : \n");
for(i = 0; menuList1[i]; i++)
{
if(i == selectedOption)
printf(" > %s\n",menuList1[i]);
else
printf(" %s\n",menuList1[i]);
maxOption++;
}
int input = ProcessInput(maxOption, &selectedOption);
if(input == maxOption-1)
{
if(currentMenu == 1)
selectedOption = 0;
else
selectedOption = 1;
currentMenu = 0;
}
else if(input >= 0)
{
basePath = selectedOption;
if(currentMenu == 1)
{
currentMenu = 2;
UpdateValidDir(1);
}
else
{
currentMenu = 5;
UpdateValidDir(0);
}
selectedOption = 0;
}
}
break;
case 5:
case 2:
{
int maxOption = 0;
if(currentMenu == 2)
printf("Save to encrypt : \n");
else
printf("Save to decrypt : \n");
if(numDirList == 0)
{
printf("No compatible data, see README for help on use\n");
}
for(i = 0; i < numDirList; i++)
{
if(i == selectedOption)
printf(" > %s\n",dirList[i].name);
else
printf(" %s\n",dirList[i].name);
maxOption++;
}
for(i = 0; menuList2[i]; i++)
{
if((i+numDirList) == selectedOption)
printf(" > %s\n",menuList2[i]);
else
printf(" %s\n",menuList2[i]);
maxOption++;
}
printf("\n Invalid path : \n");
for(i = 0; i < numInvalidDirList && i < (22-numDirList); i++)
{
switch(invalidDirList[i].errorId)
{
case 1:
printf(" %s : ENCRYPT_INFO.BIN not found\n",invalidDirList[i].name);
break;
case 2:
printf(" %s : ENCRYPT_INFO.BIN read error\n",invalidDirList[i].name);
break;
case 3:
printf(" %s : ENCRYPT_INFO.BIN wrong version\n",invalidDirList[i].name);
break;
case 4:
printf(" %s : PARAM.SFO not found\n",invalidDirList[i].name);
break;
case 5:
printf(" %s : PARAM.SFO read error\n",invalidDirList[i].name);
break;
case 6:
printf(" %s : SAVEDATA_FILE_LIST not found in PARAM.SFO\n",invalidDirList[i].name);
break;
case 7:
printf(" %s : no save name in SAVEDATA_FILE_LIST\n",invalidDirList[i].name);
break;
case 8:
printf(" %s : no save found\n",invalidDirList[i].name);
break;
default:
break;
}
}
int input = ProcessInput(maxOption, &selectedOption);
if(input == numDirList)
{
if(currentMenu == 2)
currentMenu = 1;
else
currentMenu = 4;
selectedOption = basePath;
}
else if(input >= 0)
{
if(currentMenu == 2)
currentMenu = 3;
else
currentMenu = 6;
workDir = input;
selectedOption = 0;
}
}
break;
case 6:
case 3:
{
EncryptFileInfo encryptInfo;
if(FileRead(menuList1[basePath], dirList[workDir].name, "ENCRYPT_INFO.BIN",(u8*)&encryptInfo,sizeof(encryptInfo)) < 0)
{
printf("Can't read encrypt file\n");
}
else
{
printf("Key : ");
for(i = 0; i < 16; i++)
printf(" %02x",(u8)encryptInfo.key[i]);
printf("\n");
printf("SDK Version : 0x%x\n",encryptInfo.sdkVersion);
char srcPath[128];
char dstPath[128];
if(currentMenu == 3)
{
sprintf(srcPath,"%s%s",menuList1[basePath], dirList[workDir].name);
sprintf(dstPath,"ms0:/PSP/SAVEDATA/%s",dirList[workDir].name);
sceIoMkdir(dstPath,0777);
}
else
{
sprintf(srcPath,"ms0:/PSP/SAVEDATA/%s",dirList[workDir].name);
sprintf(dstPath,"%s%s",menuList1[basePath], dirList[workDir].name);
}
int dfd;
dfd = sceIoDopen(srcPath);
if(dfd >= 0)
{
SceIoDirent dirinfo;
while(sceIoDread(dfd, &dirinfo) > 0)
{
if(!(dirinfo.d_stat.st_mode & 0x2000)) // is not a file
continue;
if(strcmp(dirinfo.d_name,"ENCRYPT_INFO.BIN") == 0) // don't copy encrypt info
continue;
FileCopy(srcPath, dstPath, dirinfo.d_name);
}
sceIoDclose(dfd);
}
if(currentMenu == 3)
{
char decryptedFile[258], encryptedFile[258], srcSFO[258], dstSFO[258];
sprintf(decryptedFile,"%s/%s",srcPath ,dirList[workDir].saveFile);
sprintf(srcSFO,"%s/PARAM.SFO",srcPath);
sprintf(encryptedFile,"%s/%s",dstPath ,dirList[workDir].saveFile);
sprintf(dstSFO,"%s/PARAM.SFO",dstPath);
printf("Encoding %s into %s\n",decryptedFile, encryptedFile);
int ret = encrypt_file(decryptedFile,
encryptedFile,
dirList[workDir].saveFile,
srcSFO,
dstSFO,
encryptInfo.key[0] != 0 ? encryptInfo.key : NULL,
GetSDKMainVersion(encryptInfo.sdkVersion)
);
if(ret < 0) {
printf("Error: encrypt_file() returned %d\n\n", ret);
} else {
printf("Successfully wrote %d bytes to\n", ret);
printf(" %s\n", encryptedFile);
printf("and updated hashes in\n");
printf(" %s\n\n", dstSFO);
}
}
else
{
char decryptedFile[258], encryptedFile[258];
sprintf(encryptedFile,"%s/%s",srcPath ,dirList[workDir].saveFile);
sprintf(decryptedFile,"%s/%s",dstPath ,dirList[workDir].saveFile);
printf("Decoding %s into %s\n",encryptedFile, decryptedFile);
int ret = decrypt_file(decryptedFile, encryptedFile, encryptInfo.key[0] != 0 ? encryptInfo.key : NULL, GetSDKMainVersion(encryptInfo.sdkVersion));
if(ret < 0) {
printf("Error: decrypt_file() returned %d\n\n", ret);
} else {
printf("Successfully wrote %d bytes to\n", ret);
printf(" %s\n", decryptedFile);
}
}
printf(" > Back\n");
int input = ProcessInput(1, &selectedOption);
if(input >= 0)
{
if(currentMenu == 3)
currentMenu = 2;
else
currentMenu = 5;
selectedOption = 0;
}
}
}
break;
default:
sceKernelExitGame();
break;
}
pspDebugScreenClear();
sceDisplayWaitVblankStart();
sceGuSwapBuffers();
}
return 0;
}

114
Tools/SaveTool/psf.c Normal file
View file

@ -0,0 +1,114 @@
/*
* PSP Software Development Kit - http://www.pspdev.org
* -----------------------------------------------------------------------
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
*
* psf.c - PSF parsing routines
*
* Copyright (c) 2005 Jim Paris <jim@jtan.com>
* Coypright (c) 2005 psp123
*
* $Id: psf.c 1560 2005-12-10 01:16:32Z jim $
*/
#include "psf.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <pspchnnlsv.h>
/* Find to the named section in the PSF file, and return an
absolute pointer to it and the section size. */
int find_psf_section(const char *name,
unsigned char *data,
int dataLen,
unsigned char **location,
int *size)
{
unsigned short int nameLoc;
int i, magicHead, strLoc, headLen, numSects;
int sectCurLen, sectBufLen, sectBufLoc, curPos;
if (dataLen < 0x14)
return -1;
/* Get the basics from the header */
magicHead = *(unsigned int *)&data[0x00];
strLoc = *(unsigned int *)&data[0x08];
headLen = *(unsigned int *)&data[0x0C];
numSects = *(unsigned int *)&data[0x10];
/* Do some error checking */
if (magicHead != 0x46535000)
return -2;
/* Verify strLoc is proper */
if ((strLoc > headLen) || (strLoc >= dataLen))
return -3;
/* Verify headLen is proper */
if (headLen >= dataLen)
return -4;
/* Verify numSects is proper */
if (numSects != ((strLoc - 0x14) / 0x10))
return -5;
/* Process all sections */
for (i = 0; i < numSects; i++)
{
/* Get the curPos */
curPos = 0x14 + (i * 0x10);
/* Verify curPos is proper */
if (curPos >= strLoc)
return -6;
/* Get some basic info about this section */
nameLoc = *(unsigned short *)&data[curPos];
sectCurLen = *(unsigned short *)&data[curPos + 0x04];
sectBufLen = *(unsigned short *)&data[curPos + 0x08];
sectBufLoc = *(unsigned short *)&data[curPos + 0x0C];
/* Do some error checking */
if ((nameLoc < dataLen) && (sectCurLen < dataLen)
&& (sectBufLen < dataLen) && (sectBufLoc < dataLen))
{
/* Check if this is the section we want */
if (!stricmp((char *)&data[strLoc + nameLoc], name))
{
/* Update the location and size */
*location = &data[headLen + sectBufLoc];
*size = sectBufLen;
return 0;
}
}
}
/* Section was not found if it makes it here */
return -7;
}
/* Find the named file inside the FILE_LIST, and return
an absolute pointer to it. */
int find_psf_datafile(const char *name,
unsigned char *filelist,
int size,
unsigned char **location)
{
int i;
/* Process all files */
for (i = 0; (i + 0x0d) <= size; i += 0x20)
{
/* Check if this is the filename we want */
if (!strncasecmp((char *)&filelist[i], name, 0x0d)) {
*location = &filelist[i];
return 0;
}
}
/* File was not found if it makes it here */
return -1;
}

29
Tools/SaveTool/psf.h Normal file
View file

@ -0,0 +1,29 @@
/*
* PSP Software Development Kit - http://www.pspdev.org
* -----------------------------------------------------------------------
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
*
* psf.h - Declarations for functions in psf.c
*
* Copyright (c) 2005 Jim Paris <jim@jtan.com>
* Coypright (c) 2005 psp123
*
* $Id: psf.h 1559 2005-12-10 01:10:11Z jim $
*/
#include <pspchnnlsv.h>
/* Find the named section in the PSF file, and return an
absolute pointer to it and the section size. */
int find_psf_section(const char *name,
unsigned char *data,
int dataLen,
unsigned char **location,
int *size);
/* Find the named file inside the FILE_LIST, and return
an absolute pointer to it. */
int find_psf_datafile(const char *name,
unsigned char *filelist,
int size,
unsigned char **location);