mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
commit
5d303f1577
21 changed files with 1863 additions and 58 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -49,5 +49,6 @@ void sceKernelFreeFpl();
|
|||
void sceKernelCancelFpl();
|
||||
void sceKernelReferFplStatus();
|
||||
|
||||
int sceKernelGetCompiledSdkVersion();
|
||||
|
||||
void Register_SysMemUserForUser();
|
||||
|
|
44
Tools/SaveTool/Makefile
Normal file
44
Tools/SaveTool/Makefile
Normal 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
77
Tools/SaveTool/README
Normal 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
164
Tools/SaveTool/decrypt.c
Normal 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
31
Tools/SaveTool/decrypt.h
Normal 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
233
Tools/SaveTool/encrypt.c
Normal 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
38
Tools/SaveTool/encrypt.h
Normal 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
129
Tools/SaveTool/hash.c
Normal 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, ¶msLen)) < 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
34
Tools/SaveTool/hash.h
Normal 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);
|
BIN
Tools/SaveTool/kernelcall.prx
Normal file
BIN
Tools/SaveTool/kernelcall.prx
Normal file
Binary file not shown.
24
Tools/SaveTool/kernelcall/Makefile
Normal file
24
Tools/SaveTool/kernelcall/Makefile
Normal 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
|
84
Tools/SaveTool/kernelcall/kernelcall.c
Normal file
84
Tools/SaveTool/kernelcall/kernelcall.c
Normal 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;
|
||||
}
|
9
Tools/SaveTool/kernelcall/kernelcall.h
Normal file
9
Tools/SaveTool/kernelcall/kernelcall.h
Normal 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
579
Tools/SaveTool/main.c
Normal 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*)¶msfo,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
114
Tools/SaveTool/psf.c
Normal 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
29
Tools/SaveTool/psf.h
Normal 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);
|
Loading…
Add table
Reference in a new issue