Imported existing sources

This commit is contained in:
0xFEEDC0DE64
2018-09-15 20:45:40 +02:00
parent 13c3c2e365
commit 14d9b15a2f
4 changed files with 457 additions and 0 deletions

22
DbHashCracker.pro Normal file
View File

@@ -0,0 +1,22 @@
QT += core sql
QT -= gui widgets
DBLIBS +=
TARGET = hashcracker
PROJECT_ROOT = ..
SOURCES += main.cpp \
workerthread.cpp
HEADERS += \
workerthread.h
FORMS +=
RESOURCES +=
TRANSLATIONS +=
include($${PROJECT_ROOT}/app.pri)

271
main.cpp Normal file
View File

@@ -0,0 +1,271 @@
#include <QCoreApplication>
#include <qlogging.h>
#include <QCommandLineParser>
#include <QCommandLineOption>
#include <QString>
#include <QDebug>
#include <QStringList>
#include <QFile>
#include <QTextStream>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>
#include <QVector>
#include <QStringList>
#include <QDateTime>
#include <QTimer>
#include <algorithm>
#include "workerthread.h"
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
qSetMessagePattern(QStringLiteral("%{time HH:mm:ss.zzz} "
"["
"%{if-debug}D%{endif}"
"%{if-info}I%{endif}"
"%{if-warning}W%{endif}"
"%{if-critical}C%{endif}"
"%{if-fatal}F%{endif}"
"] "
"%{message}"));
QCommandLineParser parser;
parser.addHelpOption();
parser.addVersionOption();
parser.addOptions({
{
{ QStringLiteral("f"), QStringLiteral("filename") },
QCoreApplication::translate("main", "File containing the wordlist"),
QCoreApplication::translate("main", "filename"),
QStringLiteral("wordlist.txt")
},
{
{ QStringLiteral("n"), QStringLiteral("table-name") },
QCoreApplication::translate("main", "Name of the table to be filled"),
QCoreApplication::translate("main", "table"),
QStringLiteral("Hashes")
},
{
{ QStringLiteral("d"), QStringLiteral("no-drop-table") },
QCoreApplication::translate("main", "Don't drop the (old) hash table at the beginning"),
},
{
{ QStringLiteral("c"), QStringLiteral("no-create-table") },
QCoreApplication::translate("main", "Don't create a table at the beginning"),
},
{
{ QStringLiteral("i"), QStringLiteral("no-index") },
QCoreApplication::translate("main", "Don't add an index on hash column"),
},
{
{ QStringLiteral("p"), QStringLiteral("no-primary") },
QCoreApplication::translate("main", "Don't add an primary key on value column"),
},
{
{ QStringLiteral("t"), QStringLiteral("threads") },
QCoreApplication::translate("main", "Thread count"),
QCoreApplication::translate("main", "threads"),
QString::number(QThread::idealThreadCount())
},
{
{ QStringLiteral("b"), QStringLiteral("buffer-size") },
QCoreApplication::translate("main", "Buffer size (per thread)"),
QCoreApplication::translate("main", "buffer-size"),
QString::number(100)
},
{
{ QStringLiteral("r"), QStringLiteral("no-replace-into") },
QCoreApplication::translate("main", "Use INSERT INTO instead of REPLACE INTO")
},
{
QStringLiteral("no-delayed"),
QCoreApplication::translate("main", "Dont add DELAYED keyword when inserting")
}
});
parser.process(app);
bool ok;
const auto filename = parser.value(QStringLiteral("filename"));
const auto tableName = parser.value(QStringLiteral("table-name"));
const auto noDropTable = parser.isSet(QStringLiteral("no-drop-table"));
const auto noCreateTable = parser.isSet(QStringLiteral("no-create-table"));
const auto noIndex = parser.isSet(QStringLiteral("no-index"));
const auto noPrimary = parser.isSet(QStringLiteral("no-primary"));
const auto threads = parser.value(QStringLiteral("threads")).toInt(&ok);
if(!ok)
{
qFatal("could not parse threads");
return -1;
}
const auto bufferSize = parser.value(QStringLiteral("buffer-size")).toInt(&ok);;
if(!ok)
{
qFatal("could not parse bufferSize");
return -2;
}
const auto noReplace = parser.isSet(QStringLiteral("no-replace-into"));
const auto noDelayed = parser.isSet(QStringLiteral("no-delayed"));
qDebug() << "filename =" << filename;
qDebug() << "tableName =" << tableName;
qDebug() << "noDropTable =" << noDropTable;
qDebug() << "noCreateTable =" << noCreateTable;
qDebug() << "noIndex =" << noIndex;
qDebug() << "noPrimary =" << noPrimary;
qDebug() << "threads =" << threads;
qDebug() << "bufferSize =" << bufferSize;
qDebug() << "noReplace =" << noReplace;
qDebug() << "noDelayed =" << noDelayed;
qDebug() << "reading wordlist...";
QStringList wordlist;
{
QFile file(filename);
if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
qCritical() << file.errorString();
return -1;
}
QTextStream textStream(&file);
while(!textStream.atEnd())
wordlist.append(textStream.readLine());
}
{
QSqlDatabase db = WorkerThread::getDatabase();
if(!noDropTable)
{
qDebug() << "dropping old table...";
auto query = db.exec(QStringLiteral("DROP TABLE IF EXISTS `%0`").arg(tableName));
if(query.lastError().isValid())
{
qCritical() << query.lastError().text();
qCritical() << query.lastError().databaseText();
qFatal("could not delete old table");
return -3;
}
}
if(!noCreateTable)
{
qDebug() << "creating table...";
QString indexSql;
if(noIndex)
qWarning() << "will not add an index for hash";
else
indexSql.append(QStringLiteral(",INDEX(`Hash`)"));
if(noPrimary)
qWarning() << "will not add an primary for value";
else
indexSql.append(QStringLiteral(",PRIMARY KEY(`Value`)"));
auto query = db.exec(QStringLiteral("CREATE TABLE `%0` ("
" `Hash` CHAR(32) NOT NULL,"
" `Value` VARCHAR(64) NOT NULL"
" %1"
")").arg(tableName).arg(indexSql));
if(query.lastError().isValid())
{
qCritical() << query.lastError().text();
qCritical() << query.lastError().databaseText();
qFatal("could not create table");
return -4;
}
}
}
QVector<QStringList> prefixes(threads);
for(auto iter = wordlist.constBegin(); iter != wordlist.constEnd(); )
for(int i = 0; i < threads && iter != wordlist.constEnd(); i++, iter++)
prefixes[i].append(*iter);
const quint64 allcount = quint64(wordlist.count()) * quint64(wordlist.count());
QVector<WorkerThread*> workers(threads);
for(int i = 0; i < threads; i++)
{
workers[i] = new WorkerThread(prefixes.at(i), wordlist, tableName, bufferSize, noReplace, noDelayed);
workers.at(i)->start();
QObject::connect(workers.at(i), &QThread::finished, [&workers](){
qDebug() << "thread finished";
const auto allFinished = std::all_of(workers.constBegin(), workers.constEnd(), [](const WorkerThread *worker){
return worker->isFinished();
});
if(allFinished)
{
qDeleteAll(workers);
workers.clear();
qApp->quit();
}
});
}
const auto started = QDateTime::currentDateTime();
QTimer timer;
timer.setInterval(1000);
QObject::connect(&timer, &QTimer::timeout, [allcount, started](){
try {
auto formatTime = [](quint64 total){
auto seconds = total % 60;
total -= seconds;
total /= 60;
auto minutes = total % 60;
total -= minutes;
total /= 60;
const auto hours = total;
return QString("%0:%1:%2")
.arg(hours)
.arg(minutes, 2, 10, QLatin1Char('0'))
.arg(seconds, 2, 10, QLatin1Char('0'));
};
const quint64 sum = WorkerThread::m_counter;
const auto speed = WorkerThread::m_speed.fetchAndStoreOrdered(0);
const auto elapsed = started.secsTo(QDateTime::currentDateTime());
const auto avgSpeed = elapsed == 0 ? 0 : sum / elapsed;
const auto remaining = allcount-sum;
qInfo().nospace().noquote() << formatTime(elapsed) << " | "
<< sum << "/" << allcount
<< " (" << QString::number(qreal(sum)/allcount*100., 'f', 2) << "%) | NOW "
<< speed << "/sec "
<< formatTime(speed == 0 ? 0 : remaining/speed) << " | AVG "
<< avgSpeed << "/sec "
<< formatTime(avgSpeed == 0 ? 0 : remaining/avgSpeed);
} catch (...) {
qCritical() << "exception while printing stats";
}
});
timer.start();
const auto result = app.exec();
qDebug() << "finished.";
return result;
}

124
workerthread.cpp Normal file
View File

@@ -0,0 +1,124 @@
#include "workerthread.h"
#include <QQueue>
#include <QPair>
#include <QCryptographicHash>
#include <QDebug>
#include <QProcessEnvironment>
#include <QSqlError>
QAtomicInt WorkerThread::m_dbIdentifier;
QAtomicInteger<quint64> WorkerThread::m_counter;
QAtomicInt WorkerThread::m_speed;
WorkerThread::WorkerThread(const QStringList &prefixes, const QStringList &suffixes, const QString &tableName,
const int bufferSize, const bool noReplace, const bool noDelayed, QObject *parent) :
QThread(parent), m_prefixes(prefixes), m_suffixes(suffixes), m_tableName(tableName),
m_bufferSize(bufferSize), m_noReplace(noReplace), m_noDelayed(noDelayed)
{
}
void WorkerThread::run()
{
QSqlDatabase db = getDatabase(QStringLiteral("thread%0").arg(m_dbIdentifier++));
if(!db.isOpen())
return;
QSqlQuery query = getQuery(db, m_tableName, m_noReplace, m_noDelayed, m_bufferSize);
//TODO error handling
QQueue<QPair<QString, QString> > queue;
for(const auto &prefix : m_prefixes)
for(const auto &suffix : m_suffixes)
{
const auto word = prefix + suffix;
queue.enqueue(qMakePair(QCryptographicHash::hash(word.toUtf8(), QCryptographicHash::Md5).toHex(), word));
m_counter++;
m_speed++;
if(queue.count() == m_bufferSize)
if(!bindAndExecute(query, queue))
return;
if(isInterruptionRequested())
return;
}
if(!queue.isEmpty())
{
query = getQuery(db, m_tableName, m_noReplace, m_noDelayed, queue.count());
//TODO error handling
if(!bindAndExecute(query, queue))
return;
}
}
QSqlDatabase WorkerThread::getDatabase(const QString &connectionName)
{
qDebug() << "connecting to database for" << connectionName;
QSqlDatabase db(QSqlDatabase::addDatabase(QStringLiteral("QMYSQL"), connectionName));
db.setHostName(QProcessEnvironment::systemEnvironment().value(QStringLiteral("MYSQL_HOSTNAME"), QStringLiteral("localhost")));
db.setUserName(QProcessEnvironment::systemEnvironment().value(QStringLiteral("MYSQL_USERNAME"), QStringLiteral("hashcracker")));
db.setPassword(QProcessEnvironment::systemEnvironment().value(QStringLiteral("MYSQL_PASSWORD"), QStringLiteral("topsecret")));
db.setDatabaseName(QProcessEnvironment::systemEnvironment().value(QStringLiteral("MYSQL_DATABASE"), QStringLiteral("hashcracker")));
if(!db.open())
{
qCritical() << db.lastError().text();
qCritical() << db.lastError().databaseText();
qFatal("could not connect to database");
}
return db;
}
QSqlQuery WorkerThread::getQuery(const QSqlDatabase &db, const QString &tableName, const bool noReplace, const bool noDelayed, const int rowCount)
{
QSqlQuery query(db);
QString columns;
for(int i = 0; i < rowCount; i++)
{
if(i > 0)
columns.append(',');
columns.append(QStringLiteral(" (:Hash%0, :Value%0)").arg(i));
}
if(!query.prepare(QStringLiteral("%0%1 INTO `%2` (`Hash`, `Value`) VALUES%3")
.arg(noReplace ? QStringLiteral("INSERT") : QStringLiteral("REPLACE"))
.arg(noDelayed ? QString() : QStringLiteral(" DELAYED"))
.arg(tableName)
.arg(columns)))
{
qCritical() << query.lastError().text();
qCritical() << query.lastError().databaseText();
qFatal("could not prepare query");
}
return query;
}
bool WorkerThread::bindAndExecute(QSqlQuery &query, QQueue<QPair<QString, QString> > &queue)
{
for(int i = 0; !queue.isEmpty(); i++)
{
const auto pair = queue.dequeue();
query.bindValue(QStringLiteral(":Hash%0").arg(i), pair.first);
query.bindValue(QStringLiteral(":Value%0").arg(i), pair.second);
}
const auto result = query.exec();
if(!result)
{
qCritical() << query.lastError().text();
qCritical() << query.lastError().databaseText();
qFatal("could not execute query");
}
return result;
}

40
workerthread.h Normal file
View File

@@ -0,0 +1,40 @@
#pragma once
#include <QThread>
#include <QAtomicInteger>
#include <QAtomicInt>
#include <QStringList>
#include <QString>
#include <QSqlDatabase>
#include <QSqlQuery>
template <class T> class QQueue;
template <class T1, class T2> struct QPair;
class WorkerThread : public QThread
{
Q_OBJECT
static QAtomicInt m_dbIdentifier;
public:
static QAtomicInteger<quint64> m_counter;
static QAtomicInt m_speed;
explicit WorkerThread(const QStringList &prefixes, const QStringList &suffixes, const QString &tableName,
const int bufferSize, const bool noReplace, const bool noDelayed, QObject *parent = Q_NULLPTR);
void run() Q_DECL_OVERRIDE;
static QSqlDatabase getDatabase(const QString &connectionName = QLatin1String(QSqlDatabase::defaultConnection));
static QSqlQuery getQuery(const QSqlDatabase &db, const QString &tableName, const bool noReplace, const bool noDelayed, const int rowCount);
static bool bindAndExecute(QSqlQuery &query, QQueue<QPair<QString, QString> > &queue);
private:
const QStringList m_prefixes;
const QStringList m_suffixes;
const QString m_tableName;
const int m_bufferSize;
const bool m_noReplace;
const bool m_noDelayed;
};