// Specific to BinaryFile objects that implement a "global pointer" // Gets a pair of unsigned integers representing the address of %agp, // and the value for GLOBALOFFSET. For Palm, the latter is the amount of // space allocated below %a5, i.e. the difference between %a5 and %agp // (%agp points to the bottom of the global data area). std::pair<unsigned,unsigned> PalmBinaryFile::GetGlobalPointerInfo() { unsigned agp = 0; const SectionInfo* ps = GetSectionInfoByName("data0"); if (ps) agp = ps->uNativeAddr; std::pair<unsigned, unsigned> ret(agp, m_SizeBelowA5); return ret; }
// This is provided for completeness only... std::list<SectionInfo*>& PalmBinaryFile::GetEntryPoints(const char* pEntry /* = "main" */) { std::list<SectionInfo*>* ret = new std::list<SectionInfo*>; SectionInfo* pSect = GetSectionInfoByName("code1"); if (pSect == 0) return *ret; // Failed ret->push_back(pSect); return *ret; }
// This is provided for completeness only... std::list<SectionInfo*>& ExeBinaryFile::GetEntryPoints(const char* pEntry /* = "main"*/) { std::list<SectionInfo*>* ret = new std::list<SectionInfo*>; #if 0 // Copied from PalmBinaryFile.cc SectionInfo* pSect = GetSectionInfoByName("code1"); if (pSect == 0) return *ret; // Failed ret->push_back(pSect); #endif return *ret; }
// Find the native address for the start of the main entry function. // For Palm binaries, this is PilotMain. ADDRESS PalmBinaryFile::GetMainEntryPoint() { SectionInfo* pSect = GetSectionInfoByName("code1"); if (pSect == 0) return 0; // Failed // Return the start of the code1 section SWord* startCode = (SWord*) pSect->uHostAddr; ptrdiff_t delta = pSect->uHostAddr - (unsigned char *)pSect->uNativeAddr; // First try the CW first jump pattern SWord* res = findPattern(startCode, CWFirstJump, sizeof(CWFirstJump) / sizeof(SWord), 1); if (res) { // We have the code warrior first jump. Get the addil operand int addilOp = (startCode[5] << 16) + startCode[6]; SWord* startupCode = (SWord*)((unsigned char *)startCode + 10 + addilOp); // Now check the next 60 SWords for the call to PilotMain res = findPattern(startupCode, CWCallMain, sizeof(CWCallMain) / sizeof(SWord), 60); if (res) { // Get the addil operand addilOp = (res[5] << 16) + res[6]; // That operand plus the address of that operand is PilotMain return (ADDRESS)res + 10 + addilOp - delta; } else { fprintf( stderr, "Could not find call to PilotMain in CW app\n" ); return 0; } } // Check for gcc call to main res = findPattern(startCode, GccCallMain, sizeof(GccCallMain) / sizeof(SWord), 75); if (res) { // Get the operand to the bsr SWord bsrOp = res[7]; return (ADDRESS)res + 14 + bsrOp - delta; } fprintf(stderr,"Cannot find call to PilotMain\n"); return 0; }
ADDRESS DOS4GWBinaryFile::GetMainEntryPoint() { ADDRESS aMain = GetAddressByName ("main", true); if (aMain != NO_ADDRESS) return aMain; aMain = GetAddressByName ("__CMain", true); if (aMain != NO_ADDRESS) return aMain; // Search with this crude pattern: call, sub ebp, ebp, call __Cmain in the first 0x300 bytes // Start at program entry point unsigned p = LMMH(m_pLXHeader->eip); unsigned lim = p + 0x300; unsigned char op1, op2; ADDRESS addr; //unsigned lastOrdCall = 0; //TODO: identify the point of setting this variable bool gotSubEbp = false; // True if see sub ebp, ebp bool lastWasCall = false; // True if the last instruction was a call SectionInfo* si = GetSectionInfoByName("seg0"); // Assume the first section is text if (si == nullptr) si = GetSectionInfoByName(".text"); if (si == nullptr) si = GetSectionInfoByName("CODE"); assert(si); ADDRESS nativeOrigin = si->uNativeAddr; unsigned textSize = si->uSectionSize; if (textSize < 0x300) lim = p + textSize; while (p < lim) { op1 = *(unsigned char*)(p + base); op2 = *(unsigned char*)(p + base + 1); //std::cerr << std::hex << "At " << p << ", ops " << (unsigned)op1 << ", " << (unsigned)op2 << std::dec << "\n"; switch (op1) { case 0xE8: { // An ordinary call if (gotSubEbp) { // This is the call we want. Get the offset from the call instruction addr = nativeOrigin + p + 5 + LMMH(*(p + base + 1)); // std::cerr << "__CMain at " << std::hex << addr << "\n"; return addr; } //lastOrdCall = p; lastWasCall = true; break; } case 0x2B: // 0x2B 0xED is sub ebp,ebp if (op2 == 0xED && lastWasCall) gotSubEbp = true; lastWasCall = false; break; default: gotSubEbp = false; lastWasCall = false; break; case 0xEB: // Short relative jump if (op2 >= 0x80) // Branch backwards? break; // Yes, just ignore it // Otherwise, actually follow the branch. May have to modify this some time... p += op2+2; // +2 for the instruction itself, and op2 for the displacement continue; // Don't break, we have the new "pc" set already } int size = microX86Dis(p + base); if (size == 0x40) { fprintf(stderr, "Warning! Microdisassembler out of step at offset 0x%x\n", p); size = 1; } p += size; } return NO_ADDRESS; }
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; }