Example #1
0
QStringList MemoryMap::loadedKernelModules()
{
    QStringList ret;
    const MemoryDump* mem = _symbols->memDumps().at(_vmem->memDumpIndex());
    Instance modules = mem->queryInstance("modules", ksNone);
    const Structured* module_t = dynamic_cast<const Structured*>(
                factory()->findBaseTypeByName("module"));

    if (modules.isValid() && module_t) {
        // First module in the list
        Instance m = modules.member("next", BaseType::trAny, 1, ksNone);
        qint64 offset = -module_t->memberOffset("list");
        // Go through linked list and add all module names
        while (m.isValid() && m.address() != modules.address()) {
            m.setType(module_t);
            m.addToAddress(offset);
            QString name = m.member("name").toString();
            if (!name.isEmpty()) {
                // Get rid of quotes
                if (name.startsWith('"'))
                    name = name.mid(1, name.size() - 2);
                // Module binaries use dashes, the names use underscores
                name.replace('_', "-");
                ret += name + ".ko";
            }
            m = m.member("list").member("next", BaseType::trAny, 1, ksNone);
        }
    }

    return ret;
}
void MemoryMapBuilderCS::processInstance(const Instance &inst, MemoryMapNode *node,
                                         VariableTypeContainerList *path)
{
    // Ignore user-land objects
    if (inst.address() < _map->_vmem->memSpecs().pageOffset)
        return;

    // Ignore instances which we cannot access
    if (!inst.isValid() || !inst.isAccessible())
        return;

    try {
        if (MemoryMapHeuristics::isFunctionPointer(inst))
            processFunctionPointer(inst, node, path);
        else if (inst.type()->type() & rtPointer)
            processPointer(inst, node);
        else if (inst.type()->type() & rtArray)
            processArray(inst, node, path);
        else if (inst.type()->type() & StructOrUnion)
            processStructured(inst, node, path);
    }
    catch (GenericException&) {
        // Do nothing
    }
}
Example #3
0
QString MemoryDump::query(const int queryId, const ColorPalette& col,
                          KnowledgeSources src) const
{
    QString ret;

    Instance instance = queryInstance(queryId, src);

    QString s = QString("%1%2%3%4: ")
            .arg(col.color(ctTypeId))
            .arg("0x")
            .arg(queryId, 0, 16)
            .arg(col.color(ctReset));
    if (instance.isValid()) {
        s += QString("%1%2%3 (ID%4 0x%5%6)")
                .arg(col.color(ctType))
                .arg(instance.typeName())
                .arg(col.color(ctReset))
                .arg(col.color(ctTypeId))
                .arg((uint)instance.type()->id(), 0, 16)
                .arg(col.color(ctReset));
        ret = instance.toString(&col);
    }
    else
        s += "(unresolved type)";
    s += QString(" @%1 0x%2%3\n")
            .arg(col.color(ctAddress))
            .arg(instance.address(), _specs.sizeofPointer << 1, 16, QChar('0'))
            .arg(col.color(ctReset));

    ret = s + ret;

    return ret;
}
Example #4
0
QString MemoryDump::query(const QString& queryString,
                          const ColorPalette& col, KnowledgeSources src) const
{
    QString ret;

    if (queryString.isEmpty()) {
        // Generate a list of all global variables
        for (int i = 0; i < _factory->vars().size(); i++) {
            if (i > 0)
                ret += "\n";
            Variable* var = _factory->vars().at(i);
            ret += var->prettyName();
        }
    }
    else {
        Instance instance = queryInstance(queryString, src);

        QString s = QString("%1%2%3: ")
                .arg(col.color(ctBold))
                .arg(queryString)
                .arg(col.color(ctReset));
        if (instance.isValid()) {
            s += QString("%1%2%3 (ID%4 0x%5%6)")
                    .arg(col.color(ctType))
                    .arg(instance.typeName())
                    .arg(col.color(ctReset))
                    .arg(col.color(ctTypeId))
                    .arg((uint)instance.type()->id(), 0, 16)
                    .arg(col.color(ctReset));
            if (instance.isNull())
                ret = QString(col.color(ctAddress)) + "NULL" + QString(col.color(ctReset));
            else {
                ret = instance.toString(&col);
            }
        }
        else
            s += "(unresolved type)";

        s += QString(" @%1 0x%2%3")
                .arg(col.color(ctAddress))
                .arg(instance.address(), _specs.sizeofPointer << 1, 16, QChar('0'))
                .arg(col.color(ctReset));

        if (instance.bitSize() >= 0) {
            s += QString("[%1%3%2:%1%4%2]")
                    .arg(col.color(ctOffset))
                    .arg(col.color(ctReset))
                    .arg((instance.size() << 3) - instance.bitOffset() - 1)
                    .arg((instance.size() << 3) - instance.bitOffset() -
                         instance.bitSize());

        }

        ret = s + "\n" + ret;
    }


    return ret;
}
void MemoryMapBuilderCS::processStructured(const Instance& inst,
                                           MemoryMapNode *node,
                                           VariableTypeContainerList *path)
{
    assert(inst.type()->type() & StructOrUnion);

    // Ignore non-nested structs/unions that are not aligned at a four-byte
    // boundary
    if (!path && (inst.address() & 0x3ULL))
        return;

    addMembers(inst, node, path);
}
Example #6
0
MemMapList MemoryMap::findAllNodes(const Instance& origInst,
                                   const InstanceList &candidates) const
{
    // Find all nodes in the affected memory ranges
    MemMapList nodes;
    quint64 addrStart = origInst.address(),
            addrEnd = addrStart ? origInst.endAddress() : 0;

    for (int i = 0; i < candidates.size(); ++i) {
        quint64 c_start = candidates[i].address();
        quint64 c_end   = candidates[i].endAddress();
        // If the interval is invalid, initialize it
        if (!addrStart && !addrEnd) {
            if ( (addrStart = c_start) )
                addrEnd = c_end;
            else
                continue;
        }

        // If the memory regions overlap, we enlarge the interval
        bool overlap = false;
        if (c_start < addrStart) {
            if (addrStart <= c_end) {
                overlap = true;
                addrStart = c_start;
                addrEnd = qMax(addrEnd, c_end);
            }
        }
        else if (c_start <= addrEnd) {
            overlap = true;
            addrEnd = qMax(c_end, addrEnd);
        }
        // If we have a valid interval, append all nodes and reset it to zero
        if (!overlap && (addrStart || addrEnd)) {
            _shared->vmemMapLock.lockForRead();
            nodes += _vmemMap.objectsInRangeFast(addrStart, addrEnd);
            _shared->vmemMapLock.unlock();
            addrStart = c_start;
            addrEnd = c_end;
        }
    }

    // Request nodes from the final interval
    if (addrStart || addrEnd) {
        _shared->vmemMapLock.lockForRead();
        nodes += _vmemMap.objectsInRangeFast(addrStart, addrEnd);
        _shared->vmemMapLock.unlock();
    }

    return nodes;
}
float MemoryMapBuilderCS::calculateNodeProb(const Instance &inst,
                                            float parentProbability,
                                            MemoryMap *map)
{
//    if (inst.type()->name() == "sysfs_dirent")
//        debugmsg("Calculating prob. of " << inst.typeName());

    // Degradation of 0.1% per parent-child relation.
    static const float degPerGeneration = 0.00001;
//    static const float degPerGeneration = 0.0;

    // Degradation of 20% for objects not matching the magic numbers
    static const float degForInvalidMagicNumbers = 0.3;

    // Degradation of 5% for address begin in userland
//    static const float degForUserlandAddr = 0.05;

    // Degradation of 90% for an invalid address of this node
    static const float degForInvalidAddr = 0.9;

//    // Max. degradation of 30% for non-aligned pointer childen the type of this
//    // node has
//    static const float degForNonAlignedChildAddr = 0.3;

    // Max. degradation of 80% for invalid pointer childen the type of this node
    // has
    static const float degForInvalidChildAddr = 0.8;

    // Invalid Instance degradation - 99%
    static const float degInvalidInstance = 0.99;

//    // Invalid Pointer degradation - 90%
//    static const float degInvalidPointer = 0.1;

    float prob = parentProbability < 0 ?
                 1.0 :
                 parentProbability * (1.0 - degPerGeneration);

    if (map && parentProbability >= 0)
        map->_shared->degPerGenerationCnt++;

    // Is the instance valid?
    if (!MemoryMapHeuristics::isValidInstance(inst)) {
        // Instance is invalid, so do not check futher
        return (prob * (1.0 - degInvalidInstance));
    }

    // Find the BaseType of this instance, dereference any lexical type(s)
    const BaseType* instType =
            inst.type()->dereferencedBaseType(BaseType::trLexical);

    // Function Pointer ?
    if (MemoryMapHeuristics::isFunctionPointer(inst)) {
        if (!MemoryMapHeuristics::isValidFunctionPointer(inst))
            // Invalid function pointer that has no default value
            return (prob * (1.0 - degForInvalidAddr));

        return prob;
    }
    // Pointer ?
    else if (instType && instType->type() & rtPointer) {
        // Verify. Default values are fine.
        if (!MemoryMapHeuristics::isValidPointer(inst))
            // Invalid pointer that has no default value
            return (prob * (1.0 - degForInvalidAddr));

        return prob;
    }
    // If this a union or struct, we have to consider the pointer members
    // For unions, the largest prob. of all children is taken
    else if ( instType && (instType->type() & StructOrUnion) ) {

        if (!inst.isValidConcerningMagicNumbers())
            prob *= (1.0 - degForInvalidMagicNumbers);

        int testedChildren = 0;
        int invalidChildren = countInvalidChildren(
                    inst.dereference(BaseType::trLexical), &testedChildren);

        // A count < 0 results from an invalid list_head
        if (invalidChildren < 0) {
            return (prob * (1.0 - degInvalidInstance));
        }
        else if (invalidChildren > 0) {
            float invalidPct = invalidChildren / (float) testedChildren;
            prob *= invalidPct * (1.0 - degForInvalidChildAddr) + (1.0 - invalidPct);

            if (map)
                map->_shared->degForInvalidChildAddrCnt++;
        }
    }

    if (prob < 0 || prob > 1) {
        debugerr("Probability for of type '" << inst.typeName() << "' at 0x"
                 << QString::number(inst.address(), 16) << " is " << prob
                 << ", should be between 0 and 1.");
        prob = 0; // Make it safe
    }

    return prob;
}
Example #8
0
QString MemoryDump::dump(const QString& type, quint64 address, int length,
                         const ColorPalette& col) const
{
    if (type == "char") {
        char c;
        if (_vmem->readAtomic(address, &c, sizeof(char)) != sizeof(char))
            queryError(QString("Cannot read memory from address 0x%1")
                       .arg(address, (_specs.sizeofPointer << 1), 16, QChar('0')));
        return QString("%1 (0x%2)").arg(c).arg(c, (sizeof(c) << 1), 16, QChar('0'));
    }
    if (type == "int") {
        qint32 i;
        if (_vmem->readAtomic(address, (char*)&i, sizeof(qint32)) != sizeof(qint32))
            queryError(QString("Cannot read memory from address 0x%1")
                       .arg(address, (_specs.sizeofPointer << 1), 16, QChar('0')));
        return QString("%1 (0x%2)").arg(i).arg((quint32)i, (sizeof(i) << 1), 16, QChar('0'));
    }
    if (type == "long") {
        qint64 l;
        if (_vmem->readAtomic(address, (char*)&l, sizeof(qint64)) != sizeof(qint64))
            queryError(QString("Cannot read memory from address 0x%1")
                       .arg(address, (_specs.sizeofPointer << 1), 16, QChar('0')));
        return QString("%1 (0x%2)").arg(l).arg((quint64)l, (sizeof(l) << 1), 16, QChar('0'));
    }
    if (type == "raw" || type == "hex") {
        QString ret;
        const int buflen = 256, linelen = 16;
        char buf[buflen];
        char bufstr[linelen + 1] = {0};

        // Make sure we got a valid length
        if (length < 0)
            queryError(QString("No valid length given for dumping raw memory"));

        int totalBytesRead = 0, col = 0;
        while (length > 0) {
            int bytesRead = _vmem->readAtomic(address, buf, qMin(buflen, length));
            length -= bytesRead;

            int i = 0;
            while (i < bytesRead) {
                // New line every 16 bytes begins with address
                if (totalBytesRead % 16 == 0) {
                    if (totalBytesRead > 0) {
                        ret += QString("  |%0|\n").arg(bufstr, -linelen);
                        memset(bufstr, 0, linelen + 1);
                        col = 0;
                    }
                    ret += QString("%1 ").arg(address, _specs.sizeofPointer << 1, 16, QChar('0'));
                }

                // Wider column after 8 bytes
                if (totalBytesRead % 8 == 0)
                    ret += ' ';
                // Write the character as hex string
                if ((unsigned char)buf[i] < 16)
                    ret += '0';
                ret += QString::number((unsigned char)buf[i], 16) + ' ';
                // Add character to string buffer, if it's an ASCII char
                if ( ((unsigned char)buf[i] >= 32) && ((unsigned char)buf[i] < 127) )
                    bufstr[col] = buf[i];
                else
                    bufstr[col] = '.';

                ++col;
                ++totalBytesRead;
                ++address;
                ++i;
            }
        }

        // Finish it up
        if (col > 0) {
            while (col < linelen) {
                ret += "   ";
                if (col % 8 == 0)
                    ret += ' ';
                ++col;
            }
            ret += QString("  |%0|").arg(bufstr, -linelen);
        }

        return ret;
    }

	QStringList components = type.split('.', QString::SkipEmptyParts);
	Instance result;
	
    if (!components.isEmpty()) {
		// Get first instance
		result = getInstanceAt(components.first(), address, QStringList("user"));
		components.pop_front();
	
		while (!components.isEmpty()) {
			result = getNextInstance(components.first(), result, ksNone);
			components.pop_front();
		}
			
		return QString("%1%2%3 (ID%4 0x%5%6) @%7 0x%8%9\n")
				.arg(col.color(ctType))
				.arg(result.typeName())
				.arg(col.color(ctReset))
				.arg(col.color(ctTypeId))
				.arg((uint)result.type()->id(), 0, 16)
				.arg(col.color(ctReset))
				.arg(col.color(ctAddress))
				.arg(result.address(), 0, 16)
				.arg(col.color(ctReset)) + result.toString(&col);
	}

    queryError3("Unknown type: " + type,
    		QueryException::ecUnresolvedType, type);

    return QString();
}
Example #9
0
Instance MemoryDump::getNextInstance(const QString& component,
									 const Instance& instance,
									 KnowledgeSources src) const
{
	Instance result;
	QString typeString, symbol, offsetString, candidate, arrayIndexString;
	bool okay;
//    quint32 compatibleCnt = 0;

	// A component should have the form (symbol(-offset)?)?symbol(<candidate>)?([index])?
#define SYMBOL "[A-Za-z0-9_]+"
#define NUMBER "\\d+"
	QRegExp re(
				"^\\s*(?:"
					"\\(\\s*"
						"(" SYMBOL ")"
						"(?:"
							"\\s*-\\s*(" SYMBOL ")"
						")?"
					"\\s*\\)"
				")?"
				"\\s*(" SYMBOL ")\\s*"
				"(?:<\\s*(" NUMBER ")\\s*>\\s*)?"
				"((?:\\[\\s*" NUMBER "\\s*\\]\\s*)*)\\s*");
	 
	if (!re.exactMatch(component)) {
		queryError(QString("Could not parse a part of the query string: %1")
		            .arg(component));
    }
	
	// Set variables according to the matching
	typeString = re.cap(1);
	offsetString = re.cap(2).trimmed();
	symbol = re.cap(3);
	candidate = re.cap(4);
	arrayIndexString = re.cap(5).trimmed();

	int candidateIndex = candidate.isEmpty() ? -1 : candidate.toInt();

//	debugmsg(QString("1: %1, 2: %2, 3: %3, 4: %4, 5: %5")
//			 .arg(re.cap(1))
//			 .arg(re.cap(2))
//			 .arg(re.cap(3))
//			 .arg(re.cap(4))
//			 .arg(re.cap(5)));

	// A candidate index of 0 means to ignore the alternative types
	if (candidateIndex == 0)
		src = static_cast<KnowledgeSources>(src|ksNoAltTypes);

	// If the given instance is Null, we interpret this as the first component
	// in the query string and will therefore try to resolve the variable.
	if (!instance.isValid()) {
		 Variable* v = _factory->findVarByName(symbol);

		if (!v)
			queryError(QString("Variable does not exist: %1").arg(symbol));

		if (candidateIndex > 0) {
			if (v->altRefTypeCount() < candidateIndex)
				queryError(QString("Variable \"%1\" does not have a candidate "
								   "with index %2")
							.arg(symbol)
							.arg(candidateIndex));
			result = v->altRefTypeInstance(_vmem, candidateIndex - 1);
		}
		else {
			result = v->toInstance(_vmem, BaseType::trLexical, src);
		}
	}
	else {
		// Dereference any pointers/arrays first
		result = instance.dereference(BaseType::trAnyNonNull);

		// Did we get a null instance?
		if (!(result.type()->type() & StructOrUnion) &&
			(result.isNull() || !result.toPointer()))
			queryError(QString("Member \"%1\" is null")
					   .arg(result.fullName()));
		// We have a instance therefore we resolve the member
		if (!(result.type()->type() & StructOrUnion))
            queryError(QString("Member \"%1\" is not a struct or union")
                        .arg(result.fullName()));

        if (!result.memberExists(symbol))
            queryError(QString("Struct \"%1\" has no member named \"%2\"")
                        .arg(result.typeName())
                        .arg(symbol));

        // Do we have a candidate index?
        if (candidateIndex > 0) {
            if (result.memberCandidatesCount(symbol) < candidateIndex)
                queryError(QString("Member \"%1\" does not have a candidate "
                                   "with index %2")
                            .arg(symbol)
                            .arg(candidateIndex));
            result = result.memberCandidate(symbol, candidateIndex - 1);
        }
        else {
            result = result.member(symbol, BaseType::trLexical, 0, src);
        }
	}

	if (!result.isValid())
		return result;
	
	// Cast the instance if necessary
	if (!typeString.isEmpty()) {
		quint32 offset = 0;
		// Is a offset given?
		if (!offsetString.isEmpty()) {
			// Is the offset given as string or as int?
			offset = offsetString.toUInt(&okay, 10);
			
			if (!okay) {
				// String.
				BaseType* type = getType(typeString);
				
				if (!type ||
					!(type->type() & StructOrUnion))
					queryError(QString("The given type \"%1\" is not a struct "
					            "or union and therefore has no offset")
					            .arg(typeString));
				
				Structured* structd = dynamic_cast<Structured *>(type);
				
				if (!structd->memberExists(offsetString)) {
					queryError(QString("Struct of type \"%1\" has no member "
					            "named \"%2\"")
								.arg(typeString)
								.arg(offsetString));
				}
				else {
					StructuredMember* structdMember =
							structd->member(offsetString);
					offset = structdMember->offset();
				}
			}
		}

		// Get address
		size_t address;
		if (result.type()->type() & (rtPointer))
			address = (size_t)result.toPointer() - offset;
		else
			address = result.address() - offset;
		
		result = getInstanceAt(typeString, address, result.fullNameComponents());
	}
	
	// Add array index
	if (!arrayIndexString.isEmpty()) {
		QRegExp reArrayIndex("\\[\\s*(" NUMBER ")\\s*\\]\\s*");
		QStringList matches;
		int strpos = 0;
		while (strpos < arrayIndexString.size() &&
			   (strpos = arrayIndexString.indexOf(reArrayIndex, strpos)) >= 0)
		{
			matches.append(reArrayIndex.cap(1));
			strpos += reArrayIndex.cap(0).size();
		}

		for (int i = 0; i < matches.count(); ++i) {
			quint32 arrayIndex = matches[i].toUInt(&okay, 10);

			if (okay) {
				// Is the result already an instance list?
				if (result.isList()) {
					InstanceList list(result.toList());
					if (arrayIndex < (quint32)list.size())
						result = list[arrayIndex];
					else
						queryError(QString("Given array index %1 is out of bounds.")
								   .arg(arrayIndex));
				}
				else {
					// Is this a pointer or an array type?
					Instance tmp = result.arrayElem(arrayIndex);
					if (!tmp.isNull())
						result = tmp.dereference(BaseType::trLexical);
					// Manually update the address
					else {
						result.addToAddress(arrayIndex * result.type()->size());
						result.setName(QString("%1[%2]").arg(result.name()).arg(arrayIndex));
					}
				}
			}
			else {
				queryError(QString("Given array index %1 could not be converted "
								   "to a number.")
						   .arg(matches[i]));
			}
		}
		
	}
	// Try to dereference this instance as deep as possible
	return result.dereference(BaseType::trLexicalAndPointers);
}