[Exception] Remove bitmrc and upload minidumps using the helper

This commit is contained in:
momo5502 2017-03-13 21:50:42 +01:00
parent a9dd792b30
commit a257292594
17 changed files with 44 additions and 1322 deletions

9
.gitmodules vendored
View File

@ -22,15 +22,6 @@
path = deps/mongoose
url = https://github.com/cesanta/mongoose.git
branch = master
[submodule "deps/bitmrc"]
path = deps/bitmrc
url = git@github.com:iw4x/BitMRC.git
branch = master
fetchRecurseSubmodules = true
[submodule "deps/base128"]
path = deps/base128
url = https://github.com/seizu/base128.git
branch = master
[submodule "deps/protobuf"]
path = deps/protobuf
url = https://github.com/google/protobuf.git

1
deps/base128 vendored

@ -1 +0,0 @@
Subproject commit 64c8ab2755e14d316b18aff9746f0180f5fe301b

1
deps/bitmrc vendored

@ -1 +0,0 @@
Subproject commit 38e5980cf3e246f42119f687dcd8ba25d4cad893

View File

@ -1,54 +0,0 @@
base128 = {
settings = nil
}
function base128.setup(settings)
if not settings.source then error("Missing source.") end
base128.settings = settings
end
function base128.import()
if not base128.settings then error("Run base128.setup first") end
base128.links()
base128.includes()
end
function base128.links()
if not base128.settings then error("Run base128.setup first") end
links { "base128" }
end
function base128.includes()
if not base128.settings then error("Run base128.setup first") end
includedirs { path.join(base128.settings.source, "cpp") }
end
function base128.project()
if not base128.settings then error("Run base128.setup first") end
project "base128"
language "C++"
base128.includes()
files
{
path.join(base128.settings.source, "cpp/*.cpp"),
path.join(base128.settings.source, "cpp/*.h"),
}
removefiles
{
"**/demo.*",
}
-- not our code, ignore POSIX usage warnings for now
warnings "Off"
defines { "_LIB" }
removedefines { "_USRDLL", "_DLL" }
kind "StaticLib"
end

View File

@ -1,64 +0,0 @@
bitmrc = {
settings = nil,
}
function bitmrc.setup(settings)
if not settings.source then error("Missing source.") end
bitmrc.settings = settings
end
function bitmrc.import()
if not bitmrc.settings then error("Run bitmrc.setup first") end
sqlite3.links()
libcryptopp.links()
bitmrc.links()
bitmrc.includes()
end
function bitmrc.links()
links { "bitmrc" }
end
function bitmrc.includes()
if not bitmrc.settings then error("Run bitmrc.setup first") end
includedirs { path.join(bitmrc.settings.source, "BitMRC/include") }
end
function bitmrc.project()
if not bitmrc.settings then error("Run bitmrc.setup first") end
project "bitmrc"
language "C++"
includedirs
{
path.join(bitmrc.settings.source, "BitMRC/include"),
path.join(bitmrc.settings.source, "BitMRC/Storage/include"),
}
files
{
path.join(bitmrc.settings.source, "BitMRC/*.cpp"),
path.join(bitmrc.settings.source, "BitMRC/Storage/*.cpp"),
}
removefiles
{
-- path.join(bitmrc.settings.source, "src/**/*test.cc"),
path.join(bitmrc.settings.source, "BitMRC/main.*"),
path.join(bitmrc.settings.source, "BitMRC/class.*"),
path.join(bitmrc.settings.source, "BitMRC/tests/**"),
path.join(bitmrc.settings.source, "BitMRC/Storage/Storable.cpp"),
}
-- dependencies
sqlite3.import()
libcryptopp.import()
defines { "_SCL_SECURE_NO_WARNINGS" }
warnings "Off"
kind "StaticLib"
end

View File

@ -1,163 +0,0 @@
libcryptopp = {
settings = nil,
}
function libcryptopp.setup(settings)
if not settings.source then error("Missing source.") end
libcryptopp.settings = settings
end
function libcryptopp.import()
if not libcryptopp.settings then error("Run libcryptopp.setup first") end
libcryptopp.links()
libcryptopp.includes()
end
function libcryptopp.links()
links { "libcryptopp" }
end
function libcryptopp.includes()
if not libcryptopp.settings then error("Run libcryptopp.setup first") end
--defines { "CRYPTOPP_IMPORTS" }
--filter "*Static"
-- removedefines { "CRYPTOPP_IMPORTS" }
filter "Debug*"
defines { "_DEBUG" }
filter "Release*"
defines { "NDEBUG" }
filter "system:windows"
defines { "_WINDOWS", "WIN32" }
filter {}
includedirs { libcryptopp.settings.source }
end
function libcryptopp.project()
if not libcryptopp.settings then error("Run libcryptopp.setup first") end
rule "MASM_dummy"
location "./build"
fileextension ""
filename "masm_dummy"
externalrule "MASM"
filename "masm_dummy"
location "./build"
buildmessage "Building and assembling %(Identity)..."
propertydefinition {
name = "PreprocessorDefinitions",
kind = "string",
value = "",
switch = "/D",
}
propertydefinition {
name = "UseSafeExceptionHandlers",
kind = "boolean",
value = false,
switch = "/safeseh",
}
--[[
rule "CustomProtoBuildTool"
display "C++ prototype copy"
location "./build"
fileExtension ".proto"
buildmessage "Preparing %(Identity)..."
buildcommands {
'if not exist "$(ProjectDir)\\src\\%(Filename)" copy "%(Identity)" "$(ProjectDir)\\src\\%(Filename)"',
'echo: >> "src\\%(Filename).copied"',
}
buildoutputs {
'$(ProjectDir)\\src\\%(Filename)',
}
]]
project "libcryptopp"
language "C++"
characterset "MBCS"
defines {
"USE_PRECOMPILED_HEADERS"
}
includedirs
{
libcryptopp.settings.source,
}
files
{
path.join(libcryptopp.settings.source, "*.cpp"),
--path.join(libcryptopp.settings.source, "*.cpp.proto"),
path.join(libcryptopp.settings.source, "*.h"),
path.join(libcryptopp.settings.source, "*.txt"),
}
removefiles {
path.join(libcryptopp.settings.source, "eccrypto.cpp"),
path.join(libcryptopp.settings.source, "eprecomp.cpp"),
path.join(libcryptopp.settings.source, "bench*"),
path.join(libcryptopp.settings.source, "*test.*"),
path.join(libcryptopp.settings.source, "fipsalgt.*"),
path.join(libcryptopp.settings.source, "cryptlib_bds.*"),
path.join(libcryptopp.settings.source, "validat*.*"),
-- Remove linker warnings
path.join(libcryptopp.settings.source, "strciphr.cpp"),
path.join(libcryptopp.settings.source, "simple.cpp"),
path.join(libcryptopp.settings.source, "polynomi.cpp"),
path.join(libcryptopp.settings.source, "algebra.cpp"),
}
-- Pre-compiled header
pchheader "pch.h" -- must be exactly same as used in #include directives
pchsource(path.join(libcryptopp.settings.source, "pch.cpp")) -- real path
defines { "_SCL_SECURE_NO_WARNINGS" }
warnings "Off"
vectorextensions "SSE"
rules {
"MASM",
--"CustomProtoBuildTool",
}
-- SharedLib needs that
--links { "Ws2_32" }
--kind "SharedLib"
--filter "*Static"
kind "StaticLib"
filter "kind:SharedLib"
defines { "CRYPTOPP_EXPORTS" }
filter "architecture:x86"
exceptionhandling "SEH"
masmVars {
UseSafeExceptionHandlers = true,
PreprocessorDefinitions = "_M_X86",
}
filter "architecture:x64"
files {
path.join(libcryptopp.settings.source, "x64masm.asm"),
}
masmVars {
PreprocessorDefinitions = "_M_X64",
}
filter { "architecture:x64", "kind:SharedLib" }
files {
path.join(libcryptopp.settings.source, "x64dll.asm"),
}
filter("files:" .. path.join(libcryptopp.settings.source, "dll.cpp")
.. " or files:" .. path.join(libcryptopp.settings.source, "iterhash.cpp"))
flags { "NoPCH" }
end

View File

@ -1,54 +0,0 @@
sqlite3 = {
settings = nil,
}
function sqlite3.setup(settings)
if not settings.source then error("Missing source.") end
sqlite3.settings = settings
end
function sqlite3.import()
if not sqlite3.settings then error("Run sqlite3.setup first") end
sqlite3.includes()
sqlite3.links()
end
function sqlite3.links()
links { "sqlite3" }
end
function sqlite3.includes()
if not sqlite3.settings then error("Run sqlite3.setup first") end
includedirs { sqlite3.settings.source }
end
function sqlite3.project()
if not sqlite3.settings then error("Run sqlite3.setup first") end
project "sqlite3"
language "C++"
includedirs
{
sqlite3.settings.source,
}
files
{
path.join(sqlite3.settings.source, "sqlite3*.c"),
path.join(sqlite3.settings.source, "sqlite3*.h"),
}
-- not our code, ignore POSIX usage warnings for now
warnings "Off"
--kind "SharedLib"
--filter "*Static"
kind "StaticLib"
--filter "kind:StaticLib"
-- defines { "_LIB" }
-- removedefines { "_USRDLL", "_DLL" }
end

View File

@ -73,21 +73,11 @@ newoption {
description = "Upload minidumps even for Debug builds."
}
newoption {
trigger = "disable-bitmessage",
description = "Disable use of BitMessage completely."
}
newoption {
trigger = "disable-node-log",
description = "Disable debugging messages for Nodes in Debug builds."
}
newoption {
trigger = "disable-base128",
description = "Disable base128 encoding for minidumps."
}
newoption {
trigger = "enable-dxsdk",
description = "Enable DirectX SDK (required for GfxMap exporting)."
@ -188,36 +178,20 @@ newaction {
depsBasePath = "./deps"
require "premake/base128"
require "premake/bitmrc"
require "premake/json11"
require "premake/libcryptopp"
require "premake/libtomcrypt"
require "premake/libtommath"
require "premake/mongoose"
require "premake/pdcurses"
require "premake/protobuf"
require "premake/sqlite3"
require "premake/zlib"
require "premake/WinToast"
require "premake/udis86"
base128.setup
{
source = path.join(depsBasePath, "base128"),
}
bitmrc.setup
{
source = path.join(depsBasePath, "bitmrc"),
}
json11.setup
{
source = path.join(depsBasePath, "json11"),
}
libcryptopp.setup
{
source = path.join(depsBasePath, "bitmrc/libcryptopp"),
}
libtomcrypt.setup
{
defines = {
@ -246,10 +220,6 @@ protobuf.setup
{
source = path.join(depsBasePath, "protobuf"),
}
sqlite3.setup
{
source = path.join(depsBasePath, "bitmrc/windows/sqlite3"),
}
zlib.setup
{
defines = {
@ -334,18 +304,9 @@ workspace "iw4x"
if _OPTIONS["force-exception-handler"] then
defines { "FORCE_EXCEPTION_HANDLER" }
end
if _OPTIONS["disable-bitmessage"] then
defines { "DISABLE_BITMESSAGE" }
removefiles {
"./src/Components/Modules/BitMessage.*",
}
end
if _OPTIONS["disable-node-log"] then
defines { "DISABLE_NODE_LOG"}
end
if _OPTIONS["disable-base128"] then
defines { "DISABLE_BASE128" }
end
if _OPTIONS["enable-dxsdk"] then
defines { "ENABLE_DXSDK" }
includedirs { "%DXSDK_DIR%Include" }
@ -358,12 +319,6 @@ workspace "iw4x"
buildoptions { "/Zm200" }
-- Dependency libraries
if not _OPTIONS["disable-bitmessage"] then
bitmrc.import()
end
if not _OPTIONS["disable-base128"] then
base128.import()
end
json11.import()
libtomcrypt.import()
libtommath.import()
@ -476,14 +431,6 @@ workspace "iw4x"
]]
group "External dependencies"
if not _OPTIONS["disable-bitmessage"] then
bitmrc.project()
libcryptopp.project()
sqlite3.project()
end
if not _OPTIONS["disable-base128"] then
base128.project()
end
json11.project()
libtomcrypt.project()
libtommath.project()

View File

@ -74,9 +74,6 @@ namespace Components
Loader::Register(new Gametypes());
Loader::Register(new Materials());
Loader::Register(new Threading());
#ifndef DISABLE_BITMESSAGE
Loader::Register(new BitMessage());
#endif
Loader::Register(new FileSystem());
Loader::Register(new ModelSurfs());
Loader::Register(new PlayerName());
@ -90,7 +87,6 @@ namespace Components
Loader::Register(new AssetHandler());
Loader::Register(new Localization());
Loader::Register(new MusicalTalent());
Loader::Register(new MinidumpUpload());
Loader::Register(new StructuredData());
Loader::Register(new ConnectProtocol());
Loader::Register(new StartupMessages());

View File

@ -88,7 +88,6 @@ namespace Components
#include "Modules/Materials.hpp"
#include "Modules/Singleton.hpp"
#include "Modules/Threading.hpp"
#include "Modules/BitMessage.hpp"
#include "Modules/FileSystem.hpp"
#include "Modules/ModelSurfs.hpp"
#include "Modules/PlayerName.hpp"
@ -102,7 +101,6 @@ namespace Components
#include "Modules/AssetHandler.hpp"
#include "Modules/Localization.hpp"
#include "Modules/MusicalTalent.hpp"
#include "Modules/MinidumpUpload.hpp"
#include "Modules/StructuredData.hpp"
#include "Modules/ConnectProtocol.hpp"
#include "Modules/StartupMessages.hpp"

View File

@ -513,6 +513,7 @@ namespace Components
AntiCheat::AntiCheat()
{
time(nullptr);
AntiCheat::Flags = NO_FLAG;
AntiCheat::Hash.clear();

View File

@ -1,412 +0,0 @@
#include "STDInclude.hpp"
#ifndef DISABLE_BITMESSAGE
namespace Components
{
std::thread BitMessage::ShutDownThread;
BitMRC* BitMessage::BMClient;
BitMessage::BitMessage()
{
if (Monitor::IsEnabled()) return;
#ifdef DEBUG
Logger::Print("Initializing BitMessage...\n");
#endif
QuickPatch::OnShutdown([] ()
{
BitMessage::ShutDownThread = std::thread(BitMessage::ShutDown);
if (BitMessage::ShutDownThread.joinable())
{
BitMessage::ShutDownThread.join();
}
});
BitMessage::BMClient = new BitMRC(BITMESSAGE_OBJECT_STORAGE_FILENAME, BITMESSAGE_KEYS_FILENAME);
BitMessage::BMClient->init();
BitMessage::BMClient->defaultTTL = 1 * 60 * 60; // 1 hour
if (BitMessage::BMClient->PrivAddresses.empty())
{
if (!this->InitAddr())
{
// Generate a random address ready to use
throw std::runtime_error("Failed to prepare source address for exception handling");
}
BitMessage::BMClient->save();
}
BitMessage::BMClient->start();
#ifdef DEBUG
Command::Add("bm_send", [] (Command::Params* params)
{
if (params->length() < 3) return;
ustring pubAddrString;
pubAddrString.fromString(params->get(1));
PubAddr pubAddr;
if (pubAddr.loadAddr(pubAddrString))
{
ustring msg;
msg.fromString(params->join(2));
Logger::Print("Sending message (this may take a while)...\n");
BitMessage::BMClient->sendMessage(msg, pubAddr, BitMessage::BMClient->PrivAddresses[0]);
Logger::Print("Message sent.\n");
}
else
{
Logger::Print("Address not correct!\n");
}
});
Command::Add("bm_sendb", [] (Command::Params* params)
{
if (params->length() < 2) return;
ustring msg;
msg.appendVarString(params->join(1));
Logger::Print("Sending broadcast...\n");
BitMessage::BMClient->sendBroadcast(msg, BitMessage::BMClient->PrivAddresses[0]);
Logger::Print("Broadcast done.\n");
});
Command::Add("bm_check_messages", [] (Command::Params*)
{
if (!BitMessage::BMClient) return;
while (BitMessage::BMClient->new_messages.size() > 0)
{
auto msg = BitMessage::BMClient->new_messages.pop();
Logger::Print("New message:\nFrom: %s\nTo: %s\nMessage:\n%s\n", msg.from.data(), msg.to.data(), msg.info.data());
}
});
Command::Add("bm_check_connections", [] (Command::Params*)
{
if (!BitMessage::BMClient) return;
std::shared_lock<std::shared_timed_mutex> mlock(BitMessage::BMClient->mutex_nodes);
for (auto& node : BitMessage::BMClient->Nodes)
{
switch (node->state)
{
case 0: // Not connected
Logger::Print("%s: Disconnected\n", node->Ip.data());
break;
case 1: // Connecting
Logger::Print("%s: Connecting\n", node->Ip.data());
break;
case 2: // Connected
Logger::Print("%s: Connected\n", node->Ip.data());
break;
case 3: // Reconnecting
Logger::Print("%s: Reconnecting\n", node->Ip.data());
break;
default:
break;
}
}
mlock.unlock();
});
Command::Add("bm_check_privatekey", [] (Command::Params*)
{
if (!BitMessage::BMClient) return;
std::shared_lock<std::shared_timed_mutex> mlock(BitMessage::BMClient->mutex_priv);
if (BitMessage::BMClient->PrivAddresses.empty())
{
Logger::Print("No private key\n");
}
else
{
for (auto& addr : BitMessage::BMClient->PrivAddresses)
{
Logger::Print("%s\n", addr.getAddress().data());
}
}
mlock.unlock();
});
Command::Add("bm_check_publickey", [] (Command::Params*)
{
if (!BitMessage::BMClient) return;
std::shared_lock<std::shared_timed_mutex> mlock(BitMessage::BMClient->mutex_pub);
if (BitMessage::BMClient->PubAddresses.empty())
{
Logger::Print("No public key\n");
}
else
for (auto& addr : BitMessage::BMClient->PubAddresses)
{
Logger::Print("%s (waiting for public key: %s)\n", addr.getAddress().data(), addr.waitingPubKey() ? "yes" : "no");
}
mlock.unlock();
});
Command::Add("bm_save", [] (Command::Params*)
{
BitMessage::Save();
});
Command::Add("bm_address_public", [] (Command::Params* params)
{
if (!BitMessage::BMClient) return;
if (params->length() < 2) return;
ustring addre;
addre.fromString(params->join(1));
PubAddr address;
if (address.loadAddr(addre))
{
Logger::Print("Asking public key!\n");
BitMessage::BMClient->getPubKey(address);
Logger::Print("Asked! check publickey for news on that address!\n");
}
else
{
Logger::Print("Address not correct!\n");
}
});
Command::Add("bm_address_broadcast", [] (Command::Params* params)
{
if (!BitMessage::BMClient) return;
if (params->length() < 2) return;
ustring addre;
addre.fromString(params->join(1));
PubAddr address;
if (address.loadAddr(addre))
{
Logger::Print("Adding subscription!\n");
BitMessage::BMClient->addSubscription(address);
}
else
{
Logger::Print("Address not correct!\n");
}
});
#endif
}
void BitMessage::ShutDown()
{
if (BitMessage::BMClient)
{
BitMessage::Save();
delete BitMessage::BMClient;
BitMessage::BMClient = nullptr;
}
}
BitMessage::~BitMessage()
{
BitMessage::ShutDown();
}
void BitMessage::SetDefaultTTL(time_t ttl)
{
if (!BitMessage::BMClient) return;
BitMessage::BMClient->defaultTTL = ttl;
}
bool BitMessage::RequestPublicKey(std::string targetAddress)
{
if (!BitMessage::BMClient) return false;
// Convert to ustring
ustring targetAddressU;
targetAddressU.fromString(targetAddress);
// Convert to PubAddr
PubAddr pubAddr;
if (!pubAddr.loadAddr(targetAddressU))
{
return false;
}
// Request public key!
BitMessage::BMClient->getPubKey(pubAddr);
return true;
}
PubAddr* BitMessage::FindPublicKey(PubAddr address)
{
if (!BitMessage::BMClient) return nullptr;
std::shared_lock<std::shared_timed_mutex> mlock(BitMessage::BMClient->mutex_pub);
PubAddr* retval = nullptr;
for (auto& pubKey : BitMessage::BMClient->PubAddresses)
{
if (pubKey.getVersion() == address.getVersion()) //check same version
{
if ((address.getVersion() >= 4 && pubKey.getTag() == address.getTag()) // version 4+ equality check
|| (pubKey.getRipe() == address.getRipe())) // version 3- equality check
{
retval = &pubKey;
break;
}
}
}
mlock.unlock();
return retval;
}
bool BitMessage::WaitForPublicKey(std::string targetAddress)
{
if (!BitMessage::BMClient) return false;
// Convert to ustring
ustring targetAddressU;
targetAddressU.fromString(targetAddress);
// Convert to PubAddr
PubAddr address;
if (!address.loadAddr(targetAddressU))
{
return false;
}
// Resolve our own copy to the registered PubAddr copy in BitMRC if possible
auto resolvedAddress = BitMessage::FindPublicKey(address);
if (resolvedAddress != nullptr &&
!resolvedAddress->waitingPubKey() && !resolvedAddress->getPubEncryptionKey().empty())
return true;
if (resolvedAddress == nullptr ||
(!resolvedAddress->waitingPubKey() && resolvedAddress->getPubEncryptionKey().empty()))
{
// Request public key
BitMessage::BMClient->getPubKey(address);
resolvedAddress = BitMessage::FindPublicKey(address);
}
BitMessage::Save();
// TODO: Wait for public key by using signaling in BitMRC, needs to be done directly in the fork.
while (resolvedAddress->waitingPubKey())
{
std::this_thread::sleep_for(1500ms);
}
BitMessage::Save();
return true;
}
bool BitMessage::Subscribe(std::string targetAddress)
{
if (!BitMessage::BMClient) return false;
// Convert to ustring
ustring targetAddressU;
targetAddressU.fromString(targetAddress);
// Convert to PubAddr
PubAddr pubAddr;
if (!pubAddr.loadAddr(targetAddressU))
{
return false;
}
// Subscribe!
BitMessage::BMClient->addSubscription(pubAddr);
return true;
}
bool BitMessage::SendMsg(std::string targetAddress, std::string message, time_t ttl)
{
if (!BitMessage::BMClient) return false;
// Convert target address to ustring
ustring targetAddressU;
targetAddressU.fromString(targetAddress);
// Convert target address to PubAddr
PubAddr pubAddr;
if (!pubAddr.loadAddr(targetAddressU))
{
return false;
}
// Convert message to ustring
ustring messageU;
messageU.fromString(message);
// Send the message
// TODO - Set mutex on priv when accessing first private address
if (ttl > 0)
{
BitMessage::BMClient->sendMessage(messageU, pubAddr, BitMessage::BMClient->PrivAddresses[0], ttl);
}
else
{
BitMessage::BMClient->sendMessage(messageU, pubAddr, BitMessage::BMClient->PrivAddresses[0]);
}
return true;
}
bool BitMessage::SendBroadcast(std::string message, time_t ttl)
{
if (!BitMessage::BMClient) return false;
// Convert message to ustring
ustring messageU;
messageU.fromString(message);
// TODO - Set mutex on priv when accessing first private address
if (ttl > 0)
{
BitMessage::BMClient->sendBroadcast(messageU, BitMessage::BMClient->PrivAddresses[0], ttl);
}
else
{
BitMessage::BMClient->sendBroadcast(messageU, BitMessage::BMClient->PrivAddresses[0]);
}
return true;
}
bool BitMessage::InitAddr()
{
if (!BitMessage::BMClient) return false;
#ifdef DEBUG
Logger::Print("Generating BM address...\n");
#endif
Addr myAddress;
if (!myAddress.generateRandom())
{
return false;
}
BitMessage::BMClient->addAddr(myAddress);
return true;
}
void BitMessage::Save()
{
if (BitMessage::BMClient)
{
BitMessage::BMClient->save();
}
}
}
#endif

View File

@ -1,40 +0,0 @@
#pragma once
#ifndef DISABLE_BITMESSAGE
#define BITMESSAGE_KEYS_FILENAME "players/bmk.dat"s
#define BITMESSAGE_OBJECT_STORAGE_FILENAME "players/storage.dat"s
namespace Components
{
class BitMessage : public Component
{
public:
BitMessage();
~BitMessage();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "BitMessage"; };
#endif
static void SetDefaultTTL(time_t ttl);
static bool RequestPublicKey(std::string targetAddress);
static bool WaitForPublicKey(std::string targetAddress);
static bool Subscribe(std::string targetAddress);
static bool SendMsg(std::string targetAddress, std::string message, time_t ttl = 0);
static bool SendBroadcast(std::string message, time_t ttl = 0);
static void Save();
static BitMRC* BMClient;
private:
static std::thread ShutDownThread;
static PubAddr* FindPublicKey(PubAddr addr);
static bool InitAddr();
static void ShutDown();
};
}
#endif

View File

@ -85,18 +85,34 @@ namespace Components
Exception::SetMiniDumpType(true, false);
}
auto minidump = MinidumpUpload::CreateQueuedMinidump(ExceptionInfo, Exception::MiniDumpType);
if (!minidump)
// Current executable name
char exeFileName[MAX_PATH];
GetModuleFileNameA(nullptr, exeFileName, MAX_PATH);
PathStripPathA(exeFileName);
PathRemoveExtensionA(exeFileName);
// Generate filename
char filenameFriendlyTime[MAX_PATH];
__time64_t time;
tm ltime;
_time64(&time);
_localtime64_s(&ltime, &time);
strftime(filenameFriendlyTime, sizeof(filenameFriendlyTime) - 1, "%Y%m%d%H%M%S", &ltime);
// Combine with queuedMinidumpsFolder
char filename[MAX_PATH] = { 0 };
PathCombineA(filename, "minidumps\\", Utils::String::VA("%s-" VERSION "-%s.dmp", exeFileName, filenameFriendlyTime));
DWORD fileShare = FILE_SHARE_READ | FILE_SHARE_WRITE;
HANDLE hFile = CreateFileA(filename, GENERIC_WRITE | GENERIC_READ, fileShare, nullptr, (fileShare & FILE_SHARE_WRITE) > 0 ? OPEN_ALWAYS : OPEN_EXISTING, NULL, nullptr);
MINIDUMP_EXCEPTION_INFORMATION ex = { GetCurrentThreadId(), ExceptionInfo, FALSE };
if (!!MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, static_cast<MINIDUMP_TYPE>(Exception::MiniDumpType), &ex, nullptr, nullptr))
{
MessageBoxA(nullptr, Utils::String::VA("There was an error creating the minidump (%s)! Hit OK to close the program.", Utils::GetLastWindowsError().data()), "Minidump Error", MB_OK | MB_ICONERROR);
OutputDebugStringA("Failed to create new minidump!");
Utils::OutputDebugLastError();
TerminateProcess(GetCurrentProcess(), ExceptionInfo->ExceptionRecord->ExceptionCode);
}
else
{
delete minidump;
}
if (ExceptionInfo->ExceptionRecord->ExceptionFlags == EXCEPTION_NONCONTINUABLE)
{
@ -241,6 +257,21 @@ namespace Components
Exception::ExceptionFilter(&eptr);
});
#pragma warning(pop)
if (Utils::IO::FileExists("crash-helper.exe"))
{
STARTUPINFOA sInfo;
PROCESS_INFORMATION pInfo;
ZeroMemory(&sInfo, sizeof(sInfo));
ZeroMemory(&pInfo, sizeof(pInfo));
sInfo.cb = sizeof(sInfo);
CreateProcessA("crash-helper.exe", const_cast<char*>(Utils::String::VA("crash-helper.exe %s", VERSION)), nullptr, nullptr, false, NULL, nullptr, nullptr, &sInfo, &pInfo);
if (pInfo.hThread && pInfo.hThread != INVALID_HANDLE_VALUE) CloseHandle(pInfo.hThread);
if (pInfo.hProcess && pInfo.hProcess != INVALID_HANDLE_VALUE) CloseHandle(pInfo.hProcess);
}
}
Exception::~Exception()

View File

@ -1,381 +0,0 @@
#include "STDInclude.hpp"
#include "Shlwapi.h"
namespace Components
{
#pragma region Minidump class implementation
Minidump::Minidump()
{
this->fileHandle = this->mapFileHandle = INVALID_HANDLE_VALUE;
}
Minidump::~Minidump()
{
if (this->mapFileHandle != nullptr && this->mapFileHandle != INVALID_HANDLE_VALUE)
{
CloseHandle(this->mapFileHandle);
this->mapFileHandle = INVALID_HANDLE_VALUE;
}
if (this->fileHandle != nullptr && this->fileHandle != INVALID_HANDLE_VALUE)
{
CloseHandle(this->fileHandle);
this->fileHandle = INVALID_HANDLE_VALUE;
}
}
std::string Minidump::ToString()
{
if (!this->EnsureFileMapping()) return nullptr;
auto pBuf = MapViewOfFile(this->mapFileHandle, FILE_MAP_READ, 0, 0, 0);
if (!pBuf)
{
Utils::OutputDebugLastError();
throw new std::runtime_error("Could not read minidump.");
}
size_t fileSize;
DWORD fileSizeHi;
fileSize = GetFileSize(this->fileHandle, &fileSizeHi);
#ifdef _WIN64
fileSize |= ((size_t)fileSizeHi << 32);
#endif
std::string retval = std::string(static_cast<const char*>(pBuf), fileSize * sizeof(const char));
UnmapViewOfFile(pBuf);
return retval;
}
bool Minidump::GetStream(MINIDUMP_STREAM_TYPE type, PMINIDUMP_DIRECTORY* directoryPtr, PVOID* streamBeginningPtr, ULONG* streamSizePtr)
{
if (!this->EnsureFileMapping()) return false;
auto pBuf = MapViewOfFile(this->mapFileHandle, FILE_MAP_READ, 0, 0, 0);
if (!pBuf)
{
Utils::OutputDebugLastError();
throw new std::runtime_error("Could not read minidump.");
}
BOOL success = MiniDumpReadDumpStream(pBuf, type, directoryPtr, streamBeginningPtr, streamSizePtr);
UnmapViewOfFile(pBuf);
if (success != TRUE)
return false;
return true;
}
inline bool Minidump::Check()
{
/*PMINIDUMP_DIRECTORY directory;
PVOID stream;
ULONG streamSize;
return Minidump::GetStream(ExceptionStream, &directory, &stream, &streamSize);*/
return Minidump::GetStream(ExceptionStream, nullptr, nullptr, nullptr);
}
Minidump* Minidump::Create(std::string path, LPEXCEPTION_POINTERS exceptionInfo, int type)
{
Minidump* minidump = Minidump::Initialize(path);
if (!minidump) return minidump;
// Do the dump generation
MINIDUMP_EXCEPTION_INFORMATION ex = { GetCurrentThreadId(), exceptionInfo, FALSE };
if (!MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), minidump->fileHandle, static_cast<MINIDUMP_TYPE>(type), &ex, nullptr, nullptr))
{
Utils::OutputDebugLastError();
delete minidump;
return nullptr;
}
if (SetFilePointer(minidump->fileHandle, 0, nullptr, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
{
Utils::OutputDebugLastError();
delete minidump;
DeleteFileA(path.data());
return nullptr;
}
return minidump;
}
Minidump* Minidump::Open(std::string path)
{
return Minidump::Initialize(path, FILE_SHARE_READ);
}
bool Minidump::EnsureFileMapping()
{
if (this->mapFileHandle == nullptr || this->mapFileHandle == INVALID_HANDLE_VALUE)
{
this->mapFileHandle = CreateFileMappingA(this->fileHandle, nullptr, PAGE_READONLY, 0, 0, nullptr);
if (this->mapFileHandle == nullptr || this->mapFileHandle == INVALID_HANDLE_VALUE)
{
Utils::OutputDebugLastError();
return false;
}
}
return true;
}
Minidump* Minidump::Initialize(std::string path, DWORD fileShare)
{
Minidump* minidump = new Minidump();
minidump->fileHandle = CreateFileA(path.data(),
GENERIC_WRITE | GENERIC_READ, fileShare,
nullptr, (fileShare & FILE_SHARE_WRITE) > 0 ? OPEN_ALWAYS : OPEN_EXISTING, NULL, nullptr);
if (minidump->fileHandle == nullptr || minidump->fileHandle == INVALID_HANDLE_VALUE)
{
Utils::OutputDebugLastError();
delete minidump;
return nullptr;
}
return minidump;
}
#pragma endregion
#pragma region Minidump uploader class implementation
const std::string MinidumpUpload::QueuedMinidumpsFolder = "minidumps\\";
#ifdef DISABLE_BITMESSAGE
const std::vector<std::string> MinidumpUpload::TargetUrls =
{
"https://reich.io/upload.php",
"https://hitlers.kz/upload.php"
};
#else
const std::string MinidumpUpload::TargetAddress = "BM-2cSksR7gyyFcNK7MaFoxGCjRJWxtoGckdj";
const unsigned int MinidumpUpload::MaxSegmentSize = 200 * 1024; // 200 kB
#endif
MinidumpUpload::MinidumpUpload()
{
if (Monitor::IsEnabled()) return;
#if !defined(DEBUG) || defined(FORCE_MINIDUMP_UPLOAD)
if (Loader::PerformingUnitTests() || ZoneBuilder::IsEnabled()) return;
this->uploadThread = std::thread([&]() { this->UploadQueuedMinidumps(); });
#endif
}
MinidumpUpload::~MinidumpUpload()
{
if (this->uploadThread.joinable())
{
this->uploadThread.join();
}
}
Minidump* MinidumpUpload::CreateQueuedMinidump(LPEXCEPTION_POINTERS exceptionInfo, int minidumpType)
{
Utils::IO::CreateDir(MinidumpUpload::QueuedMinidumpsFolder);
// Current executable name
char exeFileName[MAX_PATH];
GetModuleFileNameA(nullptr, exeFileName, MAX_PATH);
PathStripPathA(exeFileName);
PathRemoveExtensionA(exeFileName);
// Generate filename
char filenameFriendlyTime[MAX_PATH];
__time64_t time;
tm ltime;
_time64(&time);
_localtime64_s(&ltime, &time);
strftime(filenameFriendlyTime, sizeof(filenameFriendlyTime) - 1, "%Y%m%d%H%M%S", &ltime);
// Combine with queuedMinidumpsFolder
char filename[MAX_PATH] = { 0 };
PathCombineA(filename, MinidumpUpload::QueuedMinidumpsFolder.data(), Utils::String::VA("%s-" VERSION "-%s.dmp", exeFileName, filenameFriendlyTime));
// Generate the dump
return Minidump::Create(filename, exceptionInfo, minidumpType);
}
bool MinidumpUpload::UploadQueuedMinidumps()
{
#ifndef DISABLE_BITMESSAGE
// Preload public key for our target that will receive minidumps
Logger::Print("About to send request for public key for minidump upload address.\n");
if (!BitMessage::RequestPublicKey(MinidumpUpload::TargetAddress))
{
Logger::Error("Failed to request public key for minidump collection address.\n");
}
Logger::Print("Waiting for public key for minidump upload address.\n");
if (!BitMessage::WaitForPublicKey(MinidumpUpload::TargetAddress))
{
Logger::Error("Failed to fetch public key for minidump collection address.\n");
}
#endif
// Check if folder exists
if (!PathIsDirectoryA(MinidumpUpload::QueuedMinidumpsFolder.data()))
{
// Nothing to upload
Logger::Print("No minidumps to upload.\n");
return PathFileExistsA(MinidumpUpload::QueuedMinidumpsFolder.data()) == FALSE;
}
// Walk through directory and search for valid minidumps
WIN32_FIND_DATAA ffd;
HANDLE hFind = FindFirstFileA(Utils::String::VA("%s\\*.dmp", MinidumpUpload::QueuedMinidumpsFolder.data()), &ffd);
if (hFind != INVALID_HANDLE_VALUE)
{
do
{
if ((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) continue; // ignore directory
char fullPath[MAX_PATH_SIZE];
PathCombineA(fullPath, MinidumpUpload::QueuedMinidumpsFolder.data(), ffd.cFileName);
// Only upload if less than 5MB
if(Utils::IO::FileSize(fullPath) > (5 * 1024 * 1024)) continue;
// Try to open this minidump
Logger::Print("Trying to upload %s...\n", fullPath);
auto minidump = Minidump::Open(fullPath);
if (!minidump)
{
Logger::Print("Couldn't open minidump.\n");
continue; // file can't be opened
}
// Upload!
if (!MinidumpUpload::Upload(minidump))
{
Logger::Print("Couldn't upload minidump.\n");
continue; // couldn't upload that minidump, keep for another attempt
}
delete minidump;
#ifndef KEEP_MINIDUMPS_AFTER_UPLOAD
// Delete minidump if possible
DeleteFileA(fullPath);
#endif
} while (FindNextFileA(hFind, &ffd));
}
Logger::Print("All minidumps uploaded.\n");
return true;
}
bool MinidumpUpload::Upload(Minidump* minidump)
{
// Checking if we can extract any information from minidump first, just to be sure that this is valid.
if (!minidump->Check())
{
Utils::OutputDebugLastError();
return false;
}
auto id = Utils::String::GenerateUUIDString();
std::map<std::string, std::string> extraHeaders = {
{"Hash-SHA512", Utils::Cryptography::SHA512::Compute(minidump->ToString(), true)},
{"Compression", "deflate"},
{"ID", id},
};
std::string compressedMinidump = minidump->ToString();
Logger::Print("Compressing minidump %s (currently %d bytes)...\n", id.data(), compressedMinidump.size());
compressedMinidump = Utils::Compression::ZLib::Compress(compressedMinidump);
#ifndef DISABLE_BASE128
Logger::Print("Encoding minidump %s (currently %d bytes)...\n", id.data(), compressedMinidump.size());
extraHeaders["Encoding"] = "base128";
compressedMinidump = Utils::String::EncodeBase128(compressedMinidump);
#endif
Logger::Print("Minidump %s now prepared for uploading (currently %d bytes)...\n", id.data(), compressedMinidump.size());
#ifdef DISABLE_BITMESSAGE
for (auto& targetUrl : TargetUrls)
{
Utils::WebIO webio("Firefucks", targetUrl);
std::string buffer = MinidumpUpload::Encode(compressedMinidump, extraHeaders);
std::string result = webio.postFile(buffer, "files[]", "minidump.dmpx");
std::string errors;
json11::Json object = json11::Json::parse(result, errors);
if (!object.is_object()) continue;
json11::Json success = object["success"];
if (!success.is_bool() || !success.bool_value()) return false;
json11::Json files = object["files"];
if (!files.is_array()) continue;
for (auto file : files.array_items())
{
json11::Json url = file["url"];
json11::Json hash = file["hash"];
if (hash.is_string() && url.is_string())
{
if (Utils::String::ToLower(Utils::Cryptography::SHA1::Compute(buffer, true)) == Utils::String::ToLower(hash.string_value()))
{
MessageBoxA(0, url.string_value().data(), 0, 0);
return true;
}
}
}
}
return false;
#else
// BitMessage has a max msg size that is somewhere around 220 KB, split it up as necessary!
auto totalParts = compressedMinidump.size() / MinidumpUpload::MaxSegmentSize + 1;
extraHeaders.insert({ "Parts", Utils::String::VA("%d", totalParts) });
for (size_t offset = 0; offset < compressedMinidump.size(); offset += MinidumpUpload::MaxSegmentSize)
{
auto extraPartHeaders = extraHeaders;
auto part = compressedMinidump.substr(offset, std::min(MinidumpUpload::MaxSegmentSize, compressedMinidump.size() - offset));
auto partNum = offset / MinidumpUpload::MaxSegmentSize + 1;
extraPartHeaders.insert({ "Part", Utils::String::VA("%d", partNum) });
Logger::Print("Uploading minidump %s (part %d out of %d, %d bytes)...\n", id.data(), partNum, totalParts, part.size());
BitMessage::SendMsg(MinidumpUpload::TargetAddress, MinidumpUpload::Encode(part, extraPartHeaders));
}
return true;
#endif
}
std::string MinidumpUpload::Encode(std::string data, std::map<std::string, std::string> extraHeaders)
{
std::string marker = "MINIDUMP";
std::stringstream output;
if (extraHeaders.find("Encoding") == extraHeaders.end())
extraHeaders["Encoding"] = "raw";
extraHeaders["Version"] = VERSION;
output << "-----BEGIN " << marker << "-----\n";
// Insert extra headers
for (auto& header : extraHeaders)
{
output << header.first << ": " << header.second << "\n";
}
output << "\n"
<< data << "\n"
<< "-----END " << marker << "-----\n";
return output.str();
}
#pragma endregion
}

View File

@ -1,70 +0,0 @@
#pragma once
#pragma warning(push)
#pragma warning(disable: 4091)
#include <dbghelp.h>
#pragma comment(lib, "dbghelp.lib")
#pragma warning(pop)
namespace Components
{
// This class holds a Minidump and allows easy access to its aspects.
class Minidump
{
public:
~Minidump();
static Minidump* Create(std::string path, LPEXCEPTION_POINTERS exceptionInfo, int type);
static Minidump* Open(std::string path);
bool GetStream(MINIDUMP_STREAM_TYPE type, PMINIDUMP_DIRECTORY* directoryPtr, PVOID* streamPtr, ULONG* streamSizePtr);
bool Check();
std::string ToString();
private:
Minidump();
bool EnsureFileMapping();
static Minidump* Initialize(std::string path, DWORD fileShare = FILE_SHARE_READ | FILE_SHARE_WRITE);
HANDLE fileHandle;
HANDLE mapFileHandle;
};
class MinidumpUpload : public Component
{
public:
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "MinidumpUpload"; };
#endif
MinidumpUpload();
~MinidumpUpload();
// Uploads the given minidump.
static bool Upload(Minidump* minidump);
// Generates a new minidump and saves it to the folder for queued minidumps.
static Minidump* CreateQueuedMinidump(LPEXCEPTION_POINTERS exceptionInfo, int minidumpType);
// Browses the folder for queued minidumps and uploads each queued minidump.
// On Release builds this will also delete every successfully uploaded minidump.
static bool UploadQueuedMinidumps();
private:
std::thread uploadThread;
// Encodes the given minidump so that it can be uploaded in a proper format.
// Internally, this will compress the minidump and decorate it with proper markers and first-look headers.
static std::string Encode(std::string data, std::map<std::string, std::string> extraHeaders = {});
// Contains the path to the minidumps folder.
static const std::string QueuedMinidumpsFolder;
#ifdef DISABLE_BITMESSAGE
static const std::vector<std::string> TargetUrls;
#else
static const std::string TargetAddress;
static const unsigned int MaxSegmentSize;
#endif
};
}

View File

@ -20,6 +20,11 @@
#include <Psapi.h>
#include <tlhelp32.h>
#pragma warning(push)
#pragma warning(disable: 4091)
#include <dbghelp.h>
#pragma warning(pop)
#include <sstream>
#include <fstream>
#include <cctype>
@ -67,9 +72,6 @@ template <size_t S> class Sizer { };
#include <mongoose.h>
#include <json11.hpp>
#include <tomcrypt.h>
#ifndef DISABLE_BITMESSAGE
#include <BitMRC.h>
#endif
#include <wintoastlib.h>
#include <udis86.h>
@ -92,11 +94,6 @@ template <size_t S> class Sizer { };
#pragma warning(pop)
#define ENABLE_BASE64
#ifndef DISABLE_BASE128
#define ENABLE_BASE128
#endif
#include "Utils/IO.hpp"
#include "Utils/CSV.hpp"
#include "Utils/Time.hpp"
@ -131,6 +128,7 @@ template <size_t S> class Sizer { };
#pragma comment(lib, "Urlmon.lib")
#pragma comment(lib, "Advapi32.lib")
#pragma comment(lib, "rpcrt4.lib")
#pragma comment(lib, "dbghelp.lib")
// Enable additional literals
using namespace std::literals;