/** * Test the dominator frontier code. */ void CfgTest::testDominators() { #define FRONTIER_FOUR 0x08048347 #define FRONTIER_FIVE 0x08048351 #define FRONTIER_TWELVE 0x080483b2 #define FRONTIER_THIRTEEN 0x080483b9 auto prog = Prog::open(FRONTIER_PENTIUM); CPPUNIT_ASSERT(prog); auto fe = prog->getFrontEnd(); Type::clearNamedTypes(); fe->decode(); bool gotMain; ADDRESS addr = fe->getMainEntryPoint(gotMain); CPPUNIT_ASSERT(addr != NO_ADDRESS); UserProc *pProc = (UserProc *)prog->getProc(0); Cfg *cfg = pProc->getCFG(); DataFlow *df = pProc->getDataFlow(); df->dominators(cfg); // Find BB "5" (as per Appel, Figure 19.5). BasicBlock *bb = nullptr; for (const auto &b : *cfg) { if (b->getLowAddr() == FRONTIER_FIVE) { bb = b; break; } } CPPUNIT_ASSERT(bb); std::ostringstream expected, actual; #if 0 expected << std::hex << FRONTIER_FIVE << " " << FRONTIER_THIRTEEN << " " << FRONTIER_TWELVE << " " << FRONTIER_FOUR << " " << std::dec; #endif expected << std::hex << FRONTIER_THIRTEEN << " " << FRONTIER_FOUR << " " << FRONTIER_TWELVE << " " << FRONTIER_FIVE << " " << std::dec; int n5 = df->pbbToNode(bb); std::set<int> &DFset = df->getDF(n5); for (const auto &ii : DFset) actual << std::hex << (unsigned)df->nodeToBB(ii)->getLowAddr() << std::dec << " "; CPPUNIT_ASSERT_EQUAL(expected.str(), actual.str()); delete prog; }
/** * Test a case where semi dominators are different to dominators. */ void CfgTest::testSemiDominators() { #define SEMI_L 0x80483b0 #define SEMI_M 0x80483e2 #define SEMI_B 0x8048345 #define SEMI_D 0x8048354 #define SEMI_M 0x80483e2 auto prog = Prog::open(SEMI_PENTIUM); CPPUNIT_ASSERT(prog); auto fe = prog->getFrontEnd(); Type::clearNamedTypes(); fe->decode(); bool gotMain; ADDRESS addr = fe->getMainEntryPoint(gotMain); CPPUNIT_ASSERT(addr != NO_ADDRESS); UserProc *pProc = (UserProc *)prog->getProc(0); Cfg *cfg = pProc->getCFG(); DataFlow *df = pProc->getDataFlow(); df->dominators(cfg); // Find BB "L (6)" (as per Appel, Figure 19.8). BasicBlock *bb = nullptr; for (const auto &b : *cfg) { if (b->getLowAddr() == SEMI_L) { bb = b; break; } } CPPUNIT_ASSERT(bb); int nL = df->pbbToNode(bb); // The dominator for L should be B, where the semi dominator is D // (book says F) unsigned actual_dom = (unsigned)df->nodeToBB(df->getIdom(nL))->getLowAddr(); unsigned actual_semi = (unsigned)df->nodeToBB(df->getSemi(nL))->getLowAddr(); CPPUNIT_ASSERT_EQUAL((unsigned)SEMI_B, actual_dom); CPPUNIT_ASSERT_EQUAL((unsigned)SEMI_D, actual_semi); // Check the final dominator frontier as well; should be M and B std::ostringstream expected, actual; #if 0 expected << std::hex << SEMI_M << " " << SEMI_B << " " << std::dec; #endif expected << std::hex << SEMI_B << " " << SEMI_M << " " << std::dec; std::set<int> &DFset = df->getDF(nL); for (const auto &ii : DFset) actual << std::hex << (unsigned)df->nodeToBB(ii)->getLowAddr() << std::dec << " "; CPPUNIT_ASSERT_EQUAL(expected.str(), actual.str()); delete prog; }
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; }
void FrontEnd::decode(Prog* prog, bool decodeMain, const char *pname) { if (pname) {prog->setName(pname); std::cout<<"decode pname == "<<pname<<"\n"; } else {std::cout<<"decode pname==null\n";} if (!decodeMain) return; Boomerang::get()->alert_start_decode(pBF->getLimitTextLow(), pBF->getLimitTextHigh() - pBF->getLimitTextLow()); bool gotMain; ADDRESS a; a = getMainEntryPoint(gotMain); std::cout<< "start: " << a << " gotmain: " << (gotMain ? "true" : "false") << "\n"; if (VERBOSE) LOG << "start: " << a << " gotmain: " << (gotMain ? "true" : "false") << "\n"; if (a == NO_ADDRESS) { std::vector<ADDRESS> entrypoints = getEntryPoints(); for (std::vector<ADDRESS>::iterator it = entrypoints.begin(); it != entrypoints.end(); it++) decode(prog, *it); return; } decode(prog, a); prog->setEntryPoint(a); if (gotMain) { static const char *mainName[] = { "main", "WinMain", "DriverEntry" }; const char *name = pBF->SymbolByAddress(a); std::cout<<"Proc name "<<name<<"\n"; if (name == NULL) name = mainName[0]; for (size_t i = 0; i < sizeof(mainName)/sizeof(char*); i++) { if (!strcmp(name, mainName[i])) { Proc *proc = prog->findProc(a); if (proc == NULL) { if (VERBOSE) LOG << "no proc found for address " << a << "\n"; return; } FuncType *fty = dynamic_cast<FuncType*>(Type::getNamedType(name)); if (fty == NULL) LOG << "unable to find signature for known entrypoint " << name << "\n"; else { std::cout<<"Sig type:"<<fty->getSignature()->getReturns()[0]->type->prints(); proc->setSignature(fty->getSignature()->clone()); proc->getSignature()->setName(name); //proc->getSignature()->setFullSig(true); // Don't add or remove parameters proc->getSignature()->setForced(true); // Don't add or remove parameters } break; } } } return; }
std::vector<ADDRESS> FrontEnd::getEntryPoints() { std::vector<ADDRESS> entrypoints; bool gotMain = false; ADDRESS a = getMainEntryPoint(gotMain); if (a != NO_ADDRESS) entrypoints.push_back(a); else { // try some other tricks const char *fname = pBF->getFilename(); // X11 Module if (!strcmp(fname + strlen(fname) - 6, "_drv.o")) { const char *p = fname + strlen(fname) - 6; while (*p != '/' && *p != '\\' && p != fname) p--; if (p != fname) { p++; char *name = (char*)malloc(strlen(p) + 30); strcpy(name, p); name[strlen(name)-6] = 0; strcat(name, "ModuleData"); ADDRESS a = pBF->GetAddressByName(name, true); if (a != NO_ADDRESS) { ADDRESS vers, setup, teardown; vers = pBF->readNative4(a); setup = pBF->readNative4(a+4); teardown = pBF->readNative4(a+8); if (setup) { Type *ty = NamedType::getNamedType("ModuleSetupProc"); assert(ty->isFunc()); UserProc *proc = (UserProc*)prog->setNewProc(setup); assert(proc); Signature *sig = ty->asFunc()->getSignature()->clone(); const char *sym = pBF->SymbolByAddress(setup); if (sym) sig->setName(sym); sig->setForced(true); proc->setSignature(sig); entrypoints.push_back(setup); } if (teardown) { Type *ty = NamedType::getNamedType("ModuleTearDownProc"); assert(ty->isFunc()); UserProc *proc = (UserProc*)prog->setNewProc(teardown); assert(proc); Signature *sig = ty->asFunc()->getSignature()->clone(); const char *sym = pBF->SymbolByAddress(teardown); if (sym) sig->setName(sym); sig->setForced(true); proc->setSignature(sig); entrypoints.push_back(teardown); } } } } // Linux kernel module if (!strcmp(fname + strlen(fname) - 3, ".ko")) { a = pBF->GetAddressByName("init_module"); if (a != NO_ADDRESS) entrypoints.push_back(a); a = pBF->GetAddressByName("cleanup_module"); if (a != NO_ADDRESS) entrypoints.push_back(a); } } return entrypoints; }