void A5InitLoader::load(const CodeSegment &code, const uint32 offset, const uint32 size, std::ostream &out) throw(std::exception) { byte *memory = _executable.getMemory(); const uint32 internalOffset = (code.is32BitSegment() ? 46 : 10); const uint32 infoOffset = READ_UINT16_BE(memory + offset + internalOffset) + internalOffset; const uint32 dataSize = READ_UINT32_BE(memory + offset + infoOffset + 0); const uint16 needLoadBit = READ_UINT16_BE(memory + offset + infoOffset + 4); const uint32 dataOffset = READ_UINT32_BE(memory + offset + infoOffset + 8); const uint32 relocationDataOffset = READ_UINT32_BE(memory + offset + infoOffset + 12); // Output various information about the %A5Init segment out << "%A5Init info data:\n" "\tData size: " << dataSize << "\n" "\tNeed to load: " << needLoadBit << "\n" "\tData offset: " << dataOffset << "\n" "\tRelocation offset: " << relocationDataOffset << std::endl; // Check whether we actually have to do some work if (needLoadBit != 1) { out << "A5 data does not need any initialization" << std::endl; return; } const Code0Segment &code0 = _executable.getCode0Segment(); uint8 *dst = memory + code0.getApplicationGlobalsSize() - dataSize; // uncompress the world uncompressA5World(dst, memory + offset + infoOffset + dataOffset); // relocate the world relocateWorld(code0.getApplicationGlobalsSize(), dst, memory + offset + infoOffset + relocationDataOffset, out); // Mark segment as initialized WRITE_UINT16_BE(memory + offset + infoOffset + 4, 0); }
bool A5InitLoader::isSupported(const CodeSegment &code, const uint32 offset, const uint32 size) throw() { // Check whether the name matches if (code.getName() != "%A5Init") return false; const byte *memory = _executable.getMemory(); const uint32 memorySize = _executable.getMemorySize(); // Check whether it only exports one function if (!code.is32BitSegment() && READ_UINT16_BE(memory + offset + 2) != 0x0001) return false; else if (READ_UINT32_BE(memory + offset + 8) != 0x00000001) return false; const uint32 internalOffset = (code.is32BitSegment() ? 46 : 10); const uint32 infoOffset = READ_UINT16_BE(memory + offset + internalOffset) + internalOffset; // Check whether the information area is still inside the memory dump if (offset + infoOffset + 16 >= memorySize) return false; const uint32 dataOffset = READ_UINT32_BE(memory + offset + infoOffset + 8); const uint32 relocationDataOffset = READ_UINT32_BE(memory + offset + infoOffset + 12); // Check whether the compressed data is still in the memory dump if (offset + dataOffset >= memorySize) return false; // Check whether the relocation data is still in the memory dump if (offset + relocationDataOffset >= memorySize) return false; // Looks like it is an %A5Init segment return true; }
bool Data00Loader::isSupported(const CodeSegment &code, const uint32 offset, const uint32 size) throw() { const byte *memory = _executable.getMemory(); const uint32 memorySize = _executable.getMemorySize(); // TODO: This detection heuristic is probably all wrong... // Chechk whether the segment is big enough if (memorySize < offset + 0x210) return false; // Check whether the offset into the jump table is 0 if (READ_UINT16_BE(memory + offset + 0) != 0) return false; // Check whether just one function is exported if (READ_UINT16_BE(memory + offset + 2) != 1) return false; // Check whether a "CODE" tag is at 0xA if (READ_UINT32_BE(memory + offset + 0x0A) != 0x434F4445) return false; // Check whether a "DATA" tag is at 0x44 if (READ_UINT32_BE(memory + offset + 0x44) != 0x44415441) return false; // Check whether we have an DATA00 resource _data00 = _resFork.getResource(0x44415441, 0x0000); if (_data00 == nullptr) return false; return true; }
uint32 A5InitLoader::getRunLength(const uint8 *&src, uint32 &special) const throw() { assert(src != nullptr); uint32 rl = *src++; if (!(rl & 0x80)) { return rl; } else if (!(rl & 0x40)) { rl &= 0x3F; rl <<= 8; rl |= *src++; return rl; } else if (!(rl & 0x20)) { rl &= 0x1F; rl <<= 8; rl |= *src++; rl <<= 8; rl |= *src++; return rl; } else if (!(rl & 0x10)) { rl = READ_UINT32_BE(src); src += 4; return rl; } else { rl = getRunLength(src, special); special = getRunLength(src, special); return rl; } }
void A5InitLoader::relocateWorld(const uint32 a5, uint8 *dst, const uint8 *src, std::ostream &out) const throw() { assert(dst != nullptr); assert(src != nullptr); uint32 dummy = 0; while (true) { uint32 loops = 1; uint32 offset = *src++; if (offset) { if (offset & 0x80) { offset &= 0x7F; offset <<= 8; offset |= *src++; } } else { offset = *src++; if (!offset) return; if (offset & 0x80) { offset <<= 8; offset |= *src++; offset <<= 8; offset |= *src++; offset <<= 8; offset |= *src++; } else { loops = getRunLength(src, dummy); } } offset += offset; do { dst += offset; out << boost::format("Relocation at 0x%1$08X\n") % (dst - _executable.getMemory()); WRITE_UINT32_BE(dst, READ_UINT32_BE(dst) + a5); } while (--loops); } }
uint8_t DBUtils::hgtxToDupID(const BinaryData& hgtx) { return (READ_UINT32_BE(hgtx) & 0x7f); }
void ZeroConfContainer::loadZeroConfMempool( function<bool(const BinaryData&)> filter, bool clearMempool) { //run this in its own scope so the iter and tx are closed in order to open //RW tx afterwards { auto dbs = db_->getDbSelect(HISTORY); LMDBEnv::Transaction tx; db_->beginDBTransaction(&tx, dbs, LMDB::ReadOnly); LDBIter dbIter(db_->getIterator(dbs)); if (!dbIter.seekToStartsWith(DB_PREFIX_ZCDATA)) { enabled_ = true; return; } do { BinaryDataRef zcKey = dbIter.getKeyRef(); if (zcKey.getSize() == 7) { //Tx, grab it from DB StoredTx zcStx; db_->getStoredZcTx(zcStx, zcKey); //add to newZCMap_ Tx& zcTx = newZCMap_[zcKey.getSliceCopy(1, 6)]; zcTx = Tx(zcStx.getSerializedTx()); zcTx.setTxTime(zcStx.unixTime_); } else if (zcKey.getSize() == 9) { //TxOut, ignore it continue; } else { //shouldn't hit this LOGERR << "Unknown key found in ZC mempool"; break; } } while (dbIter.advanceAndRead(DB_PREFIX_ZCDATA)); } if (clearMempool == true) { vector<BinaryData> keysToWrite, keysToDelete; for (const auto& zcTx : newZCMap_) keysToDelete.push_back(zcTx.first); newZCMap_.clear(); updateZCinDB(keysToWrite, keysToDelete); } else if (newZCMap_.size()) { //copy newZCmap_ to keep the pre parse ZC map auto oldZCMap = newZCMap_; //now parse the new ZC parseNewZC(filter); //set the zckey to the highest used index if (txMap_.size() > 0) { BinaryData topZcKey = txMap_.rbegin()->first; topId_.store(READ_UINT32_BE(topZcKey.getSliceCopy(2, 4)) +1); } //intersect oldZCMap and txMap_ to figure out the invalidated ZCs vector<BinaryData> keysToWrite, keysToDelete; for (const auto& zcTx : oldZCMap) { if (txMap_.find(zcTx.first) == txMap_.end()) keysToDelete.push_back(zcTx.first); } //no need to run this in a side thread, this code only runs when we have //full control over the main thread updateZCinDB(keysToWrite, keysToDelete); } enabled_ = true; }
const byte *Data00Loader::uncompress(const uint32 offset, std::ostream &out) throw(std::exception) { byte * const memory = _executable.getMemory(); Code0Segment &code0 = _executable.getCode0Segment(); byte * const a5Base = memory + code0.getApplicationGlobalsSize(); const byte *src = _data00->data + 4; // Whether data was written to the jump table bool dataWrittenToJumpTable = false; for (uint i = 0; i < 3; ++i) { // Read the offset const int32 offset = (int32)READ_UINT32_BE(src); src += 4; uint8 *dst = a5Base + offset; // Whether we uncompress data onto the uninitialized part of the jump table if (offset >= int32(code0.getApplicationParametersSize() + 8)) { out << "\tData write to jump table offset: " << offset << std::endl; dataWrittenToJumpTable = true; } while (true) { uint8 code = *src++; if (code & 0x80) { code &= 0x7F; code += 1; std::memcpy(dst, src, code); src += code; dst += code; } else if (code & 0x40) { code &= 0x3F; code += 1; std::memset(dst, 0, code); dst += code; } else if (code & 0x20) { code &= 0x1F; code += 2; const uint8 data = *src++; std::memset(dst, data, code); dst += code; } else if (code & 0x10) { code &= 0x0F; code += 1; std::memset(dst, 0xFF, code); dst += code; } else { if (code == 0) { break; } else if (code == 1) { *dst++ = 0x00; *dst++ = 0x00; *dst++ = 0x00; *dst++ = 0x00; *dst++ = 0xFF; *dst++ = 0xFF; *dst++ = *src++; *dst++ = *src++; } else if (code == 2) { *dst++ = 0x00; *dst++ = 0x00; *dst++ = 0x00; *dst++ = 0x00; *dst++ = 0xFF; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; } else if (code == 3) { *dst++ = 0xA9; *dst++ = 0xF0; *dst++ = 0x00; *dst++ = 0x00; *dst++ = *src++; *dst++ = *src++; *dst++ = 0x0; *dst++ = *src++; } else if (code == 4) { *dst++ = 0xA9; *dst++ = 0xF0; *dst++ = 0x00; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = 0x0; *dst++ = *src++; } else { throw std::runtime_error("DATA00 Loader: Invalid code " + boost::lexical_cast<std::string>(int(code)) + " encountered"); } } } } // Check whether data was written to the jump table if (dataWrittenToJumpTable) { // Load the data from entry 1 to the last entry into our jump table structure for (uint i = 1, end = code0.getJumpTableEntryCount(); i < end; ++i) std::memcpy(code0.getJumpTableEntry(i).rawData, memory + code0.getJumpTableOffset() + i * 8, 8); code0.outputJumptable(out); } return src; }