forked from qt-creator/qt-creator
Code Cleanup: Remove sharedlibraryinjector.
Make NameDemangler's message non-translateable.
This commit is contained in:
@@ -31,17 +31,15 @@
|
|||||||
**
|
**
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
|
#include "name_demangler.h"
|
||||||
|
|
||||||
#include <QtCore/QChar>
|
#include <QtCore/QChar>
|
||||||
#include <QtCore/QCoreApplication>
|
|
||||||
#include <QtCore/QLatin1String>
|
|
||||||
#include <QtCore/QMap>
|
#include <QtCore/QMap>
|
||||||
#include <QtCore/QRegExp>
|
#include <QtCore/QRegExp>
|
||||||
#include <QtCore/QSet>
|
#include <QtCore/QSet>
|
||||||
#include <QtCore/QString>
|
#include <QtCore/QString>
|
||||||
#include <QtCore/QStringList>
|
#include <QtCore/QStringList>
|
||||||
|
|
||||||
#include "name_demangler.h"
|
|
||||||
|
|
||||||
// Debugging facility.
|
// Debugging facility.
|
||||||
//#define DO_TRACE
|
//#define DO_TRACE
|
||||||
#ifdef DO_TRACE
|
#ifdef DO_TRACE
|
||||||
@@ -59,7 +57,6 @@ namespace Internal {
|
|||||||
|
|
||||||
class NameDemanglerPrivate
|
class NameDemanglerPrivate
|
||||||
{
|
{
|
||||||
Q_DECLARE_TR_FUNCTIONS(NameDemanglerPrivate)
|
|
||||||
public:
|
public:
|
||||||
NameDemanglerPrivate();
|
NameDemanglerPrivate();
|
||||||
~NameDemanglerPrivate();
|
~NameDemanglerPrivate();
|
||||||
@@ -332,7 +329,7 @@ bool NameDemanglerPrivate::demangle(const QString &mangledName)
|
|||||||
if (m_demangledName.startsWith(QLatin1String("::")))
|
if (m_demangledName.startsWith(QLatin1String("::")))
|
||||||
m_demangledName.remove(0, 2);
|
m_demangledName.remove(0, 2);
|
||||||
if (!parseError && pos != mangledName.size())
|
if (!parseError && pos != mangledName.size())
|
||||||
error(tr("Premature end of input"));
|
error(QString::fromLatin1("Premature end of input"));
|
||||||
|
|
||||||
#ifdef DO_TRACE
|
#ifdef DO_TRACE
|
||||||
qDebug("%d", substitutions.size());
|
qDebug("%d", substitutions.size());
|
||||||
@@ -422,7 +419,7 @@ const QString NameDemanglerPrivate::parseEncoding()
|
|||||||
} else if (firstSetSpecialName.contains(next)) {
|
} else if (firstSetSpecialName.contains(next)) {
|
||||||
encoding = parseSpecialName();
|
encoding = parseSpecialName();
|
||||||
} else {
|
} else {
|
||||||
error(tr("Invalid encoding"));
|
error(QString::fromLatin1("Invalid encoding"));
|
||||||
}
|
}
|
||||||
|
|
||||||
FUNC_END(encoding);
|
FUNC_END(encoding);
|
||||||
@@ -476,7 +473,7 @@ const QString NameDemanglerPrivate::parseName()
|
|||||||
} else if (firstSetLocalName.contains(next)) {
|
} else if (firstSetLocalName.contains(next)) {
|
||||||
name = parseLocalName();
|
name = parseLocalName();
|
||||||
} else {
|
} else {
|
||||||
error(tr("Invalid name"));
|
error(QString::fromLatin1("Invalid name"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -516,7 +513,7 @@ const QString NameDemanglerPrivate::parseNestedName()
|
|||||||
|
|
||||||
QString name;
|
QString name;
|
||||||
if (advance() != 'N') {
|
if (advance() != 'N') {
|
||||||
error(tr("Invalid nested-name"));
|
error(QString::fromLatin1("Invalid nested-name"));
|
||||||
} else {
|
} else {
|
||||||
QString cvQualifiers;
|
QString cvQualifiers;
|
||||||
if (firstSetCvQualifiers.contains(peek()) && peek(1) != 'm'
|
if (firstSetCvQualifiers.contains(peek()) && peek(1) != 'm'
|
||||||
@@ -525,7 +522,7 @@ const QString NameDemanglerPrivate::parseNestedName()
|
|||||||
if (!parseError) {
|
if (!parseError) {
|
||||||
name = parsePrefix();
|
name = parsePrefix();
|
||||||
if (!parseError && advance() != 'E')
|
if (!parseError && advance() != 'E')
|
||||||
error(tr("Invalid nested-name"));
|
error(QString::fromLatin1("Invalid nested-name"));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These are member function qualifiers which will have to
|
* These are member function qualifiers which will have to
|
||||||
@@ -636,7 +633,7 @@ const QString NameDemanglerPrivate::parseTemplateArgs()
|
|||||||
|
|
||||||
QString args = QLatin1String("<");
|
QString args = QLatin1String("<");
|
||||||
if (advance() != 'I') {
|
if (advance() != 'I') {
|
||||||
error(tr("Invalid template args"));
|
error(QString::fromLatin1("Invalid template args"));
|
||||||
} else {
|
} else {
|
||||||
do {
|
do {
|
||||||
if (args.length() > 1)
|
if (args.length() > 1)
|
||||||
@@ -644,7 +641,7 @@ const QString NameDemanglerPrivate::parseTemplateArgs()
|
|||||||
args += parseTemplateArg();
|
args += parseTemplateArg();
|
||||||
} while (!parseError && firstSetTemplateArg.contains(peek()));
|
} while (!parseError && firstSetTemplateArg.contains(peek()));
|
||||||
if (!parseError && advance() != 'E')
|
if (!parseError && advance() != 'E')
|
||||||
error(tr("Invalid template args"));
|
error(QString::fromLatin1("Invalid template args"));
|
||||||
}
|
}
|
||||||
|
|
||||||
args += '>';
|
args += '>';
|
||||||
@@ -662,7 +659,7 @@ const QString NameDemanglerPrivate::parseTemplateParam()
|
|||||||
|
|
||||||
QString param;
|
QString param;
|
||||||
if (advance() != 'T') {
|
if (advance() != 'T') {
|
||||||
error(tr("Invalid template-param"));
|
error(QString::fromLatin1("Invalid template-param"));
|
||||||
} else {
|
} else {
|
||||||
int index;
|
int index;
|
||||||
if (peek() == '_')
|
if (peek() == '_')
|
||||||
@@ -670,7 +667,7 @@ const QString NameDemanglerPrivate::parseTemplateParam()
|
|||||||
else
|
else
|
||||||
index = parseNonNegativeNumber() + 1;
|
index = parseNonNegativeNumber() + 1;
|
||||||
if (!parseError && advance() != '_')
|
if (!parseError && advance() != '_')
|
||||||
error(tr("Invalid template-param"));
|
error(QString::fromLatin1("Invalid template-param"));
|
||||||
param = templateParams.at(index);
|
param = templateParams.at(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -689,7 +686,7 @@ const QString NameDemanglerPrivate::parseCvQualifiers()
|
|||||||
while (true) {
|
while (true) {
|
||||||
if (peek() == 'V') {
|
if (peek() == 'V') {
|
||||||
if (volatileFound || constFound) {
|
if (volatileFound || constFound) {
|
||||||
error(tr("Invalid qualifiers: unexpected 'volatile'"));
|
error(QString::fromLatin1("Invalid qualifiers: unexpected 'volatile'"));
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
volatileFound = true;
|
volatileFound = true;
|
||||||
@@ -698,7 +695,7 @@ const QString NameDemanglerPrivate::parseCvQualifiers()
|
|||||||
}
|
}
|
||||||
} else if (peek() == 'K') {
|
} else if (peek() == 'K') {
|
||||||
if (constFound) {
|
if (constFound) {
|
||||||
error(tr("Invalid qualifiers: 'const' appears twice"));
|
error(QString::fromLatin1("Invalid qualifiers: 'const' appears twice"));
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
constFound = true;
|
constFound = true;
|
||||||
@@ -741,7 +738,7 @@ int NameDemanglerPrivate::parseNonNegativeNumber(int base)
|
|||||||
advance();
|
advance();
|
||||||
int number;
|
int number;
|
||||||
if (pos == startPos) {
|
if (pos == startPos) {
|
||||||
error(tr("Invalid non-negative number"));
|
error(QString::fromLatin1("Invalid non-negative number"));
|
||||||
number = 0;
|
number = 0;
|
||||||
} else {
|
} else {
|
||||||
number = mangledName.mid(startPos, pos - startPos).toInt(0, base);
|
number = mangledName.mid(startPos, pos - startPos).toInt(0, base);
|
||||||
@@ -799,7 +796,7 @@ const QString NameDemanglerPrivate::parseTemplateArg()
|
|||||||
advance();
|
advance();
|
||||||
arg = parseExpression();
|
arg = parseExpression();
|
||||||
if (!parseError && advance() != 'E')
|
if (!parseError && advance() != 'E')
|
||||||
error(tr("Invalid template-arg"));
|
error(QString::fromLatin1("Invalid template-arg"));
|
||||||
} else if (next == 'I') {
|
} else if (next == 'I') {
|
||||||
advance();
|
advance();
|
||||||
while (!parseError && firstSetTemplateArg.contains(peek())) {
|
while (!parseError && firstSetTemplateArg.contains(peek())) {
|
||||||
@@ -808,9 +805,9 @@ const QString NameDemanglerPrivate::parseTemplateArg()
|
|||||||
arg += parseTemplateArg();
|
arg += parseTemplateArg();
|
||||||
}
|
}
|
||||||
if (!parseError && advance() != 'E')
|
if (!parseError && advance() != 'E')
|
||||||
error(tr("Invalid template-arg"));
|
error(QString::fromLatin1("Invalid template-arg"));
|
||||||
} else {
|
} else {
|
||||||
error(tr("Invalid template-arg"));
|
error(QString::fromLatin1("Invalid template-arg"));
|
||||||
}
|
}
|
||||||
|
|
||||||
templateParams.append(arg);
|
templateParams.append(arg);
|
||||||
@@ -874,7 +871,7 @@ const QString NameDemanglerPrivate::parseExpression()
|
|||||||
while (!parseError && firstSetExpression.contains(peek()))
|
while (!parseError && firstSetExpression.contains(peek()))
|
||||||
expr += parseExpression();
|
expr += parseExpression();
|
||||||
if (!parseError && advance() != 'E')
|
if (!parseError && advance() != 'E')
|
||||||
error(tr("Invalid expression"));
|
error(QString::fromLatin1("Invalid expression"));
|
||||||
} else if (str == QLatin1String("cv")) {
|
} else if (str == QLatin1String("cv")) {
|
||||||
advance(2);
|
advance(2);
|
||||||
expr = parseType() + QLatin1String("(");
|
expr = parseType() + QLatin1String("(");
|
||||||
@@ -889,7 +886,7 @@ const QString NameDemanglerPrivate::parseExpression()
|
|||||||
expr += parseExpression();
|
expr += parseExpression();
|
||||||
}
|
}
|
||||||
if (!parseError && advance() != 'E')
|
if (!parseError && advance() != 'E')
|
||||||
error(tr("Invalid expression"));
|
error(QString::fromLatin1("Invalid expression"));
|
||||||
} else {
|
} else {
|
||||||
expr += parseExpression();
|
expr += parseExpression();
|
||||||
}
|
}
|
||||||
@@ -932,7 +929,7 @@ const QString NameDemanglerPrivate::parseExpression()
|
|||||||
} else if (firstSetExprPrimary.contains(next)) {
|
} else if (firstSetExprPrimary.contains(next)) {
|
||||||
expr = parseExprPrimary();
|
expr = parseExprPrimary();
|
||||||
} else {
|
} else {
|
||||||
error(tr("Invalid expression"));
|
error(QString::fromLatin1("Invalid expression"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -952,7 +949,7 @@ const QString NameDemanglerPrivate::parseExprPrimary()
|
|||||||
|
|
||||||
QString expr;
|
QString expr;
|
||||||
if (advance() != 'L') {
|
if (advance() != 'L') {
|
||||||
error(tr("Invalid primary expression"));
|
error(QString::fromLatin1("Invalid primary expression"));
|
||||||
} else {
|
} else {
|
||||||
QChar next = peek();
|
QChar next = peek();
|
||||||
if (firstSetType.contains(next)) {
|
if (firstSetType.contains(next)) {
|
||||||
@@ -963,15 +960,15 @@ const QString NameDemanglerPrivate::parseExprPrimary()
|
|||||||
else if (true /* type just parsed indicates float */)
|
else if (true /* type just parsed indicates float */)
|
||||||
expr += QString::number(parseFloat());
|
expr += QString::number(parseFloat());
|
||||||
else
|
else
|
||||||
error(tr("Invalid expr-primary"));
|
error(QString::fromLatin1("Invalid expr-primary"));
|
||||||
}
|
}
|
||||||
} else if (firstSetMangledName.contains(next)) {
|
} else if (firstSetMangledName.contains(next)) {
|
||||||
expr = parseMangledName();
|
expr = parseMangledName();
|
||||||
} else {
|
} else {
|
||||||
error(tr("Invalid expr-primary"));
|
error(QString::fromLatin1("Invalid expr-primary"));
|
||||||
}
|
}
|
||||||
if (!parseError && advance() != 'E')
|
if (!parseError && advance() != 'E')
|
||||||
error(tr("Invalid expr-primary"));
|
error(QString::fromLatin1("Invalid expr-primary"));
|
||||||
}
|
}
|
||||||
|
|
||||||
FUNC_END(expr);
|
FUNC_END(expr);
|
||||||
@@ -1106,12 +1103,12 @@ const QString NameDemanglerPrivate::parseType()
|
|||||||
advance(2);
|
advance(2);
|
||||||
type = parseExpression(); // TODO: See above
|
type = parseExpression(); // TODO: See above
|
||||||
if (!parseError && advance() != 'E')
|
if (!parseError && advance() != 'E')
|
||||||
error(tr("Invalid type"));
|
error(QString::fromLatin1("Invalid type"));
|
||||||
} else if (str == QLatin1String("DT")) {
|
} else if (str == QLatin1String("DT")) {
|
||||||
advance(2);
|
advance(2);
|
||||||
type = parseExpression(); // TODO: See above
|
type = parseExpression(); // TODO: See above
|
||||||
if (!parseError && advance() != 'E')
|
if (!parseError && advance() != 'E')
|
||||||
error(tr("Invalid type"));
|
error(QString::fromLatin1("Invalid type"));
|
||||||
} else {
|
} else {
|
||||||
QChar next = peek();
|
QChar next = peek();
|
||||||
if (str == QLatin1String("Dd") || str == QLatin1String("De")
|
if (str == QLatin1String("Dd") || str == QLatin1String("De")
|
||||||
@@ -1179,7 +1176,7 @@ const QString NameDemanglerPrivate::parseType()
|
|||||||
if (!parseError)
|
if (!parseError)
|
||||||
type += parseType(); // TODO: handle this correctly
|
type += parseType(); // TODO: handle this correctly
|
||||||
} else {
|
} else {
|
||||||
error(tr("Invalid type"));
|
error(QString::fromLatin1("Invalid type"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1317,14 +1314,14 @@ const QString NameDemanglerPrivate::parseBuiltinType()
|
|||||||
break;
|
break;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
error(tr("Invalid built-in type"));
|
error(QString::fromLatin1("Invalid built-in type"));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'u':
|
case 'u':
|
||||||
type = parseSourceName();
|
type = parseSourceName();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
error(tr("Invalid builtin-type"));
|
error(QString::fromLatin1("Invalid builtin-type"));
|
||||||
}
|
}
|
||||||
|
|
||||||
FUNC_END(type);
|
FUNC_END(type);
|
||||||
@@ -1340,7 +1337,7 @@ const QString NameDemanglerPrivate::parseFunctionType()
|
|||||||
QString funcType;
|
QString funcType;
|
||||||
bool externC = false;
|
bool externC = false;
|
||||||
if (advance() != 'F') {
|
if (advance() != 'F') {
|
||||||
error(tr("Invalid function type"));
|
error(QString::fromLatin1("Invalid function type"));
|
||||||
} else {
|
} else {
|
||||||
if (peek() == 'Y') {
|
if (peek() == 'Y') {
|
||||||
advance();
|
advance();
|
||||||
@@ -1348,7 +1345,7 @@ const QString NameDemanglerPrivate::parseFunctionType()
|
|||||||
}
|
}
|
||||||
const QStringList &signature = parseBareFunctionType();
|
const QStringList &signature = parseBareFunctionType();
|
||||||
if (!parseError && advance() != 'E')
|
if (!parseError && advance() != 'E')
|
||||||
error(tr("Invalid function type"));
|
error(QString::fromLatin1("Invalid function type"));
|
||||||
if (!parseError) {
|
if (!parseError) {
|
||||||
QString returnType = signature.first();
|
QString returnType = signature.first();
|
||||||
QString argList = QLatin1String("(");
|
QString argList = QLatin1String("(");
|
||||||
@@ -1428,7 +1425,7 @@ const QString NameDemanglerPrivate::parseUnqualifiedName()
|
|||||||
else if (firstSetSourceName.contains(next))
|
else if (firstSetSourceName.contains(next))
|
||||||
name = QLatin1String("::") + parseSourceName();
|
name = QLatin1String("::") + parseSourceName();
|
||||||
else
|
else
|
||||||
error(tr("Invalid unqualified-name"));
|
error(QString::fromLatin1("Invalid unqualified-name"));
|
||||||
|
|
||||||
FUNC_END(name);
|
FUNC_END(name);
|
||||||
return name;
|
return name;
|
||||||
@@ -1519,7 +1516,7 @@ const NameDemanglerPrivate::Operator &NameDemanglerPrivate::parseOperatorName()
|
|||||||
static const UnaryOperator pseudoOp(QLatin1String("invalid"),
|
static const UnaryOperator pseudoOp(QLatin1String("invalid"),
|
||||||
QLatin1String("invalid"));
|
QLatin1String("invalid"));
|
||||||
op = &pseudoOp;
|
op = &pseudoOp;
|
||||||
error(tr("Invalid operator-name '%s'").arg(id));
|
error(QString::fromLatin1("Invalid operator-name '%s'").arg(id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1541,7 +1538,7 @@ const QString NameDemanglerPrivate::parseArrayType()
|
|||||||
|
|
||||||
QString type;
|
QString type;
|
||||||
if (advance() != 'A') {
|
if (advance() != 'A') {
|
||||||
error(tr("Invalid array-type"));
|
error(QString::fromLatin1("Invalid array-type"));
|
||||||
} else {
|
} else {
|
||||||
QChar next = peek();
|
QChar next = peek();
|
||||||
QString dimension;
|
QString dimension;
|
||||||
@@ -1551,7 +1548,7 @@ const QString NameDemanglerPrivate::parseArrayType()
|
|||||||
dimension = parseExpression();
|
dimension = parseExpression();
|
||||||
}
|
}
|
||||||
if (!parseError && advance() != '_')
|
if (!parseError && advance() != '_')
|
||||||
error(tr("Invalid array-type"));
|
error(QString::fromLatin1("Invalid array-type"));
|
||||||
if (!parseError)
|
if (!parseError)
|
||||||
type = QString::fromLocal8Bit("%1[%2]").
|
type = QString::fromLocal8Bit("%1[%2]").
|
||||||
arg(parseType()).arg(dimension);
|
arg(parseType()).arg(dimension);
|
||||||
@@ -1568,7 +1565,7 @@ const QString NameDemanglerPrivate::parsePointerToMemberType()
|
|||||||
|
|
||||||
QString type;
|
QString type;
|
||||||
if (advance() != 'M') {
|
if (advance() != 'M') {
|
||||||
error(tr("Invalid pointer-to-member-type"));
|
error(QString::fromLatin1("Invalid pointer-to-member-type"));
|
||||||
} else {
|
} else {
|
||||||
const QString classType = parseType();
|
const QString classType = parseType();
|
||||||
QString memberType;
|
QString memberType;
|
||||||
@@ -1615,22 +1612,22 @@ const QString NameDemanglerPrivate::parseSubstitution()
|
|||||||
|
|
||||||
QString substitution;
|
QString substitution;
|
||||||
if (advance() != 'S') {
|
if (advance() != 'S') {
|
||||||
error(tr("Invalid substitution"));
|
error(QString::fromLatin1("Invalid substitution"));
|
||||||
} else if (firstSetSeqId.contains(peek())) {
|
} else if (firstSetSeqId.contains(peek())) {
|
||||||
int substIndex = parseSeqId() + 1;
|
int substIndex = parseSeqId() + 1;
|
||||||
if (!parseError && substIndex >= substitutions.size())
|
if (!parseError && substIndex >= substitutions.size())
|
||||||
error(tr("Invalid substitution: element %1 was requested, "
|
error(QString::fromLatin1("Invalid substitution: element %1 was requested, "
|
||||||
"but there are only %2").
|
"but there are only %2").
|
||||||
arg(substIndex + 1).arg(substitutions.size()));
|
arg(substIndex + 1).arg(substitutions.size()));
|
||||||
else
|
else
|
||||||
substitution = substitutions.at(substIndex);
|
substitution = substitutions.at(substIndex);
|
||||||
if (!parseError && advance() != '_')
|
if (!parseError && advance() != '_')
|
||||||
error(tr("Invalid substitution"));
|
error(QString::fromLatin1("Invalid substitution"));
|
||||||
} else {
|
} else {
|
||||||
switch (advance().toAscii()) {
|
switch (advance().toAscii()) {
|
||||||
case '_':
|
case '_':
|
||||||
if (substitutions.isEmpty())
|
if (substitutions.isEmpty())
|
||||||
error(tr("Invalid substitution: There are no elements"));
|
error(QString::fromLatin1("Invalid substitution: There are no elements"));
|
||||||
else
|
else
|
||||||
substitution = substitutions.first();
|
substitution = substitutions.first();
|
||||||
break;
|
break;
|
||||||
@@ -1661,7 +1658,7 @@ const QString NameDemanglerPrivate::parseSubstitution()
|
|||||||
"::std::basic_iostream<char, std::char_traits<char> >");
|
"::std::basic_iostream<char, std::char_traits<char> >");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
error(tr("Invalid substitution"));
|
error(QString::fromLatin1("Invalid substitution"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1733,7 +1730,7 @@ const QString NameDemanglerPrivate::parseSpecialName()
|
|||||||
if (!parseError)
|
if (!parseError)
|
||||||
parseEncoding();
|
parseEncoding();
|
||||||
} else {
|
} else {
|
||||||
error(tr("Invalid special-name"));
|
error(QString::fromLatin1("Invalid special-name"));
|
||||||
}
|
}
|
||||||
|
|
||||||
FUNC_END(name);
|
FUNC_END(name);
|
||||||
@@ -1756,7 +1753,7 @@ const QString NameDemanglerPrivate::parseUnscopedName()
|
|||||||
} else if (firstSetUnqualifiedName.contains(peek())) {
|
} else if (firstSetUnqualifiedName.contains(peek())) {
|
||||||
name = parseUnqualifiedName();
|
name = parseUnqualifiedName();
|
||||||
} else {
|
} else {
|
||||||
error(tr("Invalid unqualified-name"));
|
error(QString::fromLatin1("Invalid unqualified-name"));
|
||||||
}
|
}
|
||||||
|
|
||||||
FUNC_END(name);
|
FUNC_END(name);
|
||||||
@@ -1776,11 +1773,11 @@ const QString NameDemanglerPrivate::parseLocalName()
|
|||||||
|
|
||||||
QString name;
|
QString name;
|
||||||
if (advance() != 'Z') {
|
if (advance() != 'Z') {
|
||||||
error(tr("Invalid local-name"));
|
error(QString::fromLatin1("Invalid local-name"));
|
||||||
} else {
|
} else {
|
||||||
name = parseEncoding();
|
name = parseEncoding();
|
||||||
if (!parseError && advance() != 'E') {
|
if (!parseError && advance() != 'E') {
|
||||||
error(tr("Invalid local-name"));
|
error(QString::fromLatin1("Invalid local-name"));
|
||||||
} else {
|
} else {
|
||||||
QString str = readAhead(2);
|
QString str = readAhead(2);
|
||||||
QChar next = peek();
|
QChar next = peek();
|
||||||
@@ -1793,7 +1790,7 @@ const QString NameDemanglerPrivate::parseLocalName()
|
|||||||
advance();
|
advance();
|
||||||
name += QLatin1String("::\"string literal\"");
|
name += QLatin1String("::\"string literal\"");
|
||||||
} else {
|
} else {
|
||||||
error(tr("Invalid local-name"));
|
error(QString::fromLatin1("Invalid local-name"));
|
||||||
}
|
}
|
||||||
if (!parseError && firstSetDiscriminator.contains(peek()))
|
if (!parseError && firstSetDiscriminator.contains(peek()))
|
||||||
parseDiscriminator();
|
parseDiscriminator();
|
||||||
@@ -1809,7 +1806,7 @@ int NameDemanglerPrivate::parseDiscriminator()
|
|||||||
{
|
{
|
||||||
int index;
|
int index;
|
||||||
if (advance() != '_') {
|
if (advance() != '_') {
|
||||||
error(tr("Invalid discriminator"));
|
error(QString::fromLatin1("Invalid discriminator"));
|
||||||
index = -1;
|
index = -1;
|
||||||
} else {
|
} else {
|
||||||
index = parseNonNegativeNumber();
|
index = parseNonNegativeNumber();
|
||||||
@@ -1841,7 +1838,7 @@ const QString NameDemanglerPrivate::parseCtorDtorName()
|
|||||||
case '3':
|
case '3':
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
error(tr("Invalid ctor-dtor-name"));
|
error(QString::fromLatin1("Invalid ctor-dtor-name"));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'D':
|
case 'D':
|
||||||
@@ -1852,11 +1849,11 @@ const QString NameDemanglerPrivate::parseCtorDtorName()
|
|||||||
destructor = true;
|
destructor = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
error(tr("Invalid ctor-dtor-name"));
|
error(QString::fromLatin1("Invalid ctor-dtor-name"));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
error(tr("Invalid ctor-dtor-name"));
|
error(QString::fromLatin1("Invalid ctor-dtor-name"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!parseError) {
|
if (!parseError) {
|
||||||
@@ -1904,10 +1901,10 @@ void NameDemanglerPrivate::parseCallOffset()
|
|||||||
parseVOffset();
|
parseVOffset();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
error(tr("Invalid call-offset"));
|
error(QString::fromLatin1("Invalid call-offset"));
|
||||||
}
|
}
|
||||||
if (!parseError && advance() != '_')
|
if (!parseError && advance() != '_')
|
||||||
error(tr("Invalid call-offset"));
|
error(QString::fromLatin1("Invalid call-offset"));
|
||||||
FUNC_END(QString());
|
FUNC_END(QString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1929,7 +1926,7 @@ void NameDemanglerPrivate::parseVOffset()
|
|||||||
|
|
||||||
parseNumber();
|
parseNumber();
|
||||||
if (advance() != '_')
|
if (advance() != '_')
|
||||||
error(tr("Invalid v-offset"));
|
error(QString::fromLatin1("Invalid v-offset"));
|
||||||
parseNumber();
|
parseNumber();
|
||||||
|
|
||||||
FUNC_END(QString());
|
FUNC_END(QString());
|
||||||
@@ -1941,7 +1938,7 @@ int NameDemanglerPrivate::parseDigit()
|
|||||||
|
|
||||||
int digit = advance().digitValue();
|
int digit = advance().digitValue();
|
||||||
if (digit == -1)
|
if (digit == -1)
|
||||||
error(tr("Invalid digit"));
|
error(QString::fromLatin1("Invalid digit"));
|
||||||
|
|
||||||
FUNC_END(QString::number(digit));
|
FUNC_END(QString::number(digit));
|
||||||
return digit;
|
return digit;
|
||||||
@@ -1950,7 +1947,7 @@ int NameDemanglerPrivate::parseDigit()
|
|||||||
void NameDemanglerPrivate::error(const QString &errorSpec)
|
void NameDemanglerPrivate::error(const QString &errorSpec)
|
||||||
{
|
{
|
||||||
parseError = true;
|
parseError = true;
|
||||||
m_errorString = tr("At position %1: ").arg(pos) + errorSpec;
|
m_errorString = QString::fromLatin1("At position %1: ").arg(pos) + errorSpec;
|
||||||
}
|
}
|
||||||
|
|
||||||
QChar NameDemanglerPrivate::peek(int ahead)
|
QChar NameDemanglerPrivate::peek(int ahead)
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
#ifndef NAME_DEMANGLER_H
|
#ifndef NAME_DEMANGLER_H
|
||||||
#define NAME_DEMANGLER_H
|
#define NAME_DEMANGLER_H
|
||||||
|
|
||||||
|
#include <QtCore/QtGlobal>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
class QString;
|
class QString;
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|||||||
@@ -8,12 +8,10 @@ INCLUDEPATH+=$$PWD
|
|||||||
|
|
||||||
win32 {
|
win32 {
|
||||||
SOURCES += $$PWD/peutils.cpp \
|
SOURCES += $$PWD/peutils.cpp \
|
||||||
$$PWD/dbgwinutils.cpp \
|
$$PWD/dbgwinutils.cpp
|
||||||
$$PWD/sharedlibraryinjector.cpp
|
|
||||||
|
|
||||||
HEADERS += $$PWD/peutils.h \
|
HEADERS += $$PWD/peutils.h \
|
||||||
$$PWD/dbgwinutils.h \
|
$$PWD/dbgwinutils.h
|
||||||
$$PWD/sharedlibraryinjector.h
|
|
||||||
|
|
||||||
contains(QMAKE_CXX, cl) {
|
contains(QMAKE_CXX, cl) {
|
||||||
# For the Privilege manipulation functions in sharedlibraryinjector.cpp.
|
# For the Privilege manipulation functions in sharedlibraryinjector.cpp.
|
||||||
|
|||||||
@@ -1,465 +0,0 @@
|
|||||||
/**************************************************************************
|
|
||||||
**
|
|
||||||
** This file is part of Qt Creator
|
|
||||||
**
|
|
||||||
** Copyright (c) 2010 Marius Storm-Olsen
|
|
||||||
**
|
|
||||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
|
||||||
**
|
|
||||||
** No Commercial Usage
|
|
||||||
**
|
|
||||||
** This file contains pre-release code and may not be distributed.
|
|
||||||
** You may use this file in accordance with the terms and conditions
|
|
||||||
** contained in the Technology Preview License Agreement accompanying
|
|
||||||
** this package.
|
|
||||||
**
|
|
||||||
** GNU Lesser General Public License Usage
|
|
||||||
**
|
|
||||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
||||||
** General Public License version 2.1 as published by the Free Software
|
|
||||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
|
||||||
** packaging of this file. Please review the following information to
|
|
||||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
|
||||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
||||||
**
|
|
||||||
** In addition, as a special exception, Nokia gives you certain additional
|
|
||||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
|
||||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
||||||
**
|
|
||||||
** If you have questions regarding the use of this file, please contact
|
|
||||||
** Nokia at qt-info@nokia.com.
|
|
||||||
**
|
|
||||||
**************************************************************************/
|
|
||||||
|
|
||||||
#include "sharedlibraryinjector.h"
|
|
||||||
#include <utils/winutils.h>
|
|
||||||
|
|
||||||
#include <QtCore/QDebug>
|
|
||||||
|
|
||||||
#ifdef __GNUC__ // MinGW does not have a complete windows.h
|
|
||||||
|
|
||||||
typedef DWORD (__stdcall *PTHREAD_START_ROUTINE) (LPVOID lpThreadParameter);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
enum { debug = 0 };
|
|
||||||
|
|
||||||
static QString msgFuncFailed(const char *f, unsigned long error)
|
|
||||||
{
|
|
||||||
return QString::fromLatin1("%1 failed: %2").arg(QLatin1String(f), Utils::winErrorMessage(error));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resolve a symbol from a library handle
|
|
||||||
template <class SymbolType>
|
|
||||||
inline bool resolveSymbol(const char *libraryName, HMODULE libraryHandle, const char *symbolName, SymbolType *s, QString *errorMessage)
|
|
||||||
{
|
|
||||||
*s = 0;
|
|
||||||
FARPROC vs = ::GetProcAddress(libraryHandle, symbolName);
|
|
||||||
if (vs == 0) {
|
|
||||||
*errorMessage = QString::fromLatin1("Unable to resolve '%2' in '%1'.").arg(QString::fromAscii(symbolName), QString::fromAscii(libraryName));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
*s = reinterpret_cast<SymbolType>(vs);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resolve a symbol from a library
|
|
||||||
template <class SymbolType>
|
|
||||||
inline bool resolveSymbol(const char *library, const char *symbolName, SymbolType *s, QString *errorMessage)
|
|
||||||
{
|
|
||||||
*s = 0;
|
|
||||||
const HMODULE hm = ::GetModuleHandleA(library);
|
|
||||||
if (hm == NULL) {
|
|
||||||
*errorMessage = QString::fromLatin1("Module '%1' does not exist.").arg(QString::fromAscii(library));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return resolveSymbol(library, hm , symbolName, s, errorMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
namespace Debugger {
|
|
||||||
namespace Internal {
|
|
||||||
|
|
||||||
SharedLibraryInjector::SharedLibraryInjector(unsigned long processId,
|
|
||||||
unsigned long threadId) :
|
|
||||||
m_processId(processId),
|
|
||||||
m_threadId(threadId),
|
|
||||||
m_hasEscalatedPrivileges(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
SharedLibraryInjector::~SharedLibraryInjector()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void SharedLibraryInjector::setPid(unsigned long pid)
|
|
||||||
{
|
|
||||||
m_processId = pid;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SharedLibraryInjector::setThreadId(unsigned long tid)
|
|
||||||
{
|
|
||||||
m_threadId = tid;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SharedLibraryInjector::setModulePath(const QString &modulePath)
|
|
||||||
{
|
|
||||||
m_modulePath = modulePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SharedLibraryInjector::remoteInject(const QString &modulePath,
|
|
||||||
bool waitForThread, QString *errorMessage)
|
|
||||||
{
|
|
||||||
setModulePath(modulePath);
|
|
||||||
return doRemoteInjection(m_processId, NULL, m_modulePath, waitForThread, errorMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SharedLibraryInjector::stubInject(const QString &modulePath, unsigned long entryPoint, QString *errorMessage)
|
|
||||||
{
|
|
||||||
setModulePath(modulePath);
|
|
||||||
return doStubInjection(m_processId, m_modulePath, entryPoint, errorMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SharedLibraryInjector::unload(HMODULE hFreeModule, QString *errorMessage)
|
|
||||||
{
|
|
||||||
return doRemoteInjection(m_processId, hFreeModule, QString(), true, errorMessage); // Always use remote thread to unload
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SharedLibraryInjector::unload(const QString &modulePath, QString *errorMessage)
|
|
||||||
{
|
|
||||||
const HMODULE hMod = modulePath.isEmpty() ?
|
|
||||||
findModuleHandle(m_modulePath, errorMessage) :
|
|
||||||
findModuleHandle(modulePath, errorMessage);
|
|
||||||
if (!hMod)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return doRemoteInjection(m_processId, hMod, NULL, true, errorMessage); // Always use remote thread to unload
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SharedLibraryInjector::hasLoaded(const QString &modulePath)
|
|
||||||
{
|
|
||||||
QString errorMessage;
|
|
||||||
return findModuleHandle(modulePath.isEmpty() ? m_modulePath : modulePath, &errorMessage) != NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString SharedLibraryInjector::findModule(const QString &moduleName)
|
|
||||||
{
|
|
||||||
const TCHAR *moduleNameC = reinterpret_cast<const TCHAR*>(moduleName.utf16());
|
|
||||||
if (GetFileAttributesW(moduleNameC) != INVALID_FILE_ATTRIBUTES)
|
|
||||||
return moduleName;
|
|
||||||
|
|
||||||
TCHAR testpathC[MAX_PATH];
|
|
||||||
// Check application path first
|
|
||||||
GetModuleFileNameW(NULL, testpathC, MAX_PATH);
|
|
||||||
QString testPath = QString::fromUtf16(reinterpret_cast<unsigned short*>(testpathC));
|
|
||||||
const int lastSlash = testPath.lastIndexOf(QLatin1Char('\\'));
|
|
||||||
if (lastSlash != -1)
|
|
||||||
testPath.truncate(lastSlash + 1);
|
|
||||||
testPath += moduleName;
|
|
||||||
if (GetFileAttributesW(reinterpret_cast<const TCHAR*>(testPath.utf16())) != INVALID_FILE_ATTRIBUTES)
|
|
||||||
return testPath;
|
|
||||||
// Path Search
|
|
||||||
if (SearchPathW(NULL, reinterpret_cast<const TCHAR*>(moduleName.utf16()), NULL, sizeof(testpathC)/2, testpathC, NULL))
|
|
||||||
return QString::fromUtf16(reinterpret_cast<unsigned short*>(testpathC));
|
|
||||||
// Last chance, if the module has already been loaded in this process, then use that path
|
|
||||||
const HMODULE loadedModule = GetModuleHandleW(reinterpret_cast<const TCHAR*>(moduleName.utf16()));
|
|
||||||
if (loadedModule) {
|
|
||||||
GetModuleFileNameW(loadedModule, testpathC, sizeof(testpathC));
|
|
||||||
if (GetFileAttributes(testpathC) != INVALID_FILE_ATTRIBUTES)
|
|
||||||
return QString::fromUtf16(reinterpret_cast<unsigned short*>(testpathC));
|
|
||||||
}
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long SharedLibraryInjector::getModuleEntryPoint(const QString &moduleName)
|
|
||||||
{
|
|
||||||
// If file doesn't exist, just treat it like we cannot figure out the entry point
|
|
||||||
if (moduleName.isEmpty() || GetFileAttributesW(reinterpret_cast<const TCHAR*>(moduleName.utf16())) == INVALID_FILE_ATTRIBUTES)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// Read the first 1K of data from the file
|
|
||||||
unsigned char peData[1024];
|
|
||||||
unsigned long peDataSize = 0;
|
|
||||||
const HANDLE hFile = CreateFileW(reinterpret_cast<const WCHAR*>(moduleName.utf16()), FILE_READ_DATA, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
|
||||||
if (hFile == INVALID_HANDLE_VALUE
|
|
||||||
|| !ReadFile(hFile, peData, sizeof(peData), &peDataSize, NULL))
|
|
||||||
return 0;
|
|
||||||
CloseHandle(hFile);
|
|
||||||
|
|
||||||
// Now we check to see if there is an optional header we can read
|
|
||||||
IMAGE_DOS_HEADER *dosHeader = reinterpret_cast<IMAGE_DOS_HEADER *>(peData);
|
|
||||||
if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE // DOS signature is incorrect, or
|
|
||||||
|| dosHeader->e_lfanew == 0) // executable's PE data contains no offset to New EXE header
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
IMAGE_NT_HEADERS *ntHeaders = (IMAGE_NT_HEADERS *)(peData + dosHeader->e_lfanew);
|
|
||||||
if (ntHeaders->Signature != IMAGE_NT_SIGNATURE // NT signature is incorrect, or
|
|
||||||
|| !ntHeaders->OptionalHeader.ImageBase // ImageBase or EntryPoint addresses are incorrect
|
|
||||||
|| !ntHeaders->OptionalHeader.AddressOfEntryPoint)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return ntHeaders->OptionalHeader.ImageBase
|
|
||||||
+ ntHeaders->OptionalHeader.AddressOfEntryPoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SharedLibraryInjector::escalatePrivileges(QString *errorMessage)
|
|
||||||
{
|
|
||||||
if (debug)
|
|
||||||
qDebug() << Q_FUNC_INFO << m_hasEscalatedPrivileges;
|
|
||||||
|
|
||||||
if (m_hasEscalatedPrivileges)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
bool success = false;
|
|
||||||
HANDLE hToken = 0;
|
|
||||||
do {
|
|
||||||
TOKEN_PRIVILEGES Debug_Privileges;
|
|
||||||
if (!LookupPrivilegeValue (NULL, SE_DEBUG_NAME, &Debug_Privileges.Privileges[0].Luid)) {
|
|
||||||
*errorMessage = msgFuncFailed("LookupPrivilegeValue", GetLastError());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Debug_Privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; // set to enable privilege
|
|
||||||
Debug_Privileges.PrivilegeCount = 1; // working with only 1
|
|
||||||
|
|
||||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) {
|
|
||||||
*errorMessage = msgFuncFailed("OpenProcessToken", GetLastError());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!AdjustTokenPrivileges(hToken, FALSE, &Debug_Privileges, 0, NULL, NULL)) {
|
|
||||||
*errorMessage = msgFuncFailed("AdjustTokenPrivileges", GetLastError());
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
success = true;
|
|
||||||
} while (false);
|
|
||||||
|
|
||||||
if (hToken)
|
|
||||||
CloseHandle (hToken);
|
|
||||||
|
|
||||||
m_hasEscalatedPrivileges = success;
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *writeDataToProcess(HANDLE process, void *data, unsigned size, QString *errorMessage)
|
|
||||||
{
|
|
||||||
void *memory = VirtualAllocEx(process, NULL, size, MEM_COMMIT, PAGE_READWRITE);
|
|
||||||
if (!memory) {
|
|
||||||
*errorMessage = msgFuncFailed("VirtualAllocEx", GetLastError());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (!WriteProcessMemory(process, memory, data, size, NULL)) {
|
|
||||||
*errorMessage = msgFuncFailed("WriteProcessMemory", GetLastError());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return memory;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *writeUtf16StringToProcess(HANDLE process, const QString &what, QString *errorMessage)
|
|
||||||
{
|
|
||||||
QByteArray whatData = QByteArray(reinterpret_cast<const char*>(what.utf16()), what.size() * 2);
|
|
||||||
whatData += '\0';
|
|
||||||
whatData += '\0';
|
|
||||||
return writeDataToProcess(process, whatData.data(), whatData.size(), errorMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SharedLibraryInjector::doStubInjection(unsigned long pid,
|
|
||||||
const QString &modulePath,
|
|
||||||
unsigned long entryPoint,
|
|
||||||
QString *errorMessage)
|
|
||||||
{
|
|
||||||
if (debug)
|
|
||||||
qDebug() << pid << modulePath << entryPoint;
|
|
||||||
if (modulePath.isEmpty())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!escalatePrivileges(errorMessage))
|
|
||||||
return false;
|
|
||||||
// MinGW lacks OpenThread() and the advapi.lib as of 6.5.2009
|
|
||||||
#if (defined(WIN64) || defined(_WIN64) || defined(__WIN64__)) || defined(__GNUC__)
|
|
||||||
*errorMessage = QLatin1String("Not implemented for this architecture.");
|
|
||||||
return false;
|
|
||||||
#else
|
|
||||||
byte stubCode[] = {
|
|
||||||
0x68, 0, 0, 0, 0, // push 0x00000000 - Placeholder for the entrypoint address
|
|
||||||
0x9C, // pushfd - Save the flags and registers
|
|
||||||
0x60, // pushad
|
|
||||||
0x68, 0, 0, 0, 0, // push 0x00000000 - Placeholder for the string address
|
|
||||||
0xB8, 0, 0, 0, 0, // mov eax, 0x00000000 - Placeholder for the LoadLibrary address
|
|
||||||
0xFF, 0xD0, // call eax - Call LoadLibrary with string address
|
|
||||||
0x61, // popad - Restore flags and registry
|
|
||||||
0x9D, // popfd
|
|
||||||
0xC3 // retn - Return (pops the entrypoint, and executes)
|
|
||||||
};
|
|
||||||
|
|
||||||
const HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
|
|
||||||
if (!hProcess)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const HANDLE hThread = OpenThread(THREAD_GET_CONTEXT | THREAD_SET_CONTEXT, false, m_threadId);
|
|
||||||
if (!hThread) {
|
|
||||||
CloseHandle(hProcess);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get address of LoadLibraryW in kernel32.dll
|
|
||||||
unsigned long funcPtr;
|
|
||||||
if (!resolveSymbol("kernel32.dll", "LoadLibraryW", &funcPtr, errorMessage))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Allocate and write DLL path to target process' memory
|
|
||||||
// 0-terminated Utf16 string.
|
|
||||||
void *dllString = writeUtf16StringToProcess(hProcess, modulePath, errorMessage);
|
|
||||||
if (!dllString)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Allocate memory in target process, for the stubCode which will load the module, and execute
|
|
||||||
// the process' entry-point
|
|
||||||
const unsigned long stubLen = sizeof(stubCode);
|
|
||||||
// Modify the stubCode to have the proper entry-point, DLL module string, and function pointer
|
|
||||||
*(unsigned long*)(stubCode+1) = entryPoint;
|
|
||||||
*(unsigned long*)(stubCode+8) = reinterpret_cast<unsigned long>(dllString);
|
|
||||||
*(unsigned long*)(stubCode+13) = funcPtr;
|
|
||||||
|
|
||||||
// If we cannot write the stubCode into the process, we simply bail out, and the process will
|
|
||||||
// continues execution as normal
|
|
||||||
void *stub = writeDataToProcess(hProcess, stubCode, stubLen, errorMessage);
|
|
||||||
if (!stub)
|
|
||||||
return false;
|
|
||||||
// Set the process' main thread to start executing from the stubCode address which we've just
|
|
||||||
// allocated in the process' memory.. If we cannot do that, bail out
|
|
||||||
CONTEXT ctx;
|
|
||||||
ctx.ContextFlags = CONTEXT_CONTROL;
|
|
||||||
if(!GetThreadContext(hThread, &ctx))
|
|
||||||
return false;
|
|
||||||
ctx.Eip = reinterpret_cast<DWORD>(stub);
|
|
||||||
ctx.ContextFlags = CONTEXT_CONTROL;
|
|
||||||
if(!SetThreadContext(hThread, &ctx))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
CloseHandle(hProcess);
|
|
||||||
CloseHandle(hThread);
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
bool SharedLibraryInjector::doRemoteInjection(unsigned long pid,
|
|
||||||
HMODULE hFreeModule,
|
|
||||||
const QString &modulePath,
|
|
||||||
bool waitForThread,
|
|
||||||
QString *errorMessage)
|
|
||||||
{
|
|
||||||
if (debug)
|
|
||||||
qDebug() << Q_FUNC_INFO << '\n' << hFreeModule << pid << waitForThread<< modulePath;
|
|
||||||
|
|
||||||
if (!hFreeModule && modulePath.isEmpty())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
escalatePrivileges(errorMessage);
|
|
||||||
|
|
||||||
const HANDLE hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
|
|
||||||
if (hProcess == NULL) {
|
|
||||||
*errorMessage = msgFuncFailed("OpenProcess", GetLastError());
|
|
||||||
qDebug() << "Failed to open process PID %d with all access\n" << pid;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *pszLibFileRemote = 0;
|
|
||||||
HANDLE hThread = 0;
|
|
||||||
// Call "FreeLibrary(hFreeModule)" to unload
|
|
||||||
if (hFreeModule) {
|
|
||||||
PTHREAD_START_ROUTINE pfnThreadRtn;
|
|
||||||
if (!resolveSymbol("Kernel32", "FreeLibrary", &pfnThreadRtn, errorMessage))
|
|
||||||
return false;
|
|
||||||
hThread = ::CreateRemoteThread(hProcess, NULL, 0, pfnThreadRtn, hFreeModule, 0, NULL);
|
|
||||||
} else {
|
|
||||||
pszLibFileRemote = writeUtf16StringToProcess(hProcess, modulePath, errorMessage);
|
|
||||||
if (!pszLibFileRemote)
|
|
||||||
return false;
|
|
||||||
// Loadlibrary routine
|
|
||||||
PTHREAD_START_ROUTINE pfnThreadRtn;
|
|
||||||
if (!resolveSymbol("Kernel32", "LoadLibraryW", &pfnThreadRtn, errorMessage))
|
|
||||||
return false;
|
|
||||||
hThread = ::CreateRemoteThread(hProcess, NULL, 0, pfnThreadRtn, pszLibFileRemote, 0, NULL);
|
|
||||||
}
|
|
||||||
if (hThread == NULL) {
|
|
||||||
*errorMessage = msgFuncFailed("CreateRemoteThread", GetLastError());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!SetThreadPriority(hThread, THREAD_PRIORITY_HIGHEST)) {
|
|
||||||
*errorMessage = msgFuncFailed("SetThreadPriority", GetLastError());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (waitForThread) {
|
|
||||||
if (::WaitForSingleObject(hThread, 20000) != WAIT_OBJECT_0) {
|
|
||||||
*errorMessage = QString::fromLatin1("WaitForSingleObject timeout");
|
|
||||||
::CloseHandle(hThread);
|
|
||||||
::CloseHandle(hProcess);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pszLibFileRemote)
|
|
||||||
::VirtualFreeEx(hProcess, pszLibFileRemote, 0, MEM_RELEASE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hThread)
|
|
||||||
::CloseHandle(hThread);
|
|
||||||
|
|
||||||
if (hProcess)
|
|
||||||
::CloseHandle(hProcess);
|
|
||||||
if (debug)
|
|
||||||
qDebug() << "success" << Q_FUNC_INFO;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef BOOL (WINAPI *PFNENUMPROCESSMODULES) (HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded);
|
|
||||||
typedef DWORD (WINAPI *PFNGETMODULEFILENAMEEXW) (HANDLE hProcess, HMODULE hModule, LPTSTR lpFilename, DWORD nSize);
|
|
||||||
|
|
||||||
// We will require this function to get a module handle of our original module
|
|
||||||
HMODULE SharedLibraryInjector::findModuleHandle(const QString &modulePath, QString *errorMessage)
|
|
||||||
{
|
|
||||||
if (debug)
|
|
||||||
qDebug() << Q_FUNC_INFO << modulePath;
|
|
||||||
|
|
||||||
if (!escalatePrivileges(errorMessage))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
HMODULE hMods[1024];
|
|
||||||
DWORD cbNeeded;
|
|
||||||
|
|
||||||
HANDLE hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, m_processId);
|
|
||||||
if (hProcess == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
const char *psAPI_Lib = "PSAPI.DLL";
|
|
||||||
HMODULE m_hModPSAPI = ::LoadLibraryA(psAPI_Lib);
|
|
||||||
PFNENUMPROCESSMODULES m_pfnEnumProcessModules;
|
|
||||||
PFNGETMODULEFILENAMEEXW m_pfnGetModuleFileNameExW;
|
|
||||||
if (!resolveSymbol(psAPI_Lib, m_hModPSAPI, "EnumProcessModules", &m_pfnEnumProcessModules, errorMessage)
|
|
||||||
|| !resolveSymbol(psAPI_Lib, m_hModPSAPI, "GetModuleFileNameExW", &m_pfnGetModuleFileNameExW, errorMessage))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if(m_pfnEnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded)) {
|
|
||||||
const unsigned count = cbNeeded / sizeof(HMODULE);
|
|
||||||
for (unsigned i = 0; i < count; i++) {
|
|
||||||
TCHAR szModName[MAX_PATH];
|
|
||||||
if (m_pfnGetModuleFileNameExW(hProcess, hMods[i], szModName, sizeof(szModName))) {
|
|
||||||
if (QString::fromUtf16(reinterpret_cast<const unsigned short *>(szModName)) == modulePath) {
|
|
||||||
::FreeLibrary(m_hModPSAPI);
|
|
||||||
::CloseHandle(hProcess);
|
|
||||||
return hMods[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
::CloseHandle(hProcess);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Internal
|
|
||||||
} // namespace Debugger
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
/**************************************************************************
|
|
||||||
**
|
|
||||||
** This file is part of Qt Creator
|
|
||||||
**
|
|
||||||
** Copyright (c) 2010 Marius Storm-Olsen
|
|
||||||
**
|
|
||||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
|
||||||
**
|
|
||||||
** No Commercial Usage
|
|
||||||
**
|
|
||||||
** This file contains pre-release code and may not be distributed.
|
|
||||||
** You may use this file in accordance with the terms and conditions
|
|
||||||
** contained in the Technology Preview License Agreement accompanying
|
|
||||||
** this package.
|
|
||||||
**
|
|
||||||
** GNU Lesser General Public License Usage
|
|
||||||
**
|
|
||||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
||||||
** General Public License version 2.1 as published by the Free Software
|
|
||||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
|
||||||
** packaging of this file. Please review the following information to
|
|
||||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
|
||||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
||||||
**
|
|
||||||
** In addition, as a special exception, Nokia gives you certain additional
|
|
||||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
|
||||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
||||||
**
|
|
||||||
** If you have questions regarding the use of this file, please contact
|
|
||||||
** Nokia at qt-info@nokia.com.
|
|
||||||
**
|
|
||||||
**************************************************************************/
|
|
||||||
|
|
||||||
#ifndef SHAREDLIBRARYINJECTOR_H
|
|
||||||
#define SHAREDLIBRARYINJECTOR_H
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
#include <QtCore/QString>
|
|
||||||
|
|
||||||
namespace Debugger {
|
|
||||||
namespace Internal {
|
|
||||||
|
|
||||||
/* SharedLibraryInjector: Injects a DLL into a remote process.
|
|
||||||
* Escalates the calling process rights. */
|
|
||||||
class SharedLibraryInjector {
|
|
||||||
Q_DISABLE_COPY(SharedLibraryInjector)
|
|
||||||
public:
|
|
||||||
|
|
||||||
explicit SharedLibraryInjector(unsigned long remotePid, unsigned long remoteThreadId = 0);
|
|
||||||
~SharedLibraryInjector();
|
|
||||||
|
|
||||||
void setModulePath(const QString &modulePath);
|
|
||||||
bool hasLoaded(const QString &modulePath = QString());
|
|
||||||
|
|
||||||
// Remote injection, to be used for running processes
|
|
||||||
bool remoteInject(const QString &modulePath, bool waitForThread, QString *errorMessage);
|
|
||||||
|
|
||||||
// Stub injection, to be used before execution starts
|
|
||||||
bool stubInject(const QString &modulePath, unsigned long entryPoint, QString *errorMessage);
|
|
||||||
|
|
||||||
bool unload(const QString &modulePath /* = QString()*/, QString *errorMessage);
|
|
||||||
bool unload(HMODULE hFreeModule, QString *errorMessage);
|
|
||||||
|
|
||||||
void setPid(unsigned long pid);
|
|
||||||
void setThreadId(unsigned long tid);
|
|
||||||
|
|
||||||
static QString findModule(const QString &moduleName);
|
|
||||||
static unsigned long getModuleEntryPoint(const QString &moduleName);
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool escalatePrivileges(QString *errorMessage);
|
|
||||||
bool doRemoteInjection(unsigned long pid, HMODULE hFreeModule,
|
|
||||||
const QString &modulePath, bool waitForThread,
|
|
||||||
QString *errorMessage);
|
|
||||||
bool doStubInjection(unsigned long pid, const QString &modulePath,
|
|
||||||
unsigned long entryPoint, QString *errorMessage);
|
|
||||||
|
|
||||||
HMODULE findModuleHandle(const QString &modulePath, QString *errorMessage);
|
|
||||||
|
|
||||||
unsigned long m_processId;
|
|
||||||
unsigned long m_threadId;
|
|
||||||
QString m_modulePath;
|
|
||||||
bool m_hasEscalatedPrivileges;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Internal
|
|
||||||
} // namespace Debugger
|
|
||||||
|
|
||||||
#endif // SHAREDLIBRARYINJECTOR_H
|
|
||||||
Reference in New Issue
Block a user