Compare commits
6 Commits
3de7a7bb44
...
9ac9be7302
| Author | SHA1 | Date | |
|---|---|---|---|
| 9ac9be7302 | |||
| 2553f5ab4b | |||
| 3231638ce7 | |||
| 93900a56cb | |||
| 93685b7ff0 | |||
| 25d9f9f631 |
@@ -73,6 +73,11 @@ endif()
|
||||
# ------------------------------
|
||||
file(GLOB_RECURSE UNLOCKER_SOURCES CONFIGURE_DEPENDS "src/unlocker/*.cpp" "src/unlocker/*.h")
|
||||
add_executable(dbd-unlocker ${UNLOCKER_SOURCES})
|
||||
|
||||
# randomize exe name
|
||||
string(RANDOM LENGTH 12 ALPHABET "abcdefghijklmnopqrstuvwxyz0123456789" RANDOM_EXE_NAME)
|
||||
set_target_properties(dbd-unlocker PROPERTIES OUTPUT_NAME "${RANDOM_EXE_NAME}")
|
||||
|
||||
target_link_libraries(dbd-unlocker PRIVATE dbd-unlocker-warnings OpenSSL::SSL OpenSSL::Crypto nerutils wsock32 ws2_32 wininet simdjson-wrapped)
|
||||
|
||||
set_property(TARGET dbd-unlocker PROPERTY USE_FOLDERS ON)
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
@echo off
|
||||
echo formatting sources
|
||||
|
||||
for /r "src" %%f in (*.cpp *.h *.cs) do (
|
||||
echo Formatting: %%f
|
||||
clang-format -i "%%f"
|
||||
)
|
||||
|
||||
echo done
|
||||
pause
|
||||
+16
-15
@@ -5,22 +5,23 @@
|
||||
#include <mutex>
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
class CertManager {
|
||||
public:
|
||||
CertManager();
|
||||
~CertManager();
|
||||
class CertManager
|
||||
{
|
||||
public:
|
||||
CertManager();
|
||||
~CertManager();
|
||||
|
||||
bool Init();
|
||||
SSL_CTX* CreateHostContext(const std::string& host);
|
||||
bool Init();
|
||||
SSL_CTX* CreateHostContext(const std::string& host);
|
||||
|
||||
private:
|
||||
bool GenerateCA();
|
||||
bool LoadCA();
|
||||
private:
|
||||
bool GenerateCA();
|
||||
bool LoadCA();
|
||||
|
||||
EVP_PKEY* _caPkey = nullptr;
|
||||
X509* _caCert = nullptr;
|
||||
EVP_PKEY* _sessionPkey = nullptr;
|
||||
|
||||
std::mutex _mutex;
|
||||
std::unordered_map<std::string, SSL_CTX*> _hostContexts;
|
||||
EVP_PKEY* _caPkey = nullptr;
|
||||
X509* _caCert = nullptr;
|
||||
EVP_PKEY* _sessionPkey = nullptr;
|
||||
|
||||
std::mutex _mutex;
|
||||
std::unordered_map<std::string, SSL_CTX*> _hostContexts;
|
||||
};
|
||||
|
||||
+59
-72
@@ -85,7 +85,8 @@ void cleanup()
|
||||
|
||||
BOOL WINAPI consoleHandler(DWORD dwType)
|
||||
{
|
||||
if (dwType == CTRL_C_EVENT || dwType == CTRL_CLOSE_EVENT || dwType == CTRL_LOGOFF_EVENT || dwType == CTRL_SHUTDOWN_EVENT)
|
||||
if (dwType == CTRL_C_EVENT || dwType == CTRL_CLOSE_EVENT || dwType == CTRL_LOGOFF_EVENT ||
|
||||
dwType == CTRL_SHUTDOWN_EVENT)
|
||||
{
|
||||
running = false;
|
||||
cleanup();
|
||||
@@ -295,44 +296,19 @@ int main()
|
||||
|
||||
if (url.find("api/v1/extensions/store/getCatalogItems") != std::string::npos)
|
||||
updateCatalog(data);
|
||||
else if (url.find("api/v1/dbd-inventories/all") != std::string::npos)
|
||||
else if (url.find("api/v1/dbd-inventories/") != std::string::npos)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_dataMutex);
|
||||
if (!g_allObjectIds.empty() || !g_stackableItems.empty() || !g_uniqueItems.empty())
|
||||
if (!g_allObjectIds.empty())
|
||||
{
|
||||
Log::info("Merging catalog and custom items into real inventory response");
|
||||
|
||||
std::regex qtyRegex(R"("quantity"\s*:\s*\d+)");
|
||||
for (const auto& id : g_stackableItems)
|
||||
{
|
||||
size_t pos = data.find("\"objectId\":\"" + id + "\"");
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
size_t start = data.rfind("{", pos);
|
||||
size_t end = data.find("}", pos);
|
||||
if (start != std::string::npos && end != std::string::npos && start < end)
|
||||
{
|
||||
std::string objStr = data.substr(start, end - start + 1);
|
||||
objStr = std::regex_replace(objStr, qtyRegex, "\"quantity\":100");
|
||||
data.replace(start, end - start + 1, objStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
Log::info("Merging catalog items into real inventory response");
|
||||
|
||||
size_t closePos = data.rfind("]}");
|
||||
if (closePos != std::string::npos)
|
||||
{
|
||||
uint64_t now = time(nullptr);
|
||||
std::string injected;
|
||||
injected.reserve((g_allObjectIds.size() + g_stackableItems.size() + g_uniqueItems.size()) * 60);
|
||||
|
||||
std::unordered_set<std::string> dbIds;
|
||||
for (auto& id : g_stackableItems)
|
||||
dbIds.insert(id);
|
||||
for (auto& id : g_uniqueItems)
|
||||
dbIds.insert(id);
|
||||
for (auto& id : g_perks)
|
||||
dbIds.insert(id);
|
||||
injected.reserve(g_allObjectIds.size() * 60);
|
||||
|
||||
std::unordered_set<std::string> handledIds;
|
||||
auto injectItem = [&](const std::string& id, int qty) {
|
||||
@@ -351,30 +327,20 @@ int main()
|
||||
handledIds.insert(id);
|
||||
};
|
||||
|
||||
for (const auto& id : g_stackableItems)
|
||||
injectItem(id, 100);
|
||||
for (const auto& id : g_uniqueItems)
|
||||
injectItem(id, 1);
|
||||
for (const auto& id : g_perks)
|
||||
injectItem(id, 3);
|
||||
|
||||
for (const auto& id : g_allObjectIds)
|
||||
{
|
||||
if (dbIds.find(id) == dbIds.end()) injectItem(id, 1);
|
||||
}
|
||||
injectItem(id, 1);
|
||||
|
||||
if (!injected.empty()) data.insert(closePos, injected);
|
||||
|
||||
Log::info("Injected {} new items into inventory",
|
||||
Log::info("Injected {} catalog items into global inventory",
|
||||
injected.empty() ? 0 : std::count(injected.begin(), injected.end(), '{'));
|
||||
}
|
||||
}
|
||||
else
|
||||
Log::warning("No catalog or custom data available to inject into inventory yet!");
|
||||
Log::warning("No catalog data available to inject into global inventory yet!");
|
||||
}
|
||||
else if (url.find("api/v1/dbd-character-data/get-all") != std::string::npos)
|
||||
else if (url.find("api/v1/dbd-character-data/") != std::string::npos)
|
||||
{
|
||||
|
||||
std::vector<std::string> localStackable;
|
||||
std::vector<std::string> localUnique;
|
||||
std::vector<std::string> localPerks;
|
||||
@@ -387,42 +353,65 @@ int main()
|
||||
|
||||
if (!localStackable.empty() || !localUnique.empty() || !localPerks.empty())
|
||||
{
|
||||
size_t pos = 0;
|
||||
size_t count = 0;
|
||||
std::unordered_set<std::string> stackableSet(localStackable.begin(), localStackable.end());
|
||||
std::unordered_set<std::string> uniqueSet(localUnique.begin(), localUnique.end());
|
||||
std::unordered_set<std::string> perkSet(localPerks.begin(), localPerks.end());
|
||||
std::unordered_set<std::string> uniqueSet(localUnique.begin(), localUnique.end());
|
||||
std::regex qtyRegex(R"("quantity"\s*:\s*\d+)");
|
||||
|
||||
while ((pos = data.find("\"characterItems\":[", pos)) != std::string::npos)
|
||||
const char* targetArrays[] = {"\"characterItems\":[", "\"inventory\":["};
|
||||
size_t arraysModified = 0;
|
||||
|
||||
for (const char* arrayKey : targetArrays)
|
||||
{
|
||||
pos += 18;
|
||||
|
||||
size_t endPos = data.find("]", pos);
|
||||
if (endPos != std::string::npos)
|
||||
size_t pos = 0;
|
||||
while ((pos = data.find(arrayKey, pos)) != std::string::npos)
|
||||
{
|
||||
std::string currentItems = data.substr(pos, endPos - pos);
|
||||
std::string newItems;
|
||||
newItems.reserve(currentItems.size() * 2);
|
||||
pos += strlen(arrayKey);
|
||||
size_t endPos = data.find("]", pos);
|
||||
if (endPos == std::string::npos) break;
|
||||
|
||||
std::string currentItems = data.substr(pos, endPos - pos);
|
||||
std::unordered_set<std::string> seenIds;
|
||||
std::unordered_set<std::string> stackableSet(localStackable.begin(), localStackable.end());
|
||||
|
||||
size_t itemPos = 0;
|
||||
while ((itemPos = currentItems.find("\"itemId\":\"", itemPos)) != std::string::npos)
|
||||
{
|
||||
itemPos += 10;
|
||||
size_t quotePos = currentItems.find("\"", itemPos);
|
||||
if (quotePos == std::string::npos) break;
|
||||
size_t idStart = itemPos + 10;
|
||||
size_t idEnd = currentItems.find("\"", idStart);
|
||||
if (idEnd == std::string::npos) break;
|
||||
|
||||
std::string id = currentItems.substr(itemPos, quotePos - itemPos);
|
||||
std::string id = currentItems.substr(idStart, idEnd - idStart);
|
||||
seenIds.insert(id);
|
||||
|
||||
int qty = 100;
|
||||
int qty = -1;
|
||||
if (perkSet.count(id))
|
||||
qty = 3;
|
||||
else if (uniqueSet.count(id))
|
||||
qty = 1;
|
||||
else if (stackableSet.count(id))
|
||||
qty = 100;
|
||||
|
||||
newItems += "{\"itemId\":\"" + id + "\",\"quantity\":" + std::to_string(qty) + "},";
|
||||
if (qty != -1)
|
||||
{
|
||||
size_t objStart = currentItems.rfind("{", itemPos);
|
||||
size_t objEnd = currentItems.find("}", itemPos);
|
||||
if (objStart != std::string::npos && objEnd != std::string::npos && objStart < objEnd)
|
||||
{
|
||||
std::string objStr = currentItems.substr(objStart, objEnd - objStart + 1);
|
||||
if (std::regex_search(objStr, qtyRegex))
|
||||
objStr =
|
||||
std::regex_replace(objStr, qtyRegex, "\"quantity\":" + std::to_string(qty));
|
||||
else
|
||||
objStr.insert(objStr.length() - 1, ",\"quantity\":" + std::to_string(qty));
|
||||
|
||||
currentItems.replace(objStart, objEnd - objStart + 1, objStr);
|
||||
itemPos = objStart + objStr.length();
|
||||
}
|
||||
else
|
||||
itemPos = idEnd;
|
||||
}
|
||||
else
|
||||
itemPos = idEnd;
|
||||
}
|
||||
|
||||
auto injectIfMissing = [&](const std::vector<std::string>& list, int qty) {
|
||||
@@ -430,7 +419,9 @@ int main()
|
||||
{
|
||||
if (seenIds.find(id) == seenIds.end())
|
||||
{
|
||||
newItems += "{\"itemId\":\"" + id + "\",\"quantity\":" + std::to_string(qty) + "},";
|
||||
if (!currentItems.empty() && currentItems.back() != ',') currentItems += ",";
|
||||
currentItems +=
|
||||
"{\"itemId\":\"" + id + "\",\"quantity\":" + std::to_string(qty) + "}";
|
||||
seenIds.insert(id);
|
||||
}
|
||||
}
|
||||
@@ -440,19 +431,15 @@ int main()
|
||||
injectIfMissing(localUnique, 1);
|
||||
injectIfMissing(localPerks, 3);
|
||||
|
||||
if (!newItems.empty()) newItems.pop_back(); // trailing comma
|
||||
|
||||
data.replace(pos, endPos - pos, newItems);
|
||||
|
||||
endPos = pos + newItems.length();
|
||||
pos = endPos;
|
||||
count++;
|
||||
data.replace(pos, endPos - pos, currentItems);
|
||||
pos += currentItems.length();
|
||||
arraysModified++;
|
||||
}
|
||||
}
|
||||
Log::info("Added missing items and targeted perk tiers in {} character inventories", count);
|
||||
Log::info("Spoofed items in {} character data arrays across response", arraysModified);
|
||||
}
|
||||
else
|
||||
Log::warning("No custom dumped items available to inject into character inventory!");
|
||||
Log::warning("No custom dumped items available to inject into character data!");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -549,4 +549,4 @@ void Proxy::handleClient(SOCKET hClientSocket)
|
||||
if (connectionClosed) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
TO-DO:
|
||||
use random port, test availability
|
||||
*/
|
||||
#define PROXY_PORT 58421
|
||||
#define PROXY_PORT 58421
|
||||
|
||||
typedef unsigned __int64 SOCKET;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user