コード例 #1
0
bool PalmBinaryLoader::loadFromMemory(QByteArray &img)
{
    const int size = img.size();
    m_image        = reinterpret_cast<uint8_t *>(img.data());

    if (static_cast<unsigned long>(size) < sizeof(PRCHeader) + sizeof(PRCRecordList)) {
        LOG_ERROR("This is not a standard .prc file");
        return false;
    }

    PRCHeader *prcHeader = reinterpret_cast<PRCHeader *>(img.data());

    // Check type at offset 0x3C; should be "appl" (or "palm"; ugh!)
    if ((strncmp(prcHeader->type, "appl", 4) != 0) && (strncmp(prcHeader->type, "panl", 4) != 0) &&
        (strncmp(prcHeader->type, "libr", 4) != 0)) {
        LOG_ERROR("This is not a standard .prc file");
        return false;
    }

    addTrapSymbols();

    // Get the number of resource headers (one section per resource)
    PRCRecordList *records = reinterpret_cast<PRCRecordList *>(m_image + sizeof(PRCHeader));
    if (records->nextRecordListOffset != 0) {
        LOG_ERROR("Reading PRC files with multiple record lists is not supported!");
        return false;
    }

    const SWord numSections = Util::readWord(&records->resourceCount, Endian::Big);

    // Iterate through the resource headers (generating section info structs)
    PRCResource *resource = reinterpret_cast<PRCResource *>(m_image + sizeof(PRCHeader) +
                                                            sizeof(PRCRecordList));

    std::vector<SectionProperties> sectionProperties;

    for (unsigned i = 0; i < numSections; i++) {
        char buf[5];
        strncpy(buf, reinterpret_cast<char *>(&resource[i].type), 4);
        buf[4] = 0;

        SWord id         = Util::readWord(&resource[i].id, Endian::Big);
        QString name     = QString("%1%2").arg(buf).arg(id);
        DWord dataOffset = Util::readDWord(&resource[i].dataOffset, Endian::Big);

        Address startAddr(dataOffset);

        if (i > 0) {
            sectionProperties[i - 1].to = startAddr;
        }

        sectionProperties.push_back(
            { name, startAddr, Address::INVALID, HostAddress(m_image + dataOffset) });
    }

    // last section extends until eof
    sectionProperties[numSections - 1].to = Address(size);

    for (SectionProperties props : sectionProperties) {
        assert(props.to != Address::INVALID);
        BinarySection *sect = m_binaryImage->createSection(props.name, props.from, props.to);

        if (sect) {
            // Decide if code or data; note that code0 is a special case (not code)
            sect->setHostAddr(props.hostAddr);
            sect->setCode((props.name != "code0") && (props.name.startsWith("code")));
            sect->setData(props.name.startsWith("data"));
            sect->setEndian(Endian::Little);            // little endian
            sect->setEntrySize(1);                      // No info available
            sect->addDefinedArea(props.from, props.to); // no BSS
        }
    }

    // Create a separate, uncompressed, initialised data section
    BinarySection *dataSection = m_binaryImage->getSectionByName("data0");

    if (dataSection == nullptr) {
        LOG_ERROR("No data section found!");
        return false;
    }

    const BinarySection *code0Section = m_binaryImage->getSectionByName("code0");

    if (code0Section == nullptr) {
        LOG_ERROR("No code 0 section found!");
        return false;
    }

    // When the info is all boiled down, the two things we need from the
    // code 0 section are at offset 0, the size of data above a5, and at
    // offset 4, the size below. Save the size below as a member variable
    m_sizeBelowA5 = UINT4ADDR(code0Section->getHostAddr() + 4);

    // Total size is this plus the amount above (>=) a5
    unsigned sizeData = m_sizeBelowA5 + UINT4ADDR(code0Section->getHostAddr());

    // Allocate a new data section
    m_data = new unsigned char[sizeData];

    if (m_data == nullptr) {
        LOG_FATAL("Could not allocate %1 bytes for data section", sizeData);
    }

    // Uncompress the data. Skip first long (offset of CODE1 "xrefs")
    Byte *p   = reinterpret_cast<Byte *>((dataSection->getHostAddr() + 4).value());
    int start = static_cast<int>(UINT4(p));
    p += 4;
    unsigned char *q = (m_data + m_sizeBelowA5 + start);
    bool done        = false;

    while (!done && (p < reinterpret_cast<unsigned char *>(
                             (dataSection->getHostAddr() + dataSection->getSize()).value()))) {
        unsigned char rle = *p++;

        if (rle == 0) {
            done = true;
            break;
        }
        else if (rle == 1) {
            // 0x01 b_0 b_1
            // => 0x00 0x00 0x00 0x00 0xFF 0xFF b_0 b_1
            *q++ = 0x00;
            *q++ = 0x00;
            *q++ = 0x00;
            *q++ = 0x00;
            *q++ = 0xFF;
            *q++ = 0xFF;
            *q++ = *p++;
            *q++ = *p++;
        }
        else if (rle == 2) {
            // 0x02 b_0 b_1 b_2
            // => 0x00 0x00 0x00 0x00 0xFF b_0 b_1 b_2
            *q++ = 0x00;
            *q++ = 0x00;
            *q++ = 0x00;
            *q++ = 0x00;
            *q++ = 0xFF;
            *q++ = *p++;
            *q++ = *p++;
            *q++ = *p++;
        }
        else if (rle == 3) {
            // 0x03 b_0 b_1 b_2
            // => 0xA9 0xF0 0x00 0x00 b_0 b_1 0x00 b_2
            *q++ = 0xA9;
            *q++ = 0xF0;
            *q++ = 0x00;
            *q++ = 0x00;
            *q++ = *p++;
            *q++ = *p++;
            *q++ = 0x00;
            *q++ = *p++;
        }
        else if (rle == 4) {
            // 0x04 b_0 b_1 b_2 b_3
            // => 0xA9 axF0 0x00 b_0 b_1 b_3 0x00 b_3
            *q++ = 0xA9;
            *q++ = 0xF0;
            *q++ = 0x00;
            *q++ = *p++;
            *q++ = *p++;
            *q++ = *p++;
            *q++ = 0x00;
            *q++ = *p++;
        }
        else if (rle < 0x10) {
            // 5-0xF are invalid.
            assert(false);
        }
        else if (rle >= 0x80) {
            // n+1 bytes of literal data
            for (int k = 0; k <= (rle - 0x80); k++) {
                *q++ = *p++;
            }
        }
        else if (rle >= 40) {
            // n+1 repetitions of 0
            for (int k = 0; k <= (rle - 0x40); k++) {
                *q++ = 0x00;
            }
        }
        else if (rle >= 20) {
            // n+2 repetitions of b
            unsigned char b = *p++;

            for (int k = 0; k < (rle - 0x20 + 2); k++) {
                *q++ = b;
            }
        }
        else {
            // 0x10: n+1 repetitions of 0xFF
            for (int k = 0; k <= (rle - 0x10); k++) {
                *q++ = 0xFF;
            }
        }
    }

    if (!done) {
        LOG_WARN("Compressed data section premature end");
    }

    LOG_VERBOSE("Used %1 bytes of %2 in decompressing data section",
                p - reinterpret_cast<unsigned char *>(dataSection->getHostAddr().value()),
                dataSection->getSize());

    // Replace the data pointer and size with the uncompressed versions

    dataSection->setHostAddr(HostAddress(m_data));
    dataSection->resize(sizeData);

    m_symbols->createSymbol(getMainEntryPoint(), "PilotMain")->setAttribute("EntryPoint", true);
    return true;
}
コード例 #2
0
ファイル: PalmBinaryFile.cpp プロジェクト: JFreaker/boomerang
bool PalmBinaryFile::RealLoad(const char* sName)
{
    FILE    *fp;
    char    buf[32];

    m_pFileName = sName;

    if ((fp = fopen(sName, "rb")) == NULL)
        {
            fprintf(stderr, "Could not open binary file %s\n", sName);
            return false;
        }

    fseek(fp, 0, SEEK_END);
    long size = ftell(fp);

    // Allocate a buffer for the image
    m_pImage = new unsigned char[size];
    if (m_pImage == 0)
        {
            fprintf(stderr, "Could not allocate %ld bytes for image\n", size);
            return false;
        }
    memset(m_pImage, size, 0);

    fseek(fp, 0, SEEK_SET);
    if (fread(m_pImage, 1, size, fp) != (unsigned)size)
        {
            fprintf(stderr, "Error reading binary file %s\n", sName);
            return false;
        }

    // Check type at offset 0x3C; should be "appl" (or "palm"; ugh!)
    if ((strncmp((char*)(m_pImage+0x3C), "appl", 4) != 0) &&
            (strncmp((char*)(m_pImage+0x3C), "panl", 4) != 0) &&
            (strncmp((char*)(m_pImage+0x3C), "libr", 4) != 0))
        {
            fprintf(stderr, "%s is not a standard .prc file\n", sName);
            return false;
        }

    // Get the number of resource headers (one section per resource)
    m_iNumSections = (m_pImage[0x4C] << 8) + m_pImage[0x4D];

    // Allocate the section information
    m_pSections = new SectionInfo[m_iNumSections];
    if (m_pSections == 0)
        {
            fprintf(stderr, "Could not allocate section info array of %d items\n",
                    m_iNumSections);
            if (m_pImage)
                {
                    delete m_pImage;
                    m_pImage = 0;
                }
        }

    // Iterate through the resource headers (generating section info structs)
    unsigned char* p = m_pImage + 0x4E;          // First resource header
    unsigned off = 0;
    for (int i=0; i < m_iNumSections; i++)
        {
            // First get the name (4 alpha)
            strncpy(buf, (char*)p, 4);
            buf[4] = '\0';
            std::string name(buf);
            // Now get the identifier (2 byte binary)
            unsigned id = (p[4] << 8) + p[5];
            sprintf(buf, "%d", id);
            // Join the id to the name, e.g. code0, data12
            name += buf;
            m_pSections[i].pSectionName = new char[name.size()+1];
            strcpy(m_pSections[i].pSectionName, name.c_str());
            p += 4+2;
            off = UINT4(p);
            p += 4;
            m_pSections[i].uNativeAddr = off;
            m_pSections[i].uHostAddr = off + m_pImage;

            // Guess the length
            if (i > 0)
                {
                    m_pSections[i-1].uSectionSize = off - m_pSections[i-1].uNativeAddr;
                    m_pSections[i].uSectionEntrySize = 1;        // No info available
                }

            // Decide if code or data; note that code0 is a special case (not code)
            m_pSections[i].bCode =
                (name != "code0") && (name.substr(0, 4) == "code");
            m_pSections[i].bData = name.substr(0, 4) == "data";

        }

    // Set the length for the last section
    m_pSections[m_iNumSections-1].uSectionSize = size - off;

    // Create a separate, uncompressed, initialised data section
    SectionInfo* pData = GetSectionInfoByName("data0");
    if (pData == 0)
        {
            fprintf(stderr, "No data section!\n");
            return false;
        }

    SectionInfo* pCode0 = GetSectionInfoByName("code0");
    if (pCode0 == 0)
        {
            fprintf(stderr, "No code 0 section!\n");
            return false;
        }

    // When the info is all boiled down, the two things we need from the
    // code 0 section are at offset 0, the size of data above a5, and at
    // offset 4, the size below. Save the size below as a member variable
    m_SizeBelowA5 = UINT4(pCode0->uHostAddr+4);
    // Total size is this plus the amount above (>=) a5
    unsigned sizeData = m_SizeBelowA5 + UINT4(pCode0->uHostAddr);

    // Allocate a new data section
    m_pData = new unsigned char[sizeData];
    if (m_pData == 0)
        {
            fprintf(stderr, "Could not allocate %u bytes for data section\n",
                    sizeData);
        }

    // Uncompress the data. Skip first long (offset of CODE1 "xrefs")
    p = (unsigned char*)(pData->uHostAddr+4);
    int start = (int) UINT4(p);
    p += 4;
    unsigned char* q = (m_pData + m_SizeBelowA5 + start);
    bool done = false;
    while (!done && (p < (unsigned char*)(pData->uHostAddr +
                                          pData->uSectionSize)))
        {
            unsigned char rle = *p++;
            if (rle == 0)
                {
                    done = true;
                    break;
                }
            else if (rle == 1)
                {
                    // 0x01 b_0 b_1
                    // => 0x00 0x00 0x00 0x00 0xFF 0xFF b_0 b_1
                    *q++ = 0;
                    *q++ = 0;
                    *q++ = 0;
                    *q++ = 0;
                    *q++ = 0xFF;
                    *q++ = 0xFF;
                    *q++ = *p++;
                    *q++ = *p++;
                }
            else if (rle == 2)
                {
                    // 0x02 b_0 b_1 b_2
                    // => 0x00 0x00 0x00 0x00 0xFF b_0 b_1 b_2
                    *q++ = 0;
                    *q++ = 0;
                    *q++ = 0;
                    *q++ = 0;
                    *q++ = 0xFF;
                    *q++ = *p++;
                    *q++ = *p++;
                    *q++ = *p++;
                }
            else if (rle == 3)
                {
                    // 0x03 b_0 b_1 b_2
                    // => 0xA9 0xF0 0x00 0x00 b_0 b_1 0x00 b_2
                    *q++ = 0xA9;
                    *q++ = 0xF0;
                    *q++ = 0;
                    *q++ = 0;
                    *q++ = *p++;
                    *q++ = *p++;
                    *q++ = 0;
                    *q++ = *p++;
                }
            else if (rle == 4)
                {
                    // 0x04 b_0 b_1 b_2 b_3
                    // => 0xA9 axF0 0x00 b_0 b_1 b_3 0x00 b_3
                    *q++ = 0xA9;
                    *q++ = 0xF0;
                    *q++ = 0;
                    *q++ = *p++;
                    *q++ = *p++;
                    *q++ = *p++;
                    *q++ = 0;
                    *q++ = *p++;
                }
            else if (rle < 0x10)
                {
                    // 5-0xF are invalid.
                    assert(0);
                }
            else if (rle >= 0x80)
                {
                    // n+1 bytes of literal data
                    for (int k=0; k <= (rle-0x80); k++)
                        *q++ = *p++;
                }
            else if (rle >= 40)
                {
                    // n+1 repetitions of 0
                    for (int k=0; k <= (rle-0x40); k++)
                        *q++ = 0;
                }
            else if (rle >= 20)
                {
                    // n+2 repetitions of b
                    unsigned char b = *p++;
                    for (int k=0; k < (rle-0x20+2); k++)
                        *q++ = b;
                }
            else
                {
                    // 0x10: n+1 repetitions of 0xFF
                    for (int k=0; k <= (rle-0x10); k++)
                        *q++ = 0xFF;
                }
        }

    if (!done)
        fprintf(stderr, "Warning! Compressed data section premature end\n");
//printf("Used %u bytes of %u in decompressing data section\n",
//p-(unsigned char*)pData->uHostAddr, pData->uSectionSize);

    // Replace the data pointer and size with the uncompressed versions
    pData->uHostAddr = m_pData;
    pData->uSectionSize = sizeData;
    // May as well make the native address zero; certainly the offset in the
    // file is no longer appropriate (and is confusing)
    pData->uNativeAddr = 0;

    return true;
}