**
**************************************************************************/
+#include "name_demangler.h"
+
#include <QtCore/QChar>
-#include <QtCore/QCoreApplication>
-#include <QtCore/QLatin1String>
#include <QtCore/QMap>
#include <QtCore/QRegExp>
#include <QtCore/QSet>
#include <QtCore/QString>
#include <QtCore/QStringList>
-#include "name_demangler.h"
-
// Debugging facility.
//#define DO_TRACE
#ifdef DO_TRACE
class NameDemanglerPrivate
{
- Q_DECLARE_TR_FUNCTIONS(NameDemanglerPrivate)
public:
NameDemanglerPrivate();
~NameDemanglerPrivate();
if (m_demangledName.startsWith(QLatin1String("::")))
m_demangledName.remove(0, 2);
if (!parseError && pos != mangledName.size())
- error(tr("Premature end of input"));
+ error(QString::fromLatin1("Premature end of input"));
#ifdef DO_TRACE
qDebug("%d", substitutions.size());
} else if (firstSetSpecialName.contains(next)) {
encoding = parseSpecialName();
} else {
- error(tr("Invalid encoding"));
+ error(QString::fromLatin1("Invalid encoding"));
}
FUNC_END(encoding);
} else if (firstSetLocalName.contains(next)) {
name = parseLocalName();
} else {
- error(tr("Invalid name"));
+ error(QString::fromLatin1("Invalid name"));
}
}
QString name;
if (advance() != 'N') {
- error(tr("Invalid nested-name"));
+ error(QString::fromLatin1("Invalid nested-name"));
} else {
QString cvQualifiers;
if (firstSetCvQualifiers.contains(peek()) && peek(1) != 'm'
if (!parseError) {
name = parsePrefix();
if (!parseError && advance() != 'E')
- error(tr("Invalid nested-name"));
+ error(QString::fromLatin1("Invalid nested-name"));
/*
* These are member function qualifiers which will have to
QString args = QLatin1String("<");
if (advance() != 'I') {
- error(tr("Invalid template args"));
+ error(QString::fromLatin1("Invalid template args"));
} else {
do {
if (args.length() > 1)
args += parseTemplateArg();
} while (!parseError && firstSetTemplateArg.contains(peek()));
if (!parseError && advance() != 'E')
- error(tr("Invalid template args"));
+ error(QString::fromLatin1("Invalid template args"));
}
args += '>';
QString param;
if (advance() != 'T') {
- error(tr("Invalid template-param"));
+ error(QString::fromLatin1("Invalid template-param"));
} else {
int index;
if (peek() == '_')
else
index = parseNonNegativeNumber() + 1;
if (!parseError && advance() != '_')
- error(tr("Invalid template-param"));
+ error(QString::fromLatin1("Invalid template-param"));
param = templateParams.at(index);
}
while (true) {
if (peek() == 'V') {
if (volatileFound || constFound) {
- error(tr("Invalid qualifiers: unexpected 'volatile'"));
+ error(QString::fromLatin1("Invalid qualifiers: unexpected 'volatile'"));
break;
} else {
volatileFound = true;
}
} else if (peek() == 'K') {
if (constFound) {
- error(tr("Invalid qualifiers: 'const' appears twice"));
+ error(QString::fromLatin1("Invalid qualifiers: 'const' appears twice"));
break;
} else {
constFound = true;
advance();
int number;
if (pos == startPos) {
- error(tr("Invalid non-negative number"));
+ error(QString::fromLatin1("Invalid non-negative number"));
number = 0;
} else {
number = mangledName.mid(startPos, pos - startPos).toInt(0, base);
advance();
arg = parseExpression();
if (!parseError && advance() != 'E')
- error(tr("Invalid template-arg"));
+ error(QString::fromLatin1("Invalid template-arg"));
} else if (next == 'I') {
advance();
while (!parseError && firstSetTemplateArg.contains(peek())) {
arg += parseTemplateArg();
}
if (!parseError && advance() != 'E')
- error(tr("Invalid template-arg"));
+ error(QString::fromLatin1("Invalid template-arg"));
} else {
- error(tr("Invalid template-arg"));
+ error(QString::fromLatin1("Invalid template-arg"));
}
templateParams.append(arg);
while (!parseError && firstSetExpression.contains(peek()))
expr += parseExpression();
if (!parseError && advance() != 'E')
- error(tr("Invalid expression"));
+ error(QString::fromLatin1("Invalid expression"));
} else if (str == QLatin1String("cv")) {
advance(2);
expr = parseType() + QLatin1String("(");
expr += parseExpression();
}
if (!parseError && advance() != 'E')
- error(tr("Invalid expression"));
+ error(QString::fromLatin1("Invalid expression"));
} else {
expr += parseExpression();
}
} else if (firstSetExprPrimary.contains(next)) {
expr = parseExprPrimary();
} else {
- error(tr("Invalid expression"));
+ error(QString::fromLatin1("Invalid expression"));
}
}
QString expr;
if (advance() != 'L') {
- error(tr("Invalid primary expression"));
+ error(QString::fromLatin1("Invalid primary expression"));
} else {
QChar next = peek();
if (firstSetType.contains(next)) {
else if (true /* type just parsed indicates float */)
expr += QString::number(parseFloat());
else
- error(tr("Invalid expr-primary"));
+ error(QString::fromLatin1("Invalid expr-primary"));
}
} else if (firstSetMangledName.contains(next)) {
expr = parseMangledName();
} else {
- error(tr("Invalid expr-primary"));
+ error(QString::fromLatin1("Invalid expr-primary"));
}
if (!parseError && advance() != 'E')
- error(tr("Invalid expr-primary"));
+ error(QString::fromLatin1("Invalid expr-primary"));
}
FUNC_END(expr);
advance(2);
type = parseExpression(); // TODO: See above
if (!parseError && advance() != 'E')
- error(tr("Invalid type"));
+ error(QString::fromLatin1("Invalid type"));
} else if (str == QLatin1String("DT")) {
advance(2);
type = parseExpression(); // TODO: See above
if (!parseError && advance() != 'E')
- error(tr("Invalid type"));
+ error(QString::fromLatin1("Invalid type"));
} else {
QChar next = peek();
if (str == QLatin1String("Dd") || str == QLatin1String("De")
if (!parseError)
type += parseType(); // TODO: handle this correctly
} else {
- error(tr("Invalid type"));
+ error(QString::fromLatin1("Invalid type"));
}
}
break;
break;
default:
- error(tr("Invalid built-in type"));
+ error(QString::fromLatin1("Invalid built-in type"));
}
break;
case 'u':
type = parseSourceName();
break;
default:
- error(tr("Invalid builtin-type"));
+ error(QString::fromLatin1("Invalid builtin-type"));
}
FUNC_END(type);
QString funcType;
bool externC = false;
if (advance() != 'F') {
- error(tr("Invalid function type"));
+ error(QString::fromLatin1("Invalid function type"));
} else {
if (peek() == 'Y') {
advance();
}
const QStringList &signature = parseBareFunctionType();
if (!parseError && advance() != 'E')
- error(tr("Invalid function type"));
+ error(QString::fromLatin1("Invalid function type"));
if (!parseError) {
QString returnType = signature.first();
QString argList = QLatin1String("(");
else if (firstSetSourceName.contains(next))
name = QLatin1String("::") + parseSourceName();
else
- error(tr("Invalid unqualified-name"));
+ error(QString::fromLatin1("Invalid unqualified-name"));
FUNC_END(name);
return name;
static const UnaryOperator pseudoOp(QLatin1String("invalid"),
QLatin1String("invalid"));
op = &pseudoOp;
- error(tr("Invalid operator-name '%s'").arg(id));
+ error(QString::fromLatin1("Invalid operator-name '%s'").arg(id));
}
}
}
QString type;
if (advance() != 'A') {
- error(tr("Invalid array-type"));
+ error(QString::fromLatin1("Invalid array-type"));
} else {
QChar next = peek();
QString dimension;
dimension = parseExpression();
}
if (!parseError && advance() != '_')
- error(tr("Invalid array-type"));
+ error(QString::fromLatin1("Invalid array-type"));
if (!parseError)
type = QString::fromLocal8Bit("%1[%2]").
arg(parseType()).arg(dimension);
QString type;
if (advance() != 'M') {
- error(tr("Invalid pointer-to-member-type"));
+ error(QString::fromLatin1("Invalid pointer-to-member-type"));
} else {
const QString classType = parseType();
QString memberType;
QString substitution;
if (advance() != 'S') {
- error(tr("Invalid substitution"));
+ error(QString::fromLatin1("Invalid substitution"));
} else if (firstSetSeqId.contains(peek())) {
int substIndex = parseSeqId() + 1;
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").
arg(substIndex + 1).arg(substitutions.size()));
else
substitution = substitutions.at(substIndex);
if (!parseError && advance() != '_')
- error(tr("Invalid substitution"));
+ error(QString::fromLatin1("Invalid substitution"));
} else {
switch (advance().toAscii()) {
case '_':
if (substitutions.isEmpty())
- error(tr("Invalid substitution: There are no elements"));
+ error(QString::fromLatin1("Invalid substitution: There are no elements"));
else
substitution = substitutions.first();
break;
"::std::basic_iostream<char, std::char_traits<char> >");
break;
default:
- error(tr("Invalid substitution"));
+ error(QString::fromLatin1("Invalid substitution"));
}
}
if (!parseError)
parseEncoding();
} else {
- error(tr("Invalid special-name"));
+ error(QString::fromLatin1("Invalid special-name"));
}
FUNC_END(name);
} else if (firstSetUnqualifiedName.contains(peek())) {
name = parseUnqualifiedName();
} else {
- error(tr("Invalid unqualified-name"));
+ error(QString::fromLatin1("Invalid unqualified-name"));
}
FUNC_END(name);
QString name;
if (advance() != 'Z') {
- error(tr("Invalid local-name"));
+ error(QString::fromLatin1("Invalid local-name"));
} else {
name = parseEncoding();
if (!parseError && advance() != 'E') {
- error(tr("Invalid local-name"));
+ error(QString::fromLatin1("Invalid local-name"));
} else {
QString str = readAhead(2);
QChar next = peek();
advance();
name += QLatin1String("::\"string literal\"");
} else {
- error(tr("Invalid local-name"));
+ error(QString::fromLatin1("Invalid local-name"));
}
if (!parseError && firstSetDiscriminator.contains(peek()))
parseDiscriminator();
{
int index;
if (advance() != '_') {
- error(tr("Invalid discriminator"));
+ error(QString::fromLatin1("Invalid discriminator"));
index = -1;
} else {
index = parseNonNegativeNumber();
case '3':
break;
default:
- error(tr("Invalid ctor-dtor-name"));
+ error(QString::fromLatin1("Invalid ctor-dtor-name"));
}
break;
case 'D':
destructor = true;
break;
default:
- error(tr("Invalid ctor-dtor-name"));
+ error(QString::fromLatin1("Invalid ctor-dtor-name"));
}
break;
default:
- error(tr("Invalid ctor-dtor-name"));
+ error(QString::fromLatin1("Invalid ctor-dtor-name"));
}
if (!parseError) {
parseVOffset();
break;
default:
- error(tr("Invalid call-offset"));
+ error(QString::fromLatin1("Invalid call-offset"));
}
if (!parseError && advance() != '_')
- error(tr("Invalid call-offset"));
+ error(QString::fromLatin1("Invalid call-offset"));
FUNC_END(QString());
}
parseNumber();
if (advance() != '_')
- error(tr("Invalid v-offset"));
+ error(QString::fromLatin1("Invalid v-offset"));
parseNumber();
FUNC_END(QString());
int digit = advance().digitValue();
if (digit == -1)
- error(tr("Invalid digit"));
+ error(QString::fromLatin1("Invalid digit"));
FUNC_END(QString::number(digit));
return digit;
void NameDemanglerPrivate::error(const QString &errorSpec)
{
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)
+++ /dev/null
-/**************************************************************************
-**
-** 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
+++ /dev/null
-/**************************************************************************
-**
-** 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