diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt
index f128a9240..03398f150 100644
--- a/launcher/CMakeLists.txt
+++ b/launcher/CMakeLists.txt
@@ -12,6 +12,7 @@ set(launcher_SRCS
 		modManager/cmodlistview_moc.cpp
 		modManager/cmodmanager.cpp
 		modManager/imageviewer_moc.cpp
+		modManager/chroniclesextractor.cpp
 		settingsView/csettingsview_moc.cpp
 		firstLaunch/firstlaunch_moc.cpp
 		main.cpp
@@ -42,6 +43,7 @@ set(launcher_HEADERS
 		modManager/cmodlistview_moc.h
 		modManager/cmodmanager.h
 		modManager/imageviewer_moc.h
+		modManager/chroniclesextractor.h
 		settingsView/csettingsview_moc.h
 		firstLaunch/firstlaunch_moc.h
 		mainwindow_moc.h
diff --git a/launcher/modManager/chroniclesextractor.cpp b/launcher/modManager/chroniclesextractor.cpp
new file mode 100644
index 000000000..79a6c2919
--- /dev/null
+++ b/launcher/modManager/chroniclesextractor.cpp
@@ -0,0 +1,58 @@
+/*
+ * chroniclesextractor.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+#include "StdInc.h"
+
+#include "chroniclesextractor.h"
+
+void ChroniclesExtractor::installExe(QWidget *parent, QStringList exe)
+{
+	for(QString f : exe)
+	{
+		QFile file(f);
+		if(!file.open(QIODevice::ReadOnly))
+		{
+			QMessageBox::critical(parent, tr("File cannot opened"), file.errorString());
+			continue;
+		}
+
+		QByteArray magic{"MZ"};
+		QByteArray magicFile = file.read(magic.length());
+		if(!magicFile.startsWith(magic))
+		{
+			QMessageBox::critical(parent, tr("Invalid file selected"), tr("You have to select an gog installer file!"));
+			continue;
+		}
+
+		QByteArray dataBegin = file.read(10'000'000);
+		const std::map<int, QByteArray> chronicles = {
+			{1, QByteArray{reinterpret_cast<const char*>(u"Heroes Chronicles - Warlords of the Wasteland"), 90}},
+			{2, QByteArray{reinterpret_cast<const char*>(u"Heroes Chronicles - Conquest of the Underworld"), 92}},
+			{3, QByteArray{reinterpret_cast<const char*>(u"Heroes Chronicles - Masters of the Elements"), 86}},
+			{4, QByteArray{reinterpret_cast<const char*>(u"Heroes Chronicles - Clash of the Dragons"), 80}},
+			{5, QByteArray{reinterpret_cast<const char*>(u"Heroes Chronicles - The World Tree"), 68}},
+			{6, QByteArray{reinterpret_cast<const char*>(u"Heroes Chronicles - The Fiery Moon"), 68}},
+			{7, QByteArray{reinterpret_cast<const char*>(u"Heroes Chronicles - Revolt of the Beastmasters"), 92}},
+			{8, QByteArray{reinterpret_cast<const char*>(u"Heroes Chronicles - The Sword of Frost"), 76}}
+		};
+		int chronicle = 0;
+		for (const auto& kv : chronicles) {
+			if(dataBegin.contains(kv.second))
+			{
+				chronicle = kv.first;
+				break;
+			}
+		}
+		if(!chronicle)
+		{
+			QMessageBox::critical(parent, tr("Invalid file selected"), tr("You have to select an chronicle installer file!"));
+			continue;
+		}
+	}
+}
\ No newline at end of file
diff --git a/launcher/modManager/chroniclesextractor.h b/launcher/modManager/chroniclesextractor.h
new file mode 100644
index 000000000..c87751c36
--- /dev/null
+++ b/launcher/modManager/chroniclesextractor.h
@@ -0,0 +1,20 @@
+/*
+ * chroniclesextractor.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+#pragma once
+
+#include "../StdInc.h"
+
+class ChroniclesExtractor : public QObject
+{
+	Q_OBJECT
+
+public:
+	static void installExe(QWidget *parent, QStringList exe);
+};
\ No newline at end of file
diff --git a/launcher/modManager/cmodlistview_moc.cpp b/launcher/modManager/cmodlistview_moc.cpp
index 5c351b366..e3459d021 100644
--- a/launcher/modManager/cmodlistview_moc.cpp
+++ b/launcher/modManager/cmodlistview_moc.cpp
@@ -20,6 +20,7 @@
 #include "cmodlistmodel_moc.h"
 #include "cmodmanager.h"
 #include "cdownloadmanager_moc.h"
+#include "chroniclesextractor.h"
 #include "../settingsView/csettingsview_moc.h"
 #include "../launcherdirs.h"
 #include "../jsonutils.h"
@@ -55,7 +56,7 @@ void CModListView::dragEnterEvent(QDragEnterEvent* event)
 {
 	if(event->mimeData()->hasUrls())
 		for(const auto & url : event->mimeData()->urls())
-			for(const auto & ending : QStringList({".zip", ".h3m", ".h3c", ".vmap", ".vcmp", ".json"}))
+			for(const auto & ending : QStringList({".zip", ".h3m", ".h3c", ".vmap", ".vcmp", ".json", ".exe"}))
 				if(url.fileName().endsWith(ending, Qt::CaseInsensitive))
 				{
 					event->acceptProposedAction();
@@ -636,8 +637,8 @@ void CModListView::on_installFromFileButton_clicked()
 	// https://bugreports.qt.io/browse/QTBUG-98651
 	QTimer::singleShot(0, this, [this]
 	{
-		QString filter = tr("All supported files") + " (*.h3m *.vmap *.h3c *.vcmp *.zip *.json);;" + tr("Maps") + " (*.h3m *.vmap);;" + tr("Campaigns") + " (*.h3c *.vcmp);;" + tr("Configs") + " (*.json);;" + tr("Mods") + " (*.zip)";
-		QStringList files = QFileDialog::getOpenFileNames(this, tr("Select files (configs, mods, maps, campaigns) to install..."), QDir::homePath(), filter);
+		QString filter = tr("All supported files") + " (*.h3m *.vmap *.h3c *.vcmp *.zip *.json *.exe);;" + tr("Maps") + " (*.h3m *.vmap);;" + tr("Campaigns") + " (*.h3c *.vcmp);;" + tr("Configs") + " (*.json);;" + tr("Mods") + " (*.zip);;" + tr("Gog files") + " (*.exe)";
+		QStringList files = QFileDialog::getOpenFileNames(this, tr("Select files (configs, mods, maps, campaigns, gog files) to install..."), QDir::homePath(), filter);
 
 		for(const auto & file : files)
 		{
@@ -786,6 +787,7 @@ void CModListView::installFiles(QStringList files)
 	QStringList mods;
 	QStringList maps;
 	QStringList images;
+	QStringList exe;
 	QVector<QVariantMap> repositories;
 
 	// TODO: some better way to separate zip's with mods and downloaded repository files
@@ -795,6 +797,8 @@ void CModListView::installFiles(QStringList files)
 			mods.push_back(filename);
 		else if(filename.endsWith(".h3m", Qt::CaseInsensitive) || filename.endsWith(".h3c", Qt::CaseInsensitive) || filename.endsWith(".vmap", Qt::CaseInsensitive) || filename.endsWith(".vcmp", Qt::CaseInsensitive))
 			maps.push_back(filename);
+		if(filename.endsWith(".exe", Qt::CaseInsensitive))
+			exe.push_back(filename);
 		else if(filename.endsWith(".json", Qt::CaseInsensitive))
 		{
 			//download and merge additional files
@@ -832,6 +836,9 @@ void CModListView::installFiles(QStringList files)
 	if(!maps.empty())
 		installMaps(maps);
 
+	if(!exe.empty())
+		ChroniclesExtractor::installExe(this, exe);
+
 	if(!images.empty())
 		loadScreenshots();
 }