mirror of
https://github.com/AkaiiKitsune/TAL_CardReader
synced 2024-11-23 17:10:57 +01:00
First working version
The game sometimes crashes, throwing an access violation at offset 00000000002f399a. I haven't been able to recreate accurately.
This commit is contained in:
parent
6c6aabed78
commit
c047663c90
6
.gitignore
vendored
6
.gitignore
vendored
@ -50,3 +50,9 @@ modules.order
|
||||
Module.symvers
|
||||
Mkfile.old
|
||||
dkms.conf
|
||||
|
||||
# Vscode specific
|
||||
.vscode/
|
||||
|
||||
subprojects/minhook
|
||||
subprojects/tomlc99
|
24
LICENSE
Normal file
24
LICENSE
Normal file
@ -0,0 +1,24 @@
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <https://unlicense.org>
|
64
PLUGINS.md
Normal file
64
PLUGINS.md
Normal file
@ -0,0 +1,64 @@
|
||||
# Guide for making additional plugins
|
||||
|
||||
Plugins are just libraries with certain exported functions that go in the plugins folder.
|
||||
|
||||
```C
|
||||
void PreInit()
|
||||
```
|
||||
|
||||
Runs in dllmain, may run into loader locks. You can also just use your own dllmain for this but that involves writing out all the arguments.
|
||||
|
||||
```C
|
||||
void Init()
|
||||
```
|
||||
|
||||
Runs on bngrw_Init, may be a bit late for some things but should generally allow functions which would cause loader locks to run fine if a bit late.
|
||||
|
||||
```C
|
||||
void Exit()
|
||||
```
|
||||
|
||||
Runs on bnusio_Close, dispose of any data here.
|
||||
|
||||
```C
|
||||
void Update()
|
||||
```
|
||||
|
||||
Runs once per frame.
|
||||
|
||||
```C
|
||||
void WaitTouch(i32 (*callback) (i32, i32, u8[168], u64), u64 data)
|
||||
```
|
||||
|
||||
Runs on bngrw_reqWaitTouch. Call the callback like so when you wish to have a card scanned.
|
||||
|
||||
```C
|
||||
u8 cardData[168]= { 0x01, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x2E, 0x58, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x5C, 0x97, 0x44, 0xF0, 0x88, 0x04, 0x00, 0x43, 0x26, 0x2C, 0x33, 0x00, 0x04, 0x06, 0x10, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4E, 0x42, 0x47, 0x49, 0x43, 0x36, 0x00, 0x00, 0xFA, 0xE9, 0x69, 0x00, 0xF6, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
memcpy (cardData + 0x2C, chipId, 33);
|
||||
memcpy (cardData + 0x50, accessCode, 21);
|
||||
callback(0, 0, cardData, data);
|
||||
```
|
||||
|
||||
```C
|
||||
void Card1Insert()
|
||||
```
|
||||
|
||||
Runs when user presses CARD_INSERT_1, causes TAL to not insert a card if any plugins have this present
|
||||
|
||||
```C
|
||||
void Card2Insert()
|
||||
```
|
||||
|
||||
Runs when user presses CARD_INSERT_2, causes TAL to not insert a card if any plugins have this present
|
||||
|
||||
```C
|
||||
void BeforeCard1Insert()
|
||||
```
|
||||
|
||||
Runs before CARD_INSERT_1 is handled
|
||||
|
||||
```C
|
||||
void BeforeCard2Insert()
|
||||
```
|
||||
|
||||
Runs before CARD_INSERT_2 is handled
|
24
README.md
24
README.md
@ -1,2 +1,22 @@
|
||||
# TAL_CardIO
|
||||
Allows you to use USB HID card readers (cardio) with TAL
|
||||
# TAL CardIO
|
||||
|
||||
This is a plugin that allows you to use USB HID card readers (cardio) with [TaikoArcadeLoader](https://github.com/BroGamer4256/TaikoArcadeLoader)
|
||||
|
||||
# Acknowledgments
|
||||
|
||||
This is a plugin destined to be used with [BroGamer4256](https://github.com/BroGamer4256)'s TaikoArcadeLoader.
|
||||
|
||||
CardIO implementation taken from [Spicetools](https://github.com/spicetools/spicetools) and adapted with the help of [CrazyRedMachine](https://github.com/CrazyRedMachine) (Huge thanks!)
|
||||
|
||||
Initial project setup done with the help of [Stepland](https://github.com/Stepland)
|
||||
|
||||
# How to use
|
||||
|
||||
To build this, you'll need two things :
|
||||
|
||||
- [Meson 1.1.0](https://mesonbuild.com)
|
||||
- [Build Tools pour Visual Studio 2022](https://visualstudio.microsoft.com/fr/downloads/)
|
||||
|
||||
Once you've edited your build64.bat file to point to your local installation of the VS2022 build tools, you should be good to go.
|
||||
|
||||
Copy the cardio.dll to your TAL's plugin folder. You should be able to see the plugin initializing in the game's console.
|
||||
|
11
build64.bat
Normal file
11
build64.bat
Normal file
@ -0,0 +1,11 @@
|
||||
cd /d %~dp0
|
||||
|
||||
REM Edit this with the right path to vcvarsall.bat.
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" x64
|
||||
meson setup build64 --buildtype=release
|
||||
meson configure build64
|
||||
ninja -C build64
|
||||
|
||||
mkdir bin
|
||||
copy build64\src\cardio.dll bin\cardio.dll
|
||||
pause
|
9
meson.build
Normal file
9
meson.build
Normal file
@ -0,0 +1,9 @@
|
||||
project(
|
||||
'TAL_CardIO',
|
||||
'c',
|
||||
version : '0.1.0'
|
||||
)
|
||||
|
||||
inc = include_directories('.')
|
||||
|
||||
subdir('src/')
|
6
src/cardio.def
Normal file
6
src/cardio.def
Normal file
@ -0,0 +1,6 @@
|
||||
LIBRARY cardio
|
||||
|
||||
EXPORTS
|
||||
Init
|
||||
WaitTouch
|
||||
Exit
|
437
src/cardio_plugin/cardio.c
Normal file
437
src/cardio_plugin/cardio.c
Normal file
@ -0,0 +1,437 @@
|
||||
/**
|
||||
* MIT-License
|
||||
* Copyright (c) 2018 by Felix
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
* Modified version.
|
||||
*/
|
||||
|
||||
#include "cardio.h"
|
||||
|
||||
#define DEFAULT_ALLOCATED_CONTEXTS 2
|
||||
#define CARD_READER_USAGE_PAGE 0xffca
|
||||
|
||||
extern char module[];
|
||||
|
||||
// GUID_DEVCLASS_HIDCLASS
|
||||
static GUID hidclass_guid = {0x745a17a0, 0x74d3, 0x11d0, {0xb6, 0xfe, 0x00, 0xa0, 0xc9, 0x0f, 0x57, 0xda}};
|
||||
|
||||
// globals
|
||||
CRITICAL_SECTION CARDIO_HID_CRIT_SECTION;
|
||||
struct cardio_hid_device *CARDIO_HID_CONTEXTS = NULL;
|
||||
size_t CARDIO_HID_CONTEXTS_LENGTH = 0;
|
||||
|
||||
void hid_ctx_init(struct cardio_hid_device *ctx) {
|
||||
ctx->dev_path = NULL;
|
||||
ctx->dev_handle = INVALID_HANDLE_VALUE;
|
||||
ctx->initialized = FALSE;
|
||||
ctx->io_pending = FALSE;
|
||||
ctx->read_size = 0;
|
||||
ctx->pp_data = NULL;
|
||||
ctx->collection = NULL;
|
||||
ctx->collection_length = 0;
|
||||
|
||||
memset(&ctx->read_state, 0, sizeof(OVERLAPPED));
|
||||
memset(&ctx->report_buffer, 0, sizeof(ctx->report_buffer));
|
||||
memset(&ctx->u.usage_value, 0, sizeof(ctx->u.usage_value));
|
||||
memset(&ctx->caps, 0, sizeof(HIDP_CAPS));
|
||||
}
|
||||
|
||||
void hid_ctx_free(struct cardio_hid_device *ctx) {
|
||||
if (ctx->dev_path != NULL) {
|
||||
HeapFree(GetProcessHeap(), 0, ctx->dev_path);
|
||||
ctx->dev_path = NULL;
|
||||
}
|
||||
|
||||
if (ctx->dev_handle != INVALID_HANDLE_VALUE) {
|
||||
CancelIo(ctx->dev_handle);
|
||||
CloseHandle(ctx->dev_handle);
|
||||
ctx->dev_handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
if (ctx->pp_data != NULL) {
|
||||
HidD_FreePreparsedData(ctx->pp_data);
|
||||
ctx->pp_data = NULL;
|
||||
}
|
||||
|
||||
if (ctx->collection != NULL) {
|
||||
HeapFree(GetProcessHeap(), 0, ctx->collection);
|
||||
ctx->collection = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void hid_ctx_reset(struct cardio_hid_device *ctx) {
|
||||
ctx->initialized = FALSE;
|
||||
ctx->io_pending = FALSE;
|
||||
ctx->read_size = 0;
|
||||
ctx->collection_length = 0;
|
||||
|
||||
hid_ctx_free(ctx);
|
||||
|
||||
memset(&ctx->read_state, 0, sizeof(OVERLAPPED));
|
||||
memset(&ctx->report_buffer, 0, sizeof(ctx->report_buffer));
|
||||
memset(&ctx->u.usage_value, 0, sizeof(ctx->u.usage_value));
|
||||
memset(&ctx->caps, 0, sizeof(HIDP_CAPS));
|
||||
}
|
||||
|
||||
BOOL cardio_hid_init() {
|
||||
size_t i, contexts_size;
|
||||
|
||||
InitializeCriticalSectionAndSpinCount(&CARDIO_HID_CRIT_SECTION, 0x00000400);
|
||||
|
||||
contexts_size = DEFAULT_ALLOCATED_CONTEXTS * sizeof(struct cardio_hid_device);
|
||||
CARDIO_HID_CONTEXTS = (struct cardio_hid_device *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, contexts_size);
|
||||
if (CARDIO_HID_CONTEXTS == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CARDIO_HID_CONTEXTS_LENGTH = DEFAULT_ALLOCATED_CONTEXTS;
|
||||
|
||||
for (i = 0; i < CARDIO_HID_CONTEXTS_LENGTH; i++) {
|
||||
hid_ctx_init(&CARDIO_HID_CONTEXTS[i]);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void cardio_hid_close() {
|
||||
size_t i;
|
||||
|
||||
if (CARDIO_HID_CONTEXTS_LENGTH > 0) {
|
||||
for (i = 0; i < CARDIO_HID_CONTEXTS_LENGTH; i++) {
|
||||
hid_ctx_free(&CARDIO_HID_CONTEXTS[i]);
|
||||
}
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, CARDIO_HID_CONTEXTS);
|
||||
CARDIO_HID_CONTEXTS = NULL;
|
||||
CARDIO_HID_CONTEXTS_LENGTH = 0;
|
||||
|
||||
DeleteCriticalSection(&CARDIO_HID_CRIT_SECTION);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL cardio_hid_add_device(LPCWSTR device_path) {
|
||||
BOOL res = FALSE;
|
||||
size_t i;
|
||||
|
||||
EnterCriticalSection(&CARDIO_HID_CRIT_SECTION);
|
||||
|
||||
for (i = 0; i < CARDIO_HID_CONTEXTS_LENGTH; i++) {
|
||||
if (!CARDIO_HID_CONTEXTS[i].initialized) {
|
||||
res = cardio_hid_scan_device(&CARDIO_HID_CONTEXTS[i], device_path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&CARDIO_HID_CRIT_SECTION);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
BOOL cardio_hid_remove_device(LPCWSTR device_path) {
|
||||
BOOL res = FALSE;
|
||||
size_t i;
|
||||
|
||||
EnterCriticalSection(&CARDIO_HID_CRIT_SECTION);
|
||||
|
||||
for (i = 0; i < CARDIO_HID_CONTEXTS_LENGTH; i++) {
|
||||
// The device paths in `hid_scan` are partially lower-case, so perform a
|
||||
// case-insensitive comparison here
|
||||
if (CARDIO_HID_CONTEXTS[i].initialized && (_wcsicmp(device_path, CARDIO_HID_CONTEXTS[i].dev_path) == 0)) {
|
||||
hid_ctx_reset(&CARDIO_HID_CONTEXTS[i]);
|
||||
res = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&CARDIO_HID_CRIT_SECTION);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Scan HID device to see if it is a HID reader
|
||||
*/
|
||||
BOOL cardio_hid_scan_device(struct cardio_hid_device *ctx, LPCWSTR device_path) {
|
||||
NTSTATUS res;
|
||||
|
||||
size_t dev_path_size = (wcslen(device_path) + 1) * sizeof(WCHAR);
|
||||
ctx->dev_path = (LPWSTR) HeapAlloc(GetProcessHeap(), 0, dev_path_size);
|
||||
if (ctx->dev_path == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
memcpy(ctx->dev_path, device_path, dev_path_size);
|
||||
ctx->dev_path[dev_path_size - 1] = '\0';
|
||||
ctx->dev_handle = CreateFileW(
|
||||
ctx->dev_path,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_OVERLAPPED,
|
||||
NULL);
|
||||
if (ctx->dev_handle == INVALID_HANDLE_VALUE) {
|
||||
printWarning ("%s (%s): could not open device: %ls\n", __func__, module, ctx->dev_path);
|
||||
HeapFree(GetProcessHeap(), 0, ctx->dev_path);
|
||||
ctx->dev_path = NULL;
|
||||
ctx->dev_handle = INVALID_HANDLE_VALUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!HidD_GetPreparsedData(ctx->dev_handle, &ctx->pp_data)) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
res = HidP_GetCaps(ctx->pp_data, &ctx->caps);
|
||||
if (res != HIDP_STATUS_SUCCESS) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
// 0xffca is the card reader usage page ID
|
||||
if (ctx->caps.UsagePage != CARD_READER_USAGE_PAGE) {
|
||||
goto end;
|
||||
} else if (ctx->caps.NumberInputValueCaps == 0) {
|
||||
goto end;
|
||||
}
|
||||
ctx->collection_length = ctx->caps.NumberInputValueCaps;
|
||||
ctx->collection = (HIDP_VALUE_CAPS *) HeapAlloc(GetProcessHeap(), 0,
|
||||
ctx->collection_length * sizeof(HIDP_VALUE_CAPS));
|
||||
if (ctx->collection == NULL) {
|
||||
goto end;
|
||||
}
|
||||
res = HidP_GetValueCaps(
|
||||
HidP_Input,
|
||||
ctx->collection,
|
||||
&ctx->collection_length,
|
||||
ctx->pp_data);
|
||||
if (res != HIDP_STATUS_SUCCESS) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
printWarning ("%s (%s): detected reader: %ls\n", __func__, module, ctx->dev_path);
|
||||
ctx->initialized = TRUE;
|
||||
return TRUE;
|
||||
|
||||
end:
|
||||
hid_ctx_reset(ctx);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks all devices registered with the HIDClass GUID. If the usage page of
|
||||
* the device is 0xffca, then a compatible card reader was found.
|
||||
*
|
||||
* Usage 0x41 => ISO_15693
|
||||
* Usage 0x42 => ISO_18092 (FeliCa)
|
||||
*/
|
||||
BOOL cardio_hid_scan() {
|
||||
BOOL res = TRUE;
|
||||
SP_DEVINFO_DATA devinfo_data;
|
||||
SP_DEVICE_INTERFACE_DATA device_interface_data;
|
||||
SP_DEVICE_INTERFACE_DETAIL_DATA_W *device_interface_detail_data = NULL;
|
||||
HDEVINFO device_info_set;
|
||||
GUID hid_guid;
|
||||
DWORD device_index = 0;
|
||||
DWORD dwSize = 0;
|
||||
size_t hid_devices = 0;
|
||||
|
||||
// get GUID
|
||||
HidD_GetHidGuid(&hid_guid);
|
||||
|
||||
// HID collection opening needs `DIGCF_DEVICEINTERFACE` and ignore
|
||||
// disconnected devices
|
||||
device_info_set = SetupDiGetClassDevs(&hid_guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
|
||||
if (device_info_set == INVALID_HANDLE_VALUE) {
|
||||
res = FALSE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
memset(&devinfo_data, 0, sizeof(SP_DEVINFO_DATA));
|
||||
devinfo_data.cbSize = sizeof(SP_DEVINFO_DATA);
|
||||
device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
|
||||
|
||||
// `SetupDiEnumDeviceInterfaces` must come before `SetupDiEnumDeviceInfo`
|
||||
// else `SetupDiEnumDeviceInterfaces` will fail with error 259
|
||||
while (SetupDiEnumDeviceInterfaces(device_info_set, NULL, &hid_guid, device_index, &device_interface_data)) {
|
||||
|
||||
// Get the required size
|
||||
if (SetupDiGetDeviceInterfaceDetailW(device_info_set, &device_interface_data, NULL, 0, &dwSize, NULL)) {
|
||||
goto cont;
|
||||
}
|
||||
|
||||
device_interface_detail_data = (SP_DEVICE_INTERFACE_DETAIL_DATA_W *) HeapAlloc(GetProcessHeap(), 0, dwSize);
|
||||
if (device_interface_detail_data == NULL) {
|
||||
goto cont;
|
||||
}
|
||||
|
||||
device_interface_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
|
||||
|
||||
if (!SetupDiGetDeviceInterfaceDetailW(device_info_set, &device_interface_data, device_interface_detail_data, dwSize, NULL, NULL)) {
|
||||
goto cont;
|
||||
}
|
||||
|
||||
if (!SetupDiEnumDeviceInfo(device_info_set, device_index, &devinfo_data)) {
|
||||
goto cont;
|
||||
}
|
||||
|
||||
if (!IsEqualGUID((const void *)&hidclass_guid, (const void *)&devinfo_data.ClassGuid)) {
|
||||
goto cont;
|
||||
}
|
||||
|
||||
EnterCriticalSection(&CARDIO_HID_CRIT_SECTION);
|
||||
|
||||
if (hid_devices == CARDIO_HID_CONTEXTS_LENGTH) {
|
||||
CARDIO_HID_CONTEXTS_LENGTH++;
|
||||
|
||||
CARDIO_HID_CONTEXTS = (struct cardio_hid_device *) HeapReAlloc(
|
||||
GetProcessHeap(),
|
||||
HEAP_ZERO_MEMORY,
|
||||
CARDIO_HID_CONTEXTS,
|
||||
CARDIO_HID_CONTEXTS_LENGTH * sizeof(struct cardio_hid_device)
|
||||
);
|
||||
if (CARDIO_HID_CONTEXTS == NULL) {
|
||||
LeaveCriticalSection(&CARDIO_HID_CRIT_SECTION);
|
||||
HeapFree(GetProcessHeap(), 0, device_interface_detail_data);
|
||||
res = FALSE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
hid_ctx_init(&CARDIO_HID_CONTEXTS[hid_devices]);
|
||||
}
|
||||
|
||||
if (cardio_hid_scan_device(&CARDIO_HID_CONTEXTS[hid_devices], device_interface_detail_data->DevicePath)) {
|
||||
hid_devices++;
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&CARDIO_HID_CRIT_SECTION);
|
||||
|
||||
cont:
|
||||
if (device_interface_detail_data) {
|
||||
HeapFree(GetProcessHeap(), 0, device_interface_detail_data);
|
||||
device_interface_detail_data = NULL;
|
||||
}
|
||||
|
||||
device_index++;
|
||||
}
|
||||
|
||||
end:
|
||||
if (device_info_set != INVALID_HANDLE_VALUE) {
|
||||
SetupDiDestroyDeviceInfoList(device_info_set);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
cardio_hid_poll_value_t cardio_hid_device_poll(struct cardio_hid_device *ctx) {
|
||||
DWORD error = 0;
|
||||
|
||||
if (!ctx->initialized) {
|
||||
return HID_POLL_ERROR;
|
||||
}
|
||||
|
||||
if (ctx->io_pending) {
|
||||
// Do this if inside to not have more `ReadFile` overlapped I/O requests.
|
||||
// If there are more calls to `ReadFile` than `GetOverlappedResult` then
|
||||
// eventually the working set quota will run out triggering error 1426
|
||||
// (ERROR_WORKING_SET_QUOTA).
|
||||
if (HasOverlappedIoCompleted(&ctx->read_state)) {
|
||||
ctx->io_pending = FALSE;
|
||||
|
||||
if (!GetOverlappedResult(ctx->dev_handle, &ctx->read_state, &ctx->read_size, FALSE)) {
|
||||
return HID_POLL_ERROR;
|
||||
}
|
||||
|
||||
memset(&ctx->read_state, 0, sizeof(OVERLAPPED));
|
||||
|
||||
return HID_POLL_CARD_READY;
|
||||
}
|
||||
} else {
|
||||
if (!ReadFile(
|
||||
ctx->dev_handle,
|
||||
&ctx->report_buffer,
|
||||
sizeof(ctx->report_buffer),
|
||||
&ctx->read_size,
|
||||
&ctx->read_state)) {
|
||||
error = GetLastError();
|
||||
|
||||
if (error == ERROR_IO_PENDING) {
|
||||
ctx->io_pending = TRUE;
|
||||
} else {
|
||||
return HID_POLL_ERROR;
|
||||
}
|
||||
} else {
|
||||
// The read completed right away
|
||||
return HID_POLL_CARD_READY;
|
||||
}
|
||||
}
|
||||
|
||||
return HID_POLL_CARD_NOT_READY;
|
||||
}
|
||||
|
||||
cardio_hid_card_type_t cardio_hid_device_read(struct cardio_hid_device *hid_ctx) {
|
||||
|
||||
// check if not initialized
|
||||
if (!hid_ctx->initialized) {
|
||||
return HID_CARD_NONE;
|
||||
}
|
||||
|
||||
// check if IO is pending
|
||||
if (hid_ctx->io_pending) {
|
||||
return HID_CARD_NONE;
|
||||
}
|
||||
|
||||
// check if nothing was read
|
||||
if (hid_ctx->read_size == 0) {
|
||||
return HID_CARD_NONE;
|
||||
}
|
||||
|
||||
// iterate collections
|
||||
for (int i = 0; i < hid_ctx->collection_length; i++) {
|
||||
HIDP_VALUE_CAPS *item = &hid_ctx->collection[i];
|
||||
|
||||
// get usages
|
||||
NTSTATUS res = HidP_GetUsageValueArray(
|
||||
HidP_Input,
|
||||
CARD_READER_USAGE_PAGE,
|
||||
0, // LinkCollection
|
||||
item->NotRange.Usage,
|
||||
(PCHAR) &hid_ctx->u.usage_value,
|
||||
sizeof(hid_ctx->u.usage_value),
|
||||
hid_ctx->pp_data,
|
||||
(PCHAR) &hid_ctx->report_buffer,
|
||||
hid_ctx->read_size);
|
||||
|
||||
// loop through the collection to find the entry that handles this report ID
|
||||
if (res == HIDP_STATUS_INCOMPATIBLE_REPORT_ID) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// check if failed
|
||||
if (res != HIDP_STATUS_SUCCESS) {
|
||||
return HID_CARD_NONE;
|
||||
}
|
||||
|
||||
// return card type
|
||||
return (cardio_hid_card_type_t) item->NotRange.Usage;
|
||||
}
|
||||
|
||||
return HID_CARD_NONE;
|
||||
}
|
86
src/cardio_plugin/cardio.h
Normal file
86
src/cardio_plugin/cardio.h
Normal file
@ -0,0 +1,86 @@
|
||||
/**
|
||||
* MIT-License
|
||||
* Copyright (c) 2018 by Felix
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
* Modified version.
|
||||
*/
|
||||
#pragma once
|
||||
#ifndef SPICETOOLS_CARDIO_HID_H
|
||||
#define SPICETOOLS_CARDIO_HID_H
|
||||
|
||||
#include "../helpers.h"
|
||||
#include <hidsdi.h>
|
||||
#include <setupapi.h>
|
||||
|
||||
|
||||
extern CRITICAL_SECTION CARDIO_HID_CRIT_SECTION;
|
||||
extern struct cardio_hid_device *CARDIO_HID_CONTEXTS;
|
||||
extern size_t CARDIO_HID_CONTEXTS_LENGTH;
|
||||
|
||||
struct cardio_hid_device {
|
||||
LPWSTR dev_path;
|
||||
HANDLE dev_handle;
|
||||
OVERLAPPED read_state;
|
||||
BOOL initialized;
|
||||
BOOL io_pending;
|
||||
|
||||
BYTE report_buffer[128];
|
||||
union {
|
||||
unsigned char usage_value[128];
|
||||
uint64_t usage64[8];
|
||||
} u;
|
||||
DWORD read_size;
|
||||
|
||||
PHIDP_PREPARSED_DATA pp_data;
|
||||
HIDP_CAPS caps;
|
||||
PHIDP_VALUE_CAPS collection;
|
||||
USHORT collection_length;
|
||||
};
|
||||
|
||||
typedef enum cardio_poll_value {
|
||||
HID_POLL_ERROR = 0,
|
||||
HID_POLL_CARD_NOT_READY = 1,
|
||||
HID_POLL_CARD_READY = 2,
|
||||
} cardio_hid_poll_value_t;
|
||||
|
||||
typedef enum cardio_hid_card_type {
|
||||
HID_CARD_NONE = 0,
|
||||
HID_CARD_ISO_15693 = 0x41,
|
||||
HID_CARD_ISO_18092 = 0x42,
|
||||
} cardio_hid_card_type_t;
|
||||
|
||||
BOOL cardio_hid_init();
|
||||
|
||||
void cardio_hid_close();
|
||||
|
||||
BOOL cardio_hid_add_device(LPCWSTR device_path);
|
||||
|
||||
BOOL cardio_hid_remove_device(LPCWSTR device_path);
|
||||
|
||||
BOOL cardio_hid_scan_device(struct cardio_hid_device *ctx, LPCWSTR device_path);
|
||||
|
||||
BOOL cardio_hid_scan();
|
||||
|
||||
cardio_hid_poll_value_t cardio_hid_device_poll(struct cardio_hid_device *ctx);
|
||||
|
||||
cardio_hid_card_type_t cardio_hid_device_read(struct cardio_hid_device *ctx);
|
||||
|
||||
#endif //SPICETOOLS_CARDIO_HID_H
|
138
src/cardio_plugin/dllmain.c
Normal file
138
src/cardio_plugin/dllmain.c
Normal file
@ -0,0 +1,138 @@
|
||||
#include "cardio.h"
|
||||
char module[] = "TAL HID";
|
||||
|
||||
static bool CARDIO_RUNNER_INITIALIZED = false;
|
||||
|
||||
static HANDLE CARDIO_POLL_THREAD;
|
||||
static bool CARDIO_POLL_STOP_FLAG;
|
||||
static bool waitingForTouch = false;
|
||||
|
||||
typedef void (*callbackTouch) (i32, i32, u8[168], u64);
|
||||
callbackTouch touchCallback;
|
||||
u64 touchData;
|
||||
static char AccessID[21] = "00000000000000000001";
|
||||
// static char ChipID[33] = "00000000000000000000000000000001";
|
||||
|
||||
void PollReader(){
|
||||
// update HID devices
|
||||
EnterCriticalSection(&CARDIO_HID_CRIT_SECTION);
|
||||
for (size_t device_no = 0; device_no < CARDIO_HID_CONTEXTS_LENGTH; device_no++) {
|
||||
struct cardio_hid_device *device = &CARDIO_HID_CONTEXTS[device_no];
|
||||
|
||||
// get status
|
||||
cardio_hid_poll_value_t status = cardio_hid_device_poll(device);
|
||||
if (status == HID_POLL_CARD_READY) {
|
||||
|
||||
// read card
|
||||
if (cardio_hid_device_read(device) == HID_CARD_NONE)
|
||||
continue;
|
||||
|
||||
// if card not empty
|
||||
if (*((uint64_t*) &device->u.usage_value[0]) > 0) {
|
||||
printWarning ("%s (%s): Read card %02X%02X%02X%02X%02X%02X%02X%02X\n", __func__, module, device->u.usage_value[0], device->u.usage_value[1], device->u.usage_value[2], device->u.usage_value[3], device->u.usage_value[4], device->u.usage_value[5], device->u.usage_value[6], device->u.usage_value[7]);
|
||||
|
||||
if(waitingForTouch){
|
||||
static u8 cardData[168]
|
||||
= { 0x01, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x2E, 0x58, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x5C, 0x97, 0x44, 0xF0, 0x88, 0x04, 0x00, 0x43, 0x26, 0x2C, 0x33, 0x00, 0x04,
|
||||
0x06, 0x10, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
|
||||
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30,
|
||||
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4E, 0x42, 0x47, 0x49, 0x43, 0x36,
|
||||
0x00, 0x00, 0xFA, 0xE9, 0x69, 0x00, 0xF6, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
//Convert card to proper format
|
||||
sprintf(AccessID, "%020llu", device->u.usage64[0]);
|
||||
LeaveCriticalSection(&CARDIO_HID_CRIT_SECTION);
|
||||
memset(AccessID, '0', 10);
|
||||
|
||||
//Generating a ChipID Derived from the AccessID
|
||||
char ChipID[33] = "000000000000";
|
||||
strcat(ChipID, AccessID);
|
||||
memset(ChipID, '0', 25);
|
||||
|
||||
//Insert card in game
|
||||
printWarning ("%s (%s): AccessID %s, ChipID %s\n", __func__, module, AccessID, ChipID);
|
||||
memcpy (cardData + 0x2C, ChipID, 33);
|
||||
memcpy (cardData + 0x50, AccessID, 21);
|
||||
touchCallback(0, 0, cardData, touchData);
|
||||
}else{
|
||||
LeaveCriticalSection(&CARDIO_HID_CRIT_SECTION);
|
||||
}
|
||||
}else{
|
||||
LeaveCriticalSection(&CARDIO_HID_CRIT_SECTION);
|
||||
}
|
||||
}
|
||||
}
|
||||
Sleep(500);
|
||||
}
|
||||
|
||||
static unsigned int __stdcall cardio_poll_thread_proc(void *ctx)
|
||||
{
|
||||
while (!CARDIO_POLL_STOP_FLAG) {
|
||||
PollReader();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cardio_runner_start() {
|
||||
// initialize
|
||||
if (!CARDIO_RUNNER_INITIALIZED) {
|
||||
CARDIO_RUNNER_INITIALIZED = true;
|
||||
printWarning ("%s (%s): Initializing CARDIO\n", __func__, module);
|
||||
|
||||
// initialize
|
||||
if (!cardio_hid_init()) {
|
||||
printWarning ("%s (%s): Couldn't init CARDIO HID\n", __func__, module);
|
||||
return;
|
||||
}
|
||||
|
||||
// scan HID devices
|
||||
if (!cardio_hid_scan()) {
|
||||
printWarning ("%s (%s): Couldn't scan for CARDIO devices\n", __func__, module);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void cardio_runner_stop() {
|
||||
// shutdown HID
|
||||
cardio_hid_close();
|
||||
|
||||
// set initialized to false
|
||||
CARDIO_RUNNER_INITIALIZED = false;
|
||||
}
|
||||
|
||||
void Init(){
|
||||
printWarning ("%s (%s): Starting HID Service...\n", __func__, module);
|
||||
//Find and initialize reader(s)
|
||||
cardio_runner_start();
|
||||
|
||||
//Start reader thread
|
||||
CARDIO_POLL_STOP_FLAG = false;
|
||||
CARDIO_POLL_THREAD = (HANDLE) _beginthreadex(
|
||||
NULL,
|
||||
0,
|
||||
cardio_poll_thread_proc,
|
||||
NULL,
|
||||
0,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void WaitTouch(i32 (*callback) (i32, i32, u8[168], u64), u64 data){
|
||||
printWarning ("%s (%s): Waiting for touch\n", __func__, module);
|
||||
waitingForTouch = true;
|
||||
touchCallback = callback;
|
||||
touchData = data;
|
||||
}
|
||||
|
||||
void Exit(){
|
||||
cardio_runner_stop();
|
||||
CARDIO_POLL_STOP_FLAG = true;
|
||||
WaitForSingleObject(CARDIO_POLL_THREAD, INFINITE);
|
||||
CloseHandle(CARDIO_POLL_THREAD);
|
||||
CARDIO_POLL_THREAD = NULL;
|
||||
CARDIO_POLL_STOP_FLAG = false;
|
||||
}
|
80
src/helpers.c
Normal file
80
src/helpers.c
Normal file
@ -0,0 +1,80 @@
|
||||
#include "helpers.h"
|
||||
|
||||
void *consoleHandle = 0;
|
||||
|
||||
char *
|
||||
configPath (char *name) {
|
||||
static char buffer[MAX_PATH];
|
||||
GetModuleFileNameA (NULL, buffer, MAX_PATH);
|
||||
*(strrchr (buffer, '\\') + 1) = 0;
|
||||
strcat_s (buffer, MAX_PATH, name);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
toml_table_t *
|
||||
openConfig (char *configFilePath) {
|
||||
FILE *file = fopen (configFilePath, "r");
|
||||
if (!file) {
|
||||
printWarning ("%s (%s): cannot open file\n", __func__, configFilePath);
|
||||
return 0;
|
||||
}
|
||||
char errorbuf[200];
|
||||
toml_table_t *config = toml_parse_file (file, errorbuf, 200);
|
||||
fclose (file);
|
||||
|
||||
if (!config) {
|
||||
printWarning ("%s (%s): %s\n", __func__, configFilePath, errorbuf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
toml_table_t *
|
||||
openConfigSection (toml_table_t *config, char *sectionName) {
|
||||
toml_table_t *section = toml_table_in (config, sectionName);
|
||||
if (!section) {
|
||||
printWarning ("%s (%s): cannot find section\n", __func__, sectionName);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return section;
|
||||
}
|
||||
|
||||
bool
|
||||
readConfigBool (toml_table_t *table, char *key, bool notFoundValue) {
|
||||
toml_datum_t data = toml_bool_in (table, key);
|
||||
if (!data.ok) return notFoundValue;
|
||||
|
||||
return (bool)data.u.b;
|
||||
}
|
||||
|
||||
int64_t
|
||||
readConfigInt (toml_table_t *table, char *key, int64_t notFoundValue) {
|
||||
toml_datum_t data = toml_int_in (table, key);
|
||||
if (!data.ok) return notFoundValue;
|
||||
|
||||
return data.u.i;
|
||||
}
|
||||
|
||||
char *
|
||||
readConfigString (toml_table_t *table, char *key, char *notFoundValue) {
|
||||
toml_datum_t data = toml_string_in (table, key);
|
||||
if (!data.ok) return notFoundValue;
|
||||
|
||||
return data.u.s;
|
||||
}
|
||||
|
||||
void
|
||||
printColour (int colour, const char *format, ...) {
|
||||
va_list args;
|
||||
va_start (args, format);
|
||||
|
||||
if (consoleHandle == 0) consoleHandle = GetStdHandle (STD_OUTPUT_HANDLE);
|
||||
|
||||
SetConsoleTextAttribute (consoleHandle, colour);
|
||||
vprintf (format, args);
|
||||
SetConsoleTextAttribute (consoleHandle, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
|
||||
|
||||
va_end (args);
|
||||
}
|
118
src/helpers.h
Normal file
118
src/helpers.h
Normal file
@ -0,0 +1,118 @@
|
||||
#pragma once
|
||||
#include <MinHook.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <toml.h>
|
||||
#include <windows.h>
|
||||
|
||||
typedef int8_t i8;
|
||||
typedef int16_t i16;
|
||||
typedef int32_t i32;
|
||||
typedef int64_t i64;
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
typedef uint64_t u64;
|
||||
|
||||
#ifdef DEFINE_GUID
|
||||
#undef DEFINE_GUID
|
||||
#endif
|
||||
|
||||
#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) const GUID name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
|
||||
|
||||
#ifdef BASE_ADDRESS
|
||||
#define ASLR(address, handle) ((u64)handle + (u64)address - (u64)BASE_ADDRESS)
|
||||
#endif
|
||||
|
||||
#define FUNCTION_PTR(returnType, callingConvention, function, location, ...) \
|
||||
returnType (callingConvention *function) (__VA_ARGS__) = (returnType (callingConvention *) (__VA_ARGS__)) (location)
|
||||
|
||||
#define PROC_ADDRESS(libraryName, procName) GetProcAddress (LoadLibrary (TEXT (libraryName)), procName)
|
||||
|
||||
#define HOOK(returnType, callingConvention, functionName, location, ...) \
|
||||
typedef returnType callingConvention (*functionName) (__VA_ARGS__); \
|
||||
functionName original##functionName = NULL; \
|
||||
void *where##functionName = (void *)location; \
|
||||
returnType callingConvention implOf##functionName (__VA_ARGS__)
|
||||
|
||||
#define HOOK_DYNAMIC(returnType, callingConvention, functionName, ...) \
|
||||
typedef returnType callingConvention (*functionName) (__VA_ARGS__); \
|
||||
functionName original##functionName = NULL; \
|
||||
void *where##functionName = NULL; \
|
||||
returnType callingConvention implOf##functionName (__VA_ARGS__)
|
||||
|
||||
#define INSTALL_HOOK(functionName) \
|
||||
{ \
|
||||
MH_Initialize (); \
|
||||
MH_CreateHook ((void *)where##functionName, (void *)implOf##functionName, (void **)(&original##functionName)); \
|
||||
MH_EnableHook ((void *)where##functionName); \
|
||||
}
|
||||
|
||||
#define INSTALL_HOOK_DYNAMIC(functionName, location) \
|
||||
{ \
|
||||
where##functionName = (void *)location; \
|
||||
INSTALL_HOOK (functionName); \
|
||||
}
|
||||
|
||||
#define WRITE_MEMORY(location, type, ...) \
|
||||
{ \
|
||||
const type data[] = { __VA_ARGS__ }; \
|
||||
DWORD oldProtect; \
|
||||
VirtualProtect ((void *)(location), sizeof (data), PAGE_EXECUTE_READWRITE, &oldProtect); \
|
||||
memcpy ((void *)(location), data, sizeof (data)); \
|
||||
VirtualProtect ((void *)(location), sizeof (data), oldProtect, &oldProtect); \
|
||||
}
|
||||
|
||||
#define WRITE_MEMORY_STRING(location, data, length) \
|
||||
{ \
|
||||
DWORD oldProtect; \
|
||||
VirtualProtect ((void *)(location), length, PAGE_EXECUTE_READWRITE, &oldProtect); \
|
||||
memcpy ((void *)(location), data, length); \
|
||||
VirtualProtect ((void *)(location), length, oldProtect, &oldProtect); \
|
||||
}
|
||||
|
||||
#define WRITE_NOP(location, count) \
|
||||
{ \
|
||||
DWORD oldProtect; \
|
||||
VirtualProtect ((void *)(location), (size_t)(count), PAGE_EXECUTE_READWRITE, &oldProtect); \
|
||||
for (size_t i = 0; i < (size_t)(count); i++) \
|
||||
*((uint8_t *)(location) + i) = 0x90; \
|
||||
VirtualProtect ((void *)(location), (size_t)(count), oldProtect, &oldProtect); \
|
||||
}
|
||||
|
||||
#define WRITE_NULL(location, count) \
|
||||
{ \
|
||||
DWORD oldProtect; \
|
||||
VirtualProtect ((void *)(location), (size_t)(count), PAGE_EXECUTE_READWRITE, &oldProtect); \
|
||||
for (size_t i = 0; i < (size_t)(count); i++) \
|
||||
*((uint8_t *)(location) + i) = 0x00; \
|
||||
VirtualProtect ((void *)(location), (size_t)(count), oldProtect, &oldProtect); \
|
||||
}
|
||||
|
||||
#define COUNTOFARR(arr) sizeof (arr) / sizeof (arr[0])
|
||||
#define RETURN_FALSE(returnType, callingConvention, functionName, ...) \
|
||||
returnType callingConvention functionName (__VA_ARGS__) { return 0; }
|
||||
#define RETURN_TRUE(returnType, callingConvention, functionName, ...) \
|
||||
returnType callingConvention functionName (__VA_ARGS__) { return 1; }
|
||||
|
||||
#define INFO_COLOUR FOREGROUND_GREEN
|
||||
#define WARNING_COLOUR (FOREGROUND_RED | FOREGROUND_GREEN)
|
||||
#define ERROR_COLOUR FOREGROUND_RED
|
||||
#define printInfo(format, ...) printColour (INFO_COLOUR, format, __VA_ARGS__)
|
||||
#define printWarning(format, ...) printColour (WARNING_COLOUR, format, __VA_ARGS__)
|
||||
#define printError(format, ...) printColour (ERROR_COLOUR, format, __VA_ARGS__)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
char *configPath (char *name);
|
||||
toml_table_t *openConfig (char *configFilePath);
|
||||
toml_table_t *openConfigSection (toml_table_t *config, char *sectionName);
|
||||
bool readConfigBool (toml_table_t *table, char *key, bool notFoundValue);
|
||||
int64_t readConfigInt (toml_table_t *table, char *key, int64_t notFoundValue);
|
||||
char *readConfigString (toml_table_t *table, char *key, char *notFoundValue);
|
||||
void printColour (int colour, const char *format, ...);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
25
src/meson.build
Normal file
25
src/meson.build
Normal file
@ -0,0 +1,25 @@
|
||||
compiler = meson.get_compiler('c')
|
||||
hid_lib = compiler.find_library('hid')
|
||||
setupapi_lib = compiler.find_library('setupapi')
|
||||
|
||||
deps = [
|
||||
dependency('tomlc99'),
|
||||
dependency('minhook'),
|
||||
hid_lib,
|
||||
setupapi_lib
|
||||
]
|
||||
|
||||
shared_library(
|
||||
'cardio',
|
||||
implicit_include_directories : false,
|
||||
vs_module_defs : 'cardio.def',
|
||||
sources: [
|
||||
'helpers.c',
|
||||
'cardio_plugin/dllmain.c',
|
||||
'cardio_plugin/cardio.c',
|
||||
],
|
||||
dependencies: deps,
|
||||
include_directories: [
|
||||
inc
|
||||
]
|
||||
)
|
6
subprojects/minhook.wrap
Normal file
6
subprojects/minhook.wrap
Normal file
@ -0,0 +1,6 @@
|
||||
[wrap-git]
|
||||
url = https://github.com/TsudaKageyu/minhook
|
||||
revision = 426cb6880035ee3cceed05384bb3f2db01a20a15
|
||||
# Overlays subproject/packagefiles/minhook over the fresh git
|
||||
# clone of minhook
|
||||
patch_directory = minhook
|
29
subprojects/packagefiles/minhook/meson.build
Normal file
29
subprojects/packagefiles/minhook/meson.build
Normal file
@ -0,0 +1,29 @@
|
||||
project(
|
||||
'minhook',
|
||||
'c',
|
||||
default_options : ['c_std=c99']
|
||||
)
|
||||
|
||||
sources = files(
|
||||
'src/buffer.c',
|
||||
'src/hde/hde32.c',
|
||||
'src/hde/hde64.c',
|
||||
'src/hook.c',
|
||||
'src/trampoline.c'
|
||||
)
|
||||
|
||||
includes = include_directories('include')
|
||||
|
||||
minhook_lib = static_library(
|
||||
'minhook',
|
||||
sources,
|
||||
include_directories: includes,
|
||||
)
|
||||
|
||||
minhook_dep = declare_dependency(
|
||||
include_directories: includes,
|
||||
link_with: minhook_lib,
|
||||
)
|
||||
|
||||
meson.override_dependency('minhook', minhook_dep)
|
||||
|
22
subprojects/packagefiles/tomlc99/meson.build
Normal file
22
subprojects/packagefiles/tomlc99/meson.build
Normal file
@ -0,0 +1,22 @@
|
||||
project(
|
||||
'tomlc99',
|
||||
'c',
|
||||
default_options : ['c_std=c99']
|
||||
)
|
||||
|
||||
sources = files('toml.c')
|
||||
|
||||
includes = include_directories('.')
|
||||
|
||||
tomlc99_lib = static_library(
|
||||
'tomlc99',
|
||||
sources,
|
||||
include_directories: includes,
|
||||
)
|
||||
|
||||
tomlc99_dep = declare_dependency(
|
||||
include_directories: includes,
|
||||
link_with: tomlc99_lib,
|
||||
)
|
||||
|
||||
meson.override_dependency('tomlc99', tomlc99_dep)
|
6
subprojects/tomlc99.wrap
Normal file
6
subprojects/tomlc99.wrap
Normal file
@ -0,0 +1,6 @@
|
||||
[wrap-git]
|
||||
url = https://github.com/cktan/tomlc99
|
||||
revision = 894902820a3ea2f1ec470cd7fe338bde54045cf5
|
||||
# Overlays subproject/packagefiles/tomlc99 over the fresh git
|
||||
# clone of tomlc99
|
||||
patch_directory = tomlc99
|
Loading…
Reference in New Issue
Block a user