mirror of
https://gitea.tendokyu.moe/TeamTofuShop/segatools.git
synced 2026-10-06 00:37:55 +03:00
refactor all common parts and games
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "hooklib/config.h"
|
||||
#include "hooklib/dvd.h"
|
||||
|
||||
void dvd_config_load(struct dvd_config *cfg, const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
cfg->enable = GetPrivateProfileIntW(L"dvd", L"enable", 1, filename);
|
||||
}
|
||||
|
||||
void touch_screen_config_load(struct touch_screen_config *cfg, const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
cfg->enable = GetPrivateProfileIntW(L"touch", L"enable", 1, filename);
|
||||
cfg->remap = GetPrivateProfileIntW(L"touch", L"remap", 1, filename);
|
||||
cfg->cursor = GetPrivateProfileIntW(L"touch", L"cursor", 1, filename);
|
||||
}
|
||||
|
||||
void printer_config_load(struct printer_config *cfg, const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
wchar_t tmpstr[16];
|
||||
|
||||
cfg->enable = GetPrivateProfileIntW(L"printer", L"enable", 0, filename);
|
||||
cfg->rotate_180 = GetPrivateProfileIntW(L"printer", L"rotate180", 0, filename);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"printer",
|
||||
L"serial_no",
|
||||
L"5A-A123",
|
||||
tmpstr,
|
||||
_countof(tmpstr),
|
||||
filename);
|
||||
|
||||
size_t n = wcstombs(cfg->serial_no, tmpstr, sizeof(cfg->serial_no));
|
||||
for (int i = n; i < sizeof(cfg->serial_no); i++)
|
||||
{
|
||||
cfg->serial_no[i] = '\0';
|
||||
}
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"printer",
|
||||
L"mainFwPath",
|
||||
L"DEVICE\\printer_main_fw.bin",
|
||||
cfg->main_fw_path,
|
||||
_countof(cfg->main_fw_path),
|
||||
filename);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"printer",
|
||||
L"dspFwPath",
|
||||
L"DEVICE\\printer_dsp_fw.bin",
|
||||
cfg->dsp_fw_path,
|
||||
_countof(cfg->dsp_fw_path),
|
||||
filename);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"printer",
|
||||
L"paramFwPath",
|
||||
L"DEVICE\\printer_param_fw.bin",
|
||||
cfg->param_fw_path,
|
||||
_countof(cfg->param_fw_path),
|
||||
filename);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"printer",
|
||||
L"printerOutPath",
|
||||
L"DEVICE\\print",
|
||||
cfg->printer_out_path,
|
||||
_countof(cfg->printer_out_path),
|
||||
filename);
|
||||
|
||||
cfg->wait_time = GetPrivateProfileIntW(L"printer", L"waitTime", 0, filename);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "hooklib/dvd.h"
|
||||
#include "hooklib/touch.h"
|
||||
#include "hooklib/printer.h"
|
||||
|
||||
void dvd_config_load(struct dvd_config *cfg, const wchar_t *filename);
|
||||
void touch_screen_config_load(struct touch_screen_config *cfg, const wchar_t *filename);
|
||||
void printer_config_load(struct printer_config *cfg, const wchar_t *filename);
|
||||
@@ -0,0 +1,258 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "hooklib/createprocess.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
void createprocess_hook_init();
|
||||
static BOOL WINAPI my_CreateProcessA(
|
||||
LPCSTR lpApplicationName,
|
||||
LPSTR lpCommandLine,
|
||||
LPSECURITY_ATTRIBUTES lpProcessAttributes,
|
||||
LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
||||
BOOL bInheritHandles,
|
||||
DWORD dwCreationFlags,
|
||||
LPVOID lpEnvironment,
|
||||
LPCSTR lpCurrentDirectory,
|
||||
LPSTARTUPINFOA lpStartupInfo,
|
||||
LPPROCESS_INFORMATION lpProcessInformation
|
||||
);
|
||||
BOOL my_CreateProcessW(
|
||||
LPCWSTR lpApplicationName,
|
||||
LPWSTR lpCommandLine,
|
||||
LPSECURITY_ATTRIBUTES lpProcessAttributes,
|
||||
LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
||||
BOOL bInheritHandles,
|
||||
DWORD dwCreationFlags,
|
||||
LPVOID lpEnvironment,
|
||||
LPCWSTR lpCurrentDirectory,
|
||||
LPSTARTUPINFOW lpStartupInfo,
|
||||
LPPROCESS_INFORMATION lpProcessInformation
|
||||
);
|
||||
|
||||
static BOOL (WINAPI *next_CreateProcessA)(
|
||||
LPCSTR lpApplicationName,
|
||||
LPSTR lpCommandLine,
|
||||
LPSECURITY_ATTRIBUTES lpProcessAttributes,
|
||||
LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
||||
BOOL bInheritHandles,
|
||||
DWORD dwCreationFlags,
|
||||
LPVOID lpEnvironment,
|
||||
LPCSTR lpCurrentDirectory,
|
||||
LPSTARTUPINFOA lpStartupInfo,
|
||||
LPPROCESS_INFORMATION lpProcessInformation
|
||||
);
|
||||
|
||||
static BOOL (WINAPI *next_CreateProcessW)(
|
||||
LPCWSTR lpApplicationName,
|
||||
LPWSTR lpCommandLine,
|
||||
LPSECURITY_ATTRIBUTES lpProcessAttributes,
|
||||
LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
||||
BOOL bInheritHandles,
|
||||
DWORD dwCreationFlags,
|
||||
LPVOID lpEnvironment,
|
||||
LPCWSTR lpCurrentDirectory,
|
||||
LPSTARTUPINFOW lpStartupInfo,
|
||||
LPPROCESS_INFORMATION lpProcessInformation
|
||||
);
|
||||
|
||||
static const struct hook_symbol win32_hooks[] = {
|
||||
{
|
||||
.name = "CreateProcessA",
|
||||
.patch = my_CreateProcessA,
|
||||
.link = (void **) &next_CreateProcessA
|
||||
},
|
||||
{
|
||||
.name = "CreateProcessW",
|
||||
.patch = my_CreateProcessW,
|
||||
.link = (void **) &next_CreateProcessW
|
||||
},
|
||||
};
|
||||
|
||||
static bool did_init = false;
|
||||
|
||||
static struct process_hook_sym_w *process_syms_w;
|
||||
static struct process_hook_sym_a *process_syms_a;
|
||||
|
||||
static size_t process_nsyms_a = 0;
|
||||
static size_t process_nsyms_w = 0;
|
||||
|
||||
static CRITICAL_SECTION createproc_lock;
|
||||
|
||||
HRESULT createprocess_push_hook_w(const wchar_t *name, const wchar_t *head, const wchar_t *tail, bool replace_all) {
|
||||
struct process_hook_sym_w *new_mem;
|
||||
struct process_hook_sym_w *new_proc;
|
||||
HRESULT hr;
|
||||
|
||||
assert(name != NULL);
|
||||
assert(head != NULL);
|
||||
|
||||
createprocess_hook_init();
|
||||
EnterCriticalSection(&createproc_lock);
|
||||
|
||||
new_mem = realloc(
|
||||
process_syms_w,
|
||||
(process_nsyms_w + 1) * sizeof(struct process_hook_sym_w));
|
||||
|
||||
if (new_mem == NULL) {
|
||||
|
||||
LeaveCriticalSection(&createproc_lock);
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
new_proc = &new_mem[process_nsyms_w];
|
||||
memset(new_proc, 0, sizeof(*new_proc));
|
||||
new_proc->name = name;
|
||||
new_proc->head = head;
|
||||
new_proc->tail = tail;
|
||||
new_proc->replace_all = replace_all;
|
||||
|
||||
process_syms_w = new_mem;
|
||||
process_nsyms_w++;
|
||||
|
||||
LeaveCriticalSection(&createproc_lock);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT createprocess_push_hook_a(const char *name, const char *head, const char *tail, bool replace_all) {
|
||||
struct process_hook_sym_a *new_mem;
|
||||
struct process_hook_sym_a *new_proc;
|
||||
|
||||
assert(name != NULL);
|
||||
assert(head != NULL);
|
||||
|
||||
createprocess_hook_init();
|
||||
|
||||
EnterCriticalSection(&createproc_lock);
|
||||
|
||||
new_mem = realloc(
|
||||
process_syms_a,
|
||||
(process_nsyms_a + 1) * sizeof(struct process_hook_sym_a));
|
||||
|
||||
if (new_mem == NULL) {
|
||||
|
||||
LeaveCriticalSection(&createproc_lock);
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
new_proc = &new_mem[process_nsyms_a];
|
||||
memset(new_proc, 0, sizeof(*new_proc));
|
||||
new_proc->name = name;
|
||||
new_proc->head = head;
|
||||
new_proc->tail = tail;
|
||||
new_proc->replace_all = replace_all;
|
||||
|
||||
process_syms_a = new_mem;
|
||||
process_nsyms_a++;
|
||||
|
||||
LeaveCriticalSection(&createproc_lock);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void createprocess_hook_init() {
|
||||
if (did_init) {
|
||||
return;
|
||||
}
|
||||
did_init = true;
|
||||
|
||||
hook_table_apply(
|
||||
NULL,
|
||||
"kernel32.dll",
|
||||
win32_hooks,
|
||||
_countof(win32_hooks));
|
||||
InitializeCriticalSection(&createproc_lock);
|
||||
dprintf("CreateProcess: Init\n");
|
||||
}
|
||||
|
||||
|
||||
static BOOL WINAPI my_CreateProcessA(
|
||||
LPCSTR lpApplicationName,
|
||||
LPSTR lpCommandLine,
|
||||
LPSECURITY_ATTRIBUTES lpProcessAttributes,
|
||||
LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
||||
BOOL bInheritHandles,
|
||||
DWORD dwCreationFlags,
|
||||
LPVOID lpEnvironment,
|
||||
LPCSTR lpCurrentDirectory,
|
||||
LPSTARTUPINFOA lpStartupInfo,
|
||||
LPPROCESS_INFORMATION lpProcessInformation
|
||||
)
|
||||
{
|
||||
for (int i = 0; i < process_nsyms_a; i++) {
|
||||
if (strncmp(process_syms_a[i].name, lpCommandLine, strlen(process_syms_a[i].name))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
dprintf("CreateProcess: Hooking child process %s %s\n", lpApplicationName, lpCommandLine);
|
||||
char new_cmd[MAX_PATH] = {0};
|
||||
strcat_s(new_cmd, MAX_PATH, process_syms_a[i].head);
|
||||
|
||||
if (!process_syms_a[i].replace_all) {
|
||||
strcat_s(new_cmd, MAX_PATH, lpCommandLine);
|
||||
}
|
||||
|
||||
if (process_syms_a[i].tail != NULL) {
|
||||
strcat_s(new_cmd, MAX_PATH, process_syms_a[i].tail);
|
||||
}
|
||||
|
||||
dprintf("CreateProcess: Replaced CreateProcessA %s\n", new_cmd);
|
||||
return next_CreateProcessA(
|
||||
lpApplicationName,
|
||||
new_cmd,
|
||||
lpProcessAttributes,
|
||||
lpThreadAttributes,
|
||||
bInheritHandles,
|
||||
dwCreationFlags,
|
||||
lpEnvironment,
|
||||
lpCurrentDirectory,
|
||||
lpStartupInfo,
|
||||
lpProcessInformation
|
||||
);
|
||||
}
|
||||
return next_CreateProcessA(
|
||||
lpApplicationName,
|
||||
lpCommandLine,
|
||||
lpProcessAttributes,
|
||||
lpThreadAttributes,
|
||||
bInheritHandles,
|
||||
dwCreationFlags,
|
||||
lpEnvironment,
|
||||
lpCurrentDirectory,
|
||||
lpStartupInfo,
|
||||
lpProcessInformation
|
||||
);
|
||||
}
|
||||
|
||||
BOOL my_CreateProcessW(
|
||||
LPCWSTR lpApplicationName,
|
||||
LPWSTR lpCommandLine,
|
||||
LPSECURITY_ATTRIBUTES lpProcessAttributes,
|
||||
LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
||||
BOOL bInheritHandles,
|
||||
DWORD dwCreationFlags,
|
||||
LPVOID lpEnvironment,
|
||||
LPCWSTR lpCurrentDirectory,
|
||||
LPSTARTUPINFOW lpStartupInfo,
|
||||
LPPROCESS_INFORMATION lpProcessInformation)
|
||||
{
|
||||
return next_CreateProcessW(
|
||||
lpApplicationName,
|
||||
lpCommandLine,
|
||||
lpProcessAttributes,
|
||||
lpThreadAttributes,
|
||||
bInheritHandles,
|
||||
dwCreationFlags,
|
||||
lpEnvironment,
|
||||
lpCurrentDirectory,
|
||||
lpStartupInfo,
|
||||
lpProcessInformation
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
HRESULT createprocess_push_hook_w(const wchar_t *name, const wchar_t *head, const wchar_t *tail, bool replace_all);
|
||||
HRESULT createprocess_push_hook_a(const char *name, const char *head, const char *tail, bool replace_all);
|
||||
|
||||
struct process_hook_sym_w {
|
||||
const wchar_t *name;
|
||||
const wchar_t *head;
|
||||
const wchar_t *tail;
|
||||
bool replace_all;
|
||||
};
|
||||
|
||||
struct process_hook_sym_a {
|
||||
const char *name;
|
||||
const char *head;
|
||||
const char *tail;
|
||||
bool replace_all;
|
||||
};
|
||||
@@ -0,0 +1,80 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hook/table.h"
|
||||
#include "util/dprintf.h"
|
||||
|
||||
static HCURSOR my_SetCursor(HCURSOR hCursor);
|
||||
static HCURSOR (*next_SetCursor)(HCURSOR hCursor);
|
||||
static BOOL my_SetCursorPos(int x, int y);
|
||||
static BOOL my_SetPhysicalCursorPos(int x, int y);
|
||||
static int my_ShowCursor(BOOL bShow);
|
||||
static int cursor_track = -1; // If no mouse is connected, this starts as -1
|
||||
|
||||
static const struct hook_symbol cursor_syms[] = {
|
||||
{
|
||||
.name = "SetCursor",
|
||||
.patch = my_SetCursor,
|
||||
.link = (void **) &next_SetCursor
|
||||
},/*{
|
||||
.name = "SetCursorPos",
|
||||
.patch = my_SetCursorPos,
|
||||
},*/ {
|
||||
.name = "SetPhysicalCursorPos",
|
||||
.patch = my_SetPhysicalCursorPos
|
||||
}, /*{
|
||||
.name = "ShowCursor",
|
||||
.patch = my_ShowCursor
|
||||
}*/
|
||||
};
|
||||
|
||||
void cursor_hook_init()
|
||||
{
|
||||
hook_table_apply(
|
||||
NULL,
|
||||
"user32.dll",
|
||||
cursor_syms,
|
||||
_countof(cursor_syms));
|
||||
|
||||
dprintf("Cursor: Init\n");
|
||||
}
|
||||
|
||||
static BOOL my_SetCursorPos(int x, int y)
|
||||
{
|
||||
// dprintf("my_SetCursorPos Hit! x %d y %d\n", x, y);
|
||||
return true;
|
||||
}
|
||||
|
||||
static BOOL my_SetPhysicalCursorPos(int x, int y)
|
||||
{
|
||||
dprintf("my_SetPhysicalCursorPos Hit! x %d y %d\n", x, y);
|
||||
return true;
|
||||
}
|
||||
|
||||
static int my_ShowCursor(BOOL bShow)
|
||||
{
|
||||
dprintf("my_ShowCursor Hit!\n");
|
||||
if (bShow) {
|
||||
cursor_track++;
|
||||
} else {
|
||||
cursor_track--;
|
||||
}
|
||||
return cursor_track;
|
||||
}
|
||||
|
||||
static HCURSOR my_SetCursor(HCURSOR hCursor)
|
||||
{
|
||||
dprintf("my_SetCursor Hit!\n");
|
||||
HCURSOR fake_cursor;
|
||||
|
||||
if ( hCursor )
|
||||
return next_SetCursor(hCursor);
|
||||
fake_cursor = LoadCursorA(0, (LPCSTR)0x7F00);
|
||||
next_SetCursor(fake_cursor);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
void cursor_hook_init();
|
||||
@@ -0,0 +1,351 @@
|
||||
/* This is general enough to break out into capnhook eventually.
|
||||
Don't introduce util/ dependencies here. */
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "hooklib/dll.h"
|
||||
|
||||
struct dll_hook_reg {
|
||||
const wchar_t *name;
|
||||
HMODULE redir_mod;
|
||||
};
|
||||
|
||||
/* Helper functions */
|
||||
|
||||
static void dll_hook_init(void);
|
||||
static HMODULE dll_hook_search_dll(const wchar_t *name);
|
||||
|
||||
/* Hook functions */
|
||||
|
||||
static BOOL WINAPI hook_FreeLibrary(HMODULE mod);
|
||||
static HMODULE WINAPI hook_GetModuleHandleA(const char *name);
|
||||
static HMODULE WINAPI hook_GetModuleHandleW(const wchar_t *name);
|
||||
static HMODULE WINAPI hook_LoadLibraryA(const char *name);
|
||||
static HMODULE WINAPI hook_LoadLibraryW(const wchar_t *name);
|
||||
static HMODULE WINAPI hook_LoadLibraryExA(const char *name, HANDLE file, DWORD flags);
|
||||
static HMODULE WINAPI hook_LoadLibraryExW(const wchar_t *name, HANDLE file, DWORD flags);
|
||||
|
||||
/* Link pointers */
|
||||
|
||||
static BOOL (WINAPI *next_FreeLibrary)(HMODULE mod);
|
||||
static HMODULE (WINAPI *next_GetModuleHandleA)(const char *name);
|
||||
static HMODULE (WINAPI *next_GetModuleHandleW)(const wchar_t *name);
|
||||
static HMODULE (WINAPI *next_LoadLibraryA)(const char *name);
|
||||
static HMODULE (WINAPI *next_LoadLibraryW)(const wchar_t *name);
|
||||
static HMODULE (WINAPI *next_LoadLibraryExA)(const char *name, HANDLE file, DWORD flags);
|
||||
static HMODULE (WINAPI *next_LoadLibraryExW)(const wchar_t *name, HANDLE file, DWORD flags);
|
||||
|
||||
static const struct hook_symbol dll_loader_syms[] = {
|
||||
{
|
||||
.name = "FreeLibrary",
|
||||
.patch = hook_FreeLibrary,
|
||||
.link = (void **) &next_FreeLibrary,
|
||||
}, {
|
||||
.name = "GetModuleHandleA",
|
||||
.patch = hook_GetModuleHandleA,
|
||||
.link = (void **) &next_GetModuleHandleA,
|
||||
}, {
|
||||
.name = "GetModuleHandleW",
|
||||
.patch = hook_GetModuleHandleW,
|
||||
.link = (void **) &next_GetModuleHandleW,
|
||||
}, {
|
||||
.name = "LoadLibraryA",
|
||||
.patch = hook_LoadLibraryA,
|
||||
.link = (void **) &next_LoadLibraryA,
|
||||
}, {
|
||||
.name = "LoadLibraryW",
|
||||
.patch = hook_LoadLibraryW,
|
||||
.link = (void **) &next_LoadLibraryW,
|
||||
}, {
|
||||
.name = "LoadLibraryExA",
|
||||
.patch = hook_LoadLibraryExA,
|
||||
.link = (void **) &next_LoadLibraryExA,
|
||||
}, {
|
||||
.name = "LoadLibraryExW",
|
||||
.patch = hook_LoadLibraryExW,
|
||||
.link = (void **) &next_LoadLibraryExW,
|
||||
}
|
||||
};
|
||||
|
||||
static bool dll_hook_initted;
|
||||
static CRITICAL_SECTION dll_hook_lock;
|
||||
static struct dll_hook_reg *dll_hook_list;
|
||||
static size_t dll_hook_count;
|
||||
|
||||
HRESULT dll_hook_push(
|
||||
HMODULE redir_mod,
|
||||
const wchar_t *name)
|
||||
{
|
||||
struct dll_hook_reg *new_item;
|
||||
struct dll_hook_reg *new_mem;
|
||||
HRESULT hr;
|
||||
|
||||
assert(name != NULL);
|
||||
|
||||
dll_hook_init();
|
||||
|
||||
EnterCriticalSection(&dll_hook_lock);
|
||||
|
||||
new_mem = realloc(
|
||||
dll_hook_list,
|
||||
(dll_hook_count + 1) * sizeof(struct dll_hook_reg));
|
||||
|
||||
if (new_mem == NULL) {
|
||||
hr = E_OUTOFMEMORY;
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
new_item = &new_mem[dll_hook_count];
|
||||
new_item->name = name;
|
||||
new_item->redir_mod = redir_mod;
|
||||
|
||||
dll_hook_list = new_mem;
|
||||
dll_hook_count++;
|
||||
hr = S_OK;
|
||||
|
||||
end:
|
||||
LeaveCriticalSection(&dll_hook_lock);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static void dll_hook_init(void)
|
||||
{
|
||||
HMODULE kernel32;
|
||||
|
||||
/* Init is not thread safe, because API hooking is not thread safe. */
|
||||
|
||||
if (dll_hook_initted) {
|
||||
return;
|
||||
}
|
||||
|
||||
dll_hook_initted = true;
|
||||
InitializeCriticalSection(&dll_hook_lock);
|
||||
|
||||
/* Protect against the (probably impossible) scenario where nothing in the
|
||||
process imports LoadLibraryW but something imports LoadLibraryA. Also
|
||||
do the same with LoadLibraryExW.
|
||||
|
||||
We know something imports GetModuleHandleW because we do, right here.
|
||||
|
||||
(we're about to hook these APIs of course, so we have to set this up
|
||||
before the hooks go in) */
|
||||
|
||||
kernel32 = GetModuleHandleW(L"kernel32.dll");
|
||||
next_LoadLibraryW = (void *) GetProcAddress(kernel32, "LoadLibraryW");
|
||||
next_LoadLibraryExW = (void *) GetProcAddress(kernel32, "LoadLibraryExW");
|
||||
|
||||
/* Now we can apply the hook table */
|
||||
|
||||
hook_table_apply(
|
||||
NULL,
|
||||
"kernel32.dll",
|
||||
dll_loader_syms,
|
||||
_countof(dll_loader_syms));
|
||||
}
|
||||
|
||||
static HMODULE dll_hook_search_dll(const wchar_t *name)
|
||||
{
|
||||
HMODULE result;
|
||||
size_t i;
|
||||
|
||||
result = NULL;
|
||||
|
||||
EnterCriticalSection(&dll_hook_lock);
|
||||
|
||||
for (i = 0 ; i < dll_hook_count ; i++) {
|
||||
if (wcsicmp(name, dll_hook_list[i].name) == 0) {
|
||||
result = dll_hook_list[i].redir_mod;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&dll_hook_lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static BOOL WINAPI hook_FreeLibrary(HMODULE mod)
|
||||
{
|
||||
bool match;
|
||||
size_t i;
|
||||
|
||||
match = false;
|
||||
EnterCriticalSection(&dll_hook_lock);
|
||||
|
||||
for (i = 0 ; i < dll_hook_count ; i++) {
|
||||
if (mod == dll_hook_list[i].redir_mod) {
|
||||
match = true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&dll_hook_lock);
|
||||
|
||||
if (match) {
|
||||
/* Block attempts to unload redirected modules, since this could cause
|
||||
a hook DLL to unexpectedly vanish and crash the whole application.
|
||||
|
||||
Reference counting might be another solution, although it is
|
||||
possible that a buggy application might cause a hook DLL unload in
|
||||
that case. */
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return next_FreeLibrary(mod);
|
||||
}
|
||||
|
||||
static HMODULE WINAPI hook_GetModuleHandleA(const char *name)
|
||||
{
|
||||
HMODULE result;
|
||||
wchar_t *name_w;
|
||||
size_t name_c;
|
||||
|
||||
if (name == NULL) {
|
||||
return next_GetModuleHandleA(NULL);
|
||||
}
|
||||
|
||||
mbstowcs_s(&name_c, NULL, 0, name, 0);
|
||||
name_w = malloc(name_c * sizeof(wchar_t));
|
||||
|
||||
if (name_w == NULL) {
|
||||
SetLastError(ERROR_OUTOFMEMORY);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mbstowcs_s(NULL, name_w, name_c, name, name_c - 1);
|
||||
result = hook_GetModuleHandleW(name_w);
|
||||
free(name_w);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static HMODULE WINAPI hook_GetModuleHandleW(const wchar_t *name)
|
||||
{
|
||||
HMODULE result;
|
||||
|
||||
if (name == NULL) {
|
||||
return next_GetModuleHandleW(NULL);
|
||||
}
|
||||
|
||||
result = dll_hook_search_dll(name);
|
||||
|
||||
if (result != NULL) {
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
} else {
|
||||
result = next_GetModuleHandleW(name);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static HMODULE WINAPI hook_LoadLibraryA(const char *name)
|
||||
{
|
||||
HMODULE result;
|
||||
wchar_t *name_w;
|
||||
size_t name_c;
|
||||
|
||||
if (name == NULL) {
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mbstowcs_s(&name_c, NULL, 0, name, 0);
|
||||
name_w = malloc(name_c * sizeof(wchar_t));
|
||||
|
||||
if (name_w == NULL) {
|
||||
SetLastError(ERROR_OUTOFMEMORY);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mbstowcs_s(NULL, name_w, name_c, name, name_c - 1);
|
||||
result = hook_LoadLibraryW(name_w);
|
||||
free(name_w);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static HMODULE WINAPI hook_LoadLibraryW(const wchar_t *name)
|
||||
{
|
||||
HMODULE result;
|
||||
|
||||
if (name == NULL) {
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
result = dll_hook_search_dll(name);
|
||||
|
||||
if (result != NULL) {
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
} else {
|
||||
result = next_LoadLibraryW(name);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static HMODULE WINAPI hook_LoadLibraryExA(const char *name, HANDLE file, DWORD flags)
|
||||
{
|
||||
HMODULE result;
|
||||
wchar_t *name_w;
|
||||
size_t name_c;
|
||||
|
||||
if (name == NULL) {
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mbstowcs_s(&name_c, NULL, 0, name, 0);
|
||||
name_w = malloc(name_c * sizeof(wchar_t));
|
||||
|
||||
if (name_w == NULL) {
|
||||
SetLastError(ERROR_OUTOFMEMORY);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mbstowcs_s(NULL, name_w, name_c, name, name_c - 1);
|
||||
result = hook_LoadLibraryExW(name_w, file, flags);
|
||||
free(name_w);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static HMODULE WINAPI hook_LoadLibraryExW(const wchar_t *name, HANDLE file, DWORD flags)
|
||||
{
|
||||
HMODULE result;
|
||||
|
||||
if (name == NULL) {
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
result = dll_hook_search_dll(name);
|
||||
|
||||
if (result != NULL) {
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
} else {
|
||||
result = next_LoadLibraryExW(name, file, flags);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
HRESULT dll_hook_push(
|
||||
HMODULE redir_mod,
|
||||
const wchar_t *name);
|
||||
@@ -0,0 +1,783 @@
|
||||
/* Might push this to capnhook, don't add any util dependencies. */
|
||||
|
||||
#include <windows.h>
|
||||
#include <windns.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <winhttp.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hook/hr.h"
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
#include "util/get_function_ordinal.h"
|
||||
|
||||
#include "hooklib/dns.h"
|
||||
|
||||
/* Latest w32headers does not include DnsQueryEx, so we'll have to "polyfill"
|
||||
its associated data types here for the time being.
|
||||
|
||||
Results and cancel handle are passed through, so we'll just use void
|
||||
pointers for those args. So are most of the fields in this structure, for
|
||||
that matter. */
|
||||
|
||||
typedef struct POLYFILL_DNS_QUERY_REQUEST {
|
||||
ULONG Version;
|
||||
PCWSTR QueryName;
|
||||
WORD QueryType;
|
||||
ULONG64 QueryOptions;
|
||||
void* pDnsServerList;
|
||||
ULONG InterfaceIndex;
|
||||
void* pQueryCompletionCallback;
|
||||
PVOID pQueryContext;
|
||||
} POLYFILL_DNS_QUERY_REQUEST;
|
||||
|
||||
struct dns_hook_entry {
|
||||
wchar_t *from;
|
||||
wchar_t *to;
|
||||
};
|
||||
|
||||
/* Hook funcs */
|
||||
|
||||
static DNS_STATUS WINAPI hook_DnsQuery_A(
|
||||
const char *pszName,
|
||||
WORD wType,
|
||||
DWORD Options,
|
||||
void *pExtra,
|
||||
DNS_RECORD **ppQueryResults,
|
||||
void *pReserved);
|
||||
|
||||
static DNS_STATUS WINAPI hook_DnsQuery_W(
|
||||
const wchar_t *pszName,
|
||||
WORD wType,
|
||||
DWORD Options,
|
||||
void *pExtra,
|
||||
DNS_RECORD **ppQueryResults,
|
||||
void *pReserved);
|
||||
|
||||
static DNS_STATUS WINAPI hook_DnsQueryEx(
|
||||
POLYFILL_DNS_QUERY_REQUEST *pRequest,
|
||||
void *pQueryResults,
|
||||
void *pCancelHandle);
|
||||
|
||||
static int WSAAPI hook_getaddrinfo(
|
||||
const char *pNodeName,
|
||||
const char *pServiceName,
|
||||
const ADDRINFOA *pHints,
|
||||
ADDRINFOA **ppResult);
|
||||
|
||||
static HINTERNET WINAPI hook_WinHttpConnect(
|
||||
HINTERNET hSession,
|
||||
const wchar_t *pwszServerName,
|
||||
INTERNET_PORT nServerPort,
|
||||
DWORD dwReserved);
|
||||
|
||||
static bool WINAPI hook_WinHttpCrackUrl(
|
||||
const wchar_t *pwszUrl,
|
||||
DWORD dwUrlLength,
|
||||
DWORD dwFlags,
|
||||
LPURL_COMPONENTS lpUrlComponents);
|
||||
|
||||
static DWORD WINAPI hook_send(
|
||||
SOCKET s,
|
||||
const char* buf,
|
||||
int len,
|
||||
int flags);
|
||||
|
||||
static int WINAPI hook_connect(
|
||||
SOCKET s,
|
||||
const struct sockaddr *name,
|
||||
int namelen);
|
||||
|
||||
/* Link pointers */
|
||||
|
||||
static DNS_STATUS (WINAPI *next_DnsQuery_A)(
|
||||
const char *pszName,
|
||||
WORD wType,
|
||||
DWORD Options,
|
||||
void *pExtra,
|
||||
DNS_RECORD **ppQueryResults,
|
||||
void *pReserved);
|
||||
|
||||
static DNS_STATUS (WINAPI *next_DnsQuery_W)(
|
||||
const wchar_t *pszName,
|
||||
WORD wType,
|
||||
DWORD Options,
|
||||
void *pExtra,
|
||||
DNS_RECORD **ppQueryResults,
|
||||
void *pReserved);
|
||||
|
||||
static DNS_STATUS (WINAPI *next_DnsQueryEx)(
|
||||
POLYFILL_DNS_QUERY_REQUEST *pRequest,
|
||||
void *pQueryResults,
|
||||
void *pCancelHandle);
|
||||
|
||||
static int (WSAAPI *next_getaddrinfo)(
|
||||
const char *pNodeName,
|
||||
const char *pServiceName,
|
||||
const ADDRINFOA *pHints,
|
||||
ADDRINFOA **ppResult);
|
||||
|
||||
static HINTERNET (WINAPI *next_WinHttpConnect)(
|
||||
HINTERNET hSession,
|
||||
const wchar_t *pwszServerName,
|
||||
INTERNET_PORT nServerPort,
|
||||
DWORD dwReserved);
|
||||
|
||||
static bool (WINAPI *next_WinHttpCrackUrl)(
|
||||
const wchar_t *pwszUrl,
|
||||
DWORD dwUrlLength,
|
||||
DWORD dwFlags,
|
||||
LPURL_COMPONENTS lpUrlComponents);
|
||||
|
||||
static DWORD (WINAPI *next_send)(
|
||||
SOCKET s,
|
||||
const char* buf,
|
||||
int len,
|
||||
int flags);
|
||||
|
||||
static int (__stdcall *next_connect)(
|
||||
SOCKET s,
|
||||
const struct sockaddr *name,
|
||||
int namelen);
|
||||
|
||||
static const struct hook_symbol dns_hook_syms_dnsapi[] = {
|
||||
{
|
||||
.name = "DnsQuery_A",
|
||||
.patch = hook_DnsQuery_A,
|
||||
.link = (void **) &next_DnsQuery_A,
|
||||
}, {
|
||||
.name = "DnsQuery_W",
|
||||
.patch = hook_DnsQuery_W,
|
||||
.link = (void **) &next_DnsQuery_W,
|
||||
}, {
|
||||
.name = "DnsQueryEx",
|
||||
.patch = hook_DnsQueryEx,
|
||||
.link = (void **) &next_DnsQueryEx,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct hook_symbol dns_hook_syms_ws2[] = {
|
||||
{
|
||||
.name = "getaddrinfo",
|
||||
.ordinal = 176,
|
||||
.patch = hook_getaddrinfo,
|
||||
.link = (void **) &next_getaddrinfo,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct hook_symbol dns_hook_syms_winhttp[] = {
|
||||
{
|
||||
.name = "WinHttpConnect",
|
||||
.patch = hook_WinHttpConnect,
|
||||
.link = (void **) &next_WinHttpConnect,
|
||||
}, {
|
||||
.name = "WinHttpCrackUrl",
|
||||
.patch = hook_WinHttpCrackUrl,
|
||||
.link = (void **) &next_WinHttpCrackUrl,
|
||||
}
|
||||
};
|
||||
|
||||
static struct hook_symbol http_hook_syms_ws2[] = {
|
||||
{
|
||||
.name = "send",
|
||||
.patch = hook_send,
|
||||
.link = (void **) &next_send
|
||||
},
|
||||
};
|
||||
|
||||
static struct hook_symbol port_hook_syms_ws2[] = {
|
||||
{
|
||||
.name = "connect",
|
||||
.patch = hook_connect,
|
||||
.link = (void **) &next_connect
|
||||
},
|
||||
};
|
||||
|
||||
static bool dns_hook_initted;
|
||||
static CRITICAL_SECTION dns_hook_lock;
|
||||
static struct dns_hook_entry *dns_hook_entries;
|
||||
static size_t dns_hook_nentries;
|
||||
static char received_title_url[255];
|
||||
static unsigned short startup_port;
|
||||
static unsigned short billing_port;
|
||||
static unsigned short aimedb_port;
|
||||
|
||||
static void dns_hook_init(void)
|
||||
{
|
||||
if (dns_hook_initted) {
|
||||
return;
|
||||
}
|
||||
|
||||
dns_hook_initted = true;
|
||||
InitializeCriticalSection(&dns_hook_lock);
|
||||
|
||||
dns_hook_apply_hooks(NULL);
|
||||
}
|
||||
|
||||
void dns_hook_apply_hooks(HMODULE mod){
|
||||
hook_table_apply(
|
||||
mod,
|
||||
"dnsapi.dll",
|
||||
dns_hook_syms_dnsapi,
|
||||
_countof(dns_hook_syms_dnsapi));
|
||||
|
||||
hook_table_apply(
|
||||
mod,
|
||||
"ws2_32.dll",
|
||||
dns_hook_syms_ws2,
|
||||
_countof(dns_hook_syms_ws2));
|
||||
|
||||
hook_table_apply(
|
||||
mod,
|
||||
"winhttp.dll",
|
||||
dns_hook_syms_winhttp,
|
||||
_countof(dns_hook_syms_winhttp));
|
||||
}
|
||||
|
||||
void http_hook_init(){
|
||||
for (size_t i = 0; i < _countof(http_hook_syms_ws2); ++i) {
|
||||
http_hook_syms_ws2[i].ordinal = get_function_ordinal("ws2_32.dll", http_hook_syms_ws2[i].name);
|
||||
}
|
||||
|
||||
hook_table_apply(
|
||||
NULL,
|
||||
"ws2_32.dll",
|
||||
http_hook_syms_ws2,
|
||||
_countof(http_hook_syms_ws2));
|
||||
}
|
||||
|
||||
void port_hook_init(unsigned short _startup_port, unsigned short _billing_port, unsigned short _aimedb_port){
|
||||
startup_port = _startup_port;
|
||||
billing_port = _billing_port;
|
||||
aimedb_port = _aimedb_port;
|
||||
for (size_t i = 0; i < _countof(port_hook_syms_ws2); ++i) {
|
||||
port_hook_syms_ws2[i].ordinal = get_function_ordinal("ws2_32.dll", port_hook_syms_ws2[i].name);
|
||||
}
|
||||
|
||||
hook_table_apply(
|
||||
NULL,
|
||||
"ws2_32.dll",
|
||||
port_hook_syms_ws2,
|
||||
_countof(port_hook_syms_ws2));
|
||||
}
|
||||
|
||||
// This function match domain and subdomains like *.naominet.jp.
|
||||
bool match_domain(const wchar_t* target, const wchar_t* pattern) {
|
||||
if (_wcsicmp(pattern, target) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int pattern_ptr_index = 0;
|
||||
int target_ptr_index = 0;
|
||||
|
||||
while (pattern[pattern_ptr_index] != '\0' && target[target_ptr_index] != '\0') {
|
||||
if (pattern[pattern_ptr_index] == '*') {
|
||||
pattern_ptr_index++; // Check next character for wildcard match.
|
||||
|
||||
while (pattern[pattern_ptr_index] != target[target_ptr_index]) {
|
||||
target_ptr_index++;
|
||||
|
||||
if (target[target_ptr_index] == '\0') return false;
|
||||
}
|
||||
}
|
||||
else if (pattern[pattern_ptr_index] != target[target_ptr_index]) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
pattern_ptr_index++;
|
||||
target_ptr_index++;
|
||||
}
|
||||
}
|
||||
|
||||
return pattern[pattern_ptr_index] == '\0' && target[target_ptr_index] == '\0';
|
||||
}
|
||||
|
||||
HRESULT dns_hook_push(const wchar_t *from_src, const wchar_t *to_src)
|
||||
{
|
||||
HRESULT hr;
|
||||
struct dns_hook_entry *newmem;
|
||||
struct dns_hook_entry *newitem;
|
||||
wchar_t *from;
|
||||
wchar_t *to;
|
||||
|
||||
assert(from_src != NULL);
|
||||
|
||||
to = NULL;
|
||||
from = NULL;
|
||||
dns_hook_init();
|
||||
|
||||
EnterCriticalSection(&dns_hook_lock);
|
||||
|
||||
from = _wcsdup(from_src);
|
||||
|
||||
if (from == NULL) {
|
||||
hr = E_OUTOFMEMORY;
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (to_src != NULL) {
|
||||
to = _wcsdup(to_src);
|
||||
|
||||
if (to == NULL) {
|
||||
hr = E_OUTOFMEMORY;
|
||||
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
newmem = realloc(
|
||||
dns_hook_entries,
|
||||
(dns_hook_nentries + 1) * sizeof(struct dns_hook_entry));
|
||||
|
||||
if (newmem == NULL) {
|
||||
hr = E_OUTOFMEMORY;
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
dns_hook_entries = newmem;
|
||||
newitem = &newmem[dns_hook_nentries++];
|
||||
newitem->from = from;
|
||||
newitem->to = to;
|
||||
|
||||
from = NULL;
|
||||
to = NULL;
|
||||
hr = S_OK;
|
||||
|
||||
end:
|
||||
LeaveCriticalSection(&dns_hook_lock);
|
||||
|
||||
free(to);
|
||||
free(from);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static DNS_STATUS WINAPI hook_DnsQuery_A(
|
||||
const char *pszName,
|
||||
WORD wType,
|
||||
DWORD Options,
|
||||
void *pExtra,
|
||||
DNS_RECORD **ppQueryResults,
|
||||
void *pReserved)
|
||||
{
|
||||
const struct dns_hook_entry *pos;
|
||||
size_t i;
|
||||
size_t wstr_c;
|
||||
wchar_t *wstr;
|
||||
size_t str_c;
|
||||
char *str;
|
||||
DNS_STATUS code;
|
||||
HRESULT hr;
|
||||
|
||||
wstr = NULL;
|
||||
str = NULL;
|
||||
|
||||
if (pszName == NULL) {
|
||||
hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
mbstowcs_s(&wstr_c, NULL, 0, pszName, 0);
|
||||
wstr = malloc(wstr_c * sizeof(wchar_t));
|
||||
|
||||
if (wstr == NULL) {
|
||||
hr = HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
mbstowcs_s(NULL, wstr, wstr_c, pszName, wstr_c - 1);
|
||||
EnterCriticalSection(&dns_hook_lock);
|
||||
|
||||
for (i = 0 ; i < dns_hook_nentries ; i++) {
|
||||
pos = &dns_hook_entries[i];
|
||||
|
||||
if (match_domain(wstr, pos->from)) {
|
||||
if (pos->to == NULL) {
|
||||
LeaveCriticalSection(&dns_hook_lock);
|
||||
hr = HRESULT_FROM_WIN32(DNS_ERROR_RCODE_NAME_ERROR);
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
wcstombs_s(&str_c, NULL, 0, pos->to, 0);
|
||||
str = malloc(str_c * sizeof(char));
|
||||
|
||||
if (str == NULL) {
|
||||
LeaveCriticalSection(&dns_hook_lock);
|
||||
hr = HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
wcstombs_s(NULL, str, str_c, pos->to, str_c - 1);
|
||||
pszName = str;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&dns_hook_lock);
|
||||
|
||||
code = next_DnsQuery_A(
|
||||
pszName,
|
||||
wType,
|
||||
Options,
|
||||
pExtra,
|
||||
ppQueryResults,
|
||||
pReserved);
|
||||
|
||||
hr = HRESULT_FROM_WIN32(code);
|
||||
|
||||
end:
|
||||
free(str);
|
||||
free(wstr);
|
||||
|
||||
return hr_to_win32_error(hr);
|
||||
}
|
||||
|
||||
static DNS_STATUS WINAPI hook_DnsQuery_W(
|
||||
const wchar_t *pszName,
|
||||
WORD wType,
|
||||
DWORD Options,
|
||||
void *pExtra,
|
||||
DNS_RECORD **ppQueryResults,
|
||||
void *pReserved)
|
||||
{
|
||||
const struct dns_hook_entry *pos;
|
||||
size_t i;
|
||||
|
||||
if (pszName == NULL) {
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
EnterCriticalSection(&dns_hook_lock);
|
||||
|
||||
for (i = 0 ; i < dns_hook_nentries ; i++) {
|
||||
pos = &dns_hook_entries[i];
|
||||
|
||||
if (match_domain(pszName, pos->from)) {
|
||||
if (pos->to == NULL) {
|
||||
LeaveCriticalSection(&dns_hook_lock);
|
||||
return HRESULT_FROM_WIN32(DNS_ERROR_RCODE_NAME_ERROR);
|
||||
}
|
||||
|
||||
pszName = pos->to;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&dns_hook_lock);
|
||||
|
||||
return next_DnsQuery_W(
|
||||
pszName,
|
||||
wType,
|
||||
Options,
|
||||
pExtra,
|
||||
ppQueryResults,
|
||||
pReserved);
|
||||
|
||||
}
|
||||
|
||||
static DNS_STATUS WINAPI hook_DnsQueryEx(
|
||||
POLYFILL_DNS_QUERY_REQUEST *pRequest,
|
||||
void *pQueryResults,
|
||||
void *pCancelHandle)
|
||||
{
|
||||
const wchar_t *orig;
|
||||
const struct dns_hook_entry *pos;
|
||||
DNS_STATUS code;
|
||||
size_t i;
|
||||
|
||||
if (pRequest == NULL) {
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
orig = pRequest->QueryName;
|
||||
EnterCriticalSection(&dns_hook_lock);
|
||||
|
||||
for (i = 0 ; i < dns_hook_nentries ; i++) {
|
||||
pos = &dns_hook_entries[i];
|
||||
|
||||
if (match_domain(pRequest->QueryName, pos->from)) {
|
||||
if (pos->to == NULL) {
|
||||
LeaveCriticalSection(&dns_hook_lock);
|
||||
return HRESULT_FROM_WIN32(DNS_ERROR_RCODE_NAME_ERROR);
|
||||
}
|
||||
|
||||
pRequest->QueryName = pos->to;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&dns_hook_lock);
|
||||
|
||||
code = next_DnsQueryEx(pRequest, pQueryResults, pCancelHandle);
|
||||
|
||||
/* Caller might not appreciate QueryName changing under its feet. It is
|
||||
strongly implied by MSDN that a copy of *pRequest is taken by WINAPI,
|
||||
so we can change it back after the call has been issued with no ill
|
||||
effect... we hope.
|
||||
|
||||
Hopefully the completion callback is issued from an APC or something
|
||||
(or otherwise happens after this returns) or we're in trouble. */
|
||||
|
||||
pRequest->QueryName = orig;
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
static int WSAAPI hook_getaddrinfo(
|
||||
const char *pNodeName,
|
||||
const char *pServiceName,
|
||||
const ADDRINFOA *pHints,
|
||||
ADDRINFOA **ppResult)
|
||||
{
|
||||
const struct dns_hook_entry *pos;
|
||||
char *str;
|
||||
size_t str_c;
|
||||
wchar_t *wstr;
|
||||
size_t wstr_c;
|
||||
int result;
|
||||
size_t i;
|
||||
|
||||
str = NULL;
|
||||
wstr = NULL;
|
||||
|
||||
if (pNodeName == NULL) {
|
||||
result = WSA_INVALID_PARAMETER;
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
mbstowcs_s(&wstr_c, NULL, 0, pNodeName, 0);
|
||||
wstr = malloc(wstr_c * sizeof(wchar_t));
|
||||
|
||||
if (wstr == NULL) {
|
||||
result = WSA_NOT_ENOUGH_MEMORY;
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
mbstowcs_s(NULL, wstr, wstr_c, pNodeName, wstr_c - 1);
|
||||
EnterCriticalSection(&dns_hook_lock);
|
||||
|
||||
for (i = 0 ; i < dns_hook_nentries ; i++) {
|
||||
pos = &dns_hook_entries[i];
|
||||
|
||||
if (match_domain(wstr, pos->from)) {
|
||||
if (pos->to == NULL) {
|
||||
LeaveCriticalSection(&dns_hook_lock);
|
||||
result = EAI_NONAME;
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
wcstombs_s(&str_c, NULL, 0, pos->to, 0);
|
||||
str = malloc(str_c * sizeof(char));
|
||||
|
||||
if (str == NULL) {
|
||||
LeaveCriticalSection(&dns_hook_lock);
|
||||
result = WSA_NOT_ENOUGH_MEMORY;
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
wcstombs_s(NULL, str, str_c, pos->to, str_c - 1);
|
||||
pNodeName = str;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&dns_hook_lock);
|
||||
|
||||
result = next_getaddrinfo(pNodeName, pServiceName, pHints, ppResult);
|
||||
|
||||
end:
|
||||
free(wstr);
|
||||
free(str);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static HINTERNET WINAPI hook_WinHttpConnect(
|
||||
HINTERNET hSession,
|
||||
const wchar_t *pwszServerName,
|
||||
INTERNET_PORT nServerPort,
|
||||
DWORD dwReserved)
|
||||
{
|
||||
const struct dns_hook_entry *pos;
|
||||
size_t i;
|
||||
|
||||
if (pwszServerName == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EnterCriticalSection(&dns_hook_lock);
|
||||
|
||||
for (i = 0 ; i < dns_hook_nentries ; i++) {
|
||||
pos = &dns_hook_entries[i];
|
||||
|
||||
if (match_domain(pwszServerName, pos->from)) {
|
||||
if (pos->to == NULL) {
|
||||
LeaveCriticalSection(&dns_hook_lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pwszServerName = pos->to;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&dns_hook_lock);
|
||||
|
||||
return next_WinHttpConnect(hSession, pwszServerName, nServerPort, dwReserved);
|
||||
}
|
||||
|
||||
// Hook to replace CXB title url
|
||||
static bool WINAPI hook_WinHttpCrackUrl(
|
||||
const wchar_t *pwszUrl,
|
||||
DWORD dwUrlLength,
|
||||
DWORD dwFlags,
|
||||
LPURL_COMPONENTS lpUrlComponents)
|
||||
{
|
||||
const struct dns_hook_entry *pos;
|
||||
size_t i;
|
||||
|
||||
EnterCriticalSection(&dns_hook_lock);
|
||||
|
||||
for (i = 0 ; i < dns_hook_nentries ; i++) {
|
||||
pos = &dns_hook_entries[i];
|
||||
|
||||
if (match_domain(pwszUrl, pos->from)) {
|
||||
wchar_t* toAddr = pos->to;
|
||||
wchar_t titleBuffer[255];
|
||||
|
||||
if (wcscmp(toAddr, L"title") == 0) {
|
||||
size_t wstr_c;
|
||||
mbstowcs_s(&wstr_c, titleBuffer, 255, received_title_url, strlen(received_title_url));
|
||||
toAddr = titleBuffer;
|
||||
}
|
||||
|
||||
bool result = next_WinHttpCrackUrl(
|
||||
toAddr,
|
||||
wcslen(toAddr),
|
||||
dwFlags,
|
||||
lpUrlComponents
|
||||
);
|
||||
LeaveCriticalSection(&dns_hook_lock);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&dns_hook_lock);
|
||||
return next_WinHttpCrackUrl(
|
||||
pwszUrl,
|
||||
dwUrlLength,
|
||||
dwFlags,
|
||||
lpUrlComponents
|
||||
);
|
||||
}
|
||||
|
||||
int WINAPI hook_connect(SOCKET s, const struct sockaddr *name, int namelen) {
|
||||
const struct sockaddr_in *n;
|
||||
struct sockaddr_in new_name;
|
||||
unsigned ip;
|
||||
unsigned short port, new_port;
|
||||
|
||||
EnterCriticalSection(&dns_hook_lock);
|
||||
|
||||
n = (const struct sockaddr_in *)name;
|
||||
ip = n->sin_addr.S_un.S_addr;
|
||||
if (WSANtohs(s, n->sin_port, &port)) return SOCKET_ERROR;
|
||||
|
||||
if (port == 80 && startup_port) {
|
||||
new_port = startup_port;
|
||||
} else if (port == 8443 && billing_port) {
|
||||
new_port = billing_port;
|
||||
} else if (port == 22345 && aimedb_port) {
|
||||
new_port = aimedb_port;
|
||||
} else { // No match
|
||||
dprintf("TCP Connect: %u.%u.%u.%u:%hu\n", ip & 0xff, (ip >> 8) & 0xff, (ip >> 16) & 0xff, (ip >> 24) & 0xff, port);
|
||||
|
||||
LeaveCriticalSection(&dns_hook_lock);
|
||||
return next_connect(
|
||||
s,
|
||||
name,
|
||||
namelen
|
||||
);
|
||||
}
|
||||
|
||||
// matched
|
||||
new_name = *n;
|
||||
if (WSAHtons(s, new_port, &new_name.sin_port)) return SOCKET_ERROR;
|
||||
|
||||
dprintf("TCP Connect: %u.%u.%u.%u:%hu, mapped to port %hu\n", ip & 0xff, (ip >> 8) & 0xff, (ip >> 16) & 0xff, (ip >> 24) & 0xff, port, new_port);
|
||||
|
||||
LeaveCriticalSection(&dns_hook_lock);
|
||||
return next_connect(
|
||||
s,
|
||||
(const struct sockaddr *)&new_name,
|
||||
sizeof(new_name)
|
||||
);
|
||||
}
|
||||
|
||||
DWORD WINAPI hook_send(SOCKET s, const char* buf, int len, int flags) {
|
||||
if (strstr(buf, "HTTP/") != NULL) {
|
||||
char *new_buf = malloc(len + 1);
|
||||
if (new_buf == NULL) return SOCKET_ERROR;
|
||||
|
||||
memcpy(new_buf, buf, len);
|
||||
new_buf[len] = '\0';
|
||||
|
||||
char *host_start = strstr(new_buf, "Host: ");
|
||||
if (host_start != NULL) {
|
||||
char *host_end = strstr(host_start, "\r\n");
|
||||
if (host_end != NULL) {
|
||||
host_end += 2;
|
||||
int host_len = host_end - host_start;
|
||||
|
||||
char *host_value_start = host_start + 6;
|
||||
char *host_value_end = strstr(host_value_start, "\r\n");
|
||||
if (host_value_end != NULL) {
|
||||
int value_len = host_value_end - host_value_start;
|
||||
char* host_value = (char*)malloc(value_len + 1);
|
||||
strncpy(host_value, host_value_start, value_len);
|
||||
host_value[value_len] = '\0';
|
||||
|
||||
for (struct dns_hook_entry *entry = dns_hook_entries; entry && entry->from; entry++) {
|
||||
char from_value[256];
|
||||
wcstombs(from_value, entry->from, sizeof(from_value));
|
||||
|
||||
if (strcmp(host_value, from_value) == 0) {
|
||||
char to_value[256];
|
||||
wcstombs(to_value, entry->to, sizeof(to_value));
|
||||
snprintf(host_start, len - (host_start - new_buf), "Host: %s\r\n", to_value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(host_value);
|
||||
}
|
||||
len = (int)strlen(new_buf);
|
||||
}
|
||||
}
|
||||
DWORD result = next_send(s, new_buf, len, flags);
|
||||
free(new_buf);
|
||||
return result;
|
||||
}
|
||||
|
||||
return next_send(s, buf, len, flags);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stddef.h>
|
||||
void http_hook_init();
|
||||
void port_hook_init(unsigned short _startup_port, unsigned short _billing_port, unsigned short _aimedb_port);
|
||||
// if to_src is NULL, all lookups for from_src will fail
|
||||
HRESULT dns_hook_push(const wchar_t *from_src, const wchar_t *to_src);
|
||||
|
||||
void dns_hook_apply_hooks(HMODULE mod);
|
||||
@@ -0,0 +1,82 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "hook/com-proxy.h"
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "hooklib/config.h"
|
||||
#include "hooklib/dll.h"
|
||||
#include "hooklib/dvd.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
/* API hooks */
|
||||
|
||||
static DWORD WINAPI hook_QueryDosDeviceW(
|
||||
const wchar_t *lpDeviceName,
|
||||
wchar_t *lpTargetPath,
|
||||
DWORD ucchMax);
|
||||
|
||||
/* Link pointers */
|
||||
|
||||
static DWORD (WINAPI *next_QueryDosDeviceW)(
|
||||
const wchar_t *lpDeviceName,
|
||||
wchar_t *lpTargetPath,
|
||||
DWORD ucchMax);
|
||||
|
||||
static bool dvd_hook_initted;
|
||||
static struct dvd_config dvd_config;
|
||||
|
||||
static const struct hook_symbol dvd_hooks[] = {
|
||||
{
|
||||
.name = "QueryDosDeviceW",
|
||||
.patch = hook_QueryDosDeviceW,
|
||||
.link = (void **) &next_QueryDosDeviceW
|
||||
},
|
||||
};
|
||||
|
||||
void dvd_hook_init(const struct dvd_config *cfg, HINSTANCE self)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
|
||||
if (!cfg->enable) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (dvd_hook_initted) {
|
||||
return;
|
||||
}
|
||||
|
||||
dvd_hook_initted = true;
|
||||
|
||||
memcpy(&dvd_config, cfg, sizeof(*cfg));
|
||||
hook_table_apply(NULL, "kernel32.dll", dvd_hooks, _countof(dvd_hooks));
|
||||
dprintf("DVD: hook enabled.\n");
|
||||
}
|
||||
|
||||
DWORD WINAPI hook_QueryDosDeviceW(
|
||||
const wchar_t *lpDeviceName,
|
||||
wchar_t *lpTargetPath,
|
||||
DWORD ucchMax)
|
||||
{
|
||||
DWORD ok;
|
||||
wchar_t *p_dest;
|
||||
wchar_t *dvd_string = L"CdRom";
|
||||
|
||||
ok = next_QueryDosDeviceW(
|
||||
lpDeviceName,
|
||||
lpTargetPath,
|
||||
ucchMax);
|
||||
|
||||
p_dest = wcsstr (lpTargetPath, dvd_string);
|
||||
|
||||
if ( p_dest != NULL ) {
|
||||
dprintf("DVD: Hiding DVD drive.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
struct dvd_config {
|
||||
bool enable;
|
||||
};
|
||||
|
||||
/* Init is not thread safe because API hook init is not thread safe blah
|
||||
blah blah you know the drill by now. */
|
||||
|
||||
void dvd_hook_init(const struct dvd_config *cfg, HINSTANCE self);
|
||||
@@ -0,0 +1,218 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hook/iobuf.h"
|
||||
#include "hook/iohook.h"
|
||||
|
||||
#include "hooklib/fdshark.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
#include "util/dump.h"
|
||||
|
||||
static const wchar_t *fdshark_path;
|
||||
static HANDLE fdshark_target_fd;
|
||||
static int fdshark_flags;
|
||||
|
||||
static HRESULT fdshark_handle_irp(struct irp *irp);
|
||||
static HRESULT fdshark_handle_open(struct irp *irp);
|
||||
static HRESULT fdshark_handle_close(struct irp *irp);
|
||||
static HRESULT fdshark_handle_read(struct irp *irp);
|
||||
static HRESULT fdshark_handle_write(struct irp *irp);
|
||||
static HRESULT fdshark_handle_ioctl(struct irp *irp);
|
||||
static bool fdshark_force_sync(struct irp *irp, HRESULT hr);
|
||||
|
||||
HRESULT fdshark_hook_init(const wchar_t *path, int flags)
|
||||
{
|
||||
assert(path != NULL);
|
||||
assert(!(flags & ~FDSHARK_ALL_FLAGS_));
|
||||
|
||||
fdshark_path = path;
|
||||
fdshark_flags = flags;
|
||||
|
||||
return iohook_push_handler(fdshark_handle_irp);
|
||||
}
|
||||
|
||||
static HRESULT fdshark_handle_irp(struct irp *irp)
|
||||
{
|
||||
assert(irp != NULL);
|
||||
|
||||
if (irp->op != IRP_OP_OPEN && irp->fd != fdshark_target_fd) {
|
||||
return iohook_invoke_next(irp);
|
||||
}
|
||||
|
||||
switch (irp->op) {
|
||||
case IRP_OP_OPEN: return fdshark_handle_open(irp);
|
||||
case IRP_OP_CLOSE: return fdshark_handle_close(irp);
|
||||
case IRP_OP_READ: return fdshark_handle_read(irp);
|
||||
case IRP_OP_WRITE: return fdshark_handle_write(irp);
|
||||
case IRP_OP_IOCTL: return fdshark_handle_ioctl(irp);
|
||||
default: return iohook_invoke_next(irp);
|
||||
}
|
||||
}
|
||||
|
||||
static HRESULT fdshark_handle_open(struct irp *irp)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
if (_wcsicmp(irp->open_filename, fdshark_path) != 0) {
|
||||
return iohook_invoke_next(irp);
|
||||
}
|
||||
|
||||
hr = iohook_invoke_next(irp);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
dprintf("FdShark: Opened %S\n", fdshark_path);
|
||||
fdshark_target_fd = irp->fd;
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT fdshark_handle_close(struct irp *irp)
|
||||
{
|
||||
dprintf("FdShark: Closed %S\n", fdshark_path);
|
||||
fdshark_target_fd = NULL;
|
||||
|
||||
return iohook_invoke_next(irp);
|
||||
}
|
||||
|
||||
static HRESULT fdshark_handle_read(struct irp *irp)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
if (!(fdshark_flags & FDSHARK_TRACE_READ)) {
|
||||
return iohook_invoke_next(irp);
|
||||
}
|
||||
|
||||
dprintf("FdShark: Read %p:%i/%i\n",
|
||||
irp->read.bytes,
|
||||
(int) irp->read.pos,
|
||||
(int) irp->read.nbytes);
|
||||
|
||||
hr = iohook_invoke_next(irp);
|
||||
|
||||
if (FAILED(hr) && !fdshark_force_sync(irp, hr)) {
|
||||
dprintf("FdShark: FAILED: %x\n", (int) hr);
|
||||
} else {
|
||||
dprintf("FdShark: Read %p:%i/%i OK\n",
|
||||
irp->read.bytes,
|
||||
(int) irp->read.pos,
|
||||
(int) irp->read.nbytes);
|
||||
dump_iobuf(&irp->read);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT fdshark_handle_write(struct irp *irp)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
if (!(fdshark_flags & FDSHARK_TRACE_WRITE)) {
|
||||
return iohook_invoke_next(irp);
|
||||
}
|
||||
|
||||
dprintf("FdShark: Write %p:%i/%i\n",
|
||||
irp->write.bytes,
|
||||
(int) irp->write.pos,
|
||||
(int) irp->write.nbytes);
|
||||
dump_const_iobuf(&irp->write);
|
||||
|
||||
hr = iohook_invoke_next(irp);
|
||||
|
||||
if (FAILED(hr) && !fdshark_force_sync(irp, hr)) {
|
||||
dprintf("FdShark: FAILED: %x\n", (int) hr);
|
||||
} else {
|
||||
dprintf("FdShark: Write %p:%i/%i OK\n",
|
||||
irp->write.bytes,
|
||||
(int) irp->write.pos,
|
||||
(int) irp->write.nbytes);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT fdshark_handle_ioctl(struct irp *irp)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
if (!(fdshark_flags & FDSHARK_TRACE_IOCTL)) {
|
||||
return iohook_invoke_next(irp);
|
||||
}
|
||||
|
||||
dprintf("FdShark: Ioctl %08x w:%p:%i/%i r:%p:%i/%i\n",
|
||||
irp->ioctl,
|
||||
irp->write.bytes,
|
||||
(int) irp->write.pos,
|
||||
(int) irp->write.nbytes,
|
||||
irp->read.bytes,
|
||||
(int) irp->read.pos,
|
||||
(int) irp->read.nbytes);
|
||||
dump_const_iobuf(&irp->write);
|
||||
|
||||
hr = iohook_invoke_next(irp);
|
||||
|
||||
if (FAILED(hr) && !fdshark_force_sync(irp, hr)) {
|
||||
dprintf("FdShark: FAILED: %x\n", (int) hr);
|
||||
} else {
|
||||
dprintf("FdShark: Ioctl %08x w:%p:%i/%i r:%p:%i/%i OK\n",
|
||||
irp->ioctl,
|
||||
irp->write.bytes,
|
||||
(int) irp->write.pos,
|
||||
(int) irp->write.nbytes,
|
||||
irp->read.bytes,
|
||||
(int) irp->read.pos,
|
||||
(int) irp->read.nbytes);
|
||||
dump_iobuf(&irp->read);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static bool fdshark_force_sync(struct irp *irp, HRESULT hr)
|
||||
{
|
||||
DWORD xferred;
|
||||
BOOL ok;
|
||||
|
||||
if (!(fdshark_flags & FDSHARK_FORCE_SYNC)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( hr != HRESULT_FROM_WIN32(ERROR_IO_PENDING) &&
|
||||
hr != HRESULT_FROM_NT(STATUS_PENDING)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ok = GetOverlappedResult(irp->fd, irp->ovl, &xferred, TRUE);
|
||||
|
||||
if (!ok) {
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
dprintf("FdShark: Synchronous block failed: %x\n", (int) hr);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (irp->op) {
|
||||
case IRP_OP_READ:
|
||||
case IRP_OP_IOCTL:
|
||||
irp->read.pos += xferred;
|
||||
|
||||
break;
|
||||
|
||||
case IRP_OP_WRITE:
|
||||
irp->write.pos += xferred;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
enum {
|
||||
FDSHARK_FORCE_SYNC = 0x1,
|
||||
FDSHARK_TRACE_READ = 0x2,
|
||||
FDSHARK_TRACE_WRITE = 0x4,
|
||||
FDSHARK_TRACE_IOCTL = 0x8,
|
||||
FDSHARK_ALL_FLAGS_ = 0xF,
|
||||
};
|
||||
|
||||
HRESULT fdshark_hook_init(const wchar_t *filename, int flags);
|
||||
@@ -0,0 +1,37 @@
|
||||
hooklib_lib = static_library(
|
||||
'hooklib',
|
||||
include_directories : inc,
|
||||
implicit_include_directories : false,
|
||||
dependencies : [
|
||||
capnhook.get_variable('hook_dep'),
|
||||
ws2_32_lib
|
||||
],
|
||||
sources : [
|
||||
'cursor.c',
|
||||
'cursor.h',
|
||||
'config.c',
|
||||
'config.h',
|
||||
'createprocess.c',
|
||||
'createprocess.h',
|
||||
'dll.c',
|
||||
'dll.h',
|
||||
'dns.c',
|
||||
'dns.h',
|
||||
'dvd.c',
|
||||
'dvd.h',
|
||||
'fdshark.c',
|
||||
'fdshark.h',
|
||||
'path.c',
|
||||
'path.h',
|
||||
'reg.c',
|
||||
'reg.h',
|
||||
'setupapi.c',
|
||||
'setupapi.h',
|
||||
'spike.c',
|
||||
'spike.h',
|
||||
'touch.c',
|
||||
'touch.h',
|
||||
'printer.c',
|
||||
'printer.h',
|
||||
],
|
||||
)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef HRESULT (*path_hook_t)(
|
||||
const wchar_t *src,
|
||||
wchar_t *dest,
|
||||
size_t *count);
|
||||
|
||||
HRESULT path_hook_push(path_hook_t hook);
|
||||
void path_hook_insert_hooks(HMODULE target);
|
||||
int path_compare_w(const wchar_t *string1, const wchar_t *string2, size_t count);
|
||||
|
||||
static inline bool path_is_separator_w(wchar_t c)
|
||||
{
|
||||
return c == L'\\' || c == L'/';
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct printer_config {
|
||||
bool enable;
|
||||
bool rotate_180;
|
||||
char serial_no[8];
|
||||
wchar_t main_fw_path[MAX_PATH];
|
||||
wchar_t dsp_fw_path[MAX_PATH];
|
||||
wchar_t param_fw_path[MAX_PATH];
|
||||
wchar_t printer_out_path[MAX_PATH];
|
||||
uint32_t wait_time;
|
||||
};
|
||||
|
||||
void printer_hook_init(const struct printer_config *cfg, int rfid_port_no, HINSTANCE self);
|
||||
void printer_hook_insert_hooks(HMODULE target);
|
||||
|
||||
void printer_set_dimensions(int width, int height);
|
||||
int WINAPI fwdlusb_updateFirmware_main(uint8_t update, LPCSTR filename, uint16_t *rResult);
|
||||
int WINAPI fwdlusb_updateFirmware_dsp(uint8_t update, LPCSTR filename, uint16_t *rResult);
|
||||
int WINAPI fwdlusb_updateFirmware_param(uint8_t update, LPCSTR filename, uint16_t *rResult);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct reg_hook_val {
|
||||
const wchar_t *name;
|
||||
HRESULT (*read)(void *bytes, uint32_t *nbytes);
|
||||
HRESULT (*write)(const void *bytes, uint32_t nbytes);
|
||||
uint32_t type;
|
||||
};
|
||||
|
||||
void reg_hook_insert_hooks(HMODULE target);
|
||||
|
||||
HRESULT reg_hook_push_key(
|
||||
HKEY root,
|
||||
const wchar_t *name,
|
||||
const struct reg_hook_val *vals,
|
||||
size_t nvals);
|
||||
|
||||
HRESULT reg_hook_read_bin(
|
||||
void *bytes,
|
||||
uint32_t *nbytes,
|
||||
const void *src_bytes,
|
||||
size_t src_nbytes);
|
||||
|
||||
HRESULT reg_hook_read_u32(
|
||||
void *bytes,
|
||||
uint32_t *nbytes,
|
||||
uint32_t src);
|
||||
|
||||
HRESULT reg_hook_read_wstr(
|
||||
void *bytes,
|
||||
uint32_t *nbytes,
|
||||
const wchar_t *src);
|
||||
@@ -0,0 +1,487 @@
|
||||
#include <windows.h>
|
||||
#include <setupapi.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "hooklib/setupapi.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
struct setupapi_class {
|
||||
const GUID *guid;
|
||||
const wchar_t *path;
|
||||
char *a_path;
|
||||
HDEVINFO cur_handle;
|
||||
};
|
||||
|
||||
static void setupapi_hook_init(void);
|
||||
|
||||
/* API hooks */
|
||||
|
||||
static HDEVINFO WINAPI my_SetupDiGetClassDevsW(
|
||||
const GUID *ClassGuid,
|
||||
wchar_t *Enumerator,
|
||||
HWND hwndParent,
|
||||
DWORD Flags);
|
||||
|
||||
static HDEVINFO WINAPI my_SetupDiGetClassDevsA(
|
||||
const GUID *ClassGuid,
|
||||
char *Enumerator,
|
||||
HWND hwndParent,
|
||||
DWORD Flags);
|
||||
|
||||
static BOOL WINAPI my_SetupDiEnumDeviceInterfaces(
|
||||
HDEVINFO DeviceInfoSet,
|
||||
SP_DEVINFO_DATA *DeviceInfoData,
|
||||
const GUID *InterfaceClassGuid,
|
||||
DWORD MemberIndex,
|
||||
SP_DEVICE_INTERFACE_DATA *DeviceInterfaceData);
|
||||
|
||||
static BOOL WINAPI my_SetupDiGetDeviceInterfaceDetailW(
|
||||
HDEVINFO DeviceInfoSet,
|
||||
SP_DEVICE_INTERFACE_DATA *DeviceInterfaceData,
|
||||
SP_DEVICE_INTERFACE_DETAIL_DATA_W *DeviceInterfaceDetailData,
|
||||
DWORD DeviceInterfaceDetailDataSize,
|
||||
DWORD *RequiredSize,
|
||||
SP_DEVINFO_DATA *DeviceInfoData);
|
||||
|
||||
static BOOL WINAPI my_SetupDiGetDeviceInterfaceDetailA(
|
||||
HDEVINFO DeviceInfoSet,
|
||||
SP_DEVICE_INTERFACE_DATA *DeviceInterfaceData,
|
||||
SP_DEVICE_INTERFACE_DETAIL_DATA_A *DeviceInterfaceDetailData,
|
||||
DWORD DeviceInterfaceDetailDataSize,
|
||||
DWORD *RequiredSize,
|
||||
SP_DEVINFO_DATA *DeviceInfoData);
|
||||
|
||||
static BOOL WINAPI my_SetupDiDestroyDeviceInfoList(HDEVINFO DeviceInfoSet);
|
||||
|
||||
/* Links */
|
||||
|
||||
static HDEVINFO (WINAPI *next_SetupDiGetClassDevsW)(
|
||||
const GUID *ClassGuid,
|
||||
wchar_t *Enumerator,
|
||||
HWND hwndParent,
|
||||
DWORD Flags);
|
||||
|
||||
static HDEVINFO (WINAPI *next_SetupDiGetClassDevsA)(
|
||||
const GUID *ClassGuid,
|
||||
char *Enumerator,
|
||||
HWND hwndParent,
|
||||
DWORD Flags);
|
||||
|
||||
static BOOL (WINAPI *next_SetupDiEnumDeviceInterfaces)(
|
||||
HDEVINFO DeviceInfoSet,
|
||||
SP_DEVINFO_DATA *DeviceInfoData,
|
||||
const GUID *InterfaceClassGuid,
|
||||
DWORD MemberIndex,
|
||||
SP_DEVICE_INTERFACE_DATA *DeviceInterfaceData);
|
||||
|
||||
static BOOL (WINAPI *next_SetupDiGetDeviceInterfaceDetailW)(
|
||||
HDEVINFO DeviceInfoSet,
|
||||
SP_DEVICE_INTERFACE_DATA *DeviceInterfaceData,
|
||||
SP_DEVICE_INTERFACE_DETAIL_DATA_W *DeviceInterfaceDetailData,
|
||||
DWORD DeviceInterfaceDetailDataSize,
|
||||
DWORD *RequiredSize,
|
||||
SP_DEVINFO_DATA *DeviceInfoData);
|
||||
|
||||
static BOOL (WINAPI *next_SetupDiGetDeviceInterfaceDetailA)(
|
||||
HDEVINFO DeviceInfoSet,
|
||||
SP_DEVICE_INTERFACE_DATA *DeviceInterfaceData,
|
||||
SP_DEVICE_INTERFACE_DETAIL_DATA_A *DeviceInterfaceDetailData,
|
||||
DWORD DeviceInterfaceDetailDataSize,
|
||||
DWORD *RequiredSize,
|
||||
SP_DEVINFO_DATA *DeviceInfoData);
|
||||
|
||||
static BOOL (WINAPI *next_SetupDiDestroyDeviceInfoList)(HDEVINFO DeviceInfoSet);
|
||||
|
||||
/* Hook tbl */
|
||||
|
||||
static const struct hook_symbol setupapi_syms[] = {
|
||||
{
|
||||
.name = "SetupDiGetClassDevsW",
|
||||
.patch = my_SetupDiGetClassDevsW,
|
||||
.link = (void *) &next_SetupDiGetClassDevsW,
|
||||
}, {
|
||||
.name = "SetupDiGetClassDevsA",
|
||||
.patch = my_SetupDiGetClassDevsA,
|
||||
.link = (void *) &next_SetupDiGetClassDevsA,
|
||||
}, {
|
||||
.name = "SetupDiEnumDeviceInterfaces",
|
||||
.patch = my_SetupDiEnumDeviceInterfaces,
|
||||
.link = (void *) &next_SetupDiEnumDeviceInterfaces,
|
||||
}, {
|
||||
.name = "SetupDiGetDeviceInterfaceDetailW",
|
||||
.patch = my_SetupDiGetDeviceInterfaceDetailW,
|
||||
.link = (void *) &next_SetupDiGetDeviceInterfaceDetailW,
|
||||
}, {
|
||||
.name = "SetupDiGetDeviceInterfaceDetailA",
|
||||
.patch = my_SetupDiGetDeviceInterfaceDetailA,
|
||||
.link = (void *) &next_SetupDiGetDeviceInterfaceDetailA,
|
||||
}, {
|
||||
.name = "SetupDiDestroyDeviceInfoList",
|
||||
.patch = my_SetupDiDestroyDeviceInfoList,
|
||||
.link = (void *) &next_SetupDiDestroyDeviceInfoList,
|
||||
}
|
||||
};
|
||||
|
||||
static bool setupapi_initted;
|
||||
static CRITICAL_SECTION setupapi_lock;
|
||||
static struct setupapi_class *setupapi_classes;
|
||||
static size_t setupapi_nclasses;
|
||||
|
||||
HRESULT setupapi_add_phantom_dev(const GUID *iface_class, const wchar_t *path)
|
||||
{
|
||||
struct setupapi_class *class_;
|
||||
struct setupapi_class *new_array;
|
||||
size_t a_path_len;
|
||||
HRESULT hr;
|
||||
|
||||
assert(iface_class != NULL);
|
||||
assert(path != NULL);
|
||||
|
||||
setupapi_hook_init();
|
||||
|
||||
EnterCriticalSection(&setupapi_lock);
|
||||
|
||||
new_array = realloc(
|
||||
setupapi_classes,
|
||||
(setupapi_nclasses + 1) * sizeof(struct setupapi_class));
|
||||
|
||||
if (new_array == NULL) {
|
||||
hr = E_OUTOFMEMORY;
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
setupapi_classes = new_array;
|
||||
|
||||
class_ = &setupapi_classes[setupapi_nclasses++];
|
||||
class_->guid = iface_class;
|
||||
class_->path = path;
|
||||
|
||||
a_path_len = wcslen(path) * sizeof(wchar_t) + 1;
|
||||
class_->a_path = (char*)malloc(a_path_len);
|
||||
wcstombs(class_->a_path, path, a_path_len);
|
||||
|
||||
hr = S_OK;
|
||||
|
||||
end:
|
||||
LeaveCriticalSection(&setupapi_lock);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static void setupapi_hook_init()
|
||||
{
|
||||
if (setupapi_initted) {
|
||||
return;
|
||||
}
|
||||
|
||||
setupapi_hook_insert_hooks(NULL);
|
||||
|
||||
InitializeCriticalSection(&setupapi_lock);
|
||||
setupapi_initted = true;
|
||||
}
|
||||
|
||||
void setupapi_hook_insert_hooks(HMODULE target)
|
||||
{
|
||||
hook_table_apply(
|
||||
target,
|
||||
"setupapi.dll",
|
||||
setupapi_syms,
|
||||
_countof(setupapi_syms));
|
||||
}
|
||||
|
||||
static HDEVINFO WINAPI my_SetupDiGetClassDevsW(
|
||||
const GUID *ClassGuid,
|
||||
wchar_t *Enumerator,
|
||||
HWND hwndParent,
|
||||
DWORD Flags)
|
||||
{
|
||||
struct setupapi_class *class_;
|
||||
HDEVINFO result;
|
||||
size_t i;
|
||||
|
||||
result = next_SetupDiGetClassDevsW(
|
||||
ClassGuid,
|
||||
Enumerator,
|
||||
hwndParent,
|
||||
Flags);
|
||||
|
||||
if (result == INVALID_HANDLE_VALUE || ClassGuid == NULL) {
|
||||
return result;
|
||||
}
|
||||
|
||||
EnterCriticalSection(&setupapi_lock);
|
||||
|
||||
for (i = 0 ; i < setupapi_nclasses ; i++) {
|
||||
class_ = &setupapi_classes[i];
|
||||
if (memcmp(ClassGuid, class_->guid, sizeof(*ClassGuid)) == 0) {
|
||||
class_->cur_handle = result;
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&setupapi_lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static HDEVINFO WINAPI my_SetupDiGetClassDevsA(
|
||||
const GUID *ClassGuid,
|
||||
char *Enumerator,
|
||||
HWND hwndParent,
|
||||
DWORD Flags)
|
||||
{
|
||||
struct setupapi_class *class_;
|
||||
HDEVINFO result;
|
||||
size_t i;
|
||||
|
||||
result = next_SetupDiGetClassDevsA(
|
||||
ClassGuid,
|
||||
Enumerator,
|
||||
hwndParent,
|
||||
Flags);
|
||||
|
||||
if (result == INVALID_HANDLE_VALUE || ClassGuid == NULL) {
|
||||
return result;
|
||||
}
|
||||
|
||||
EnterCriticalSection(&setupapi_lock);
|
||||
|
||||
for (i = 0 ; i < setupapi_nclasses ; i++) {
|
||||
class_ = &setupapi_classes[i];
|
||||
if (memcmp(ClassGuid, class_->guid, sizeof(*ClassGuid)) == 0) {
|
||||
class_->cur_handle = result;
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&setupapi_lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static BOOL WINAPI my_SetupDiEnumDeviceInterfaces(
|
||||
HDEVINFO DeviceInfoSet,
|
||||
SP_DEVINFO_DATA *DeviceInfoData,
|
||||
const GUID *InterfaceClassGuid,
|
||||
DWORD MemberIndex,
|
||||
SP_DEVICE_INTERFACE_DATA *DeviceInterfaceData)
|
||||
{
|
||||
const struct setupapi_class *class_;
|
||||
size_t i;
|
||||
|
||||
if ( DeviceInfoSet == INVALID_HANDLE_VALUE ||
|
||||
DeviceInterfaceData == NULL ||
|
||||
DeviceInterfaceData->cbSize != sizeof(*DeviceInterfaceData)) {
|
||||
goto pass;
|
||||
}
|
||||
|
||||
if (MemberIndex > 0) {
|
||||
MemberIndex--;
|
||||
|
||||
goto pass;
|
||||
}
|
||||
|
||||
EnterCriticalSection(&setupapi_lock);
|
||||
|
||||
for ( i = 0, class_ = NULL ;
|
||||
i < setupapi_nclasses && class_ == NULL ;
|
||||
i++) {
|
||||
if (DeviceInfoSet == setupapi_classes[i].cur_handle) {
|
||||
class_ = &setupapi_classes[i];
|
||||
|
||||
dprintf("SetupAPI: Interface {%08lx-...} -> Device node %S\n",
|
||||
class_->guid->Data1,
|
||||
class_->path);
|
||||
|
||||
memcpy( &DeviceInterfaceData->InterfaceClassGuid,
|
||||
class_->guid,
|
||||
sizeof(GUID));
|
||||
DeviceInterfaceData->Flags = SPINT_ACTIVE;
|
||||
DeviceInterfaceData->Reserved = (ULONG_PTR) class_->path;
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&setupapi_lock);
|
||||
|
||||
if (class_ == NULL) {
|
||||
goto pass;
|
||||
}
|
||||
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
|
||||
return TRUE;
|
||||
|
||||
pass:
|
||||
return next_SetupDiEnumDeviceInterfaces(
|
||||
DeviceInfoSet,
|
||||
DeviceInfoData,
|
||||
InterfaceClassGuid,
|
||||
MemberIndex,
|
||||
DeviceInterfaceData);
|
||||
}
|
||||
|
||||
static BOOL WINAPI my_SetupDiGetDeviceInterfaceDetailW(
|
||||
HDEVINFO DeviceInfoSet,
|
||||
SP_DEVICE_INTERFACE_DATA *DeviceInterfaceData,
|
||||
SP_DEVICE_INTERFACE_DETAIL_DATA_W *DeviceInterfaceDetailData,
|
||||
DWORD DeviceInterfaceDetailDataSize,
|
||||
DWORD *RequiredSize,
|
||||
SP_DEVINFO_DATA *DeviceInfoData)
|
||||
{
|
||||
const wchar_t *wstr;
|
||||
size_t nbytes_wstr;
|
||||
size_t nbytes_total;
|
||||
size_t i;
|
||||
bool match;
|
||||
|
||||
if (DeviceInfoSet == INVALID_HANDLE_VALUE || DeviceInterfaceData == NULL) {
|
||||
goto pass;
|
||||
}
|
||||
|
||||
EnterCriticalSection(&setupapi_lock);
|
||||
|
||||
for ( i = 0, match = false ;
|
||||
i < setupapi_nclasses && !match ;
|
||||
i++) {
|
||||
if ( DeviceInfoSet == setupapi_classes[i].cur_handle &&
|
||||
DeviceInterfaceData->Reserved == (ULONG_PTR) setupapi_classes[i].path) {
|
||||
match = true;
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&setupapi_lock);
|
||||
|
||||
if (!match) {
|
||||
goto pass;
|
||||
}
|
||||
|
||||
wstr = (const wchar_t *) DeviceInterfaceData->Reserved;
|
||||
nbytes_wstr = (wcslen(wstr) + 1) * sizeof(wchar_t);
|
||||
nbytes_total = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath);
|
||||
nbytes_total += nbytes_wstr;
|
||||
|
||||
if (RequiredSize != NULL) {
|
||||
*RequiredSize = (DWORD) nbytes_total;
|
||||
}
|
||||
|
||||
if ( DeviceInterfaceDetailData == NULL &&
|
||||
DeviceInterfaceDetailDataSize < nbytes_total) {
|
||||
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (DeviceInterfaceDetailData->cbSize!=sizeof(*DeviceInterfaceDetailData)) {
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
memcpy(DeviceInterfaceDetailData->DevicePath, wstr, nbytes_wstr);
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
|
||||
return TRUE;
|
||||
|
||||
pass:
|
||||
return next_SetupDiGetDeviceInterfaceDetailW(
|
||||
DeviceInfoSet,
|
||||
DeviceInterfaceData,
|
||||
DeviceInterfaceDetailData,
|
||||
DeviceInterfaceDetailDataSize,
|
||||
RequiredSize,
|
||||
DeviceInfoData);
|
||||
}
|
||||
|
||||
static BOOL WINAPI my_SetupDiGetDeviceInterfaceDetailA(
|
||||
HDEVINFO DeviceInfoSet,
|
||||
SP_DEVICE_INTERFACE_DATA *DeviceInterfaceData,
|
||||
SP_DEVICE_INTERFACE_DETAIL_DATA_A *DeviceInterfaceDetailData,
|
||||
DWORD DeviceInterfaceDetailDataSize,
|
||||
DWORD *RequiredSize,
|
||||
SP_DEVINFO_DATA *DeviceInfoData)
|
||||
{
|
||||
const char *str;
|
||||
size_t nbytes_str;
|
||||
size_t nbytes_total;
|
||||
size_t i;
|
||||
bool match;
|
||||
|
||||
if (DeviceInfoSet == INVALID_HANDLE_VALUE || DeviceInterfaceData == NULL) {
|
||||
goto pass;
|
||||
}
|
||||
|
||||
EnterCriticalSection(&setupapi_lock);
|
||||
|
||||
for (i = 0, match = false; i < setupapi_nclasses && !match; i++) {
|
||||
if (DeviceInfoSet == setupapi_classes[i].cur_handle &&
|
||||
DeviceInterfaceData->Reserved == (ULONG_PTR) setupapi_classes[i].path) {
|
||||
str = setupapi_classes[i].a_path;
|
||||
match = true;
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&setupapi_lock);
|
||||
|
||||
if (!match) {
|
||||
goto pass;
|
||||
}
|
||||
|
||||
nbytes_str = strlen(str) + 1;
|
||||
nbytes_total = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath);
|
||||
nbytes_total += nbytes_str;
|
||||
|
||||
if (RequiredSize != NULL) {
|
||||
*RequiredSize = (DWORD) nbytes_total;
|
||||
}
|
||||
|
||||
if ( DeviceInterfaceDetailData == NULL &&
|
||||
DeviceInterfaceDetailDataSize < nbytes_total) {
|
||||
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (DeviceInterfaceDetailData->cbSize!=sizeof(*DeviceInterfaceDetailData)) {
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
memcpy(DeviceInterfaceDetailData->DevicePath, str, nbytes_str);
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
|
||||
return TRUE;
|
||||
|
||||
pass:
|
||||
return next_SetupDiGetDeviceInterfaceDetailA(
|
||||
DeviceInfoSet,
|
||||
DeviceInterfaceData,
|
||||
DeviceInterfaceDetailData,
|
||||
DeviceInterfaceDetailDataSize,
|
||||
RequiredSize,
|
||||
DeviceInfoData);
|
||||
}
|
||||
|
||||
static BOOL WINAPI my_SetupDiDestroyDeviceInfoList(HDEVINFO DeviceInfoSet)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
EnterCriticalSection(&setupapi_lock);
|
||||
|
||||
for (i = 0 ; i < setupapi_nclasses ; i++) {
|
||||
if (setupapi_classes[i].cur_handle == DeviceInfoSet) {
|
||||
setupapi_classes[i].cur_handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&setupapi_lock);
|
||||
|
||||
return next_SetupDiDestroyDeviceInfoList(DeviceInfoSet);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
HRESULT setupapi_add_phantom_dev(const GUID *iface_class, const wchar_t *path);
|
||||
void setupapi_hook_insert_hooks(HMODULE target);
|
||||
@@ -0,0 +1,250 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include "hook/pe.h"
|
||||
|
||||
#include "hooklib/spike.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
static void spike_hook_read_config(const wchar_t *spike_file);
|
||||
|
||||
/* Spike functions. Their "style" is named after the libc function they bear
|
||||
the closest resemblance to. */
|
||||
|
||||
static void spike_fn_puts(const char *msg)
|
||||
{
|
||||
char line[512];
|
||||
|
||||
sprintf_s(line, _countof(line), "%s\n", msg);
|
||||
OutputDebugStringA(line);
|
||||
}
|
||||
|
||||
static void spike_fn_fputs(const char *msg)
|
||||
{
|
||||
OutputDebugStringA(msg);
|
||||
}
|
||||
|
||||
static void spike_fn_printf(const char *fmt, ...)
|
||||
{
|
||||
char line[512];
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsprintf_s(line, _countof(line), fmt, ap);
|
||||
strcat(line, "\n");
|
||||
OutputDebugStringA(line);
|
||||
}
|
||||
|
||||
static void spike_fn_vprintf(
|
||||
const char *proc,
|
||||
int line_no,
|
||||
const char *fmt,
|
||||
va_list ap)
|
||||
{
|
||||
char msg[512];
|
||||
char line[512];
|
||||
|
||||
vsprintf_s(msg, _countof(msg), fmt, ap);
|
||||
sprintf_s(line, _countof(line), "%s:%i: %s", proc, line_no, msg);
|
||||
OutputDebugStringA(line);
|
||||
}
|
||||
|
||||
static void spike_fn_vwprintf(
|
||||
const wchar_t *proc,
|
||||
int line_no,
|
||||
const wchar_t *fmt,
|
||||
va_list ap)
|
||||
{
|
||||
wchar_t msg[512];
|
||||
wchar_t line[512];
|
||||
|
||||
vswprintf_s(msg, _countof(msg), fmt, ap);
|
||||
swprintf_s(line, _countof(line), L"%s:%i: %s", proc, line_no, msg);
|
||||
OutputDebugStringW(line);
|
||||
}
|
||||
|
||||
static void spike_fn_perror(
|
||||
int a1,
|
||||
int a2,
|
||||
int error,
|
||||
const char *file,
|
||||
int line_no,
|
||||
const char *msg)
|
||||
{
|
||||
char line[512];
|
||||
|
||||
sprintf_s(
|
||||
line,
|
||||
_countof(line),
|
||||
"%s:%i:%08x: %s\n",
|
||||
file,
|
||||
line_no,
|
||||
error,
|
||||
msg);
|
||||
|
||||
OutputDebugStringA(line);
|
||||
}
|
||||
|
||||
/* Spike inserters */
|
||||
|
||||
static void spike_insert_jmp(ptrdiff_t rva, void *proc)
|
||||
{
|
||||
uint8_t *base;
|
||||
uint8_t *target;
|
||||
uint8_t *func_ptr;
|
||||
uint32_t delta;
|
||||
|
||||
base = (uint8_t *) GetModuleHandleW(NULL);
|
||||
|
||||
target = base + rva;
|
||||
func_ptr = proc;
|
||||
delta = func_ptr - target - 4; /* -4: EIP delta, after end of target insn */
|
||||
|
||||
pe_patch(target, &delta, sizeof(delta));
|
||||
}
|
||||
|
||||
static void spike_insert_ptr(ptrdiff_t rva, void *ptr)
|
||||
{
|
||||
uint8_t *base;
|
||||
uint8_t *target;
|
||||
|
||||
base = (uint8_t *) GetModuleHandleW(NULL);
|
||||
target = base + rva;
|
||||
|
||||
pe_patch(target, &ptr, sizeof(ptr));
|
||||
}
|
||||
|
||||
static void spike_insert_log_levels(ptrdiff_t rva, size_t count)
|
||||
{
|
||||
uint8_t *base;
|
||||
uint32_t *levels;
|
||||
size_t i;
|
||||
|
||||
base = (uint8_t *) GetModuleHandleW(NULL);
|
||||
levels = (uint32_t *) (base + rva);
|
||||
|
||||
for (i = 0 ; i < count ; i++) {
|
||||
levels[i] = 255;
|
||||
}
|
||||
}
|
||||
|
||||
/* Config reader */
|
||||
|
||||
void spike_hook_init(const wchar_t *ini_file)
|
||||
{
|
||||
wchar_t module[MAX_PATH];
|
||||
wchar_t path[MAX_PATH];
|
||||
const wchar_t *basename;
|
||||
const wchar_t *slash;
|
||||
|
||||
assert(ini_file != NULL);
|
||||
|
||||
/* Get the filename (strip path) of the host EXE */
|
||||
|
||||
GetModuleFileNameW(NULL, module, _countof(module));
|
||||
slash = wcsrchr(module, L'\\');
|
||||
|
||||
if (slash != NULL) {
|
||||
basename = slash + 1;
|
||||
} else {
|
||||
basename = module;
|
||||
}
|
||||
|
||||
/* Check our INI file to see if any spikes are configured for this EXE.
|
||||
Normally we separate out config reading into a separate module... */
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"spike",
|
||||
basename,
|
||||
L"",
|
||||
path,
|
||||
_countof(path),
|
||||
ini_file);
|
||||
|
||||
if (path[0] != L'\0') {
|
||||
dprintf("Spiking %S using config from %S\n", basename, path);
|
||||
spike_hook_read_config(path);
|
||||
}
|
||||
}
|
||||
|
||||
static void spike_hook_read_config(const wchar_t *spike_file)
|
||||
{
|
||||
int match;
|
||||
int count;
|
||||
int rva;
|
||||
char line[80];
|
||||
char *ret;
|
||||
FILE *f;
|
||||
|
||||
f = _wfopen(spike_file, L"r");
|
||||
|
||||
if (f == NULL) {
|
||||
dprintf("Error opening spike file %S\n", spike_file);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
ret = fgets(line, sizeof(line), f);
|
||||
|
||||
if (ret == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (line[0] == '#' || line[0] == '\r' || line[0] == '\n') {
|
||||
continue;
|
||||
}
|
||||
|
||||
match = sscanf(line, "levels %i %i", &rva, &count);
|
||||
|
||||
if (match == 2) {
|
||||
spike_insert_log_levels((ptrdiff_t) rva, count);
|
||||
}
|
||||
|
||||
match = sscanf(line, "j_vprintf %i", &rva);
|
||||
|
||||
if (match == 1) {
|
||||
spike_insert_jmp((ptrdiff_t) rva, spike_fn_vprintf);
|
||||
}
|
||||
|
||||
match = sscanf(line, "j_vwprintf %i", &rva);
|
||||
|
||||
if (match == 1) {
|
||||
spike_insert_jmp((ptrdiff_t) rva, spike_fn_vwprintf);
|
||||
}
|
||||
|
||||
match = sscanf(line, "j_printf %i", &rva);
|
||||
|
||||
if (match == 1) {
|
||||
spike_insert_jmp((ptrdiff_t) rva, spike_fn_printf);
|
||||
}
|
||||
|
||||
match = sscanf(line, "j_puts %i", &rva);
|
||||
|
||||
if (match == 1) {
|
||||
spike_insert_jmp((ptrdiff_t) rva, spike_fn_puts);
|
||||
}
|
||||
|
||||
match = sscanf(line, "j_perror %i", &rva);
|
||||
|
||||
if (match == 1) {
|
||||
spike_insert_jmp((ptrdiff_t) rva, spike_fn_perror);
|
||||
}
|
||||
|
||||
match = sscanf(line, "c_fputs %i", &rva); /* c == "callback" */
|
||||
|
||||
if (match == 1) {
|
||||
spike_insert_ptr((ptrdiff_t) rva, spike_fn_fputs);
|
||||
}
|
||||
}
|
||||
|
||||
dprintf("Spike insertion complete\n");
|
||||
fclose(f);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
void spike_hook_init(const wchar_t *ini_file);
|
||||
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
This part (touch screen hook) is mostly taken from spicetools, which is GPL.
|
||||
This means there can be some license issues if you do use this code in some other places without including source code.
|
||||
*/
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "hook/com-proxy.h"
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "hooklib/config.h"
|
||||
#include "hooklib/dll.h"
|
||||
#include "hooklib/touch.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
/* API hooks */
|
||||
|
||||
static LRESULT hook_wndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
static ATOM WINAPI hook_RegisterClassExA(
|
||||
WNDCLASSEXA* wndClass
|
||||
);
|
||||
|
||||
static int WINAPI hook_GetSystemMetrics(
|
||||
int nIndex
|
||||
);
|
||||
|
||||
static BOOL WINAPI hook_RegisterTouchWindow(
|
||||
HWND hwnd,
|
||||
ULONG ulFlags
|
||||
);
|
||||
|
||||
static BOOL WINAPI hook_GetTouchInputInfo(
|
||||
HANDLE hTouchInput,
|
||||
UINT cInputs,
|
||||
PTOUCHINPUT pInputs,
|
||||
int cbSize
|
||||
);
|
||||
|
||||
static HCURSOR WINAPI hook_SetCursor(HCURSOR cursor);
|
||||
|
||||
/* Link pointers */
|
||||
|
||||
static ATOM (WINAPI *next_RegisterClassExA)(
|
||||
const WNDCLASSEXA* wndClass
|
||||
);
|
||||
|
||||
static int (WINAPI *next_GetSystemMetrics)(
|
||||
int nIndex
|
||||
);
|
||||
|
||||
static BOOL (WINAPI *next_RegisterTouchWindow)(
|
||||
HWND hwnd,
|
||||
ULONG ulFlags
|
||||
);
|
||||
|
||||
static BOOL (WINAPI *next_GetTouchInputInfo)(
|
||||
HANDLE hTouchInput,
|
||||
UINT cInputs,
|
||||
PTOUCHINPUT pInputs,
|
||||
int cbSize
|
||||
);
|
||||
|
||||
static HCURSOR(WINAPI *next_SetCursor)(HCURSOR cursor);
|
||||
|
||||
static bool touch_hook_initted;
|
||||
static bool touch_held;
|
||||
static HWND registered_hWnd;
|
||||
static struct touch_screen_config touch_config;
|
||||
static WNDPROC orig_wndProc;
|
||||
static HCURSOR defaultCursor;
|
||||
|
||||
static const struct hook_symbol touch_hooks[] = {
|
||||
{
|
||||
.name = "RegisterClassExA",
|
||||
.patch = hook_RegisterClassExA,
|
||||
.link = (void**)&next_RegisterClassExA
|
||||
},
|
||||
{
|
||||
.name = "GetSystemMetrics",
|
||||
.patch = hook_GetSystemMetrics,
|
||||
.link = (void **) &next_GetSystemMetrics
|
||||
},
|
||||
{
|
||||
.name = "RegisterTouchWindow",
|
||||
.patch = hook_RegisterTouchWindow,
|
||||
.link = (void **) &next_RegisterTouchWindow
|
||||
},
|
||||
{
|
||||
.name = "GetTouchInputInfo",
|
||||
.patch = hook_GetTouchInputInfo,
|
||||
.link = (void **) &next_GetTouchInputInfo
|
||||
},
|
||||
{
|
||||
.name = "SetCursor",
|
||||
.patch = hook_SetCursor,
|
||||
.link = (void **) &next_SetCursor
|
||||
},
|
||||
};
|
||||
|
||||
void touch_screen_hook_init(const struct touch_screen_config *cfg, HINSTANCE self)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
|
||||
if (!cfg->enable) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (touch_hook_initted) {
|
||||
return;
|
||||
}
|
||||
|
||||
touch_hook_initted = true;
|
||||
|
||||
defaultCursor = LoadCursorA(NULL, IDC_CROSS);
|
||||
|
||||
memcpy(&touch_config, cfg, sizeof(*cfg));
|
||||
touch_hook_insert_hooks(NULL);
|
||||
dprintf("TOUCH: hook enabled.\n");
|
||||
}
|
||||
|
||||
void touch_hook_insert_hooks(HMODULE target)
|
||||
{
|
||||
hook_table_apply(
|
||||
target,
|
||||
"user32.dll",
|
||||
touch_hooks,
|
||||
_countof(touch_hooks));
|
||||
}
|
||||
|
||||
static HCURSOR WINAPI hook_SetCursor(HCURSOR cursor) {
|
||||
if (cursor == 0 && touch_config.cursor)
|
||||
return next_SetCursor(defaultCursor);
|
||||
|
||||
return next_SetCursor(cursor);
|
||||
}
|
||||
|
||||
// remap mouse events to touch events
|
||||
|
||||
static LRESULT hook_wndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) {
|
||||
if (hWnd == registered_hWnd && (Msg == WM_LBUTTONDOWN || Msg == WM_LBUTTONUP || (touch_held && Msg == WM_MOUSEMOVE))) {
|
||||
orig_wndProc(hWnd, WM_TOUCH, 1, 1);
|
||||
}
|
||||
|
||||
return orig_wndProc(hWnd, Msg, wParam, lParam);
|
||||
}
|
||||
|
||||
static ATOM WINAPI hook_RegisterClassExA(
|
||||
WNDCLASSEXA* wndClass
|
||||
) {
|
||||
if (wndClass->lpfnWndProc) {
|
||||
orig_wndProc = wndClass->lpfnWndProc;
|
||||
wndClass->lpfnWndProc = (WNDPROC) hook_wndProc;
|
||||
}
|
||||
|
||||
return next_RegisterClassExA(wndClass);
|
||||
}
|
||||
|
||||
// Spicetools misc/wintouchemu.cpp
|
||||
|
||||
static int WINAPI hook_GetSystemMetrics(
|
||||
int nIndex
|
||||
)
|
||||
{
|
||||
if (nIndex == 94) return 0x01 | 0x02 | 0x40 | 0x80;
|
||||
|
||||
int orig = next_GetSystemMetrics(nIndex);
|
||||
|
||||
return orig;
|
||||
}
|
||||
|
||||
static BOOL WINAPI hook_RegisterTouchWindow(
|
||||
HWND hwnd,
|
||||
ULONG ulFlags
|
||||
)
|
||||
{
|
||||
registered_hWnd = hwnd;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Converting mouse event to touch event
|
||||
static BOOL WINAPI hook_GetTouchInputInfo(
|
||||
HANDLE hTouchInput,
|
||||
UINT cInputs,
|
||||
PTOUCHINPUT pInputs,
|
||||
int cbSize
|
||||
)
|
||||
{
|
||||
bool result = false;
|
||||
int sw, sh, cw, ch;
|
||||
RECT cRect;
|
||||
sw = GetSystemMetrics(SM_CXSCREEN);
|
||||
sh = GetSystemMetrics(SM_CYSCREEN);
|
||||
GetClientRect(registered_hWnd, &cRect);
|
||||
cw = cRect.right - cRect.left;
|
||||
ch = cRect.bottom - cRect.top;
|
||||
static bool mouse_state_old = false;
|
||||
|
||||
for (UINT input = 0; input < cInputs; input++) {
|
||||
TOUCHINPUT *touch_input = &pInputs[input];
|
||||
|
||||
touch_input->x = 0;
|
||||
touch_input->y = 0;
|
||||
touch_input->hSource = NULL;
|
||||
touch_input->dwID = 0;
|
||||
touch_input->dwFlags = 0;
|
||||
touch_input->dwMask = 0;
|
||||
touch_input->dwTime = 0;
|
||||
touch_input->dwExtraInfo = 0;
|
||||
touch_input->cxContact = 0;
|
||||
touch_input->cyContact = 0;
|
||||
|
||||
bool mouse_state = (GetKeyState(VK_LBUTTON) & 0x100) != 0;
|
||||
|
||||
if (mouse_state || mouse_state_old) {
|
||||
POINT cursorPos;
|
||||
|
||||
GetCursorPos(&cursorPos);
|
||||
|
||||
if (touch_config.remap) {
|
||||
ScreenToClient(registered_hWnd, &cursorPos);
|
||||
cursorPos.x = (long)(cursorPos.x * ((double)sw / cw));
|
||||
cursorPos.y = (long)(cursorPos.y * ((double)sh / ch));
|
||||
}
|
||||
|
||||
result = true;
|
||||
touch_input->x = cursorPos.x * 100;
|
||||
touch_input->y = cursorPos.y * 100;
|
||||
touch_input->hSource = hTouchInput;
|
||||
touch_input->dwID = 0;
|
||||
touch_input->dwFlags = 0;
|
||||
if (mouse_state && !mouse_state_old) {
|
||||
touch_input->dwFlags |= TOUCHEVENTF_DOWN;
|
||||
touch_held = true;
|
||||
} else if (mouse_state && mouse_state_old) {
|
||||
touch_input->dwFlags |= TOUCHEVENTF_MOVE;
|
||||
} else if (!mouse_state && mouse_state_old) {
|
||||
touch_input->dwFlags |= TOUCHEVENTF_UP;
|
||||
touch_held = false;
|
||||
}
|
||||
touch_input->dwMask = 0;
|
||||
touch_input->dwTime = 0;
|
||||
touch_input->dwExtraInfo = 0;
|
||||
touch_input->cxContact = 0;
|
||||
touch_input->cyContact = 0;
|
||||
}
|
||||
mouse_state_old = mouse_state;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
struct touch_screen_config {
|
||||
bool enable;
|
||||
bool remap;
|
||||
bool cursor;
|
||||
};
|
||||
|
||||
/* Init is not thread safe because API hook init is not thread safe blah
|
||||
blah blah you know the drill by now. */
|
||||
|
||||
void touch_screen_hook_init(const struct touch_screen_config *cfg, HINSTANCE self);
|
||||
void touch_hook_insert_hooks(HMODULE target);
|
||||
Reference in New Issue
Block a user