static DALResult _AllocBit(uint32 * pMask, uint32 uMaxBits, uint32 *uBitPos) { uint32 i, j, bmsk,val; val=(ROUND_UP_32(uMaxBits))/32; for(i=0; i<val; i++) { bmsk = pMask[i]; if(bmsk==0xFFFFFFFF) { /*Skip loop if free bit positions are not available*/ continue; } for(j=0; j<32; j++) { if(!(bmsk&1)) { if(uMaxBits > (i*32 + j)) { *uBitPos = i*32 + j; pMask[i] |= (1<<j); return DAL_SUCCESS; } return DAL_ERROR; } bmsk >>=1; } } return DAL_ERROR; }
static DALResult _AllocateMemForBitMasks(uint32** pMask, uint32 uNumBits) { uint32 uMemSize = sizeof(uint32) * (ROUND_UP_32(uNumBits)/32); //LHT add size check because DALSYS_Malloc will assert after //DALHeap_Malloc fails on request of size zero. if (0 < uMemSize) { if(DAL_SUCCESS != DALSYS_Malloc(uMemSize, (void **)pMask)) { return DAL_ERROR; } memset(*pMask, 0, uMemSize); } return DAL_SUCCESS; }
CInputStream* CResLoader::LoadNewResourceSync(const SObjectTag& tag, void* extBuf) { void* buf = extBuf; CPakFile* file = FindResourceForLoad(tag); size_t resSz = ROUND_UP_32(x50_cachedResInfo->x8_size); if (!buf) { CCallStack cs(AT_PRETTY_FUNCTION, "UnknownType"); buf = CMemory::Alloc(resSz, IAllocator::EHint::Large, IAllocator::EScope::Default, IAllocator::EType::Primitive, cs); } file->SyncSeekRead(buf, resSz, ESeekOrigin::Begin, x50_cachedResInfo->x4_offset); CInputStream* newStrm = new CMemoryInStream((atUint8*)buf, resSz, !extBuf); if (x50_cachedResInfo->xb_compressed) { newStrm->readUint32Big(); newStrm = new CZipInputStream(std::move(std::unique_ptr<CInputStream>(newStrm))); } return newStrm; }
std::shared_ptr<IDvdRequest> CResLoader::LoadResourceAsync(const SObjectTag& tag, void* buf) { return FindResourceForLoad(tag.id)->AsyncSeekRead(buf, ROUND_UP_32(x50_cachedResInfo->x8_size), ESeekOrigin::Begin, x50_cachedResInfo->x4_offset); }
uint64_t buildFromDirectory(const SystemChar* dirIn, const SystemChar* dolIn, const SystemChar* apploaderIn, const SystemChar* partHeadIn) { /* Read head and validate key members */ std::unique_ptr<IFileIO> ph = NewFileIO(partHeadIn); uint8_t tkey[16]; { if (ph->beginReadStream(0x1BF)->read(tkey, 16) != 16) LogModule.report(logvisor::Fatal, _S("unable to read title key from %s"), partHeadIn); } uint8_t tkeyiv[16] = {}; { if (ph->beginReadStream(0x1DC)->read(tkeyiv, 8) != 8) LogModule.report(logvisor::Fatal, _S("unable to read title key IV from %s"), partHeadIn); } uint8_t ccIdx; { if (ph->beginReadStream(0x1F1)->read(&ccIdx, 1) != 1) LogModule.report(logvisor::Fatal, _S("unable to read common key index from %s"), partHeadIn); if (ccIdx > 1) LogModule.report(logvisor::Fatal, _S("common key index may only be 0 or 1")); } uint32_t tmdSz; { if (ph->beginReadStream(0x2A4)->read(&tmdSz, 4) != 4) LogModule.report(logvisor::Fatal, _S("unable to read TMD size from %s"), partHeadIn); tmdSz = SBig(tmdSz); } uint64_t h3Off; { uint32_t h3Ptr; if (ph->beginReadStream(0x2B4)->read(&h3Ptr, 4) != 4) LogModule.report(logvisor::Fatal, _S("unable to read H3 pointer from %s"), partHeadIn); h3Off = uint64_t(SBig(h3Ptr)) << 2; } uint64_t dataOff; { uint32_t dataPtr; if (ph->beginReadStream(0x2B8)->read(&dataPtr, 4) != 4) LogModule.report(logvisor::Fatal, _S("unable to read data pointer from %s"), partHeadIn); dataOff = uint64_t(SBig(dataPtr)) << 2; } m_userOffset = dataOff; std::unique_ptr<uint8_t[]> tmdData(new uint8_t[tmdSz]); if (ph->beginReadStream(0x2C0)->read(tmdData.get(), tmdSz) != tmdSz) LogModule.report(logvisor::Fatal, _S("unable to read TMD from %s"), partHeadIn); /* Copy partition head up to H3 table */ std::unique_ptr<IFileIO::IWriteStream> ws = m_parent.getFileIO().beginWriteStream(m_baseOffset); { uint64_t remCopy = h3Off; uint8_t copyBuf[8192]; std::unique_ptr<IFileIO::IReadStream> rs = ph->beginReadStream(); while (remCopy) { size_t rdBytes = rs->read(copyBuf, std::min(size_t(8192), size_t(remCopy))); if (rdBytes) { ws->write(copyBuf, rdBytes); remCopy -= rdBytes; continue; } for (size_t i=0 ; i<remCopy ; ++i) ws->write("", 1); break; } } /* Prepare crypto pass */ m_aes->setKey(COMMON_KEYS[ccIdx]); m_aes->decrypt(tkeyiv, tkey, tkey, 16); m_aes->setKey(tkey); { /* Assemble partition data */ std::unique_ptr<IPartWriteStream> cws = beginWriteStream(0x1F0000); bool result = DiscBuilderBase::PartitionBuilderBase::buildFromDirectory(*cws, dirIn, dolIn, apploaderIn); if (!result) return 0; /* Pad out user area to nearest cleartext sector */ m_curUser = cws->position(); uint64_t curUserRem = m_curUser % 0x1F0000; if (curUserRem) { curUserRem = 0x1F0000 - curUserRem; for (size_t i=0 ; i<curUserRem ; ++i) cws->write("\xff", 1); m_curUser += curUserRem; } /* Begin crypto write and add content header */ cws = beginWriteStream(0); Header header(m_gameID, m_gameTitle.c_str(), true, 0, 0, 0); header.write(*cws); /* Get Apploader Size */ Sstat theStat; if (Stat(apploaderIn, &theStat)) LogModule.report(logvisor::Fatal, _S("unable to stat %s"), apploaderIn); /* Compute boot table members and write */ size_t fstOff = 0x2440 + ROUND_UP_32(theStat.st_size); size_t fstSz = sizeof(FSTNode) * m_buildNodes.size(); fstSz += m_buildNameOff; fstSz = ROUND_UP_32(fstSz); if (fstOff + fstSz >= 0x1F0000) LogModule.report(logvisor::Fatal, "FST flows into user area (one or the other is too big)"); cws->write(nullptr, 0x420 - sizeof(Header)); uint32_t vals[4]; vals[0] = SBig(uint32_t(m_dolOffset >> uint64_t(2))); vals[1] = SBig(uint32_t(fstOff >> uint64_t(2))); vals[2] = SBig(uint32_t(fstSz)); vals[3] = SBig(uint32_t(fstSz)); cws->write(vals, 16); /* Write Apploader */ cws->write(nullptr, 0x2440 - 0x430); std::unique_ptr<IFileIO::IReadStream> rs = NewFileIO(apploaderIn)->beginReadStream(); char buf[8192]; size_t xferSz = 0; SystemString apploaderName(apploaderIn); ++m_parent.m_progressIdx; while (true) { size_t rdSz = rs->read(buf, 8192); if (!rdSz) break; cws->write(buf, rdSz); xferSz += rdSz; if (0x2440 + xferSz >= 0x1F0000) LogModule.report(logvisor::Fatal, "apploader flows into user area (one or the other is too big)"); m_parent.m_progressCB(m_parent.m_progressIdx, apploaderName, xferSz); } size_t fstOffRel = fstOff - 0x2440; if (xferSz > fstOffRel) LogModule.report(logvisor::Fatal, "apploader unexpectedly flows into FST"); for (size_t i=0 ; i<fstOffRel-xferSz ; ++i) cws->write("\xff", 1); /* Write FST */ cws->write(m_buildNodes.data(), m_buildNodes.size() * sizeof(FSTNode)); for (const std::string& str : m_buildNames) cws->write(str.data(), str.size()+1); } /* Write new crypto content size */ uint64_t groupCount = m_curUser / 0x1F0000; uint64_t cryptContentSize = (groupCount * 0x200000) >> uint64_t(2); uint32_t cryptContentSizeBig = SBig(uint32_t(cryptContentSize)); ws = m_parent.getFileIO().beginWriteStream(m_baseOffset + 0x2BC); ws->write(&cryptContentSizeBig, 0x4); /* Write new H3 */ ws = m_parent.getFileIO().beginWriteStream(m_baseOffset + h3Off); ws->write(m_h3, 0x18000); /* Compute content hash and replace in TMD */ sha1nfo sha; sha1_init(&sha); sha1_write(&sha, (char*)m_h3, 0x18000); memcpy(tmdData.get() + 0x1F4, sha1_result(&sha), 20); /* Same for content size */ uint64_t contentSize = groupCount * 0x1F0000; uint64_t contentSizeBig = SBig(contentSize); memcpy(tmdData.get() + 0x1EC, &contentSizeBig, 8); /* Zero-out TMD signature to simplify brute-force */ memset(tmdData.get() + 0x4, 0, 0x100); /* Brute-force zero-starting hash */ size_t tmdCheckSz = tmdSz - 0x140; struct BFWindow { uint64_t word[7]; }* bfWindow = (BFWindow*)(tmdData.get() + 0x19A); bool good = false; uint64_t attempts = 0; SystemString bfName(_S("Brute force attempts")); ++m_parent.m_progressIdx; for (int w=0 ; w<7 ; ++w) { for (uint64_t i=0 ; i<UINT64_MAX ; ++i) { bfWindow->word[w] = i; sha1_init(&sha); sha1_write(&sha, (char*)(tmdData.get() + 0x140), tmdCheckSz); uint8_t* hash = sha1_result(&sha); ++attempts; if (hash[0] == 0) { good = true; break; } m_parent.m_progressCB(m_parent.m_progressIdx, bfName, attempts); } if (good) break; } m_parent.m_progressCB(m_parent.m_progressIdx, bfName, attempts); ws = m_parent.getFileIO().beginWriteStream(m_baseOffset + 0x2C0); ws->write(tmdData.get(), tmdSz); return m_baseOffset + dataOff + groupCount * 0x200000; }