diff --git a/CMakeLists.txt b/CMakeLists.txt
index 08ce949..dd7be16 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -18,13 +18,16 @@ set(CHECKBRUTE_SOURCES
     src/mainthread.cpp
     src/brutethread.cpp
     src/checksum.cpp
+    src/checksum_lib.cpp
     src/checksum_qt.cpp
 )
 
 set(CHECKBRUTE_HEADERS
     src/mainthread.h
     src/brutethread.h
+    src/checkbrute.h
     src/checksum.h
+    src/checksum_lib.h
     src/checksum_qt.h
 )
 
@@ -33,6 +36,7 @@ add_executable(checkbrute
     ${CHECKBRUTE_SOURCES}
 )
 
+target_compile_definitions(checkbrute PRIVATE "CHECKBRUTE_PLUGINS=\"${CMAKE_INSTALL_PREFIX}/share/checkbrute/plugins\"")
 target_link_libraries(checkbrute PRIVATE Qt5::Core)
 
 install(TARGETS checkbrute DESTINATION bin)
diff --git a/src/brutethread.cpp b/src/brutethread.cpp
index a821d2e..46d3fb4 100644
--- a/src/brutethread.cpp
+++ b/src/brutethread.cpp
@@ -16,10 +16,11 @@
 * responsible for anything with use of the software, you are self responsible.
 *****************************************************************************/
 
+#include <QDebug>
 #include <QTextStream>
 #include "brutethread.h"
 
-brutethread::brutethread(const QByteArray &fileContent, quint64 length, QVector<checksum*> checksum_vector, QVector<QByteArray> checksums, bool strictMatch) : checksum_vector(checksum_vector), checksums(checksums), fileContent(fileContent), strictMatch(strictMatch), length(length) {}
+brutethread::brutethread(const QByteArray &fileContent, quint64 length, quint64 begin, QVector<checksum*> checksum_vector, QVector<QByteArray> checksums, bool strictMatch) : checksum_vector(checksum_vector), checksums(checksums), fileContent(fileContent), strictMatch(strictMatch), length(length), begin(begin) {}
 
 void brutethread::run()
 {
@@ -27,14 +28,14 @@ void brutethread::run()
     for (quint64 seek = 0; seek + length < size; seek++) {
         for (checksum *generator : checksum_vector) {
             const QByteArray content = fileContent.mid(seek, length);
-            const QByteArray generatedHash = generator->generateChecksum(content).toHex();
+            const QByteArray generatedHash = generator->generateChecksum(content);
             for (const QByteArray &hash : checksums) {
                 if (!strictMatch && generatedHash.left(hash.length()) == hash) {
-                    QTextStream(stdout) << "MATCH: " << generator->formatName() << " Checksum " << hash << " Start " << seek << " End " << seek+length << Qt::endl;
+                    QTextStream(stdout) << "MATCH: " << generator->formatName() << " Checksum " << hash << " Start " << begin+seek << " End " << begin+seek+length << Qt::endl;
                     emit matched();
                 }
                 else if (strictMatch && generatedHash.length() == hash.length() && generatedHash == hash) {
-                    QTextStream(stdout) << "MATCH: " << generator->formatName() << " Checksum " << hash << " Start " << seek << " End " << seek+length << Qt::endl;
+                    QTextStream(stdout) << "MATCH: " << generator->formatName() << " Checksum " << hash << " Start " << begin+seek << " End " << begin+seek+length << Qt::endl;
                     emit matched();
                 }
             }
diff --git a/src/brutethread.h b/src/brutethread.h
index d011af9..5f15b8e 100644
--- a/src/brutethread.h
+++ b/src/brutethread.h
@@ -33,7 +33,7 @@ class brutethread : public QThread
 {
     Q_OBJECT
 public:
-    explicit brutethread(const QByteArray &fileContent, quint64 length, QVector<checksum*> checksum_vector, QVector<QByteArray> checksums, bool strictMatch);
+    explicit brutethread(const QByteArray &fileContent, quint64 length, quint64 begin, QVector<checksum*> checksum_vector, QVector<QByteArray> checksums, bool strictMatch);
     void run();
 
 private:
@@ -42,6 +42,7 @@ private:
     QByteArray fileContent;
     bool strictMatch;
     quint64 length;
+    quint64 begin;
 
 signals:
     void matched();
diff --git a/src/checkbrute.h b/src/checkbrute.h
new file mode 100644
index 0000000..dbfb3bb
--- /dev/null
+++ b/src/checkbrute.h
@@ -0,0 +1,26 @@
+/*****************************************************************************
+* checkbrute Checksum Bruteforcing Tool
+* Copyright (C) 2020 Syping
+*
+* Redistribution and use in source and binary forms, with or without modification,
+* are permitted provided that the following conditions are met:
+*
+* 1. Redistributions of source code must retain the above copyright notice,
+* this list of conditions and the following disclaimer.
+*
+* 2. Redistributions in binary form must reproduce the above copyright notice,
+* this list of conditions and the following disclaimer in the documentation
+* and/or other materials provided with the distribution.
+*
+* This software is provided as-is, no warranties are given to you, we are not
+* responsible for anything with use of the software, you are self responsible.
+*****************************************************************************/
+
+#ifndef CHECKBRUTE_H
+#define CHECKBRUTE_H
+
+#ifndef CHECKBRUTE_PLUGINS
+#define CHECKBRUTE_PLUGINS "/usr/local/share/checkbrute/plugins"
+#endif
+
+#endif // CHECKBRUTE_H
diff --git a/src/checksum_lib.cpp b/src/checksum_lib.cpp
new file mode 100644
index 0000000..9138767
--- /dev/null
+++ b/src/checksum_lib.cpp
@@ -0,0 +1,63 @@
+/*****************************************************************************
+* checkbrute Checksum Bruteforcing Tool
+* Copyright (C) 2020 Syping
+*
+* Redistribution and use in source and binary forms, with or without modification,
+* are permitted provided that the following conditions are met:
+*
+* 1. Redistributions of source code must retain the above copyright notice,
+* this list of conditions and the following disclaimer.
+*
+* 2. Redistributions in binary form must reproduce the above copyright notice,
+* this list of conditions and the following disclaimer in the documentation
+* and/or other materials provided with the distribution.
+*
+* This software is provided as-is, no warranties are given to you, we are not
+* responsible for anything with use of the software, you are self responsible.
+*****************************************************************************/
+
+#include "checksum_lib.h"
+#include <iostream>
+#include <cstdint>
+#include <cstring>
+
+checksum_lib::checksum_lib(PluginFormatFunction formatFunc, PluginHash32Function hash32Func, PluginHashSzFunction hashSzFunc) : hash32Func(hash32Func)
+{
+    p_formatName = QString::fromUtf8(formatFunc());
+    p_checksumSize = hashSzFunc();
+    p_funcBit = 32;
+}
+
+checksum_lib::checksum_lib(PluginFormatFunction formatFunc, PluginHash64Function hash64Func, PluginHashSzFunction hashSzFunc) : hash64Func(hash64Func)
+{
+    p_formatName = QString::fromUtf8(formatFunc());
+    p_checksumSize = hashSzFunc();
+    p_funcBit = 64;
+}
+
+QByteArray checksum_lib::generateChecksum(const QByteArray &data)
+{
+    const size_t size = data.size();
+    unsigned char *udata = new unsigned char[size];
+    std::memcpy(udata, data.constData(), size);
+    if (p_funcBit == 32) {
+        const u_int32_t hash = hash32Func(udata, size);
+        free(udata);
+        return QByteArray::number((quint32)hash, 16);
+    }
+    else {
+        const u_int64_t hash = hash64Func(udata, size);
+        free(udata);
+        return QByteArray::number((quint64)hash, 16);
+    }
+}
+
+const QString checksum_lib::formatName()
+{
+    return p_formatName;
+}
+
+int checksum_lib::checksumSize()
+{
+    return p_checksumSize;
+}
diff --git a/src/checksum_lib.h b/src/checksum_lib.h
new file mode 100644
index 0000000..f706c2c
--- /dev/null
+++ b/src/checksum_lib.h
@@ -0,0 +1,48 @@
+/*****************************************************************************
+* checkbrute Checksum Bruteforcing Tool
+* Copyright (C) 2020 Syping
+*
+* Redistribution and use in source and binary forms, with or without modification,
+* are permitted provided that the following conditions are met:
+*
+* 1. Redistributions of source code must retain the above copyright notice,
+* this list of conditions and the following disclaimer.
+*
+* 2. Redistributions in binary form must reproduce the above copyright notice,
+* this list of conditions and the following disclaimer in the documentation
+* and/or other materials provided with the distribution.
+*
+* This software is provided as-is, no warranties are given to you, we are not
+* responsible for anything with use of the software, you are self responsible.
+*****************************************************************************/
+
+#ifndef CHECKSUM_LIB_H
+#define CHECKSUM_LIB_H
+
+#include "checksum.h"
+
+typedef int (*PluginHashSzFunction)();
+typedef const char* (*PluginFormatFunction)();
+typedef const char* (*PluginVersionFunction)();
+typedef u_int32_t (*PluginHash32Function)(unsigned char*, size_t);
+typedef u_int64_t (*PluginHash64Function)(unsigned char*, size_t);
+
+class checksum_lib : public checksum
+{
+    Q_OBJECT
+public:
+    explicit checksum_lib(PluginFormatFunction formatFunc, PluginHash32Function hash32Func, PluginHashSzFunction hashSzFunc);
+    explicit checksum_lib(PluginFormatFunction formatFunc, PluginHash64Function hash64Func, PluginHashSzFunction hashSzFunc);
+    QByteArray generateChecksum(const QByteArray &data);
+    const QString formatName();
+    int checksumSize();
+
+private:
+    PluginHash32Function hash32Func;
+    PluginHash64Function hash64Func;
+    QString p_formatName;
+    int p_checksumSize;
+    int p_funcBit;
+};
+
+#endif // CHECKSUM_LIB_H
diff --git a/src/checksum_qt.cpp b/src/checksum_qt.cpp
index 7c69284..fdcd560 100644
--- a/src/checksum_qt.cpp
+++ b/src/checksum_qt.cpp
@@ -23,7 +23,7 @@ checksum_qt::checksum_qt(QCryptographicHash::Algorithm algorithm, const QString
 
 QByteArray checksum_qt::generateChecksum(const QByteArray &data)
 {
-    return QCryptographicHash::hash(data, algorithm);
+    return QCryptographicHash::hash(data, algorithm).toHex();
 }
 
 const QString checksum_qt::formatName()
diff --git a/src/checksum_qt.h b/src/checksum_qt.h
index 95a58f0..3fdd03c 100644
--- a/src/checksum_qt.h
+++ b/src/checksum_qt.h
@@ -36,4 +36,4 @@ private:
     QString name;
 };
 
-#endif // CHECKSUM_MD5_H
+#endif // CHECKSUM_QT5_H
diff --git a/src/main.cpp b/src/main.cpp
index a85a050..c7194c3 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -22,17 +22,21 @@
 #include <QCoreApplication>
 #include <QTextStream>
 #include <QFileInfo>
+#include <QLibrary>
 #include <QThread>
+#include <QDir>
 
 // checkbrute includes
 #include "mainthread.h"
+#include "checkbrute.h"
 #include "checksum_qt.h"
+#include "checksum_lib.h"
 
 int main(int argc, char *argv[])
 {
     QCoreApplication a(argc, argv);
     a.setApplicationName("checkbrute");
-    a.setApplicationVersion("0.1.1");
+    a.setApplicationVersion("0.3.3");
 
     QCommandLineParser commandLineParser;
     commandLineParser.addHelpOption();
@@ -45,7 +49,8 @@ int main(int argc, char *argv[])
     QCommandLineOption lengthsOption = QCommandLineOption("lengths", "Lengths to use for bruteforcing.", "lengths");
     QCommandLineOption threadsOption = QCommandLineOption("threads", "Threads to use for bruteforcing.", "threads");
     QCommandLineOption strictOption = QCommandLineOption(QStringList() << "s" << "strict", "Match checksums strict.");
-    commandLineParser.addOptions(QList<QCommandLineOption>() << algorithmsOption << startOption << stopOption << lengthsOption << threadsOption << strictOption);
+    QCommandLineOption testOption = QCommandLineOption(QStringList() << "t" << "test", "Test checkbrute plugin hashes.");
+    commandLineParser.addOptions(QList<QCommandLineOption>() << algorithmsOption << startOption << stopOption << lengthsOption << threadsOption << strictOption << testOption);
     commandLineParser.process(a);
 
     QTextStream(stderr) << "INFO: Launch " << a.applicationName() << " " << a.applicationVersion() << "..." << Qt::endl;
@@ -58,6 +63,7 @@ int main(int argc, char *argv[])
     const QString bruteforceFile = args.at(0);
     const QString checksumsFile = args.at(1);
     const bool strictHash = commandLineParser.isSet(strictOption);
+    const bool testEnabled = commandLineParser.isSet(testOption);
 
     if (strictHash) {
         QTextStream(stderr) << "INFO: Strict matching enabled" << Qt::endl;
@@ -85,11 +91,11 @@ int main(int argc, char *argv[])
     std::map<std::string,checksum*> checksum_map;
     checksum_map["MD4"] = new checksum_qt(QCryptographicHash::Md4, "MD4");
     checksum_map["MD5"] = new checksum_qt(QCryptographicHash::Md5, "MD5");
-    checksum_map["SHA1"] = new checksum_qt(QCryptographicHash::Sha1, "SHA1");
-    checksum_map["SHA2-224"] = new checksum_qt(QCryptographicHash::Sha224, "SHA2-224");
-    checksum_map["SHA2-256"] = new checksum_qt(QCryptographicHash::Sha256, "SHA2-256");
-    checksum_map["SHA2-384"] = new checksum_qt(QCryptographicHash::Sha384, "SHA2-384");
-    checksum_map["SHA2-512"] = new checksum_qt(QCryptographicHash::Sha512, "SHA2-512");
+    checksum_map["SHA-1"] = new checksum_qt(QCryptographicHash::Sha1, "SHA-1");
+    checksum_map["SHA-224"] = new checksum_qt(QCryptographicHash::Sha224, "SHA-224");
+    checksum_map["SHA-256"] = new checksum_qt(QCryptographicHash::Sha256, "SHA-256");
+    checksum_map["SHA-384"] = new checksum_qt(QCryptographicHash::Sha384, "SHA-384");
+    checksum_map["SHA-512"] = new checksum_qt(QCryptographicHash::Sha512, "SHA-512");
     checksum_map["SHA3-224"] = new checksum_qt(QCryptographicHash::Sha3_224, "SHA3-224");
     checksum_map["SHA3-256"] = new checksum_qt(QCryptographicHash::Sha3_256, "SHA3-256");
     checksum_map["SHA3-384"] = new checksum_qt(QCryptographicHash::Sha3_384, "SHA3-384");
@@ -101,6 +107,47 @@ int main(int argc, char *argv[])
     checksum_map["Keccak-512"] = new checksum_qt(QCryptographicHash::Keccak_512, "Keccak-512");
 #endif
 
+    for (const QString &fileName : QDir(CHECKBRUTE_PLUGINS).entryList(QDir::Files, QDir::Name)) {
+        const QString filePath = QString("%1/%2").arg(CHECKBRUTE_PLUGINS, fileName);
+        if (QLibrary::isLibrary(filePath)) {
+            QTextStream(stderr) << "INFO: Load plugin " << fileName << "..." << Qt::endl;
+            QLibrary plugin(filePath);
+            if (plugin.load()) {
+                PluginHash32Function hash32Func = (PluginHash32Function)plugin.resolve("checkbrute_hash32");
+                PluginHash64Function hash64Func = (PluginHash64Function)plugin.resolve("checkbrute_hash64");
+                PluginHashSzFunction hashSzFunc = (PluginHashSzFunction)plugin.resolve("checkbrute_hashsz");
+                PluginFormatFunction formatFunc = (PluginFormatFunction)plugin.resolve("checkbrute_format");
+                PluginVersionFunction versionFunc = (PluginVersionFunction)plugin.resolve("checkbrute_version");
+                if (formatFunc && hash32Func && hashSzFunc) {
+                    QString version = "undefined";
+                    const char *format = formatFunc();
+                    if (versionFunc)
+                        version = QString::fromUtf8(versionFunc());
+                    checksum_map[format] = new checksum_lib(formatFunc, hash32Func, hashSzFunc);
+                    QTextStream(stderr) << "INFO: " << format << " plugin " << fileName << " loaded" << Qt::endl;
+                    if (testEnabled)
+                        QTextStream(stderr) << "TEST: " << format << " checkbrute -> " << QString::number(hash32Func((unsigned char*)"checkbrute", 7), 16) << Qt::endl;
+                }
+                else if (formatFunc && hash64Func && hashSzFunc) {
+                    QString version = "undefined";
+                    const char *format = formatFunc();
+                    if (versionFunc)
+                        version = QString::fromUtf8(versionFunc());
+                    checksum_map[format] = new checksum_lib(formatFunc, hash64Func, hashSzFunc);
+                    QTextStream(stderr) << "INFO: " << format << " plugin " << fileName << " loaded" << Qt::endl;
+                    if (testEnabled)
+                        QTextStream(stderr) << "TEST: " << format << " checkbrute -> " << QString::number(hash64Func((unsigned char*)"checkbrute", 7), 16) << Qt::endl;
+                }
+                else {
+                    QTextStream(stderr) << "WARNING: Failed loading plugin " << fileName << "!" << Qt::endl;
+                }
+            }
+            else {
+                QTextStream(stderr) << "WARNING: Failed loading plugin " << fileName << "!" << Qt::endl;
+            }
+        }
+    }
+
     mainthread instance(bruteforceFile, checksumsFile, algorithms, start, stop, lengths, threads, strictHash, checksum_map);
     QObject::connect(&instance, &mainthread::finished, &a, &QCoreApplication::quit);
     if (!instance.isInitialised())
diff --git a/src/mainthread.cpp b/src/mainthread.cpp
index 5209d38..6a54fee 100644
--- a/src/mainthread.cpp
+++ b/src/mainthread.cpp
@@ -142,9 +142,10 @@ mainthread::mainthread(const QString &bruteforceFile, const QString &checksumsFi
     }
 
     // Clear unneeded bytes
-    if (begin != 0 && end != (quint64)fileContent.size()) {
+    if (begin != 0 || end != (quint64)fileContent.size()) {
         fileContent = fileContent.mid(begin, end - begin);
         fileContent.squeeze();
+        QTextStream(stderr) << "INFO: Bruteforce Start " << begin << " End " << end << Qt::endl;
     }
 
     if (!lenghts_str.isEmpty()) {
@@ -267,7 +268,7 @@ void mainthread::run()
             if (threads >= mthreads)
                 eventLoop.exec();
             QTextStream(stderr) << "[" << std::distance(lengths.constBegin(), it) + 1 << "/" << lengthsCount << "] [" << min << "/" << max << "] Bruteforcing...\r";
-            brutethread *thread = new brutethread(fileContent, min, checksum_vector, checksums, strictHash);
+            brutethread *thread = new brutethread(fileContent, min, begin, checksum_vector, checksums, strictHash);
             QObject::connect(thread, &QThread::finished, this, &mainthread::threadFinished);
             QObject::connect(thread, &brutethread::matched, this, &mainthread::matched);
             thread->start(QThread::LowPriority);
@@ -278,7 +279,7 @@ void mainthread::run()
                 if (threads >= mthreads)
                     eventLoop.exec();
                 QTextStream(stderr) << "[" << std::distance(lengths.constBegin(), it) + 1 << "/" << lengthsCount << "] [" << clength << "/" << max << "] Bruteforcing...\r";
-                brutethread *thread = new brutethread(fileContent, clength, checksum_vector, checksums, strictHash);
+                brutethread *thread = new brutethread(fileContent, clength, begin, checksum_vector, checksums, strictHash);
                 QObject::connect(thread, &QThread::finished, this, &mainthread::threadFinished);
                 QObject::connect(thread, &brutethread::matched, this, &mainthread::matched);
                 thread->start(QThread::LowPriority);
@@ -290,7 +291,7 @@ void mainthread::run()
                 if (threads >= mthreads)
                     eventLoop.exec();
                 QTextStream(stderr) << "[" << std::distance(lengths.constBegin(), it) + 1 << "/" << lengthsCount << "] [" << clength << "/" << max << "] Bruteforcing...\r";
-                brutethread *thread = new brutethread(fileContent, clength, checksum_vector, checksums, strictHash);
+                brutethread *thread = new brutethread(fileContent, clength, begin, checksum_vector, checksums, strictHash);
                 QObject::connect(thread, &QThread::finished, this, &mainthread::threadFinished);
                 QObject::connect(thread, &brutethread::matched, this, &mainthread::matched);
                 thread->start(QThread::LowPriority);