Bemanitools v5.26 release
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
libs += hooklib
|
||||
|
||||
src_hooklib := \
|
||||
acp.c \
|
||||
app.c \
|
||||
adapter.c \
|
||||
rs232.c \
|
||||
setupapi.c \
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include <ntdef.h>
|
||||
#include <ntstatus.h>
|
||||
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "hooklib/acp.h"
|
||||
|
||||
#include "util/defs.h"
|
||||
#include "util/codepage.h"
|
||||
#include "util/log.h"
|
||||
|
||||
static NTSTATUS NTAPI my_RtlMultiByteToUnicodeN(
|
||||
wchar_t *dest, unsigned long destsz, unsigned long *out_destsz,
|
||||
const char *src, unsigned long srcsz);
|
||||
|
||||
static const struct hook_symbol acp_hook_syms[] = {
|
||||
{
|
||||
.name = "RtlMultiByteToUnicodeN",
|
||||
.patch = my_RtlMultiByteToUnicodeN,
|
||||
},
|
||||
};
|
||||
|
||||
static NTSTATUS NTAPI my_RtlMultiByteToUnicodeN(
|
||||
wchar_t *dest, unsigned long destsz, unsigned long *out_destsz,
|
||||
const char *src, unsigned long srcsz)
|
||||
{
|
||||
unsigned long result;
|
||||
|
||||
result = MultiByteToWideChar(CP_SHIFT_JIS, 0, src, srcsz, dest, destsz);
|
||||
|
||||
if (result == 0) {
|
||||
switch (GetLastError()) {
|
||||
case ERROR_INSUFFICIENT_BUFFER:
|
||||
return STATUS_BUFFER_TOO_SMALL;
|
||||
case ERROR_INVALID_FLAGS:
|
||||
case ERROR_INVALID_PARAMETER:
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
case ERROR_NO_UNICODE_TRANSLATION:
|
||||
return STATUS_UNMAPPABLE_CHARACTER;
|
||||
default:
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
}
|
||||
|
||||
if (out_destsz != NULL) {
|
||||
*out_destsz = result * sizeof(wchar_t);
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
void acp_hook_init(void)
|
||||
{
|
||||
hook_table_apply(NULL, "ntdll.dll", acp_hook_syms, lengthof(acp_hook_syms));
|
||||
log_info("ACP Hook enabled");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef HOOKLIB_ACP_H
|
||||
#define HOOKLIB_ACP_H
|
||||
|
||||
void acp_hook_init(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,81 @@
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#include <wincrypt.h> /* Required by mingw for some reason */
|
||||
#include <iphlpapi.h>
|
||||
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "hooklib/adapter.h"
|
||||
|
||||
#include "util/defs.h"
|
||||
#include "util/codepage.h"
|
||||
|
||||
static DWORD WINAPI my_GetAdaptersInfo(
|
||||
PIP_ADAPTER_INFO adapter_info,
|
||||
PULONG out_buf_len);
|
||||
|
||||
static DWORD(WINAPI *real_GetAdaptersInfo)(PIP_ADAPTER_INFO adapter_info, PULONG out_buf_len);
|
||||
|
||||
static const struct hook_symbol adapter_hook_syms[] = {
|
||||
{
|
||||
.name = "GetAdaptersInfo",
|
||||
.patch = my_GetAdaptersInfo,
|
||||
.link = (void *)&real_GetAdaptersInfo
|
||||
},
|
||||
};
|
||||
|
||||
static DWORD WINAPI my_GetAdaptersInfo(
|
||||
PIP_ADAPTER_INFO adapter_info,
|
||||
PULONG out_buf_len)
|
||||
{
|
||||
DWORD ret;
|
||||
PMIB_IPFORWARDTABLE ip_fwd_table;
|
||||
DWORD table_size;
|
||||
DWORD best_adapter;
|
||||
PIP_ADAPTER_INFO info;
|
||||
|
||||
ret = real_GetAdaptersInfo(adapter_info, out_buf_len);
|
||||
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ip_fwd_table = (MIB_IPFORWARDTABLE *)malloc(sizeof(MIB_IPFORWARDTABLE));
|
||||
table_size = 0;
|
||||
|
||||
if (GetIpForwardTable(ip_fwd_table, &table_size, 1) ==
|
||||
ERROR_INSUFFICIENT_BUFFER) {
|
||||
free(ip_fwd_table);
|
||||
ip_fwd_table = (MIB_IPFORWARDTABLE *)malloc(table_size);
|
||||
}
|
||||
|
||||
if (GetIpForwardTable(ip_fwd_table, &table_size, 1) != NO_ERROR ||
|
||||
ip_fwd_table->dwNumEntries == 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
best_adapter = ip_fwd_table->table[0].dwForwardIfIndex;
|
||||
free(ip_fwd_table);
|
||||
|
||||
info = adapter_info;
|
||||
|
||||
while (info) {
|
||||
if (info->Index == best_adapter) {
|
||||
memcpy(adapter_info, info, sizeof(*info));
|
||||
adapter_info->Next = 0;
|
||||
return ret;
|
||||
}
|
||||
info = info->Next;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void adapter_hook_init(void)
|
||||
{
|
||||
hook_table_apply(
|
||||
NULL,
|
||||
"iphlpapi.dll",
|
||||
adapter_hook_syms,
|
||||
lengthof(adapter_hook_syms));
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef HOOKLIB_ADAPTER_H
|
||||
#define HOOKLIB_ADAPTER_H
|
||||
|
||||
void adapter_hook_init(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,79 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "hooklib/app.h"
|
||||
|
||||
#include "imports/avs.h"
|
||||
#include "imports/eapki.h"
|
||||
|
||||
#include "util/log.h"
|
||||
#include "util/str.h"
|
||||
|
||||
static dll_entry_init_t hook_dll_entry_init;
|
||||
static dll_entry_main_t hook_dll_entry_main;
|
||||
static dll_entry_init_t next_dll_entry_init;
|
||||
static dll_entry_main_t next_dll_entry_main;
|
||||
static void *(STDCALL *next_GetProcAddress)(HMODULE mod, const char *sym);
|
||||
|
||||
static void * STDCALL my_GetProcAddress(HMODULE mod, const char *sym);
|
||||
|
||||
static const struct hook_symbol mod_hooks[] = {
|
||||
{
|
||||
.name = "GetProcAddress",
|
||||
.patch = my_GetProcAddress,
|
||||
.link = (void **) &next_GetProcAddress,
|
||||
},
|
||||
};
|
||||
|
||||
static void * STDCALL my_GetProcAddress(HMODULE mod, const char *sym)
|
||||
{
|
||||
void *next;
|
||||
|
||||
next = next_GetProcAddress(mod, sym);
|
||||
|
||||
if (next == NULL || ((intptr_t) sym) <= UINT16_MAX) {
|
||||
return next;
|
||||
}
|
||||
|
||||
if (str_eq(sym, "dll_entry_init")) {
|
||||
next_dll_entry_init = next;
|
||||
|
||||
if (hook_dll_entry_init != NULL) {
|
||||
return hook_dll_entry_init;
|
||||
} else {
|
||||
return next;
|
||||
}
|
||||
} else if (str_eq(sym, "dll_entry_main")) {
|
||||
next_dll_entry_main = next;
|
||||
|
||||
if (hook_dll_entry_main != NULL) {
|
||||
return hook_dll_entry_main;
|
||||
} else {
|
||||
return next;
|
||||
}
|
||||
} else {
|
||||
return next;
|
||||
}
|
||||
}
|
||||
|
||||
void app_hook_init(dll_entry_init_t init, dll_entry_main_t main_)
|
||||
{
|
||||
hook_dll_entry_init = init;
|
||||
hook_dll_entry_main = main_;
|
||||
hook_table_apply(NULL, "kernel32.dll", mod_hooks, lengthof(mod_hooks));
|
||||
}
|
||||
|
||||
bool app_hook_invoke_init(char *sidcode, struct property_node *config)
|
||||
{
|
||||
log_assert(sidcode != NULL);
|
||||
log_assert(config != NULL);
|
||||
|
||||
return next_dll_entry_init(sidcode, config);
|
||||
}
|
||||
|
||||
bool app_hook_invoke_main(void)
|
||||
{
|
||||
return next_dll_entry_main();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
#ifndef HOOKLIB_APP_H
|
||||
#define HOOKLIB_APP_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "imports/avs.h"
|
||||
#include "imports/eapki.h"
|
||||
|
||||
void app_hook_init(dll_entry_init_t init, dll_entry_main_t main_);
|
||||
bool app_hook_invoke_init(char *sidcode, struct property_node *config);
|
||||
bool app_hook_invoke_main(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,703 @@
|
||||
#include <windows.h> /* Usermode API */
|
||||
|
||||
#include <ntdef.h> /* Kernel-mode API for ioctls */
|
||||
#include <devioctl.h>
|
||||
#include <ntddser.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "hook/iohook.h"
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "util/hr.h"
|
||||
#include "util/log.h"
|
||||
|
||||
/* RS232 API hooks */
|
||||
|
||||
static BOOL STDCALL my_ClearCommError(
|
||||
HANDLE fd,
|
||||
uint32_t *errors,
|
||||
COMSTAT *status);
|
||||
|
||||
static BOOL STDCALL my_EscapeCommFunction(HANDLE fd, uint32_t func);
|
||||
static BOOL STDCALL my_GetCommState(HANDLE fd, DCB *dcb);
|
||||
static BOOL STDCALL my_PurgeComm(HANDLE fd, uint32_t flags);
|
||||
static BOOL STDCALL my_SetCommMask(HANDLE fd, uint32_t mask);
|
||||
static BOOL STDCALL my_SetCommState(HANDLE fd, const DCB *dcb);
|
||||
static BOOL STDCALL my_SetCommTimeouts(HANDLE fd, COMMTIMEOUTS *timeouts);
|
||||
static BOOL STDCALL my_SetupComm(HANDLE fd, uint32_t in_q, uint32_t out_q);
|
||||
static BOOL STDCALL my_SetCommBreak(HANDLE fd);
|
||||
static BOOL STDCALL my_ClearCommBreak(HANDLE fd);
|
||||
|
||||
static struct hook_symbol rs232_syms[] = {
|
||||
{
|
||||
.name = "ClearCommError",
|
||||
.patch = my_ClearCommError,
|
||||
},
|
||||
{
|
||||
.name = "EscapeCommFunction",
|
||||
.patch = my_EscapeCommFunction,
|
||||
},
|
||||
{
|
||||
.name = "GetCommState",
|
||||
.patch = my_GetCommState,
|
||||
},
|
||||
{
|
||||
.name = "PurgeComm",
|
||||
.patch = my_PurgeComm,
|
||||
},
|
||||
{
|
||||
.name = "SetCommMask",
|
||||
.patch = my_SetCommMask,
|
||||
},
|
||||
{
|
||||
.name = "SetCommState",
|
||||
.patch = my_SetCommState,
|
||||
},
|
||||
{
|
||||
.name = "SetCommTimeouts",
|
||||
.patch = my_SetCommTimeouts,
|
||||
},
|
||||
{
|
||||
.name = "SetupComm",
|
||||
.patch = my_SetupComm,
|
||||
},
|
||||
{
|
||||
.name = "SetCommBreak",
|
||||
.patch = my_SetCommBreak,
|
||||
},
|
||||
{
|
||||
.name = "ClearCommBreak",
|
||||
.patch = my_ClearCommBreak,
|
||||
},
|
||||
};
|
||||
|
||||
void rs232_hook_init(void)
|
||||
{
|
||||
hook_table_apply(NULL, "kernel32.dll", rs232_syms, lengthof(rs232_syms));
|
||||
log_info("IO Hook RS232 ioctl subsystem initialized");
|
||||
}
|
||||
|
||||
static BOOL STDCALL my_ClearCommError(
|
||||
HANDLE fd,
|
||||
uint32_t *errors,
|
||||
COMSTAT *status)
|
||||
{
|
||||
struct irp irp;
|
||||
SERIAL_STATUS llstatus;
|
||||
HRESULT hr;
|
||||
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = IRP_OP_IOCTL;
|
||||
irp.fd = fd;
|
||||
irp.ioctl = IOCTL_SERIAL_GET_COMMSTATUS;
|
||||
irp.read.bytes = (uint8_t *) &llstatus;
|
||||
irp.read.nbytes = sizeof(llstatus);
|
||||
|
||||
hr = irp_invoke_next(&irp);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
log_warning(
|
||||
"%s: IOCTL_SERIAL_GET_COMMSTATUS failed: %lx",
|
||||
__func__,
|
||||
hr);
|
||||
|
||||
return hr_propagate_win32(hr, FALSE);
|
||||
}
|
||||
|
||||
/* Here we just translate between two structures that carry essentially the
|
||||
same information, because Windows. */
|
||||
|
||||
if (errors != NULL) {
|
||||
*errors = 0;
|
||||
|
||||
if (llstatus.Errors & SERIAL_ERROR_QUEUEOVERRUN) {
|
||||
*errors |= CE_OVERRUN;
|
||||
}
|
||||
|
||||
if (llstatus.Errors & SERIAL_ERROR_OVERRUN) {
|
||||
*errors |= CE_RXOVER;
|
||||
}
|
||||
|
||||
if (llstatus.Errors & SERIAL_ERROR_BREAK) {
|
||||
*errors |= CE_BREAK;
|
||||
}
|
||||
|
||||
if (llstatus.Errors & SERIAL_ERROR_PARITY) {
|
||||
*errors |= CE_RXPARITY;
|
||||
}
|
||||
|
||||
if (llstatus.Errors & SERIAL_ERROR_FRAMING) {
|
||||
*errors |= CE_FRAME;
|
||||
}
|
||||
}
|
||||
|
||||
if (status != NULL) {
|
||||
memset(status, 0, sizeof(*status));
|
||||
|
||||
if (llstatus.HoldReasons & SERIAL_TX_WAITING_FOR_CTS) {
|
||||
status->fCtsHold = 1;
|
||||
}
|
||||
|
||||
if (llstatus.HoldReasons & SERIAL_TX_WAITING_FOR_DSR) {
|
||||
status->fDsrHold = 1;
|
||||
}
|
||||
|
||||
if (llstatus.HoldReasons & SERIAL_TX_WAITING_FOR_DCD) {
|
||||
status->fRlsdHold = 1;
|
||||
}
|
||||
|
||||
if (llstatus.HoldReasons & SERIAL_TX_WAITING_FOR_XON) {
|
||||
status->fXoffHold = 1;
|
||||
}
|
||||
|
||||
if (llstatus.HoldReasons & SERIAL_TX_WAITING_ON_BREAK) {
|
||||
/* hrm. No corresponding (documented field). */
|
||||
}
|
||||
|
||||
if (llstatus.HoldReasons & SERIAL_TX_WAITING_XOFF_SENT) {
|
||||
status->fXoffSent = 1;
|
||||
}
|
||||
|
||||
if (llstatus.EofReceived) {
|
||||
status->fEof = 1;
|
||||
}
|
||||
|
||||
if (llstatus.WaitForImmediate) {
|
||||
status->fTxim = 1;
|
||||
}
|
||||
|
||||
status->cbInQue = llstatus.AmountInInQueue;
|
||||
status->cbOutQue = llstatus.AmountInOutQueue;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL STDCALL my_EscapeCommFunction(HANDLE fd, uint32_t cmd)
|
||||
{
|
||||
struct irp irp;
|
||||
uint32_t ioctl;
|
||||
HRESULT hr;
|
||||
|
||||
switch (cmd) {
|
||||
case CLRBREAK: ioctl = IOCTL_SERIAL_SET_BREAK_OFF; break;
|
||||
case CLRDTR: ioctl = IOCTL_SERIAL_CLR_DTR; break;
|
||||
case CLRRTS: ioctl = IOCTL_SERIAL_CLR_RTS; break;
|
||||
case SETBREAK: ioctl = IOCTL_SERIAL_SET_BREAK_ON; break;
|
||||
case SETDTR: ioctl = IOCTL_SERIAL_SET_RTS; break;
|
||||
case SETRTS: ioctl = IOCTL_SERIAL_SET_RTS; break;
|
||||
case SETXOFF: ioctl = IOCTL_SERIAL_SET_XOFF; break;
|
||||
case SETXON: ioctl = IOCTL_SERIAL_SET_XON; break;
|
||||
default:
|
||||
log_warning("%s: Invalid comm function %08x", __func__, cmd);
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = IRP_OP_IOCTL;
|
||||
irp.fd = fd;
|
||||
irp.ioctl = ioctl;
|
||||
|
||||
hr = irp_invoke_next(&irp);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
log_warning("%s: ioctl failed: %lx", __func__, hr);
|
||||
|
||||
return hr_propagate_win32(hr, FALSE);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL STDCALL my_GetCommState(HANDLE fd, DCB *dcb)
|
||||
{
|
||||
struct irp irp;
|
||||
SERIAL_BAUD_RATE baud;
|
||||
SERIAL_CHARS chars;
|
||||
SERIAL_HANDFLOW handflow;
|
||||
SERIAL_LINE_CONTROL line_control;
|
||||
HRESULT hr;
|
||||
|
||||
/*
|
||||
* Validate params
|
||||
*/
|
||||
|
||||
if (dcb == NULL) {
|
||||
log_warning("%s: DCB pointer is NULL", __func__);
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (dcb->DCBlength != sizeof(*dcb)) {
|
||||
/* This struct has evolved in the past, but those were the Windows 95
|
||||
days. So we only support the latest size of this struct. */
|
||||
|
||||
log_warning(
|
||||
"%s: dcb->DCBlength = %d, expected %d",
|
||||
__func__,
|
||||
(int) dcb->DCBlength,
|
||||
(unsigned int) sizeof(*dcb));
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Issue ioctls
|
||||
*/
|
||||
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = IRP_OP_IOCTL;
|
||||
irp.fd = fd;
|
||||
irp.ioctl = IOCTL_SERIAL_GET_BAUD_RATE;
|
||||
irp.read.bytes = (uint8_t *) &baud;
|
||||
irp.read.nbytes = sizeof(baud);
|
||||
memset(&baud, 0, sizeof(baud));
|
||||
|
||||
hr = irp_invoke_next(&irp);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
log_warning("%s: IOCTL_SERIAL_GET_BAUD_RATE failed: %lx", __func__, hr);
|
||||
|
||||
return hr_propagate_win32(hr, FALSE);
|
||||
}
|
||||
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = IRP_OP_IOCTL;
|
||||
irp.fd = fd;
|
||||
irp.ioctl = IOCTL_SERIAL_GET_HANDFLOW;
|
||||
irp.read.bytes = (uint8_t *) &handflow;
|
||||
irp.read.nbytes = sizeof(handflow);
|
||||
memset(&handflow, 0, sizeof(handflow));
|
||||
|
||||
hr = irp_invoke_next(&irp);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
log_warning("%s: IOCTL_SERIAL_GET_HANDFLOW failed: %lx", __func__, hr);
|
||||
|
||||
return hr_propagate_win32(hr, FALSE);
|
||||
}
|
||||
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = IRP_OP_IOCTL;
|
||||
irp.fd = fd;
|
||||
irp.ioctl = IOCTL_SERIAL_GET_LINE_CONTROL;
|
||||
irp.read.bytes = (uint8_t *) &line_control;
|
||||
irp.read.nbytes = sizeof(line_control);
|
||||
memset(&line_control, 0, sizeof(line_control));
|
||||
|
||||
hr = irp_invoke_next(&irp);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
log_warning(
|
||||
"%s: IOCTL_SERIAL_GET_LINE_CONTROL failed: %lx",
|
||||
__func__,
|
||||
hr);
|
||||
|
||||
return hr_propagate_win32(hr, FALSE);
|
||||
}
|
||||
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = IRP_OP_IOCTL;
|
||||
irp.fd = fd;
|
||||
irp.ioctl = IOCTL_SERIAL_GET_CHARS;
|
||||
irp.read.bytes = (uint8_t *) &chars;
|
||||
irp.read.nbytes = sizeof(chars);
|
||||
memset(&chars, 0, sizeof(chars));
|
||||
|
||||
hr = irp_invoke_next(&irp);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
log_warning("%s: IOCTL_SERIAL_GET_CHARS failed: %lx", __func__, hr);
|
||||
|
||||
return hr_propagate_win32(hr, FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Populate output struct
|
||||
*/
|
||||
|
||||
memset(dcb, 0, sizeof(*dcb));
|
||||
dcb->DCBlength = sizeof(*dcb);
|
||||
dcb->fBinary = 1;
|
||||
dcb->BaudRate = baud.BaudRate;
|
||||
|
||||
/* Populate fParity somehow? */
|
||||
|
||||
if (handflow.ControlHandShake & SERIAL_CTS_HANDSHAKE) {
|
||||
dcb->fOutxCtsFlow = 1;
|
||||
}
|
||||
|
||||
if (handflow.ControlHandShake & SERIAL_DSR_HANDSHAKE) {
|
||||
dcb->fOutxDsrFlow = 1;
|
||||
}
|
||||
|
||||
if (handflow.ControlHandShake & SERIAL_DTR_CONTROL) {
|
||||
dcb->fDtrControl = DTR_CONTROL_ENABLE;
|
||||
}
|
||||
|
||||
if (handflow.ControlHandShake & SERIAL_DTR_HANDSHAKE) {
|
||||
dcb->fDtrControl = DTR_CONTROL_HANDSHAKE;
|
||||
}
|
||||
|
||||
if (handflow.ControlHandShake & SERIAL_DSR_SENSITIVITY) {
|
||||
dcb->fDsrSensitivity = 1;
|
||||
}
|
||||
|
||||
if (handflow.ControlHandShake & SERIAL_XOFF_CONTINUE) {
|
||||
dcb->fTXContinueOnXoff = 1;
|
||||
}
|
||||
|
||||
if (handflow.ControlHandShake & SERIAL_RTS_CONTROL) {
|
||||
dcb->fRtsControl = RTS_CONTROL_ENABLE;
|
||||
}
|
||||
|
||||
if (handflow.ControlHandShake & SERIAL_RTS_HANDSHAKE) {
|
||||
dcb->fRtsControl = RTS_CONTROL_HANDSHAKE;
|
||||
}
|
||||
|
||||
if (handflow.ControlHandShake & SERIAL_ERROR_ABORT) {
|
||||
dcb->fAbortOnError = 1;
|
||||
}
|
||||
|
||||
if (handflow.ControlHandShake & SERIAL_ERROR_CHAR) {
|
||||
dcb->fErrorChar = 1;
|
||||
}
|
||||
|
||||
if (handflow.ControlHandShake & SERIAL_NULL_STRIPPING) {
|
||||
dcb->fNull = 1;
|
||||
}
|
||||
|
||||
dcb->XonLim = handflow.XonLimit;
|
||||
dcb->XoffLim = handflow.XoffLimit;
|
||||
dcb->ByteSize = line_control.WordLength;
|
||||
dcb->Parity = line_control.Parity;
|
||||
dcb->StopBits = line_control.StopBits;
|
||||
dcb->XonChar = chars.XonChar;
|
||||
dcb->XoffChar = chars.XoffChar;
|
||||
dcb->ErrorChar = chars.ErrorChar;
|
||||
dcb->EofChar = chars.EofChar;
|
||||
dcb->EvtChar = chars.EventChar;
|
||||
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL STDCALL my_PurgeComm(HANDLE fd, uint32_t flags)
|
||||
{
|
||||
struct irp irp;
|
||||
HRESULT hr;
|
||||
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = IRP_OP_IOCTL;
|
||||
irp.fd = fd;
|
||||
irp.ioctl = IOCTL_SERIAL_PURGE;
|
||||
irp.write.bytes = (uint8_t *) &flags;
|
||||
irp.write.nbytes = sizeof(flags);
|
||||
|
||||
hr = irp_invoke_next(&irp);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
log_warning("%s: IOCTL_SERIAL_PURGE failed: %lx", __func__, hr);
|
||||
}
|
||||
|
||||
return hr_propagate_win32(hr, SUCCEEDED(hr));
|
||||
}
|
||||
|
||||
|
||||
static BOOL STDCALL my_SetCommMask(HANDLE fd, uint32_t mask)
|
||||
{
|
||||
struct irp irp;
|
||||
HRESULT hr;
|
||||
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = IRP_OP_IOCTL;
|
||||
irp.fd = fd;
|
||||
irp.ioctl = IOCTL_SERIAL_SET_WAIT_MASK;
|
||||
irp.write.bytes = (uint8_t *) &mask;
|
||||
irp.write.nbytes = sizeof(mask);
|
||||
|
||||
hr = irp_invoke_next(&irp);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
log_warning("%s: IOCTL_SERIAL_SET_WAIT_MASK failed: %lx", __func__, hr);
|
||||
}
|
||||
|
||||
return hr_propagate_win32(hr, SUCCEEDED(hr));
|
||||
}
|
||||
|
||||
static BOOL STDCALL my_SetCommState(HANDLE fd, const DCB *dcb)
|
||||
{
|
||||
struct irp irp;
|
||||
SERIAL_BAUD_RATE baud;
|
||||
SERIAL_CHARS chars;
|
||||
SERIAL_HANDFLOW handflow;
|
||||
SERIAL_LINE_CONTROL line_control;
|
||||
HRESULT hr;
|
||||
|
||||
if (dcb == NULL) {
|
||||
log_warning("%s: DCB pointer is NULL", __func__);
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (dcb->DCBlength != sizeof(*dcb)) {
|
||||
/* This struct has evolved in the past, but those were the Windows 95
|
||||
days. So we only support the latest size of this struct. */
|
||||
|
||||
log_warning(
|
||||
"%s: dcb->DCBlength = %d, expected %d",
|
||||
__func__,
|
||||
(int) dcb->DCBlength,
|
||||
(unsigned int) sizeof(*dcb));
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
memset(&baud, 0, sizeof(baud));
|
||||
baud.BaudRate = dcb->BaudRate;
|
||||
|
||||
memset(&handflow, 0, sizeof(handflow));
|
||||
|
||||
if (dcb->fOutxCtsFlow) {
|
||||
handflow.ControlHandShake |= SERIAL_CTS_HANDSHAKE;
|
||||
}
|
||||
|
||||
if (dcb->fOutxDsrFlow) {
|
||||
handflow.ControlHandShake |= SERIAL_DSR_HANDSHAKE;
|
||||
}
|
||||
|
||||
switch (dcb->fDtrControl) {
|
||||
case DTR_CONTROL_DISABLE:
|
||||
break;
|
||||
|
||||
case DTR_CONTROL_ENABLE:
|
||||
handflow.ControlHandShake |= SERIAL_DTR_CONTROL;
|
||||
|
||||
break;
|
||||
|
||||
case DTR_CONTROL_HANDSHAKE:
|
||||
handflow.ControlHandShake |= SERIAL_DTR_HANDSHAKE;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
log_warning("%s: dcb->fDtrControl value %d is invalid",
|
||||
__func__, dcb->fDtrControl);
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (dcb->fDsrSensitivity) {
|
||||
handflow.ControlHandShake |= SERIAL_DSR_SENSITIVITY;
|
||||
}
|
||||
|
||||
if (dcb->fTXContinueOnXoff) {
|
||||
handflow.ControlHandShake |= SERIAL_XOFF_CONTINUE;
|
||||
}
|
||||
|
||||
switch (dcb->fRtsControl) {
|
||||
case RTS_CONTROL_DISABLE:
|
||||
break;
|
||||
|
||||
case RTS_CONTROL_ENABLE:
|
||||
handflow.ControlHandShake |= SERIAL_RTS_CONTROL;
|
||||
|
||||
break;
|
||||
|
||||
case RTS_CONTROL_HANDSHAKE:
|
||||
handflow.ControlHandShake |= SERIAL_RTS_HANDSHAKE;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
log_warning(
|
||||
"%s: dcb->fRtsControl value %d is invalid",
|
||||
__func__,
|
||||
dcb->fRtsControl);
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
memset(&line_control, 0, sizeof(line_control));
|
||||
line_control.WordLength = dcb->ByteSize;
|
||||
line_control.Parity = dcb->Parity;
|
||||
line_control.StopBits = dcb->StopBits;
|
||||
|
||||
memset(&chars, 0, sizeof(chars));
|
||||
chars.XonChar = dcb->XonChar;
|
||||
chars.XoffChar = dcb->XoffChar;
|
||||
chars.ErrorChar = dcb->ErrorChar;
|
||||
chars.EofChar = dcb->EofChar;
|
||||
chars.EventChar = dcb->EvtChar;
|
||||
|
||||
/* Parameters populated and validated, commit new settings */
|
||||
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = IRP_OP_IOCTL;
|
||||
irp.fd = fd;
|
||||
irp.ioctl = IOCTL_SERIAL_SET_BAUD_RATE;
|
||||
irp.write.bytes = (uint8_t *) &baud;
|
||||
irp.write.nbytes = sizeof(baud);
|
||||
|
||||
hr = irp_invoke_next(&irp);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
log_warning("%s: IOCTL_SERIAL_SET_BAUD_RATE failed: %lx", __func__, hr);
|
||||
|
||||
return hr_propagate_win32(hr, FALSE);
|
||||
}
|
||||
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = IRP_OP_IOCTL;
|
||||
irp.fd = fd;
|
||||
irp.ioctl = IOCTL_SERIAL_SET_HANDFLOW;
|
||||
irp.write.bytes = (uint8_t *) &handflow;
|
||||
irp.write.nbytes = sizeof(handflow);
|
||||
|
||||
hr = irp_invoke_next(&irp);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
log_warning("%s: IOCTL_SERIAL_SET_HANDFLOW failed: %lx", __func__, hr);
|
||||
|
||||
return hr_propagate_win32(hr, FALSE);
|
||||
}
|
||||
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = IRP_OP_IOCTL;
|
||||
irp.fd = fd;
|
||||
irp.ioctl = IOCTL_SERIAL_SET_LINE_CONTROL;
|
||||
irp.write.bytes = (uint8_t *) &line_control;
|
||||
irp.write.nbytes = sizeof(line_control);
|
||||
|
||||
hr = irp_invoke_next(&irp);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
log_warning(
|
||||
"%s: IOCTL_SERIAL_SET_LINE_CONTROL failed: %lx",
|
||||
__func__,
|
||||
hr);
|
||||
|
||||
return hr_propagate_win32(hr, FALSE);
|
||||
}
|
||||
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = IRP_OP_IOCTL;
|
||||
irp.fd = fd;
|
||||
irp.ioctl = IOCTL_SERIAL_SET_CHARS;
|
||||
irp.write.bytes = (uint8_t *) &chars;
|
||||
irp.write.nbytes = sizeof(chars);
|
||||
|
||||
hr = irp_invoke_next(&irp);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
log_warning("%s: IOCTL_SERIAL_SET_CHARS failed: %lx", __func__, hr);
|
||||
|
||||
return hr_propagate_win32(hr, FALSE);
|
||||
}
|
||||
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL STDCALL my_SetCommTimeouts(HANDLE fd, COMMTIMEOUTS *src)
|
||||
{
|
||||
struct irp irp;
|
||||
SERIAL_TIMEOUTS dest;
|
||||
HRESULT hr;
|
||||
|
||||
dest.ReadIntervalTimeout = src->ReadIntervalTimeout;
|
||||
dest.ReadTotalTimeoutMultiplier = src->ReadTotalTimeoutMultiplier;
|
||||
dest.ReadTotalTimeoutConstant = src->ReadTotalTimeoutConstant;
|
||||
dest.WriteTotalTimeoutMultiplier = src->WriteTotalTimeoutMultiplier;
|
||||
dest.WriteTotalTimeoutConstant = src->WriteTotalTimeoutConstant;
|
||||
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = IRP_OP_IOCTL;
|
||||
irp.fd = fd;
|
||||
irp.ioctl = IOCTL_SERIAL_SET_TIMEOUTS;
|
||||
irp.write.bytes = (uint8_t *) &dest;
|
||||
irp.write.nbytes = sizeof(dest);
|
||||
|
||||
hr = irp_invoke_next(&irp);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
log_warning("%s: IOCTL_SERIAL_SET_TIMEOUTS failed: %lx", __func__, hr);
|
||||
}
|
||||
|
||||
return hr_propagate_win32(hr, SUCCEEDED(hr));
|
||||
}
|
||||
|
||||
static BOOL STDCALL my_SetupComm(HANDLE fd, uint32_t in_q, uint32_t out_q)
|
||||
{
|
||||
struct irp irp;
|
||||
SERIAL_QUEUE_SIZE qs;
|
||||
HRESULT hr;
|
||||
|
||||
qs.InSize = in_q;
|
||||
qs.OutSize = out_q;
|
||||
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = IRP_OP_IOCTL;
|
||||
irp.fd = fd;
|
||||
irp.ioctl = IOCTL_SERIAL_SET_QUEUE_SIZE;
|
||||
irp.write.bytes = (uint8_t *) &qs;
|
||||
irp.write.nbytes = sizeof(qs);
|
||||
|
||||
hr = irp_invoke_next(&irp);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
log_warning("%s: IOCTL_SERIAL_SET_QUEUE_SIZE failed: %lx",__func__, hr);
|
||||
}
|
||||
|
||||
return hr_propagate_win32(hr, SUCCEEDED(hr));
|
||||
}
|
||||
|
||||
static BOOL STDCALL my_SetCommBreak(HANDLE fd)
|
||||
{
|
||||
struct irp irp;
|
||||
HRESULT hr;
|
||||
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = IRP_OP_IOCTL;
|
||||
irp.fd = fd;
|
||||
irp.ioctl = IOCTL_SERIAL_SET_BREAK_ON;
|
||||
|
||||
hr = irp_invoke_next(&irp);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
log_warning("%s: IOCTL_SERIAL_SET_BREAK_ON failed: %lx", __func__, hr);
|
||||
}
|
||||
|
||||
return hr_propagate_win32(hr, SUCCEEDED(hr));
|
||||
}
|
||||
|
||||
static BOOL STDCALL my_ClearCommBreak(HANDLE fd)
|
||||
{
|
||||
struct irp irp;
|
||||
HRESULT hr;
|
||||
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = IRP_OP_IOCTL;
|
||||
irp.fd = fd;
|
||||
irp.ioctl = IOCTL_SERIAL_SET_BREAK_OFF;
|
||||
|
||||
hr = irp_invoke_next(&irp);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
log_warning("%s: IOCTL_SERIAL_SET_BREAK_OFF failed: %lx", __func__, hr);
|
||||
}
|
||||
|
||||
return hr_propagate_win32(hr, SUCCEEDED(hr));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef HOOKLIB_RS232_H
|
||||
#define HOOKLIB_RS232_H
|
||||
|
||||
void rs232_hook_init(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,330 @@
|
||||
#define LOG_MODULE "hook-setupapi"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "hooklib/setupapi.h"
|
||||
|
||||
#include "util/defs.h"
|
||||
#include "util/log.h"
|
||||
#include "util/str.h"
|
||||
|
||||
/* my hooks */
|
||||
|
||||
static BOOL STDCALL my_SetupDiDestroyDeviceInfoList(HDEVINFO dev_info);
|
||||
|
||||
static BOOL STDCALL my_SetupDiEnumDeviceInfo(
|
||||
HDEVINFO dev_info, DWORD index, SP_DEVINFO_DATA *info_data);
|
||||
|
||||
static BOOL STDCALL my_SetupDiEnumDeviceInterfaces(
|
||||
HDEVINFO dev_info, SP_DEVINFO_DATA *info_data, const GUID *iface_guid,
|
||||
DWORD index, SP_DEVICE_INTERFACE_DATA *ifd);
|
||||
|
||||
static HDEVINFO STDCALL my_SetupDiGetClassDevsA(
|
||||
const GUID *class_guid, const char *enumerator, HWND hwnd,
|
||||
DWORD flags);
|
||||
|
||||
static HDEVINFO STDCALL my_SetupDiGetClassDevsW(
|
||||
const GUID *class_guid, PCWSTR enumerator, HWND hwnd,
|
||||
DWORD flags);
|
||||
|
||||
static BOOL STDCALL my_SetupDiGetDeviceInterfaceDetailA(
|
||||
HDEVINFO dev_info, SP_DEVICE_INTERFACE_DATA *ifd,
|
||||
SP_DEVICE_INTERFACE_DETAIL_DATA_A *detail, DWORD size,
|
||||
DWORD *required_size, SP_DEVINFO_DATA *info_data);
|
||||
|
||||
static BOOL STDCALL my_SetupDiGetDeviceInterfaceDetailW(
|
||||
HDEVINFO dev_info, SP_DEVICE_INTERFACE_DATA *ifd,
|
||||
SP_DEVICE_INTERFACE_DETAIL_DATA_W *detail, DWORD size,
|
||||
DWORD *required_size, SP_DEVINFO_DATA *info_data);
|
||||
|
||||
static BOOL STDCALL my_SetupDiGetDeviceRegistryPropertyA(
|
||||
HDEVINFO dev_info, SP_DEVINFO_DATA *info_data, DWORD prop_id,
|
||||
DWORD *prop_type, void *bytes, DWORD nbytes, DWORD *required_nbytes);
|
||||
|
||||
/* real calls */
|
||||
|
||||
static BOOL (STDCALL *real_SetupDiDestroyDeviceInfoList)(
|
||||
HDEVINFO dev_info);
|
||||
|
||||
static BOOL (STDCALL *real_SetupDiEnumDeviceInfo)(
|
||||
HDEVINFO dev_info, DWORD index, SP_DEVINFO_DATA *info_data);
|
||||
|
||||
static BOOL (STDCALL *real_SetupDiEnumDeviceInterfaces)(
|
||||
HDEVINFO dev_info, SP_DEVINFO_DATA *info_data, const GUID *iface_guid,
|
||||
DWORD index, SP_DEVICE_INTERFACE_DATA *ifd);
|
||||
|
||||
static HDEVINFO (STDCALL *real_SetupDiGetClassDevsA)(
|
||||
const GUID *class_guid, const char *enumerator, HWND hwnd,
|
||||
DWORD flags);
|
||||
|
||||
static HDEVINFO (STDCALL *real_SetupDiGetClassDevsW)(
|
||||
const GUID *class_guid, PCWSTR enumerator, HWND hwnd,
|
||||
DWORD flags);
|
||||
|
||||
static BOOL (STDCALL *real_SetupDiGetDeviceInterfaceDetailA)(
|
||||
HDEVINFO dev_info, SP_DEVICE_INTERFACE_DATA *ifd,
|
||||
SP_DEVICE_INTERFACE_DETAIL_DATA_A *detail, DWORD size,
|
||||
DWORD *required_size, SP_DEVINFO_DATA *info_data);
|
||||
|
||||
static BOOL (STDCALL *real_SetupDiGetDeviceInterfaceDetailW)(
|
||||
HDEVINFO dev_info, SP_DEVICE_INTERFACE_DATA *ifd,
|
||||
SP_DEVICE_INTERFACE_DETAIL_DATA_W *detail, DWORD size,
|
||||
DWORD *required_size, SP_DEVINFO_DATA *info_data);
|
||||
|
||||
static BOOL (STDCALL *real_SetupDiGetDeviceRegistryPropertyA)(
|
||||
HDEVINFO dev_info, SP_DEVINFO_DATA *info_data, DWORD prop_id,
|
||||
DWORD *prop_type, void *bytes, DWORD nbytes, DWORD *required_nbytes);
|
||||
|
||||
static const struct hook_symbol setupapi_hook_syms[] = {
|
||||
{
|
||||
.name = "SetupDiDestroyDeviceInfoList",
|
||||
.patch = my_SetupDiDestroyDeviceInfoList,
|
||||
.link = (void **) &real_SetupDiDestroyDeviceInfoList
|
||||
},
|
||||
{
|
||||
.name = "SetupDiEnumDeviceInfo",
|
||||
.patch = my_SetupDiEnumDeviceInfo,
|
||||
.link = (void **) &real_SetupDiEnumDeviceInfo
|
||||
},
|
||||
{
|
||||
.name = "SetupDiEnumDeviceInterfaces",
|
||||
.patch = my_SetupDiEnumDeviceInterfaces,
|
||||
.link = (void **) &real_SetupDiEnumDeviceInterfaces
|
||||
},
|
||||
{
|
||||
.name = "SetupDiGetClassDevsA",
|
||||
.patch = my_SetupDiGetClassDevsA,
|
||||
.link = (void **) &real_SetupDiGetClassDevsA
|
||||
},
|
||||
{
|
||||
.name = "SetupDiGetClassDevsW",
|
||||
.patch = my_SetupDiGetClassDevsW,
|
||||
.link = (void **) &real_SetupDiGetClassDevsW
|
||||
},
|
||||
{
|
||||
.name = "SetupDiGetDeviceInterfaceDetailA",
|
||||
.patch = my_SetupDiGetDeviceInterfaceDetailA,
|
||||
.link = (void **) &real_SetupDiGetDeviceInterfaceDetailA
|
||||
},
|
||||
{
|
||||
.name = "SetupDiGetDeviceInterfaceDetailW",
|
||||
.patch = my_SetupDiGetDeviceInterfaceDetailW,
|
||||
.link = (void **) &real_SetupDiGetDeviceInterfaceDetailW
|
||||
},
|
||||
{
|
||||
.name = "SetupDiGetDeviceRegistryPropertyA",
|
||||
.patch = my_SetupDiGetDeviceRegistryPropertyA,
|
||||
.link = (void **) &real_SetupDiGetDeviceRegistryPropertyA
|
||||
},
|
||||
};
|
||||
|
||||
static int hook_setupapi_fake_handle;
|
||||
static const struct hook_setupapi_data* hook_setupapi_data;
|
||||
|
||||
static HDEVINFO STDCALL my_SetupDiGetClassDevsA(
|
||||
const GUID *class_guid, const char *enumerator, HWND hwnd,
|
||||
DWORD flags)
|
||||
{
|
||||
/* That's how iidx 9-13 detected the old C02 IO. That doesn't work
|
||||
on iidx 14 anymore... */
|
||||
/*
|
||||
if (class_guid != NULL
|
||||
&& memcmp(class_guid, &hook_setupapi_data->device_guid,
|
||||
sizeof(hook_setupapi_data->device_guid)) == 0) {
|
||||
*/
|
||||
if ((class_guid != NULL
|
||||
&& !memcmp(class_guid, &hook_setupapi_data->device_guid,
|
||||
sizeof(hook_setupapi_data->device_guid))) ||
|
||||
(enumerator != NULL && !strcmp(enumerator, "USB"))) {
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
|
||||
log_misc("SetupDiGetClassDevsA: %s", hook_setupapi_data->device_path);
|
||||
|
||||
return &hook_setupapi_fake_handle;
|
||||
} else {
|
||||
return real_SetupDiGetClassDevsA(class_guid, enumerator, hwnd, flags);
|
||||
}
|
||||
}
|
||||
|
||||
static HDEVINFO STDCALL my_SetupDiGetClassDevsW(
|
||||
const GUID *class_guid, PCWSTR enumerator, HWND hwnd,
|
||||
DWORD flags)
|
||||
{
|
||||
if (class_guid != NULL
|
||||
&& memcmp(class_guid, &hook_setupapi_data->device_guid,
|
||||
sizeof(hook_setupapi_data->device_guid)) == 0) {
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
|
||||
log_misc("SetupDiGetClassDevsW: %s", hook_setupapi_data->device_path);
|
||||
|
||||
return &hook_setupapi_fake_handle;
|
||||
} else {
|
||||
return real_SetupDiGetClassDevsW(class_guid, enumerator, hwnd, flags);
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL STDCALL my_SetupDiEnumDeviceInfo(
|
||||
HDEVINFO dev_info, DWORD index, SP_DEVINFO_DATA *info_data)
|
||||
{
|
||||
if (dev_info == &hook_setupapi_fake_handle) {
|
||||
if (index == 0) {
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
|
||||
log_misc("SetupDiEnumDeviceInfo");
|
||||
|
||||
return TRUE;
|
||||
} else {
|
||||
SetLastError(ERROR_NO_MORE_ITEMS);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
return real_SetupDiEnumDeviceInfo(dev_info, index, info_data);
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL STDCALL my_SetupDiEnumDeviceInterfaces(
|
||||
HDEVINFO dev_info, SP_DEVINFO_DATA *info_data, const GUID *iface_guid,
|
||||
DWORD index, SP_DEVICE_INTERFACE_DATA *ifd)
|
||||
{
|
||||
if (dev_info == &hook_setupapi_fake_handle) {
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
|
||||
log_misc("SetupDiEnumDeviceInterfaces");
|
||||
|
||||
return index == 0;
|
||||
} else {
|
||||
return real_SetupDiEnumDeviceInterfaces(dev_info, info_data,
|
||||
iface_guid, index, ifd);
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL STDCALL my_SetupDiGetDeviceRegistryPropertyA(
|
||||
HDEVINFO dev_info, SP_DEVINFO_DATA *info_data, DWORD prop_id,
|
||||
DWORD *prop_type, void *bytes, DWORD nbytes, DWORD *required_nbytes)
|
||||
{
|
||||
if (dev_info == &hook_setupapi_fake_handle) {
|
||||
if (prop_id != SPDRP_DEVICEDESC) {
|
||||
SetLastError(ERROR_BAD_ARGUMENTS);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (nbytes < MAX_PATH) {
|
||||
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
||||
*required_nbytes = MAX_PATH;
|
||||
|
||||
return FALSE;
|
||||
} else {
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
|
||||
*prop_type = REG_SZ;
|
||||
|
||||
if (hook_setupapi_data->device_desc) {
|
||||
log_misc("SetupDiGetDeviceRegistryPropertyA: %s",
|
||||
hook_setupapi_data->device_desc);
|
||||
str_cpy(bytes, nbytes, hook_setupapi_data->device_desc);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
} else {
|
||||
return real_SetupDiGetDeviceRegistryPropertyA(
|
||||
dev_info, info_data, prop_id, prop_type, bytes, nbytes,
|
||||
required_nbytes);
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL STDCALL my_SetupDiGetDeviceInterfaceDetailA(
|
||||
HDEVINFO dev_info, SP_DEVICE_INTERFACE_DATA *ifd,
|
||||
SP_DEVICE_INTERFACE_DETAIL_DATA_A *detail, DWORD size,
|
||||
DWORD *required_size, SP_DEVINFO_DATA *info_data)
|
||||
{
|
||||
if (dev_info == &hook_setupapi_fake_handle) {
|
||||
if (size == 0) {
|
||||
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
||||
*required_size = sizeof(DWORD) + sizeof(char) * MAX_PATH;
|
||||
|
||||
return FALSE;
|
||||
} else {
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
|
||||
log_misc("SetupDiGetDeviceInterfaceDetailA: %s",
|
||||
hook_setupapi_data->device_path);
|
||||
|
||||
detail->cbSize = strlen(hook_setupapi_data->device_path);
|
||||
memcpy(detail->DevicePath, hook_setupapi_data->device_path,
|
||||
detail->cbSize);
|
||||
detail->DevicePath[detail->cbSize] = '\0';
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
} else {
|
||||
return real_SetupDiGetDeviceInterfaceDetailA(dev_info, ifd, detail,
|
||||
size, required_size, info_data);
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL STDCALL my_SetupDiGetDeviceInterfaceDetailW(
|
||||
HDEVINFO dev_info, SP_DEVICE_INTERFACE_DATA *ifd,
|
||||
SP_DEVICE_INTERFACE_DETAIL_DATA_W *detail, DWORD size,
|
||||
DWORD *required_size, SP_DEVINFO_DATA *info_data)
|
||||
{
|
||||
if (dev_info == &hook_setupapi_fake_handle) {
|
||||
if (size == 0) {
|
||||
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
||||
*required_size = sizeof(DWORD) + sizeof(wchar_t) * MAX_PATH;
|
||||
|
||||
return FALSE;
|
||||
} else {
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
|
||||
log_misc("SetupDiGetDeviceInterfaceDetailW: %s",
|
||||
hook_setupapi_data->device_path);
|
||||
|
||||
wchar_t* wstr_path = str_widen(hook_setupapi_data->device_path);
|
||||
|
||||
detail->cbSize = strlen(hook_setupapi_data->device_path);
|
||||
memcpy(detail->DevicePath, wstr_path, (wcslen(wstr_path) + 1) *
|
||||
sizeof(wchar_t));
|
||||
detail->DevicePath[detail->cbSize] = '\0';
|
||||
|
||||
free(wstr_path);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
} else {
|
||||
return real_SetupDiGetDeviceInterfaceDetailW(dev_info, ifd, detail,
|
||||
size, required_size, info_data);
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL STDCALL my_SetupDiDestroyDeviceInfoList(HDEVINFO dev_info)
|
||||
{
|
||||
if (dev_info == &hook_setupapi_fake_handle) {
|
||||
log_misc("SetupDiDestroyDeviceInfoList");
|
||||
|
||||
return TRUE;
|
||||
} else {
|
||||
return real_SetupDiDestroyDeviceInfoList(dev_info);
|
||||
}
|
||||
}
|
||||
|
||||
void hook_setupapi_init(const struct hook_setupapi_data* data)
|
||||
{
|
||||
hook_table_apply(
|
||||
NULL,
|
||||
"setupapi.dll",
|
||||
setupapi_hook_syms,
|
||||
lengthof(setupapi_hook_syms));
|
||||
|
||||
hook_setupapi_data = data;
|
||||
log_info("Hooked setupapi for %s, %s", data->device_path,
|
||||
data->device_desc);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef HOOKLIB_SETUPAPI_H
|
||||
#define HOOKLIB_SETUPAPI_H
|
||||
|
||||
#include <windows.h>
|
||||
#include <setupapi.h>
|
||||
|
||||
struct hook_setupapi_data {
|
||||
GUID device_guid;
|
||||
const char* device_desc;
|
||||
const char* device_path;
|
||||
};
|
||||
|
||||
void hook_setupapi_init(const struct hook_setupapi_data* data);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user