diff --git a/.cargo/config.toml b/.cargo/config.toml
new file mode 100644
index 0000000..1350557
--- /dev/null
+++ b/.cargo/config.toml
@@ -0,0 +1,2 @@
+[alias]
+xtask = "run --package xtask --"
diff --git a/.env.example b/.env.example
new file mode 100644
index 0000000..68dc749
--- /dev/null
+++ b/.env.example
@@ -0,0 +1 @@
+CHIVALRY2_DIR='C:\Program Files (x86)\Steam\steamapps\common\Chivalry 2'
\ No newline at end of file
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 0bac567..78d32b4 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,4 +1,4 @@
-name: C++ CI
+name: Rust CI
on:
push:
@@ -10,7 +10,7 @@ jobs:
runs-on: windows-2022
strategy:
matrix:
- build_type: [Debug, Release]
+ build_type: [debug, release]
steps:
- uses: actions/checkout@v3
@@ -26,31 +26,36 @@ jobs:
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
- sleuth/target
+ target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}-${{ matrix.build_type }}
- - uses: lukka/get-cmake@latest
-
- uses: actions-rust-lang/setup-rust-toolchain@v1
- # Ensure build directory exists
- - name: Create build directory
- run: mkdir -p ${{github.workspace}}/build
-
- # Use the latest Visual Studio toolset in CMake
- - name: Configure CMake
+ # Run tests
+ - name: Test
+ shell: bash
run: |
- cmake -B ${{github.workspace}}/build -G "Visual Studio 17 2022" -A x64 -DCMAKE_CXX_COMPILER=cl -DCMAKE_C_COMPILER=cl -T v143 -DCMAKE_BUILD_TYPE=${{matrix.build_type}}
+ if [ "${{ matrix.build_type }}" == "release" ]; then
+ cargo test --release
+ else
+ cargo test
+ fi
# Build the project
- name: Build
+ shell: bash
run: |
- cmake --build ${{github.workspace}}/build --config ${{matrix.build_type}}
+ if [ "${{ matrix.build_type }}" == "release" ]; then
+ cargo build --release
+ else
+ cargo build
+ fi
# Upload artifacts if build succeeds
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: UnchainedPlugin-${{matrix.build_type}}
- path: ${{github.workspace}}/build/Output/*
- if-no-files-found: warn # Don't fail if no files are found
\ No newline at end of file
+ path: |
+ target/${{ matrix.build_type }}/UnchainedPlugin.dll
+ if-no-files-found: warn
\ No newline at end of file
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 6204d3c..8266ae4 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -6,7 +6,7 @@ permissions:
on:
push:
tags:
- - 'v*' # Trigger on tags starting with 'v'
+ - 'v*'
jobs:
build:
@@ -25,11 +25,9 @@ jobs:
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
- sleuth/target
+ target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}-Release
- - uses: lukka/get-cmake@latest
-
- uses: actions-rust-lang/setup-rust-toolchain@v1
# Extract version from tag (remove 'v' prefix)
@@ -37,22 +35,28 @@ jobs:
id: get_version
shell: bash
run: |
- echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
- echo "Extracted version: ${GITHUB_REF#refs/tags/v}"
-
- # Create build directory
- - name: Create build directory
- run: mkdir -p ${{github.workspace}}/build
+ VERSION=${GITHUB_REF#refs/tags/v}
+ echo "VERSION=$VERSION" >> $GITHUB_OUTPUT
+ echo "Extracted version: $VERSION"
- # Configure CMake with the version from tag
- - name: Configure CMake
+ # Check if version in Cargo.toml matches the tag
+ - name: Verify version matches tag
+ shell: bash
run: |
- cmake -B ${{github.workspace}}/build -G "Visual Studio 17 2022" -A x64 -DCMAKE_CXX_COMPILER=cl -DCMAKE_C_COMPILER=cl -T v143 -DCMAKE_BUILD_TYPE=Release -DVERSION="${{ steps.get_version.outputs.VERSION }}"
+ CARGO_VERSION=$(grep -m 1 '^version = ' Cargo.toml | sed 's/version = "\(.*\)"/\1/')
+ TAG_VERSION=${{ steps.get_version.outputs.VERSION }}
+ if [ "$CARGO_VERSION" != "$TAG_VERSION" ]; then
+ echo "Error: Cargo.toml version ($CARGO_VERSION) does not match tag version ($TAG_VERSION)"
+ exit 1
+ fi
+
+ # Run tests
+ - name: Test
+ run: cargo test --release
# Build the project
- name: Build
- run: |
- cmake --build ${{github.workspace}}/build --config Release
+ run: cargo build --release
# Create GitHub Release
- name: Create Release
@@ -62,7 +66,7 @@ jobs:
name: UnchainedPlugin v${{ steps.get_version.outputs.VERSION }}
draft: false
prerelease: false
- files: ${{github.workspace}}/build/Output/Release/UnchainedPlugin.dll
+ files: target/release/UnchainedPlugin.dll
generate_release_notes: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index c0b9891..26e7de2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,11 +10,24 @@
*.userosscache
*.sln.docstates
-sleuth/target/
+# Crate-specific ignore patterns (Cleanup from previous reorganization)
+# (Removing old sleuth/ references since it was moved to root)
CMakeFiles
Output
-.vscode
+# .vscode files
+.vscode/*
+!.vscode/launch.json
+!.vscode/tasks.json
+.env
+
+# RustRover / IntelliJ IDEA
+.idea/*
+!.idea/runConfigurations
+!.idea/modules.xml
+!.idea/vcs.xml
+!.idea/misc.xml
+!.idea/UnchainedPlugin.iml
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
@@ -41,7 +54,8 @@ bld/
[Bb]uild/
[Bb]uild[Ff]iles/
-.idea
+# Removed sleuth directory structure
+# .idea is now partially tracked
# Visual Studio 2015/2017 cache/options directory
.vs/
@@ -369,5 +383,7 @@ MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
-# Fody - auto-generated XML schema
-FodyWeavers.xsd
\ No newline at end of file
+
+target/
+
+extra-context
\ No newline at end of file
diff --git a/.idea/UnchainedPlugin.iml b/.idea/UnchainedPlugin.iml
new file mode 100644
index 0000000..b4b9e4f
--- /dev/null
+++ b/.idea/UnchainedPlugin.iml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..0b76fe5
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..1b7deee
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations/Attach_to_Chivalry_2.xml b/.idea/runConfigurations/Attach_to_Chivalry_2.xml
new file mode 100644
index 0000000..4ae390a
--- /dev/null
+++ b/.idea/runConfigurations/Attach_to_Chivalry_2.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/.idea/runConfigurations/Build_UnchainedPlugin.xml b/.idea/runConfigurations/Build_UnchainedPlugin.xml
new file mode 100644
index 0000000..4291b96
--- /dev/null
+++ b/.idea/runConfigurations/Build_UnchainedPlugin.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations/Build_and_Install_UnchainedPlugin.xml b/.idea/runConfigurations/Build_and_Install_UnchainedPlugin.xml
new file mode 100644
index 0000000..1849bb8
--- /dev/null
+++ b/.idea/runConfigurations/Build_and_Install_UnchainedPlugin.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.idea/runConfigurations/Debug_Mock_Server.xml b/.idea/runConfigurations/Debug_Mock_Server.xml
new file mode 100644
index 0000000..f3f1a40
--- /dev/null
+++ b/.idea/runConfigurations/Debug_Mock_Server.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.idea/runConfigurations/Debug_Mock_Server__Integrated_.xml b/.idea/runConfigurations/Debug_Mock_Server__Integrated_.xml
new file mode 100644
index 0000000..ca69b99
--- /dev/null
+++ b/.idea/runConfigurations/Debug_Mock_Server__Integrated_.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.idea/runConfigurations/Install_UnchainedPlugin.xml b/.idea/runConfigurations/Install_UnchainedPlugin.xml
new file mode 100644
index 0000000..fd318f7
--- /dev/null
+++ b/.idea/runConfigurations/Install_UnchainedPlugin.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.idea/runConfigurations/Launch_Chivalry2_with_Unchained_Plugin.xml b/.idea/runConfigurations/Launch_Chivalry2_with_Unchained_Plugin.xml
new file mode 100644
index 0000000..649ff1e
--- /dev/null
+++ b/.idea/runConfigurations/Launch_Chivalry2_with_Unchained_Plugin.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.idea/runConfigurations/Launch_Chivalry_2.xml b/.idea/runConfigurations/Launch_Chivalry_2.xml
new file mode 100644
index 0000000..cfedc6d
--- /dev/null
+++ b/.idea/runConfigurations/Launch_Chivalry_2.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..a7c3532
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..d748d75
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,37 @@
+{
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": "Launch Chivalry2 with Unchained Plugin",
+ "type": "cppvsdbg",
+ "request": "launch",
+ "program": "${env:CHIVALRY2_DIR}/TBL/Binaries/Win64/Chivalry2-Win64-Shipping.exe",
+ "args": ["-fileopenlog"],
+ "stopAtEntry": false,
+ "cwd": "${env:CHIVALRY2_DIR}/TBL/Binaries/Win64",
+ "envFile": "${workspaceFolder}/.env",
+ "environment": [],
+ "externalConsole": false
+ },
+ {
+ "name": "Attach to Chivalry 2",
+ "type": "cppvsdbg",
+ "request": "attach",
+ "processId": "${command:pickProcess}"
+ },
+ {
+ "name": "Debug Mock Server (Integrated)",
+ "type": "cppvsdbg",
+ "request": "launch",
+ "program": "${workspaceFolder}/target/debug/mock_server.exe",
+ "args": [],
+ "stopAtEntry": false,
+ "cwd": "${workspaceFolder}",
+ "envFile": "${workspaceFolder}/.env",
+ "environment": [],
+ "externalConsole": false,
+ "console": "integratedTerminal",
+ "preLaunchTask": "cargo-build-mock"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
new file mode 100644
index 0000000..cdda1ca
--- /dev/null
+++ b/.vscode/tasks.json
@@ -0,0 +1,51 @@
+{
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "label": "Build UnchainedPlugin",
+ "type": "shell",
+ "command": "cargo build",
+ "group": {
+ "kind": "build",
+ "isDefault": true
+ },
+ "presentation": {
+ "reveal": "always",
+ "panel": "new"
+ },
+ "problemMatcher": ["$rustc"]
+ },
+ {
+ "label": "cargo-build-mock",
+ "type": "shell",
+ "command": "cargo build --bin mock_server",
+ "options": {
+ "cwd": "${workspaceFolder}"
+ },
+ "problemMatcher": ["$rustc"]
+ },
+ {
+ "label": "Install UnchainedPlugin",
+ "type": "shell",
+ "command": "cargo xtask install",
+ "dependsOn": "Build UnchainedPlugin",
+ "group": "build",
+ "presentation": {
+ "reveal": "always",
+ "panel": "new"
+ },
+ "problemMatcher": ["$rustc"]
+ },
+ {
+ "label": "Build and Install UnchainedPlugin",
+ "type": "shell",
+ "command": "cargo xtask install --rebuild",
+ "group": "build",
+ "presentation": {
+ "reveal": "always",
+ "panel": "new"
+ },
+ "problemMatcher": ["$rustc"]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
deleted file mode 100644
index 3090b80..0000000
--- a/CMakeLists.txt
+++ /dev/null
@@ -1,126 +0,0 @@
-cmake_minimum_required(VERSION 3.10)
-
-# Set default version if not specified
-if(NOT DEFINED VERSION)
- set(VERSION "0.0.0")
-else()
- # Remove the 'v' prefix if it exists
- string(REGEX REPLACE "^v" "" VERSION ${VERSION})
-endif()
-
-project(UnchainedPlugin
- VERSION ${VERSION}
- LANGUAGES CXX C)
-
-# Parse the version into components
-string(REGEX MATCH "^([0-9]+)\\.([0-9]+)\\.([0-9]+)" VERSION_MATCH ${VERSION})
-if(VERSION_MATCH)
- set(VERSION_MAJOR ${CMAKE_MATCH_1})
- set(VERSION_MINOR ${CMAKE_MATCH_2})
- set(VERSION_PATCH ${CMAKE_MATCH_3})
-else()
- # Fallback if version doesn't match expected format
- set(VERSION_MAJOR 0)
- set(VERSION_MINOR 0)
- set(VERSION_PATCH 0)
-endif()
-
-
-# C++ standard requirements
-set(CMAKE_CXX_STANDARD 20)
-set(CMAKE_CXX_STANDARD_REQUIRED ON)
-
-set(CMAKE_BUILD_PARALLEL_LEVEL ${CMAKE_HOST_SYSTEM_PROCESSOR_COUNT})
-
-set(CMAKE_MSVC_RUNTIME_LIBRARY "$,MultiThreadedDLL,MultiThreadedDebugDLL>")
-
-# Options
-option(POST_BUILD_COPY "Copy output file to specified dir" OFF)
-set(POST_BUILD_COPY_DIR "I:\\Epic Games\\Chivalry2_c\\TBL\\Binaries\\Win64\\Plugins" CACHE STRING "Directory to copy to")
-
-# Generates a header file which includes all the headers of the source dir.
-function(generate_include_all_header SOURCE_DIR FILE_NAME)
- file(GLOB HEADER_FILES "${SOURCE_DIR}/*.h" "${SOURCE_DIR}/*.hpp")
- set(INCLUDE_ALL_CONTENT "// GENERATED FILE, DO NOT MODIFY\n")
- string(APPEND INCLUDE_ALL_CONTENT "// GENERATED FILE, DO NOT MODIFY\n")
- string(APPEND INCLUDE_ALL_CONTENT "// GENERATED FILE, DO NOT MODIFY\n")
- string(APPEND INCLUDE_ALL_CONTENT "// GENERATED FILE, DO NOT MODIFY\n")
- string(APPEND INCLUDE_ALL_CONTENT "\n")
- string(APPEND INCLUDE_ALL_CONTENT "// Reload the cmake configuration to regenerate this file.\n")
- string(APPEND INCLUDE_ALL_CONTENT "#pragma once\n")
- foreach(header ${HEADER_FILES})
- get_filename_component(header_name ${header} NAME)
- if(NOT header_name MATCHES ${FILE_NAME})
- string(APPEND INCLUDE_ALL_CONTENT "#include \"${header_name}\"\n")
- endif()
- endforeach()
- file(WRITE "${SOURCE_DIR}/${FILE_NAME}" "${INCLUDE_ALL_CONTENT}")
-endfunction()
-
-generate_include_all_header("src/hooks" "all_hooks.h")
-generate_include_all_header("src/logging/formatters" "all_formatters.h")
-
-# File collection
-file(GLOB_RECURSE SOURCES "src/*.cpp" "src/*.c")
-file(GLOB_RECURSE HEADERS CONFIGUE_DEPENDS "src/*.hpp" "src/*.h")
-
-# Configure version resource
-configure_file(
- ${CMAKE_CURRENT_SOURCE_DIR}/version.rc.in
- ${CMAKE_CURRENT_BINARY_DIR}/version.rc
- @ONLY
-)
-
-# Add dependencies
-add_subdirectory(lib/MinHook)
-add_subdirectory(lib/tiny-json)
-
-# Define the library
-add_library(${PROJECT_NAME} SHARED
- ${SOURCES}
- ${HEADERS}
- ${CMAKE_CURRENT_BINARY_DIR}/version.rc
-)
-
-# Target properties
-set_target_properties(${PROJECT_NAME} PROPERTIES
- RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/Output"
-)
-
-# Include directories
-target_include_directories(${PROJECT_NAME} PUBLIC
- ${CMAKE_CURRENT_SOURCE_DIR}/include
- ${CMAKE_CURRENT_SOURCE_DIR}/lib/Sig
-)
-
-target_compile_options(${PROJECT_NAME} PRIVATE /MP)
-target_compile_definitions(${PROJECT_NAME} PRIVATE
- NOMINMAX # Prevent Windows.h from defining min/max macros
- _DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR # Fix mutex issues on some versions of the cpp redist
- # CHAT_COMMANDS # Enable this to enable chat commands to be sent from clients to the server
-)
-
-add_subdirectory(sleuth)
-
-# Link libraries
-target_link_libraries(${PROJECT_NAME} PRIVATE
- MinHook
- tiny-json
- winhttp
- sleuthlib_interface
-)
-
-# Source grouping for better organization in IDEs
-source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SOURCES} ${HEADERS})
-
-# Post-build copy
-if(POST_BUILD_COPY)
- add_custom_command(
- TARGET ${PROJECT_NAME} POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E copy
- "$"
- "${POST_BUILD_COPY_DIR}/${PROJECT_NAME}.dll"
- COMMAND ${CMAKE_COMMAND} -E echo
- "${PROJECT_NAME}.dll copied to ${POST_BUILD_COPY_DIR}"
- )
-endif()
\ No newline at end of file
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..cadbdc6
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,189 @@
+# Contributing to Unchained Plugin
+
+Thank you for your interest in contributing! This guide will help you understand how to extend the plugin with new commands, vote types, and event subscribers.
+
+## Creating a New Command
+
+The command system uses a trait-based approach integrated with `clap` for argument parsing.
+
+### 1. Define Command Arguments
+Create a struct for your command's arguments and derive `Parser` and `CommandFactory`.
+
+```rust
+use clap::{Parser, CommandFactory};
+
+#[derive(Parser, CommandFactory, Clone, Debug)]
+#[command(name = "mycommand", about = "Description of what my command does")]
+pub struct MyCommandArgs {
+ #[arg(help = "A required argument")]
+ pub target: String,
+}
+```
+
+### 2. Implement the `Command` Trait
+Implement the `Command` trait for your command struct.
+
+```rust
+use async_trait::async_trait;
+use crate::commands::{Command, CommandResult};
+use crate::events::models::{CommandRequest, PermissionFlags};
+
+pub struct MyCommand;
+
+#[async_trait]
+impl Command for MyCommand {
+ fn required_permissions(&self) -> PermissionFlags {
+ PermissionFlags::all() // Or specific flags
+ }
+
+ async fn execute(&self, args: MyCommandArgs, req: &CommandRequest) {
+ // Your logic here
+ println!("Executing mycommand with target: {}", args.target);
+ }
+}
+```
+
+### 3. Register the Command
+Commands must be registered to the `CommandSubscriber`.
+
+- **Always Active**: Register in `src/features/events.rs` within `initialize_subscribers`.
+- **Discord Only**: Register in `src/features/discord.rs` (if applicable).
+
+Example in `src/features/events.rs`:
+```rust
+command_subscriber.register(MyCommand);
+```
+
+---
+
+## Creating a New Vote Type
+
+The voting system is similar to the command system but uses the `VoteType` trait.
+
+### 1. Define Vote Arguments
+Define a struct for the vote's arguments using `clap`.
+
+```rust
+#[derive(Parser, CommandFactory, Clone, Debug)]
+#[command(name = "myvote")]
+pub struct MyVoteArgs {
+ pub value: i32,
+}
+```
+
+### 2. Implement the `VoteType` Trait
+Implement `VoteType` for your vote logic.
+
+```rust
+use crate::modules::vote::VoteType;
+
+pub struct MyVote;
+
+impl VoteType for MyVote {
+ fn title(&self) -> String { "My Vote".to_string() }
+ fn description(&self) -> String { "Vote for something".to_string() }
+ fn vote_description(&self, args: MyVoteArgs) -> String {
+ format!("Should we set the value to {}?", args.value)
+ }
+ fn min_yes_vote_ratio(&self) -> f32 { 0.5 }
+ fn min_votes_required_ratio(&self) -> f32 { 0.2 }
+ fn on_success(&self, args: MyVoteArgs) {
+ // Success logic
+ }
+ fn clone_box(&self) -> Box {
+ Box::new(VoteTypeHandler::new(self.clone()))
+ }
+}
+```
+
+### 3. Register the Vote Type
+Register your vote type to the `VoteCommand` in `src/features/events.rs` within `initalize_vote_commands`.
+
+```rust
+vote_command.register(MyVote).await;
+```
+
+---
+
+## Creating a New Subscriber
+
+Subscribers listen for events on an `EventBus`.
+
+### 1. Implement the `Subscriber` Trait
+Implement `Subscriber` for the event type you are interested in (e.g., `GameEvent` or `BroadcastMessage`).
+
+```rust
+use async_trait::async_trait;
+use crate::events::bus::Subscriber;
+
+pub struct MySubscriber;
+
+#[async_trait]
+impl Subscriber for MySubscriber {
+ fn identifier(&self) -> &'static str { "MySubscriber" }
+
+ async fn on_event(&mut self, event: &GameEvent) {
+ // Handle the event
+ }
+
+ async fn on_tick(&mut self) {
+ // Optional: periodic logic
+ }
+}
+```
+
+### 2. Register the Subscriber
+Register the subscriber to the appropriate bus in `src/features/events.rs`.
+
+```rust
+let _ = game_event_bus.subscribe(Box::new(MySubscriber)).await;
+```
+
+## Architecture and State Management
+
+### Global Statics vs. Dependency Injection
+
+This project operates by injecting a DLL into Chivalry 2. Because we do not have full control over the game's methods or their lifecycle, some **globally accessible mutable static values** are necessary to share state between DLL hooks.
+
+However, **you should avoid adding new global statics** whenever possible.
+
+- **Global Statics**: Should only be used if the state *must* be accessible inside a low-level DLL Hook.
+- **Dependency Injection**: For all other components (Commands, Votes, Subscribers), you should inject the dependencies they need (such as event publishers or shared state) into their structs during initialization.
+
+### Example: Injecting Dependencies
+
+When creating a new component, pass its dependencies through its constructor:
+
+```rust
+pub struct MySubscriber {
+ broadcaster: &'static EventPublisher,
+ shared_data: Arc>,
+}
+
+impl MySubscriber {
+ pub fn new(
+ broadcaster: &'static EventPublisher,
+ shared_data: Arc>
+ ) -> Self {
+ Self { broadcaster, shared_data }
+ }
+}
+```
+
+Then, initialize and register it in `src/features/events.rs`:
+
+```rust
+let my_data = Arc::new(Mutex::new(MyData::new()));
+let my_subscriber = MySubscriber::new(broadcast_message_publisher, my_data);
+let _ = game_event_bus.subscribe(Box::new(my_subscriber)).await;
+```
+
+---
+
+## Logs Location
+
+If you need to debug or check the plugin's output, you can find the logs in the following directory:
+
+`%localappdata%/Chivalry 2/Saved_{saveddirsuffix}/Logs`
+
+Replace `{saveddirsuffix}` with the appropriate suffix for your installation (e.g., `Steam` or `Epic`).
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..82032f8
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,3780 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "UnchainedPlugin"
+version = "1.0.0-RC1"
+dependencies = [
+ "a2s",
+ "anyhow",
+ "async-trait",
+ "backtrace",
+ "bitflags 2.11.0",
+ "censor",
+ "clap",
+ "crc32c",
+ "crossbeam-channel",
+ "emojis",
+ "futures",
+ "inventory",
+ "itertools 0.14.0",
+ "log",
+ "log4rs",
+ "memmap2",
+ "notify",
+ "notify-debouncer-mini",
+ "once_cell",
+ "parking_lot",
+ "paste",
+ "patternsleuth",
+ "pdb",
+ "quote",
+ "rand 0.9.2",
+ "regex",
+ "reqwest 0.12.28",
+ "retour",
+ "serde",
+ "serde_json",
+ "serde_urlencoded",
+ "serde_yaml",
+ "serenity",
+ "shlex",
+ "simple-log",
+ "sleuth_macros",
+ "strum 0.26.3",
+ "tokio",
+ "tracing",
+ "unicode-segmentation",
+ "ureq",
+ "widestring",
+ "winapi",
+ "windows",
+ "winres",
+]
+
+[[package]]
+name = "a2s"
+version = "0.5.2"
+source = "git+https://github.com/Knutschbert/a2s-rs.git?rev=0376331#0376331fb19cdb9eb8fef7fa9c79ee58f1b53397"
+dependencies = [
+ "byteorder",
+ "bzip2",
+ "crc",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "addr2line"
+version = "0.25.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b"
+dependencies = [
+ "gimli",
+]
+
+[[package]]
+name = "adler2"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "android_system_properties"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "anstream"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-query",
+ "anstyle-wincon",
+ "colorchoice",
+ "is_terminal_polyfill",
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle"
+version = "1.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000"
+
+[[package]]
+name = "anstyle-parse"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e"
+dependencies = [
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle-query"
+version = "1.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
+dependencies = [
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "3.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
+dependencies = [
+ "anstyle",
+ "once_cell_polyfill",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.102"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
+
+[[package]]
+name = "arc-swap"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a07d1f37ff60921c83bdfc7407723bdefe89b44b98a9b772f225c8f9d67141a6"
+dependencies = [
+ "rustversion",
+]
+
+[[package]]
+name = "arrayvec"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "async-trait"
+version = "0.1.89"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "atomic-waker"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
+
+[[package]]
+name = "autocfg"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
+
+[[package]]
+name = "backtrace"
+version = "0.3.76"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6"
+dependencies = [
+ "addr2line",
+ "cfg-if",
+ "libc",
+ "miniz_oxide",
+ "object 0.37.3",
+ "rustc-demangle",
+ "windows-link",
+]
+
+[[package]]
+name = "base64"
+version = "0.22.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "bitflags"
+version = "2.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af"
+
+[[package]]
+name = "block-buffer"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "build_const"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4ae4235e6dac0694637c763029ecea1a2ec9e4e06ec2729bd21ba4d9c863eb7"
+
+[[package]]
+name = "bumpalo"
+version = "3.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
+
+[[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
+[[package]]
+name = "bytes"
+version = "1.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
+
+[[package]]
+name = "bzip2"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8"
+dependencies = [
+ "bzip2-sys",
+ "libc",
+]
+
+[[package]]
+name = "bzip2-sys"
+version = "0.1.13+1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14"
+dependencies = [
+ "cc",
+ "pkg-config",
+]
+
+[[package]]
+name = "camino"
+version = "1.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48"
+dependencies = [
+ "serde_core",
+]
+
+[[package]]
+name = "cargo-platform"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "cargo_metadata"
+version = "0.19.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba"
+dependencies = [
+ "camino",
+ "cargo-platform",
+ "semver",
+ "serde",
+ "serde_json",
+ "thiserror 2.0.18",
+]
+
+[[package]]
+name = "cc"
+version = "1.2.57"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423"
+dependencies = [
+ "find-msvc-tools",
+ "shlex",
+]
+
+[[package]]
+name = "censor"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d41e3b9fdbb9b3edc10dc66a06dc255822f699c432e19403fb966e6d60e0dec4"
+dependencies = [
+ "once_cell",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
+
+[[package]]
+name = "chrono"
+version = "0.4.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0"
+dependencies = [
+ "iana-time-zone",
+ "num-traits",
+ "windows-link",
+]
+
+[[package]]
+name = "clap"
+version = "4.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351"
+dependencies = [
+ "clap_builder",
+ "clap_derive",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "clap_lex",
+ "strsim",
+]
+
+[[package]]
+name = "clap_derive"
+version = "4.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a"
+dependencies = [
+ "heck 0.5.0",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "clap_lex"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
+
+[[package]]
+name = "colorchoice"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
+
+[[package]]
+name = "core-foundation"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "core-foundation"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
+
+[[package]]
+name = "cpufeatures"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "crc"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb"
+dependencies = [
+ "build_const",
+]
+
+[[package]]
+name = "crc32c"
+version = "0.6.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a47af21622d091a8f0fb295b88bc886ac74efcc613efc19f5d0b21de5c89e47"
+dependencies = [
+ "rustc_version",
+]
+
+[[package]]
+name = "crc32fast"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "crossbeam-channel"
+version = "0.5.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2"
+dependencies = [
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-deque"
+version = "0.8.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
+dependencies = [
+ "crossbeam-epoch",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-epoch"
+version = "0.9.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
+dependencies = [
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
+
+[[package]]
+name = "crypto-common"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
+dependencies = [
+ "generic-array",
+ "typenum",
+]
+
+[[package]]
+name = "darling"
+version = "0.20.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee"
+dependencies = [
+ "darling_core",
+ "darling_macro",
+]
+
+[[package]]
+name = "darling_core"
+version = "0.20.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e"
+dependencies = [
+ "fnv",
+ "ident_case",
+ "proc-macro2",
+ "quote",
+ "strsim",
+ "syn",
+]
+
+[[package]]
+name = "darling_macro"
+version = "0.20.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
+dependencies = [
+ "darling_core",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "dashmap"
+version = "5.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
+dependencies = [
+ "cfg-if",
+ "hashbrown 0.14.5",
+ "lock_api",
+ "once_cell",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "data-encoding"
+version = "2.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea"
+
+[[package]]
+name = "deranged"
+version = "0.5.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
+dependencies = [
+ "powerfmt",
+ "serde_core",
+]
+
+[[package]]
+name = "derive_more"
+version = "0.99.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "derive_more"
+version = "2.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134"
+dependencies = [
+ "derive_more-impl",
+]
+
+[[package]]
+name = "derive_more-impl"
+version = "2.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "rustc_version",
+ "syn",
+ "unicode-xid",
+]
+
+[[package]]
+name = "destructure_traitobject"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c877555693c14d2f84191cfd3ad8582790fc52b5e2274b40b59cf5f5cea25c7"
+
+[[package]]
+name = "digest"
+version = "0.10.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
+dependencies = [
+ "block-buffer",
+ "crypto-common",
+]
+
+[[package]]
+name = "displaydoc"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "dotenvy"
+version = "0.15.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b"
+
+[[package]]
+name = "either"
+version = "1.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
+
+[[package]]
+name = "emojis"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "99e1f1df1f181f2539bac8bf027d31ca5ffbf9e559e3f2d09413b9107b5c02f4"
+dependencies = [
+ "phf",
+]
+
+[[package]]
+name = "encoding_rs"
+version = "0.8.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "equivalent"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
+
+[[package]]
+name = "erased-serde"
+version = "0.4.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2add8a07dd6a8d93ff627029c51de145e12686fbc36ecb298ac22e74cf02dec"
+dependencies = [
+ "serde",
+ "serde_core",
+ "typeid",
+]
+
+[[package]]
+name = "errno"
+version = "0.3.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
+dependencies = [
+ "libc",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "fallible-iterator"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
+
+[[package]]
+name = "fastrand"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
+
+[[package]]
+name = "filetime"
+version = "0.2.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "libredox",
+]
+
+[[package]]
+name = "find-msvc-tools"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
+
+[[package]]
+name = "flate2"
+version = "1.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c"
+dependencies = [
+ "crc32fast",
+ "miniz_oxide",
+]
+
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
+name = "foldhash"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
+
+[[package]]
+name = "foreign-types"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
+dependencies = [
+ "foreign-types-shared",
+]
+
+[[package]]
+name = "foreign-types-shared"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
+
+[[package]]
+name = "form_urlencoded"
+version = "1.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf"
+dependencies = [
+ "percent-encoding",
+]
+
+[[package]]
+name = "fs_extra"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
+
+[[package]]
+name = "fsevent-sys"
+version = "4.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "futures"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-executor",
+ "futures-io",
+ "futures-sink",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-channel"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+]
+
+[[package]]
+name = "futures-core"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
+
+[[package]]
+name = "futures-executor"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d"
+dependencies = [
+ "futures-core",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-io"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718"
+
+[[package]]
+name = "futures-macro"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "futures-scopes"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ffdcf32827e803f1a3cd04c4319feb99156cb5968a3b393f8541efefa1e3b24c"
+dependencies = [
+ "crossbeam-channel",
+ "dashmap",
+ "futures",
+ "pin-project",
+]
+
+[[package]]
+name = "futures-sink"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893"
+
+[[package]]
+name = "futures-task"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
+
+[[package]]
+name = "futures-util"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-macro",
+ "futures-sink",
+ "futures-task",
+ "memchr",
+ "pin-project-lite",
+ "slab",
+]
+
+[[package]]
+name = "generic-array"
+version = "0.14.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2"
+dependencies = [
+ "typenum",
+ "version_check",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "r-efi 5.3.0",
+ "wasip2",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "r-efi 6.0.0",
+ "wasip2",
+ "wasip3",
+]
+
+[[package]]
+name = "gimli"
+version = "0.32.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7"
+
+[[package]]
+name = "h2"
+version = "0.4.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54"
+dependencies = [
+ "atomic-waker",
+ "bytes",
+ "fnv",
+ "futures-core",
+ "futures-sink",
+ "http",
+ "indexmap",
+ "slab",
+ "tokio",
+ "tokio-util",
+ "tracing",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.14.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
+
+[[package]]
+name = "hashbrown"
+version = "0.15.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
+dependencies = [
+ "foldhash",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.16.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
+
+[[package]]
+name = "heck"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
+
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "http"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a"
+dependencies = [
+ "bytes",
+ "itoa",
+]
+
+[[package]]
+name = "http-body"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
+dependencies = [
+ "bytes",
+ "http",
+]
+
+[[package]]
+name = "http-body-util"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "http",
+ "http-body",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "httparse"
+version = "1.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
+
+[[package]]
+name = "humantime"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424"
+
+[[package]]
+name = "hyper"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11"
+dependencies = [
+ "atomic-waker",
+ "bytes",
+ "futures-channel",
+ "futures-core",
+ "h2",
+ "http",
+ "http-body",
+ "httparse",
+ "itoa",
+ "pin-project-lite",
+ "pin-utils",
+ "smallvec",
+ "tokio",
+ "want",
+]
+
+[[package]]
+name = "hyper-rustls"
+version = "0.27.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58"
+dependencies = [
+ "http",
+ "hyper",
+ "hyper-util",
+ "rustls",
+ "rustls-pki-types",
+ "tokio",
+ "tokio-rustls",
+ "tower-service",
+]
+
+[[package]]
+name = "hyper-tls"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
+dependencies = [
+ "bytes",
+ "http-body-util",
+ "hyper",
+ "hyper-util",
+ "native-tls",
+ "tokio",
+ "tokio-native-tls",
+ "tower-service",
+]
+
+[[package]]
+name = "hyper-util"
+version = "0.1.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0"
+dependencies = [
+ "base64",
+ "bytes",
+ "futures-channel",
+ "futures-util",
+ "http",
+ "http-body",
+ "hyper",
+ "ipnet",
+ "libc",
+ "percent-encoding",
+ "pin-project-lite",
+ "socket2",
+ "system-configuration",
+ "tokio",
+ "tower-service",
+ "tracing",
+ "windows-registry",
+]
+
+[[package]]
+name = "iana-time-zone"
+version = "0.1.65"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470"
+dependencies = [
+ "android_system_properties",
+ "core-foundation-sys",
+ "iana-time-zone-haiku",
+ "js-sys",
+ "log",
+ "wasm-bindgen",
+ "windows-core 0.62.2",
+]
+
+[[package]]
+name = "iana-time-zone-haiku"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "iced-x86"
+version = "1.21.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c447cff8c7f384a7d4f741cfcff32f75f3ad02b406432e8d6c878d56b1edf6b"
+dependencies = [
+ "lazy_static",
+]
+
+[[package]]
+name = "icu_collections"
+version = "2.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43"
+dependencies = [
+ "displaydoc",
+ "potential_utf",
+ "yoke",
+ "zerofrom",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locale_core"
+version = "2.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6"
+dependencies = [
+ "displaydoc",
+ "litemap",
+ "tinystr",
+ "writeable",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_normalizer"
+version = "2.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599"
+dependencies = [
+ "icu_collections",
+ "icu_normalizer_data",
+ "icu_properties",
+ "icu_provider",
+ "smallvec",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_normalizer_data"
+version = "2.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a"
+
+[[package]]
+name = "icu_properties"
+version = "2.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec"
+dependencies = [
+ "icu_collections",
+ "icu_locale_core",
+ "icu_properties_data",
+ "icu_provider",
+ "zerotrie",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_properties_data"
+version = "2.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af"
+
+[[package]]
+name = "icu_provider"
+version = "2.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614"
+dependencies = [
+ "displaydoc",
+ "icu_locale_core",
+ "writeable",
+ "yoke",
+ "zerofrom",
+ "zerotrie",
+ "zerovec",
+]
+
+[[package]]
+name = "id-arena"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
+
+[[package]]
+name = "ident_case"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
+
+[[package]]
+name = "idna"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de"
+dependencies = [
+ "idna_adapter",
+ "smallvec",
+ "utf8_iter",
+]
+
+[[package]]
+name = "idna_adapter"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344"
+dependencies = [
+ "icu_normalizer",
+ "icu_properties",
+]
+
+[[package]]
+name = "indexmap"
+version = "2.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
+dependencies = [
+ "equivalent",
+ "hashbrown 0.16.1",
+ "serde",
+ "serde_core",
+]
+
+[[package]]
+name = "inotify"
+version = "0.9.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff"
+dependencies = [
+ "bitflags 1.3.2",
+ "inotify-sys",
+ "libc",
+]
+
+[[package]]
+name = "inotify-sys"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "inventory"
+version = "0.3.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "009ae045c87e7082cb72dab0ccd01ae075dd00141ddc108f43a0ea150a9e7227"
+dependencies = [
+ "rustversion",
+]
+
+[[package]]
+name = "ipnet"
+version = "2.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2"
+
+[[package]]
+name = "iri-string"
+version = "0.7.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a"
+dependencies = [
+ "memchr",
+ "serde",
+]
+
+[[package]]
+name = "is_terminal_polyfill"
+version = "1.70.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
+
+[[package]]
+name = "itertools"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itertools"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
+
+[[package]]
+name = "js-sys"
+version = "0.3.91"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c"
+dependencies = [
+ "once_cell",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "kqueue"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eac30106d7dce88daf4a3fcb4879ea939476d5074a9b7ddd0fb97fa4bed5596a"
+dependencies = [
+ "kqueue-sys",
+ "libc",
+]
+
+[[package]]
+name = "kqueue-sys"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b"
+dependencies = [
+ "bitflags 1.3.2",
+ "libc",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+
+[[package]]
+name = "leb128fmt"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
+
+[[package]]
+name = "libc"
+version = "0.2.183"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d"
+
+[[package]]
+name = "libredox"
+version = "0.1.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1744e39d1d6a9948f4f388969627434e31128196de472883b39f148769bfe30a"
+dependencies = [
+ "bitflags 2.11.0",
+ "libc",
+ "plain",
+ "redox_syscall 0.7.3",
+]
+
+[[package]]
+name = "libudis86-sys"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "139bbf9ddb1bfc90c1ac64dd2923d9c957cd433cee7315c018125d72ab08a6b0"
+dependencies = [
+ "cc",
+ "libc",
+]
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
+
+[[package]]
+name = "litemap"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77"
+
+[[package]]
+name = "lock_api"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
+dependencies = [
+ "scopeguard",
+]
+
+[[package]]
+name = "log"
+version = "0.4.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
+dependencies = [
+ "serde_core",
+]
+
+[[package]]
+name = "log-mdc"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a94d21414c1f4a51209ad204c1776a3d0765002c76c6abcb602a6f09f1e881c7"
+
+[[package]]
+name = "log4rs"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3e947bb896e702c711fccc2bf02ab2abb6072910693818d1d6b07ee2b9dfd86c"
+dependencies = [
+ "anyhow",
+ "arc-swap",
+ "chrono",
+ "derive_more 2.1.1",
+ "flate2",
+ "fnv",
+ "humantime",
+ "libc",
+ "log",
+ "log-mdc",
+ "mock_instant",
+ "parking_lot",
+ "rand 0.9.2",
+ "serde",
+ "serde-value",
+ "serde_json",
+ "serde_yaml",
+ "thiserror 2.0.18",
+ "thread-id",
+ "typemap-ors",
+ "unicode-segmentation",
+ "winapi",
+]
+
+[[package]]
+name = "mach2"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "memchr"
+version = "2.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
+
+[[package]]
+name = "memmap2"
+version = "0.9.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "mime"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
+
+[[package]]
+name = "mime_guess"
+version = "2.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e"
+dependencies = [
+ "mime",
+ "unicase",
+]
+
+[[package]]
+name = "miniz_oxide"
+version = "0.8.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
+dependencies = [
+ "adler2",
+ "simd-adler32",
+]
+
+[[package]]
+name = "mio"
+version = "0.8.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
+dependencies = [
+ "libc",
+ "log",
+ "wasi",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "mio"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc"
+dependencies = [
+ "libc",
+ "wasi",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "mmap-fixed-fixed"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0681853891801e4763dc252e843672faf32bcfee27a0aa3b19733902af450acc"
+dependencies = [
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "mock_instant"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dce6dd36094cac388f119d2e9dc82dc730ef91c32a6222170d630e5414b956e6"
+
+[[package]]
+name = "native-tls"
+version = "0.2.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2"
+dependencies = [
+ "libc",
+ "log",
+ "openssl",
+ "openssl-probe",
+ "openssl-sys",
+ "schannel",
+ "security-framework",
+ "security-framework-sys",
+ "tempfile",
+]
+
+[[package]]
+name = "notify"
+version = "6.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d"
+dependencies = [
+ "bitflags 2.11.0",
+ "crossbeam-channel",
+ "filetime",
+ "fsevent-sys",
+ "inotify",
+ "kqueue",
+ "libc",
+ "log",
+ "mio 0.8.11",
+ "walkdir",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "notify-debouncer-mini"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d40b221972a1fc5ef4d858a2f671fb34c75983eb385463dff3780eeff6a9d43"
+dependencies = [
+ "crossbeam-channel",
+ "log",
+ "notify",
+]
+
+[[package]]
+name = "num-conv"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050"
+
+[[package]]
+name = "num-traits"
+version = "0.2.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "object"
+version = "0.32.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
+dependencies = [
+ "flate2",
+ "memchr",
+ "ruzstd",
+]
+
+[[package]]
+name = "object"
+version = "0.37.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.21.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
+
+[[package]]
+name = "once_cell_polyfill"
+version = "1.70.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
+
+[[package]]
+name = "openssl"
+version = "0.10.76"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "951c002c75e16ea2c65b8c7e4d3d51d5530d8dfa7d060b4776828c88cfb18ecf"
+dependencies = [
+ "bitflags 2.11.0",
+ "cfg-if",
+ "foreign-types",
+ "libc",
+ "once_cell",
+ "openssl-macros",
+ "openssl-sys",
+]
+
+[[package]]
+name = "openssl-macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "openssl-probe"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe"
+
+[[package]]
+name = "openssl-sys"
+version = "0.9.112"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57d55af3b3e226502be1526dfdba67ab0e9c96fc293004e79576b2b9edb0dbdb"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+ "vcpkg",
+]
+
+[[package]]
+name = "ordered-float"
+version = "2.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "parking_lot"
+version = "0.12.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
+dependencies = [
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.9.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall 0.5.18",
+ "smallvec",
+ "windows-link",
+]
+
+[[package]]
+name = "paste"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
+
+[[package]]
+name = "patternsleuth"
+version = "0.1.0"
+source = "git+https://github.com/Knutschbert/patternsleuth.git?rev=644f980#644f9804e5247fe40e4d7a1e470639601254cd70"
+dependencies = [
+ "anyhow",
+ "futures",
+ "futures-scopes",
+ "iced-x86",
+ "inventory",
+ "itertools 0.12.1",
+ "libc",
+ "memchr",
+ "object 0.32.2",
+ "paste",
+ "patternsleuth_scanner",
+ "rayon",
+ "serde",
+ "strum 0.25.0",
+ "tracing",
+ "typetag",
+ "windows",
+]
+
+[[package]]
+name = "patternsleuth_scanner"
+version = "0.1.0"
+source = "git+https://github.com/Knutschbert/patternsleuth.git?rev=644f980#644f9804e5247fe40e4d7a1e470639601254cd70"
+dependencies = [
+ "anyhow",
+ "memchr",
+ "rayon",
+]
+
+[[package]]
+name = "pdb"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "82040a392923abe6279c00ab4aff62d5250d1c8555dc780e4b02783a7aa74863"
+dependencies = [
+ "fallible-iterator",
+ "scroll",
+ "uuid",
+]
+
+[[package]]
+name = "percent-encoding"
+version = "2.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
+
+[[package]]
+name = "phf"
+version = "0.11.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078"
+dependencies = [
+ "phf_shared",
+]
+
+[[package]]
+name = "phf_shared"
+version = "0.11.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5"
+dependencies = [
+ "siphasher",
+]
+
+[[package]]
+name = "pin-project"
+version = "1.1.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517"
+dependencies = [
+ "pin-project-internal",
+]
+
+[[package]]
+name = "pin-project-internal"
+version = "1.1.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
+
+[[package]]
+name = "pin-utils"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+
+[[package]]
+name = "pkg-config"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
+
+[[package]]
+name = "plain"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
+
+[[package]]
+name = "potential_utf"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77"
+dependencies = [
+ "zerovec",
+]
+
+[[package]]
+name = "powerfmt"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
+dependencies = [
+ "zerocopy",
+]
+
+[[package]]
+name = "prettyplease"
+version = "0.2.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
+dependencies = [
+ "proc-macro2",
+ "syn",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.106"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "r-efi"
+version = "5.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
+
+[[package]]
+name = "r-efi"
+version = "6.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
+
+[[package]]
+name = "rand"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
+dependencies = [
+ "libc",
+ "rand_chacha 0.3.1",
+ "rand_core 0.6.4",
+]
+
+[[package]]
+name = "rand"
+version = "0.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
+dependencies = [
+ "rand_chacha 0.9.0",
+ "rand_core 0.9.5",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+dependencies = [
+ "ppv-lite86",
+ "rand_core 0.6.4",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
+dependencies = [
+ "ppv-lite86",
+ "rand_core 0.9.5",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+dependencies = [
+ "getrandom 0.2.17",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c"
+dependencies = [
+ "getrandom 0.3.4",
+]
+
+[[package]]
+name = "rayon"
+version = "1.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f"
+dependencies = [
+ "either",
+ "rayon-core",
+]
+
+[[package]]
+name = "rayon-core"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
+dependencies = [
+ "crossbeam-deque",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.5.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
+dependencies = [
+ "bitflags 2.11.0",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ce70a74e890531977d37e532c34d45e9055d2409ed08ddba14529471ed0be16"
+dependencies = [
+ "bitflags 2.11.0",
+]
+
+[[package]]
+name = "regex"
+version = "1.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
+
+[[package]]
+name = "region"
+version = "3.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6b6ebd13bc009aef9cd476c1310d49ac354d36e240cf1bd753290f3dc7199a7"
+dependencies = [
+ "bitflags 1.3.2",
+ "libc",
+ "mach2",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "reqwest"
+version = "0.12.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147"
+dependencies = [
+ "base64",
+ "bytes",
+ "encoding_rs",
+ "futures-channel",
+ "futures-core",
+ "futures-util",
+ "h2",
+ "http",
+ "http-body",
+ "http-body-util",
+ "hyper",
+ "hyper-rustls",
+ "hyper-tls",
+ "hyper-util",
+ "js-sys",
+ "log",
+ "mime",
+ "native-tls",
+ "percent-encoding",
+ "pin-project-lite",
+ "rustls-pki-types",
+ "serde",
+ "serde_json",
+ "serde_urlencoded",
+ "sync_wrapper",
+ "tokio",
+ "tokio-native-tls",
+ "tower",
+ "tower-http",
+ "tower-service",
+ "url",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+]
+
+[[package]]
+name = "reqwest"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801"
+dependencies = [
+ "base64",
+ "bytes",
+ "futures-core",
+ "futures-util",
+ "http",
+ "http-body",
+ "http-body-util",
+ "hyper",
+ "hyper-tls",
+ "hyper-util",
+ "js-sys",
+ "log",
+ "mime_guess",
+ "native-tls",
+ "percent-encoding",
+ "pin-project-lite",
+ "rustls-pki-types",
+ "sync_wrapper",
+ "tokio",
+ "tokio-native-tls",
+ "tokio-util",
+ "tower",
+ "tower-http",
+ "tower-service",
+ "url",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "wasm-streams",
+ "web-sys",
+]
+
+[[package]]
+name = "retour"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a9af44d40e2400b44d491bfaf8eae111b09f23ac4de6e92728e79d93e699c527"
+dependencies = [
+ "cfg-if",
+ "generic-array",
+ "libc",
+ "libudis86-sys",
+ "mmap-fixed-fixed",
+ "once_cell",
+ "region",
+ "slice-pool2",
+]
+
+[[package]]
+name = "ring"
+version = "0.17.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
+dependencies = [
+ "cc",
+ "cfg-if",
+ "getrandom 0.2.17",
+ "libc",
+ "untrusted",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "rustc-demangle"
+version = "0.1.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d"
+
+[[package]]
+name = "rustc_version"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
+dependencies = [
+ "semver",
+]
+
+[[package]]
+name = "rustix"
+version = "1.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
+dependencies = [
+ "bitflags 2.11.0",
+ "errno",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "rustls"
+version = "0.23.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4"
+dependencies = [
+ "log",
+ "once_cell",
+ "ring",
+ "rustls-pki-types",
+ "rustls-webpki",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "rustls-pki-types"
+version = "1.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd"
+dependencies = [
+ "zeroize",
+]
+
+[[package]]
+name = "rustls-webpki"
+version = "0.103.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef"
+dependencies = [
+ "ring",
+ "rustls-pki-types",
+ "untrusted",
+]
+
+[[package]]
+name = "rustversion"
+version = "1.0.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
+
+[[package]]
+name = "ruzstd"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "58c4eb8a81997cf040a091d1f7e1938aeab6749d3a0dfa73af43cdc32393483d"
+dependencies = [
+ "byteorder",
+ "derive_more 0.99.20",
+ "twox-hash",
+]
+
+[[package]]
+name = "ryu"
+version = "1.0.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
+
+[[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "schannel"
+version = "0.1.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939"
+dependencies = [
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "scopeguard"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+
+[[package]]
+name = "scroll"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da"
+
+[[package]]
+name = "secrecy"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e"
+dependencies = [
+ "serde",
+ "zeroize",
+]
+
+[[package]]
+name = "security-framework"
+version = "3.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d"
+dependencies = [
+ "bitflags 2.11.0",
+ "core-foundation 0.10.1",
+ "core-foundation-sys",
+ "libc",
+ "security-framework-sys",
+]
+
+[[package]]
+name = "security-framework-sys"
+version = "2.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "semver"
+version = "1.0.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
+dependencies = [
+ "serde",
+ "serde_core",
+]
+
+[[package]]
+name = "serde"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
+dependencies = [
+ "serde_core",
+ "serde_derive",
+]
+
+[[package]]
+name = "serde-value"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c"
+dependencies = [
+ "ordered-float",
+ "serde",
+]
+
+[[package]]
+name = "serde_core"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_cow"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e7bbbec7196bfde255ab54b65e34087c0849629280028238e67ee25d6a4b7da"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.149"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
+dependencies = [
+ "itoa",
+ "memchr",
+ "serde",
+ "serde_core",
+ "zmij",
+]
+
+[[package]]
+name = "serde_urlencoded"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
+dependencies = [
+ "form_urlencoded",
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "serde_yaml"
+version = "0.9.34+deprecated"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
+dependencies = [
+ "indexmap",
+ "itoa",
+ "ryu",
+ "serde",
+ "unsafe-libyaml",
+]
+
+[[package]]
+name = "serenity"
+version = "0.12.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9bde37f42765dfdc34e2a039e0c84afbf79a3101c1941763b0beb816c2f17541"
+dependencies = [
+ "arrayvec",
+ "async-trait",
+ "base64",
+ "bitflags 2.11.0",
+ "bytes",
+ "flate2",
+ "futures",
+ "mime_guess",
+ "percent-encoding",
+ "reqwest 0.13.2",
+ "secrecy",
+ "serde",
+ "serde_cow",
+ "serde_json",
+ "time",
+ "tokio",
+ "tokio-tungstenite",
+ "tracing",
+ "typemap_rev",
+ "url",
+]
+
+[[package]]
+name = "sha1"
+version = "0.10.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "digest",
+]
+
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
+name = "simd-adler32"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2"
+
+[[package]]
+name = "simple-log"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94263a9019c994147d7dc572aa1b3bce100bbdf5b5e3a8a446a025c80ecba169"
+dependencies = [
+ "log",
+ "log4rs",
+ "once_cell",
+ "serde",
+]
+
+[[package]]
+name = "siphasher"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e"
+
+[[package]]
+name = "slab"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
+
+[[package]]
+name = "sleuth_macros"
+version = "0.1.0"
+dependencies = [
+ "darling",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "slice-pool2"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a3d689654af89bdfeba29a914ab6ac0236d382eb3b764f7454dde052f2821f8"
+
+[[package]]
+name = "smallvec"
+version = "1.15.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
+
+[[package]]
+name = "socket2"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e"
+dependencies = [
+ "libc",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "stable_deref_trait"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
+
+[[package]]
+name = "static_assertions"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+
+[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
+[[package]]
+name = "strum"
+version = "0.25.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125"
+dependencies = [
+ "strum_macros 0.25.3",
+]
+
+[[package]]
+name = "strum"
+version = "0.26.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
+dependencies = [
+ "strum_macros 0.26.4",
+]
+
+[[package]]
+name = "strum_macros"
+version = "0.25.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0"
+dependencies = [
+ "heck 0.4.1",
+ "proc-macro2",
+ "quote",
+ "rustversion",
+ "syn",
+]
+
+[[package]]
+name = "strum_macros"
+version = "0.26.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
+dependencies = [
+ "heck 0.5.0",
+ "proc-macro2",
+ "quote",
+ "rustversion",
+ "syn",
+]
+
+[[package]]
+name = "subtle"
+version = "2.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
+
+[[package]]
+name = "syn"
+version = "2.0.117"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "sync_wrapper"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
+dependencies = [
+ "futures-core",
+]
+
+[[package]]
+name = "synstructure"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "system-configuration"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b"
+dependencies = [
+ "bitflags 2.11.0",
+ "core-foundation 0.9.4",
+ "system-configuration-sys",
+]
+
+[[package]]
+name = "system-configuration-sys"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "tempfile"
+version = "3.27.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
+dependencies = [
+ "fastrand",
+ "getrandom 0.4.2",
+ "once_cell",
+ "rustix",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "thiserror"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
+dependencies = [
+ "thiserror-impl 1.0.69",
+]
+
+[[package]]
+name = "thiserror"
+version = "2.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
+dependencies = [
+ "thiserror-impl 2.0.18",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "2.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "thread-id"
+version = "5.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2010d27add3f3240c1fef7959f46c814487b216baee662af53be645ba7831c07"
+dependencies = [
+ "libc",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "time"
+version = "0.3.47"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c"
+dependencies = [
+ "deranged",
+ "itoa",
+ "num-conv",
+ "powerfmt",
+ "serde_core",
+ "time-core",
+ "time-macros",
+]
+
+[[package]]
+name = "time-core"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca"
+
+[[package]]
+name = "time-macros"
+version = "0.2.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215"
+dependencies = [
+ "num-conv",
+ "time-core",
+]
+
+[[package]]
+name = "tinystr"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869"
+dependencies = [
+ "displaydoc",
+ "zerovec",
+]
+
+[[package]]
+name = "tokio"
+version = "1.50.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d"
+dependencies = [
+ "bytes",
+ "libc",
+ "mio 1.1.1",
+ "pin-project-lite",
+ "socket2",
+ "tokio-macros",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "tokio-macros"
+version = "2.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "tokio-native-tls"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
+dependencies = [
+ "native-tls",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-rustls"
+version = "0.26.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61"
+dependencies = [
+ "rustls",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-tungstenite"
+version = "0.21.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38"
+dependencies = [
+ "futures-util",
+ "log",
+ "native-tls",
+ "tokio",
+ "tokio-native-tls",
+ "tungstenite",
+]
+
+[[package]]
+name = "tokio-util"
+version = "0.7.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "futures-sink",
+ "pin-project-lite",
+ "tokio",
+]
+
+[[package]]
+name = "toml"
+version = "0.5.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "tower"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4"
+dependencies = [
+ "futures-core",
+ "futures-util",
+ "pin-project-lite",
+ "sync_wrapper",
+ "tokio",
+ "tower-layer",
+ "tower-service",
+]
+
+[[package]]
+name = "tower-http"
+version = "0.6.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8"
+dependencies = [
+ "bitflags 2.11.0",
+ "bytes",
+ "futures-util",
+ "http",
+ "http-body",
+ "iri-string",
+ "pin-project-lite",
+ "tower",
+ "tower-layer",
+ "tower-service",
+]
+
+[[package]]
+name = "tower-layer"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
+
+[[package]]
+name = "tower-service"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
+
+[[package]]
+name = "tracing"
+version = "0.1.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
+dependencies = [
+ "log",
+ "pin-project-lite",
+ "tracing-attributes",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-attributes"
+version = "0.1.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.36"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
+dependencies = [
+ "once_cell",
+]
+
+[[package]]
+name = "try-lock"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
+
+[[package]]
+name = "tungstenite"
+version = "0.21.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1"
+dependencies = [
+ "byteorder",
+ "bytes",
+ "data-encoding",
+ "http",
+ "httparse",
+ "log",
+ "native-tls",
+ "rand 0.8.5",
+ "sha1",
+ "thiserror 1.0.69",
+ "url",
+ "utf-8",
+]
+
+[[package]]
+name = "twox-hash"
+version = "1.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675"
+dependencies = [
+ "cfg-if",
+ "static_assertions",
+]
+
+[[package]]
+name = "typeid"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c"
+
+[[package]]
+name = "typemap-ors"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a68c24b707f02dd18f1e4ccceb9d49f2058c2fb86384ef9972592904d7a28867"
+dependencies = [
+ "unsafe-any-ors",
+]
+
+[[package]]
+name = "typemap_rev"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74b08b0c1257381af16a5c3605254d529d3e7e109f3c62befc5d168968192998"
+
+[[package]]
+name = "typenum"
+version = "1.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
+
+[[package]]
+name = "typetag"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be2212c8a9b9bcfca32024de14998494cf9a5dfa59ea1b829de98bac374b86bf"
+dependencies = [
+ "erased-serde",
+ "inventory",
+ "once_cell",
+ "serde",
+ "typetag-impl",
+]
+
+[[package]]
+name = "typetag-impl"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "27a7a9b72ba121f6f1f6c3632b85604cac41aedb5ddc70accbebb6cac83de846"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "unicase"
+version = "2.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
+
+[[package]]
+name = "unicode-segmentation"
+version = "1.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
+
+[[package]]
+name = "unsafe-any-ors"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e0a303d30665362d9680d7d91d78b23f5f899504d4f08b3c4cf08d055d87c0ad"
+dependencies = [
+ "destructure_traitobject",
+]
+
+[[package]]
+name = "unsafe-libyaml"
+version = "0.2.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
+
+[[package]]
+name = "untrusted"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
+
+[[package]]
+name = "ureq"
+version = "3.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dea7109cdcd5864d4eeb1b58a1648dc9bf520360d7af16ec26d0a9354bafcfc0"
+dependencies = [
+ "base64",
+ "flate2",
+ "log",
+ "percent-encoding",
+ "rustls",
+ "rustls-pki-types",
+ "ureq-proto",
+ "utf8-zero",
+ "webpki-roots",
+]
+
+[[package]]
+name = "ureq-proto"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e994ba84b0bd1b1b0cf92878b7ef898a5c1760108fe7b6010327e274917a808c"
+dependencies = [
+ "base64",
+ "http",
+ "httparse",
+ "log",
+]
+
+[[package]]
+name = "url"
+version = "2.5.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed"
+dependencies = [
+ "form_urlencoded",
+ "idna",
+ "percent-encoding",
+ "serde",
+ "serde_derive",
+]
+
+[[package]]
+name = "utf-8"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
+
+[[package]]
+name = "utf8-zero"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8c0a043c9540bae7c578c88f91dda8bd82e59ae27c21baca69c8b191aaf5a6e"
+
+[[package]]
+name = "utf8_iter"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
+
+[[package]]
+name = "utf8parse"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
+
+[[package]]
+name = "uuid"
+version = "1.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a68d3c8f01c0cfa54a75291d83601161799e4a89a39e0929f4b0354d88757a37"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "vcpkg"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
+
+[[package]]
+name = "version_check"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
+
+[[package]]
+name = "walkdir"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
+dependencies = [
+ "same-file",
+ "winapi-util",
+]
+
+[[package]]
+name = "want"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
+dependencies = [
+ "try-lock",
+]
+
+[[package]]
+name = "wasi"
+version = "0.11.1+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
+
+[[package]]
+name = "wasip2"
+version = "1.0.2+wasi-0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5"
+dependencies = [
+ "wit-bindgen",
+]
+
+[[package]]
+name = "wasip3"
+version = "0.4.0+wasi-0.3.0-rc-2026-01-06"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5"
+dependencies = [
+ "wit-bindgen",
+]
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.114"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "rustversion",
+ "wasm-bindgen-macro",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-futures"
+version = "0.4.64"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8"
+dependencies = [
+ "cfg-if",
+ "futures-util",
+ "js-sys",
+ "once_cell",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.114"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.114"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3"
+dependencies = [
+ "bumpalo",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.114"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "wasm-encoder"
+version = "0.244.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319"
+dependencies = [
+ "leb128fmt",
+ "wasmparser",
+]
+
+[[package]]
+name = "wasm-metadata"
+version = "0.244.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909"
+dependencies = [
+ "anyhow",
+ "indexmap",
+ "wasm-encoder",
+ "wasmparser",
+]
+
+[[package]]
+name = "wasm-streams"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d1ec4f6517c9e11ae630e200b2b65d193279042e28edd4a2cda233e46670bbb"
+dependencies = [
+ "futures-util",
+ "js-sys",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+]
+
+[[package]]
+name = "wasmparser"
+version = "0.244.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe"
+dependencies = [
+ "bitflags 2.11.0",
+ "hashbrown 0.15.5",
+ "indexmap",
+ "semver",
+]
+
+[[package]]
+name = "web-sys"
+version = "0.3.91"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "webpki-roots"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed"
+dependencies = [
+ "rustls-pki-types",
+]
+
+[[package]]
+name = "widestring"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471"
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
+dependencies = [
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "windows"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
+dependencies = [
+ "windows-core 0.52.0",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-core"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
+dependencies = [
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-core"
+version = "0.62.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
+dependencies = [
+ "windows-implement",
+ "windows-interface",
+ "windows-link",
+ "windows-result",
+ "windows-strings",
+]
+
+[[package]]
+name = "windows-implement"
+version = "0.60.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "windows-interface"
+version = "0.59.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "windows-link"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
+
+[[package]]
+name = "windows-registry"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720"
+dependencies = [
+ "windows-link",
+ "windows-result",
+ "windows-strings",
+]
+
+[[package]]
+name = "windows-result"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-strings"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+dependencies = [
+ "windows-targets 0.48.5",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.61.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
+dependencies = [
+ "windows_aarch64_gnullvm 0.48.5",
+ "windows_aarch64_msvc 0.48.5",
+ "windows_i686_gnu 0.48.5",
+ "windows_i686_msvc 0.48.5",
+ "windows_x86_64_gnu 0.48.5",
+ "windows_x86_64_gnullvm 0.48.5",
+ "windows_x86_64_msvc 0.48.5",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm 0.52.6",
+ "windows_aarch64_msvc 0.52.6",
+ "windows_i686_gnu 0.52.6",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc 0.52.6",
+ "windows_x86_64_gnu 0.52.6",
+ "windows_x86_64_gnullvm 0.52.6",
+ "windows_x86_64_msvc 0.52.6",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
+[[package]]
+name = "winres"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b68db261ef59e9e52806f688020631e987592bd83619edccda9c47d42cde4f6c"
+dependencies = [
+ "toml",
+]
+
+[[package]]
+name = "wit-bindgen"
+version = "0.51.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
+dependencies = [
+ "wit-bindgen-rust-macro",
+]
+
+[[package]]
+name = "wit-bindgen-core"
+version = "0.51.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc"
+dependencies = [
+ "anyhow",
+ "heck 0.5.0",
+ "wit-parser",
+]
+
+[[package]]
+name = "wit-bindgen-rust"
+version = "0.51.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21"
+dependencies = [
+ "anyhow",
+ "heck 0.5.0",
+ "indexmap",
+ "prettyplease",
+ "syn",
+ "wasm-metadata",
+ "wit-bindgen-core",
+ "wit-component",
+]
+
+[[package]]
+name = "wit-bindgen-rust-macro"
+version = "0.51.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a"
+dependencies = [
+ "anyhow",
+ "prettyplease",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wit-bindgen-core",
+ "wit-bindgen-rust",
+]
+
+[[package]]
+name = "wit-component"
+version = "0.244.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2"
+dependencies = [
+ "anyhow",
+ "bitflags 2.11.0",
+ "indexmap",
+ "log",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "wasm-encoder",
+ "wasm-metadata",
+ "wasmparser",
+ "wit-parser",
+]
+
+[[package]]
+name = "wit-parser"
+version = "0.244.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736"
+dependencies = [
+ "anyhow",
+ "id-arena",
+ "indexmap",
+ "log",
+ "semver",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "unicode-xid",
+ "wasmparser",
+]
+
+[[package]]
+name = "writeable"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9"
+
+[[package]]
+name = "xtask"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "cargo_metadata",
+ "clap",
+ "dotenvy",
+ "fs_extra",
+]
+
+[[package]]
+name = "yoke"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954"
+dependencies = [
+ "stable_deref_trait",
+ "yoke-derive",
+ "zerofrom",
+]
+
+[[package]]
+name = "yoke-derive"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "synstructure",
+]
+
+[[package]]
+name = "zerocopy"
+version = "0.8.47"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "efbb2a062be311f2ba113ce66f697a4dc589f85e78a4aea276200804cea0ed87"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.8.47"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e8bc7269b54418e7aeeef514aa68f8690b8c0489a06b0136e5f57c4c5ccab89"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "zerofrom"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5"
+dependencies = [
+ "zerofrom-derive",
+]
+
+[[package]]
+name = "zerofrom-derive"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "synstructure",
+]
+
+[[package]]
+name = "zeroize"
+version = "1.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
+
+[[package]]
+name = "zerotrie"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851"
+dependencies = [
+ "displaydoc",
+ "yoke",
+ "zerofrom",
+]
+
+[[package]]
+name = "zerovec"
+version = "0.11.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002"
+dependencies = [
+ "yoke",
+ "zerofrom",
+ "zerovec-derive",
+]
+
+[[package]]
+name = "zerovec-derive"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "zmij"
+version = "1.0.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..48950f9
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,136 @@
+[package]
+name = "UnchainedPlugin"
+version = "1.0.0-RC2"
+edition = "2021"
+
+[workspace]
+members = [".", "xtask"]
+
+[[bin]]
+name = "mock_server"
+path = "src/bin/mock_server.rs"
+
+[lib]
+name = "UnchainedPlugin"
+crate-type = ["staticlib", "cdylib", "rlib"]
+
+[target.x86_64-pc-windows-msvc]
+
+[profile.dev]
+debug = "full"
+opt-level = 0
+panic = "unwind"
+incremental = false
+
+[profile.release]
+debug = "full"
+opt-level = 1
+panic = "unwind"
+lto = false
+
+
+
+[build-dependencies]
+winres = "0.1"
+
+[lints.rust]
+non_snake_case = "allow"
+unexpected_cfgs = { level = "warn", check-cfg = ['cfg(rust_analyzer)'] }
+
+[features]
+default = [
+ "serde-resolvers",
+ "dev",
+ # "loose_assets",
+ "verbose_hooks",
+ "cli_commands",
+ "rcon_commands",
+ "server_registration",
+ "mod_management",
+ "discord_integration",
+ # "request_dummy_hooks",
+ "syslog-client",
+ ]
+serde-resolvers = []
+image-elf = []
+dev = []
+syslog-client = [ ]
+request_dummy_hooks = [] # Enable Get*Post dummy hooks
+kismet_log = [] # Dump kismetexecutionmessage logs
+with_pdb = ["pdb"]
+loose_assets = [] # Load assets in addition to paks
+verbose_hooks = [] # print (some) hook triggers to console
+cli_commands = [] # process commands from plugin windows
+rcon_commands = [] # process commands from rcon
+server_registration = ["a2s", "reqwest"] # register server with backend
+mod_management = [] # info about mod markers and actors
+discord_integration = [ "tokio", "crossbeam-channel", "serenity" ]
+move-autonomous-desync = []
+
+
+[dependencies]
+# patternsleuth = { git = "https://github.com/trumank/patternsleuth.git", rev = "5786164", features = ["process-internal", "serde-resolvers", "image-pe"] }
+patternsleuth = { git = "https://github.com/Knutschbert/patternsleuth.git", rev = "644f980", features = ["process-internal", "serde-resolvers", "image-pe"] }
+anyhow = "1.0.79"
+serde = { version = "1.0.195", features = ["derive"] }
+serde_json = "1.0.111"
+serde_yaml = "0.9"
+serde_urlencoded = "0.7"
+tracing = "0.1.40"
+futures = "0.3.31"
+once_cell = "1.19"
+paste = "1.0"
+memmap2 = "0.9.4"
+widestring = "1.0.2"
+bitflags = "2.4.1"
+log = "0.4"
+log4rs = "1.3.0"
+simple-log = "1.6.0"
+parking_lot = "0.12.1"
+inventory = "0.3.14"
+regex = "1.11"
+ureq = "3.1.4"
+itertools = "0.14.0"
+sleuth_macros = { path = "./sleuth_macros" }
+# server registration
+a2s = { git = "https://github.com/Knutschbert/a2s-rs.git", rev = "0376331", optional = true }
+reqwest = { version = "0.12.19", optional = true, features = ["blocking", "json"] }
+# discord<
+async-trait = "0.1"
+backtrace = "0.3.76"
+notify = "6.1.1"
+notify-debouncer-mini = "0.4.1"
+# pdb loading (local tests)
+pdb = { version = "0.8.0", optional = true }
+retour = { version = "0.3.1", features = ["static-detour"]}
+clap = { version = "4.5.0", features = ["derive"] } # cli arg parsing
+winapi = { version = "0.3.9", features = ["winnt", "wincrypt", "winuser", "excpt"] }
+windows = { version = "0.52.0", features = ["Win32_Foundation",
+ "Win32_System_Console",
+ "Win32_System_LibraryLoader",
+ "Win32_System_SystemServices",
+ "Win32_Graphics_Gdi",
+ "Win32_Graphics_Direct3D",
+ "Win32_Graphics_Direct3D11",
+ "Win32_Graphics_Dxgi",
+ "Win32_Graphics_Dxgi_Common",
+ "Win32_UI_WindowsAndMessaging",
+ "Win32_System_Threading",
+ "Win32_System_Diagnostics_Debug",
+
+ "Win32_Security",
+ "Win32_System_Kernel",
+ "Win32_System_Memory",
+ "Win32_System_ProcessStatus",
+ ]}
+tokio = { version = "1.0", features = ["rt-multi-thread", "macros", "time"], optional = true }
+serenity = { version = "0.12", optional = true, default-features = false, features = ["client", "gateway", "model", "native_tls_backend"] }
+shlex = "1.3.0"
+crossbeam-channel = { version = "0.5", optional = true}
+rand = "0.9.2"
+censor = "0.3.0"
+quote = "1.0.43"
+crc32c = "0.6.8"
+strum = { version = "0.26", features = ["derive"] }
+emojis = "0.6"
+unicode-segmentation = "1.12"
diff --git a/README.md b/README.md
index 1f01200..04cfb23 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,32 @@
# Unchained Plugin
-The unchained plugin patches the Chivalry 2 Binary and allows connection to unofficial servers using an unofficial server browser. It also enables the loading of non-vanilla pak files (mods).
+The Unchained Plugin patches the Chivalry 2 binary to allow connection to unofficial servers via an unofficial server browser. It also enables loading of non-vanilla pak files (mods).
+
+## Development with VS Code and RustRover
+
+### Prerequisites
+1. **Chivalry 2**: Ensure you have the game installed.
+2. **Rust Toolchain**: Install Rust via [rustup](https://rustup.rs/).
+3. **IDE Specifics**:
+ * **VS Code**: Install `rust-analyzer` and `C/C++` extensions.
+ * **RustRover**: No additional extensions needed.
+
+### Configuration
+Both VS Code and RustRover configurations rely on the `CHIVALRY2_DIR` environment variable to locate the game files.
+
+1. **Define `CHIVALRY2_DIR`**:
+ Copy the `.env.example` file to a new file named `.env` in the project root. Then, update the `CHIVALRY2_DIR` path to your Chivalry 2 installation directory.
+ ```env
+ CHIVALRY2_DIR=C:\Program Files (x86)\Steam\steamapps\common\Chivalry 2
+ ```
+ *Note: The path should be the root of the Chivalry 2 installation (the folder containing the `TBL` directory).
+2. **Environment Variables in IDEs**:
+ - **VS Code**:
+ - **Debugging**: The `launch.json` configuration uses the `envFile` property to automatically load variables from your `.env` file.
+ - **Tasks**: VS Code tasks use `cargo xtask` (defined in the `xtask` directory) to handle building and installation.
+ - **RustRover**:
+ - **Environment Variables**: For configurations that use `$CHIVALRY2_DIR$` (like launching the game), you must ensure the variable is available to the IDE. You can set it in your system environment or use a plugin like **EnvFile** to load it from `.env`.
+ - **Install Task**: The **Install UnchainedPlugin** run configuration uses `cargo xtask install` which handles `.env` internally.
-## Version Bumps
-To bump the version, the build files must be re-generated. Recompiling via cmake is not enough
## Credits
* DrLong
diff --git a/build.rs b/build.rs
new file mode 100644
index 0000000..8180132
--- /dev/null
+++ b/build.rs
@@ -0,0 +1,29 @@
+extern crate winres;
+
+fn main() {
+ if std::env::var("CARGO_CFG_TARGET_OS").unwrap() == "windows" {
+ let mut res = winres::WindowsResource::new();
+
+ let version = env!("CARGO_PKG_VERSION");
+ let mut components = version.split('.').fuse();
+ let major = components.next().and_then(|s| s.parse::().ok()).unwrap_or(0);
+ let minor = components.next().and_then(|s| s.parse::().ok()).unwrap_or(0);
+ let patch = components.next().and_then(|s| s.parse::().ok()).unwrap_or(0);
+
+ res.set_version_info(winres::VersionInfo::FILEVERSION,
+ ((major as u64) << 48) | ((minor as u64) << 32) | ((patch as u64) << 16));
+ res.set_version_info(winres::VersionInfo::PRODUCTVERSION,
+ ((major as u64) << 48) | ((minor as u64) << 32) | ((patch as u64) << 16));
+
+ res.set("CompanyName", "UnchainedPlugin Contributors");
+ res.set("FileDescription", "UnchainedPlugin");
+ res.set("FileVersion", version);
+ res.set("InternalName", "UnchainedPlugin");
+ res.set("LegalCopyright", "Copyright (C) 2023-2025");
+ res.set("OriginalFilename", "UnchainedPlugin.dll");
+ res.set("ProductName", "UnchainedPlugin");
+ res.set("ProductVersion", version);
+
+ res.compile().unwrap();
+ }
+}
diff --git a/lib/MinHook/CMakeLists.txt b/lib/MinHook/CMakeLists.txt
deleted file mode 100644
index aee81f7..0000000
--- a/lib/MinHook/CMakeLists.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-cmake_minimum_required(VERSION 3.16)
-
-project(MinHook C)
-
-# Add include directory
-include_directories(include)
-
-# Collect source files
-file(GLOB_RECURSE MINHOOK_SOURCES
- "src/*.c"
-)
-
-# Create library
-add_library(MinHook STATIC ${MINHOOK_SOURCES})
-
-# Set include directories for users of this library
-target_include_directories(MinHook PUBLIC
- $
- $
-)
\ No newline at end of file
diff --git a/lib/MinHook/include/MinHook.h b/lib/MinHook/include/MinHook.h
deleted file mode 100644
index 492d83f..0000000
--- a/lib/MinHook/include/MinHook.h
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * MinHook - The Minimalistic API Hooking Library for x64/x86
- * Copyright (C) 2009-2017 Tsuda Kageyu.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
- * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#if !(defined _M_IX86) && !(defined _M_X64) && !(defined __i386__) && !(defined __x86_64__)
- #error MinHook supports only x86 and x64 systems.
-#endif
-
-#include
-
-// MinHook Error Codes.
-typedef enum MH_STATUS
-{
- // Unknown error. Should not be returned.
- MH_UNKNOWN = -1,
-
- // Successful.
- MH_OK = 0,
-
- // MinHook is already initialized.
- MH_ERROR_ALREADY_INITIALIZED,
-
- // MinHook is not initialized yet, or already uninitialized.
- MH_ERROR_NOT_INITIALIZED,
-
- // The hook for the specified target function is already created.
- MH_ERROR_ALREADY_CREATED,
-
- // The hook for the specified target function is not created yet.
- MH_ERROR_NOT_CREATED,
-
- // The hook for the specified target function is already enabled.
- MH_ERROR_ENABLED,
-
- // The hook for the specified target function is not enabled yet, or already
- // disabled.
- MH_ERROR_DISABLED,
-
- // The specified pointer is invalid. It points the address of non-allocated
- // and/or non-executable region.
- MH_ERROR_NOT_EXECUTABLE,
-
- // The specified target function cannot be hooked.
- MH_ERROR_UNSUPPORTED_FUNCTION,
-
- // Failed to allocate memory.
- MH_ERROR_MEMORY_ALLOC,
-
- // Failed to change the memory protection.
- MH_ERROR_MEMORY_PROTECT,
-
- // The specified module is not loaded.
- MH_ERROR_MODULE_NOT_FOUND,
-
- // The specified function is not found.
- MH_ERROR_FUNCTION_NOT_FOUND
-}
-MH_STATUS;
-
-// Can be passed as a parameter to MH_EnableHook, MH_DisableHook,
-// MH_QueueEnableHook or MH_QueueDisableHook.
-#define MH_ALL_HOOKS NULL
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
- // Initialize the MinHook library. You must call this function EXACTLY ONCE
- // at the beginning of your program.
- MH_STATUS WINAPI MH_Initialize(VOID);
-
- // Uninitialize the MinHook library. You must call this function EXACTLY
- // ONCE at the end of your program.
- MH_STATUS WINAPI MH_Uninitialize(VOID);
-
- // Creates a hook for the specified target function, in disabled state.
- // Parameters:
- // pTarget [in] A pointer to the target function, which will be
- // overridden by the detour function.
- // pDetour [in] A pointer to the detour function, which will override
- // the target function.
- // ppOriginal [out] A pointer to the trampoline function, which will be
- // used to call the original target function.
- // This parameter can be NULL.
- MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal);
-
- // Creates a hook for the specified API function, in disabled state.
- // Parameters:
- // pszModule [in] A pointer to the loaded module name which contains the
- // target function.
- // pszProcName [in] A pointer to the target function name, which will be
- // overridden by the detour function.
- // pDetour [in] A pointer to the detour function, which will override
- // the target function.
- // ppOriginal [out] A pointer to the trampoline function, which will be
- // used to call the original target function.
- // This parameter can be NULL.
- MH_STATUS WINAPI MH_CreateHookApi(
- LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal);
-
- // Creates a hook for the specified API function, in disabled state.
- // Parameters:
- // pszModule [in] A pointer to the loaded module name which contains the
- // target function.
- // pszProcName [in] A pointer to the target function name, which will be
- // overridden by the detour function.
- // pDetour [in] A pointer to the detour function, which will override
- // the target function.
- // ppOriginal [out] A pointer to the trampoline function, which will be
- // used to call the original target function.
- // This parameter can be NULL.
- // ppTarget [out] A pointer to the target function, which will be used
- // with other functions.
- // This parameter can be NULL.
- MH_STATUS WINAPI MH_CreateHookApiEx(
- LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal, LPVOID *ppTarget);
-
- // Removes an already created hook.
- // Parameters:
- // pTarget [in] A pointer to the target function.
- MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget);
-
- // Enables an already created hook.
- // Parameters:
- // pTarget [in] A pointer to the target function.
- // If this parameter is MH_ALL_HOOKS, all created hooks are
- // enabled in one go.
- MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget);
-
- // Disables an already created hook.
- // Parameters:
- // pTarget [in] A pointer to the target function.
- // If this parameter is MH_ALL_HOOKS, all created hooks are
- // disabled in one go.
- MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget);
-
- // Queues to enable an already created hook.
- // Parameters:
- // pTarget [in] A pointer to the target function.
- // If this parameter is MH_ALL_HOOKS, all created hooks are
- // queued to be enabled.
- MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget);
-
- // Queues to disable an already created hook.
- // Parameters:
- // pTarget [in] A pointer to the target function.
- // If this parameter is MH_ALL_HOOKS, all created hooks are
- // queued to be disabled.
- MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget);
-
- // Applies all queued changes in one go.
- MH_STATUS WINAPI MH_ApplyQueued(VOID);
-
- // Translates the MH_STATUS to its name as a string.
- const char * WINAPI MH_StatusToString(MH_STATUS status);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/lib/MinHook/src/buffer.c b/lib/MinHook/src/buffer.c
deleted file mode 100644
index 55412b0..0000000
--- a/lib/MinHook/src/buffer.c
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- * MinHook - The Minimalistic API Hooking Library for x64/x86
- * Copyright (C) 2009-2017 Tsuda Kageyu.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
- * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include
-#include "buffer.h"
-
-// Size of each memory block. (= page size of VirtualAlloc)
-#define MEMORY_BLOCK_SIZE 0x1000
-
-// Max range for seeking a memory block. (= 1024MB)
-#define MAX_MEMORY_RANGE 0x40000000
-
-// Memory protection flags to check the executable address.
-#define PAGE_EXECUTE_FLAGS \
- (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)
-
-// Memory slot.
-typedef struct _MEMORY_SLOT
-{
- union
- {
- struct _MEMORY_SLOT *pNext;
- UINT8 buffer[MEMORY_SLOT_SIZE];
- };
-} MEMORY_SLOT, *PMEMORY_SLOT;
-
-// Memory block info. Placed at the head of each block.
-typedef struct _MEMORY_BLOCK
-{
- struct _MEMORY_BLOCK *pNext;
- PMEMORY_SLOT pFree; // First element of the free slot list.
- UINT usedCount;
-} MEMORY_BLOCK, *PMEMORY_BLOCK;
-
-//-------------------------------------------------------------------------
-// Global Variables:
-//-------------------------------------------------------------------------
-
-// First element of the memory block list.
-PMEMORY_BLOCK g_pMemoryBlocks;
-
-//-------------------------------------------------------------------------
-VOID InitializeBuffer(VOID)
-{
- // Nothing to do for now.
-}
-
-//-------------------------------------------------------------------------
-VOID UninitializeBuffer(VOID)
-{
- PMEMORY_BLOCK pBlock = g_pMemoryBlocks;
- g_pMemoryBlocks = NULL;
-
- while (pBlock)
- {
- PMEMORY_BLOCK pNext = pBlock->pNext;
- VirtualFree(pBlock, 0, MEM_RELEASE);
- pBlock = pNext;
- }
-}
-
-//-------------------------------------------------------------------------
-#if defined(_M_X64) || defined(__x86_64__)
-static LPVOID FindPrevFreeRegion(LPVOID pAddress, LPVOID pMinAddr, DWORD dwAllocationGranularity)
-{
- ULONG_PTR tryAddr = (ULONG_PTR)pAddress;
-
- // Round down to the allocation granularity.
- tryAddr -= tryAddr % dwAllocationGranularity;
-
- // Start from the previous allocation granularity multiply.
- tryAddr -= dwAllocationGranularity;
-
- while (tryAddr >= (ULONG_PTR)pMinAddr)
- {
- MEMORY_BASIC_INFORMATION mbi;
- if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0)
- break;
-
- if (mbi.State == MEM_FREE)
- return (LPVOID)tryAddr;
-
- if ((ULONG_PTR)mbi.AllocationBase < dwAllocationGranularity)
- break;
-
- tryAddr = (ULONG_PTR)mbi.AllocationBase - dwAllocationGranularity;
- }
-
- return NULL;
-}
-#endif
-
-//-------------------------------------------------------------------------
-#if defined(_M_X64) || defined(__x86_64__)
-static LPVOID FindNextFreeRegion(LPVOID pAddress, LPVOID pMaxAddr, DWORD dwAllocationGranularity)
-{
- ULONG_PTR tryAddr = (ULONG_PTR)pAddress;
-
- // Round down to the allocation granularity.
- tryAddr -= tryAddr % dwAllocationGranularity;
-
- // Start from the next allocation granularity multiply.
- tryAddr += dwAllocationGranularity;
-
- while (tryAddr <= (ULONG_PTR)pMaxAddr)
- {
- MEMORY_BASIC_INFORMATION mbi;
- if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0)
- break;
-
- if (mbi.State == MEM_FREE)
- return (LPVOID)tryAddr;
-
- tryAddr = (ULONG_PTR)mbi.BaseAddress + mbi.RegionSize;
-
- // Round up to the next allocation granularity.
- tryAddr += dwAllocationGranularity - 1;
- tryAddr -= tryAddr % dwAllocationGranularity;
- }
-
- return NULL;
-}
-#endif
-
-//-------------------------------------------------------------------------
-static PMEMORY_BLOCK GetMemoryBlock(LPVOID pOrigin)
-{
- PMEMORY_BLOCK pBlock;
-#if defined(_M_X64) || defined(__x86_64__)
- ULONG_PTR minAddr;
- ULONG_PTR maxAddr;
-
- SYSTEM_INFO si;
- GetSystemInfo(&si);
- minAddr = (ULONG_PTR)si.lpMinimumApplicationAddress;
- maxAddr = (ULONG_PTR)si.lpMaximumApplicationAddress;
-
- // pOrigin ± 512MB
- if ((ULONG_PTR)pOrigin > MAX_MEMORY_RANGE && minAddr < (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE)
- minAddr = (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE;
-
- if (maxAddr > (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE)
- maxAddr = (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE;
-
- // Make room for MEMORY_BLOCK_SIZE bytes.
- maxAddr -= MEMORY_BLOCK_SIZE - 1;
-#endif
-
- // Look the registered blocks for a reachable one.
- for (pBlock = g_pMemoryBlocks; pBlock != NULL; pBlock = pBlock->pNext)
- {
-#if defined(_M_X64) || defined(__x86_64__)
- // Ignore the blocks too far.
- if ((ULONG_PTR)pBlock < minAddr || (ULONG_PTR)pBlock >= maxAddr)
- continue;
-#endif
- // The block has at least one unused slot.
- if (pBlock->pFree != NULL)
- return pBlock;
- }
-
-#if defined(_M_X64) || defined(__x86_64__)
- // Alloc a new block above if not found.
- {
- LPVOID pAlloc = pOrigin;
- while ((ULONG_PTR)pAlloc >= minAddr)
- {
- pAlloc = FindPrevFreeRegion(pAlloc, (LPVOID)minAddr, si.dwAllocationGranularity);
- if (pAlloc == NULL)
- break;
-
- pBlock = (PMEMORY_BLOCK)VirtualAlloc(
- pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
- if (pBlock != NULL)
- break;
- }
- }
-
- // Alloc a new block below if not found.
- if (pBlock == NULL)
- {
- LPVOID pAlloc = pOrigin;
- while ((ULONG_PTR)pAlloc <= maxAddr)
- {
- pAlloc = FindNextFreeRegion(pAlloc, (LPVOID)maxAddr, si.dwAllocationGranularity);
- if (pAlloc == NULL)
- break;
-
- pBlock = (PMEMORY_BLOCK)VirtualAlloc(
- pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
- if (pBlock != NULL)
- break;
- }
- }
-#else
- // In x86 mode, a memory block can be placed anywhere.
- pBlock = (PMEMORY_BLOCK)VirtualAlloc(
- NULL, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
-#endif
-
- if (pBlock != NULL)
- {
- // Build a linked list of all the slots.
- PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBlock + 1;
- pBlock->pFree = NULL;
- pBlock->usedCount = 0;
- do
- {
- pSlot->pNext = pBlock->pFree;
- pBlock->pFree = pSlot;
- pSlot++;
- } while ((ULONG_PTR)pSlot - (ULONG_PTR)pBlock <= MEMORY_BLOCK_SIZE - MEMORY_SLOT_SIZE);
-
- pBlock->pNext = g_pMemoryBlocks;
- g_pMemoryBlocks = pBlock;
- }
-
- return pBlock;
-}
-
-//-------------------------------------------------------------------------
-LPVOID AllocateBuffer(LPVOID pOrigin)
-{
- PMEMORY_SLOT pSlot;
- PMEMORY_BLOCK pBlock = GetMemoryBlock(pOrigin);
- if (pBlock == NULL)
- return NULL;
-
- // Remove an unused slot from the list.
- pSlot = pBlock->pFree;
- pBlock->pFree = pSlot->pNext;
- pBlock->usedCount++;
-#ifdef _DEBUG
- // Fill the slot with INT3 for debugging.
- memset(pSlot, 0xCC, sizeof(MEMORY_SLOT));
-#endif
- return pSlot;
-}
-
-//-------------------------------------------------------------------------
-VOID FreeBuffer(LPVOID pBuffer)
-{
- PMEMORY_BLOCK pBlock = g_pMemoryBlocks;
- PMEMORY_BLOCK pPrev = NULL;
- ULONG_PTR pTargetBlock = ((ULONG_PTR)pBuffer / MEMORY_BLOCK_SIZE) * MEMORY_BLOCK_SIZE;
-
- while (pBlock != NULL)
- {
- if ((ULONG_PTR)pBlock == pTargetBlock)
- {
- PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBuffer;
-#ifdef _DEBUG
- // Clear the released slot for debugging.
- memset(pSlot, 0x00, sizeof(MEMORY_SLOT));
-#endif
- // Restore the released slot to the list.
- pSlot->pNext = pBlock->pFree;
- pBlock->pFree = pSlot;
- pBlock->usedCount--;
-
- // Free if unused.
- if (pBlock->usedCount == 0)
- {
- if (pPrev)
- pPrev->pNext = pBlock->pNext;
- else
- g_pMemoryBlocks = pBlock->pNext;
-
- VirtualFree(pBlock, 0, MEM_RELEASE);
- }
-
- break;
- }
-
- pPrev = pBlock;
- pBlock = pBlock->pNext;
- }
-}
-
-//-------------------------------------------------------------------------
-BOOL IsExecutableAddress(LPVOID pAddress)
-{
- MEMORY_BASIC_INFORMATION mi;
- VirtualQuery(pAddress, &mi, sizeof(mi));
-
- return (mi.State == MEM_COMMIT && (mi.Protect & PAGE_EXECUTE_FLAGS));
-}
diff --git a/lib/MinHook/src/buffer.h b/lib/MinHook/src/buffer.h
deleted file mode 100644
index 204d551..0000000
--- a/lib/MinHook/src/buffer.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * MinHook - The Minimalistic API Hooking Library for x64/x86
- * Copyright (C) 2009-2017 Tsuda Kageyu.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
- * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-// Size of each memory slot.
-#if defined(_M_X64) || defined(__x86_64__)
- #define MEMORY_SLOT_SIZE 64
-#else
- #define MEMORY_SLOT_SIZE 32
-#endif
-
-VOID InitializeBuffer(VOID);
-VOID UninitializeBuffer(VOID);
-LPVOID AllocateBuffer(LPVOID pOrigin);
-VOID FreeBuffer(LPVOID pBuffer);
-BOOL IsExecutableAddress(LPVOID pAddress);
diff --git a/lib/MinHook/src/hde/hde32.c b/lib/MinHook/src/hde/hde32.c
deleted file mode 100644
index eb6af9b..0000000
--- a/lib/MinHook/src/hde/hde32.c
+++ /dev/null
@@ -1,324 +0,0 @@
-/*
- * Hacker Disassembler Engine 32 C
- * Copyright (c) 2008-2009, Vyacheslav Patkov.
- * All rights reserved.
- *
- */
-
-#if defined(_M_IX86) || defined(__i386__)
-
-#include
-#include "hde32.h"
-#include "table32.h"
-
-unsigned int hde32_disasm(const void *code, hde32s *hs)
-{
- uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0;
- uint8_t *ht = hde32_table, m_mod, m_reg, m_rm, disp_size = 0;
-
- memset(hs, 0, sizeof(hde32s));
-
- for (x = 16; x; x--)
- switch (c = *p++) {
- case 0xf3:
- hs->p_rep = c;
- pref |= PRE_F3;
- break;
- case 0xf2:
- hs->p_rep = c;
- pref |= PRE_F2;
- break;
- case 0xf0:
- hs->p_lock = c;
- pref |= PRE_LOCK;
- break;
- case 0x26: case 0x2e: case 0x36:
- case 0x3e: case 0x64: case 0x65:
- hs->p_seg = c;
- pref |= PRE_SEG;
- break;
- case 0x66:
- hs->p_66 = c;
- pref |= PRE_66;
- break;
- case 0x67:
- hs->p_67 = c;
- pref |= PRE_67;
- break;
- default:
- goto pref_done;
- }
- pref_done:
-
- hs->flags = (uint32_t)pref << 23;
-
- if (!pref)
- pref |= PRE_NONE;
-
- if ((hs->opcode = c) == 0x0f) {
- hs->opcode2 = c = *p++;
- ht += DELTA_OPCODES;
- } else if (c >= 0xa0 && c <= 0xa3) {
- if (pref & PRE_67)
- pref |= PRE_66;
- else
- pref &= ~PRE_66;
- }
-
- opcode = c;
- cflags = ht[ht[opcode / 4] + (opcode % 4)];
-
- if (cflags == C_ERROR) {
- hs->flags |= F_ERROR | F_ERROR_OPCODE;
- cflags = 0;
- if ((opcode & -3) == 0x24)
- cflags++;
- }
-
- x = 0;
- if (cflags & C_GROUP) {
- uint16_t t;
- t = *(uint16_t *)(ht + (cflags & 0x7f));
- cflags = (uint8_t)t;
- x = (uint8_t)(t >> 8);
- }
-
- if (hs->opcode2) {
- ht = hde32_table + DELTA_PREFIXES;
- if (ht[ht[opcode / 4] + (opcode % 4)] & pref)
- hs->flags |= F_ERROR | F_ERROR_OPCODE;
- }
-
- if (cflags & C_MODRM) {
- hs->flags |= F_MODRM;
- hs->modrm = c = *p++;
- hs->modrm_mod = m_mod = c >> 6;
- hs->modrm_rm = m_rm = c & 7;
- hs->modrm_reg = m_reg = (c & 0x3f) >> 3;
-
- if (x && ((x << m_reg) & 0x80))
- hs->flags |= F_ERROR | F_ERROR_OPCODE;
-
- if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) {
- uint8_t t = opcode - 0xd9;
- if (m_mod == 3) {
- ht = hde32_table + DELTA_FPU_MODRM + t*8;
- t = ht[m_reg] << m_rm;
- } else {
- ht = hde32_table + DELTA_FPU_REG;
- t = ht[t] << m_reg;
- }
- if (t & 0x80)
- hs->flags |= F_ERROR | F_ERROR_OPCODE;
- }
-
- if (pref & PRE_LOCK) {
- if (m_mod == 3) {
- hs->flags |= F_ERROR | F_ERROR_LOCK;
- } else {
- uint8_t *table_end, op = opcode;
- if (hs->opcode2) {
- ht = hde32_table + DELTA_OP2_LOCK_OK;
- table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK;
- } else {
- ht = hde32_table + DELTA_OP_LOCK_OK;
- table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK;
- op &= -2;
- }
- for (; ht != table_end; ht++)
- if (*ht++ == op) {
- if (!((*ht << m_reg) & 0x80))
- goto no_lock_error;
- else
- break;
- }
- hs->flags |= F_ERROR | F_ERROR_LOCK;
- no_lock_error:
- ;
- }
- }
-
- if (hs->opcode2) {
- switch (opcode) {
- case 0x20: case 0x22:
- m_mod = 3;
- if (m_reg > 4 || m_reg == 1)
- goto error_operand;
- else
- goto no_error_operand;
- case 0x21: case 0x23:
- m_mod = 3;
- if (m_reg == 4 || m_reg == 5)
- goto error_operand;
- else
- goto no_error_operand;
- }
- } else {
- switch (opcode) {
- case 0x8c:
- if (m_reg > 5)
- goto error_operand;
- else
- goto no_error_operand;
- case 0x8e:
- if (m_reg == 1 || m_reg > 5)
- goto error_operand;
- else
- goto no_error_operand;
- }
- }
-
- if (m_mod == 3) {
- uint8_t *table_end;
- if (hs->opcode2) {
- ht = hde32_table + DELTA_OP2_ONLY_MEM;
- table_end = ht + sizeof(hde32_table) - DELTA_OP2_ONLY_MEM;
- } else {
- ht = hde32_table + DELTA_OP_ONLY_MEM;
- table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM;
- }
- for (; ht != table_end; ht += 2)
- if (*ht++ == opcode) {
- if ((*ht++ & pref) && !((*ht << m_reg) & 0x80))
- goto error_operand;
- else
- break;
- }
- goto no_error_operand;
- } else if (hs->opcode2) {
- switch (opcode) {
- case 0x50: case 0xd7: case 0xf7:
- if (pref & (PRE_NONE | PRE_66))
- goto error_operand;
- break;
- case 0xd6:
- if (pref & (PRE_F2 | PRE_F3))
- goto error_operand;
- break;
- case 0xc5:
- goto error_operand;
- }
- goto no_error_operand;
- } else
- goto no_error_operand;
-
- error_operand:
- hs->flags |= F_ERROR | F_ERROR_OPERAND;
- no_error_operand:
-
- c = *p++;
- if (m_reg <= 1) {
- if (opcode == 0xf6)
- cflags |= C_IMM8;
- else if (opcode == 0xf7)
- cflags |= C_IMM_P66;
- }
-
- switch (m_mod) {
- case 0:
- if (pref & PRE_67) {
- if (m_rm == 6)
- disp_size = 2;
- } else
- if (m_rm == 5)
- disp_size = 4;
- break;
- case 1:
- disp_size = 1;
- break;
- case 2:
- disp_size = 2;
- if (!(pref & PRE_67))
- disp_size <<= 1;
- break;
- }
-
- if (m_mod != 3 && m_rm == 4 && !(pref & PRE_67)) {
- hs->flags |= F_SIB;
- p++;
- hs->sib = c;
- hs->sib_scale = c >> 6;
- hs->sib_index = (c & 0x3f) >> 3;
- if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1))
- disp_size = 4;
- }
-
- p--;
- switch (disp_size) {
- case 1:
- hs->flags |= F_DISP8;
- hs->disp.disp8 = *p;
- break;
- case 2:
- hs->flags |= F_DISP16;
- hs->disp.disp16 = *(uint16_t *)p;
- break;
- case 4:
- hs->flags |= F_DISP32;
- hs->disp.disp32 = *(uint32_t *)p;
- break;
- }
- p += disp_size;
- } else if (pref & PRE_LOCK)
- hs->flags |= F_ERROR | F_ERROR_LOCK;
-
- if (cflags & C_IMM_P66) {
- if (cflags & C_REL32) {
- if (pref & PRE_66) {
- hs->flags |= F_IMM16 | F_RELATIVE;
- hs->imm.imm16 = *(uint16_t *)p;
- p += 2;
- goto disasm_done;
- }
- goto rel32_ok;
- }
- if (pref & PRE_66) {
- hs->flags |= F_IMM16;
- hs->imm.imm16 = *(uint16_t *)p;
- p += 2;
- } else {
- hs->flags |= F_IMM32;
- hs->imm.imm32 = *(uint32_t *)p;
- p += 4;
- }
- }
-
- if (cflags & C_IMM16) {
- if (hs->flags & F_IMM32) {
- hs->flags |= F_IMM16;
- hs->disp.disp16 = *(uint16_t *)p;
- } else if (hs->flags & F_IMM16) {
- hs->flags |= F_2IMM16;
- hs->disp.disp16 = *(uint16_t *)p;
- } else {
- hs->flags |= F_IMM16;
- hs->imm.imm16 = *(uint16_t *)p;
- }
- p += 2;
- }
- if (cflags & C_IMM8) {
- hs->flags |= F_IMM8;
- hs->imm.imm8 = *p++;
- }
-
- if (cflags & C_REL32) {
- rel32_ok:
- hs->flags |= F_IMM32 | F_RELATIVE;
- hs->imm.imm32 = *(uint32_t *)p;
- p += 4;
- } else if (cflags & C_REL8) {
- hs->flags |= F_IMM8 | F_RELATIVE;
- hs->imm.imm8 = *p++;
- }
-
- disasm_done:
-
- if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) {
- hs->flags |= F_ERROR | F_ERROR_LENGTH;
- hs->len = 15;
- }
-
- return (unsigned int)hs->len;
-}
-
-#endif // defined(_M_IX86) || defined(__i386__)
diff --git a/lib/MinHook/src/hde/hde32.h b/lib/MinHook/src/hde/hde32.h
deleted file mode 100644
index 1112450..0000000
--- a/lib/MinHook/src/hde/hde32.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Hacker Disassembler Engine 32
- * Copyright (c) 2006-2009, Vyacheslav Patkov.
- * All rights reserved.
- *
- * hde32.h: C/C++ header file
- *
- */
-
-#ifndef _HDE32_H_
-#define _HDE32_H_
-
-/* stdint.h - C99 standard header
- * http://en.wikipedia.org/wiki/stdint.h
- *
- * if your compiler doesn't contain "stdint.h" header (for
- * example, Microsoft Visual C++), you can download file:
- * http://www.azillionmonkeys.com/qed/pstdint.h
- * and change next line to:
- * #include "pstdint.h"
- */
-#include "pstdint.h"
-
-#define F_MODRM 0x00000001
-#define F_SIB 0x00000002
-#define F_IMM8 0x00000004
-#define F_IMM16 0x00000008
-#define F_IMM32 0x00000010
-#define F_DISP8 0x00000020
-#define F_DISP16 0x00000040
-#define F_DISP32 0x00000080
-#define F_RELATIVE 0x00000100
-#define F_2IMM16 0x00000800
-#define F_ERROR 0x00001000
-#define F_ERROR_OPCODE 0x00002000
-#define F_ERROR_LENGTH 0x00004000
-#define F_ERROR_LOCK 0x00008000
-#define F_ERROR_OPERAND 0x00010000
-#define F_PREFIX_REPNZ 0x01000000
-#define F_PREFIX_REPX 0x02000000
-#define F_PREFIX_REP 0x03000000
-#define F_PREFIX_66 0x04000000
-#define F_PREFIX_67 0x08000000
-#define F_PREFIX_LOCK 0x10000000
-#define F_PREFIX_SEG 0x20000000
-#define F_PREFIX_ANY 0x3f000000
-
-#define PREFIX_SEGMENT_CS 0x2e
-#define PREFIX_SEGMENT_SS 0x36
-#define PREFIX_SEGMENT_DS 0x3e
-#define PREFIX_SEGMENT_ES 0x26
-#define PREFIX_SEGMENT_FS 0x64
-#define PREFIX_SEGMENT_GS 0x65
-#define PREFIX_LOCK 0xf0
-#define PREFIX_REPNZ 0xf2
-#define PREFIX_REPX 0xf3
-#define PREFIX_OPERAND_SIZE 0x66
-#define PREFIX_ADDRESS_SIZE 0x67
-
-#pragma pack(push,1)
-
-typedef struct {
- uint8_t len;
- uint8_t p_rep;
- uint8_t p_lock;
- uint8_t p_seg;
- uint8_t p_66;
- uint8_t p_67;
- uint8_t opcode;
- uint8_t opcode2;
- uint8_t modrm;
- uint8_t modrm_mod;
- uint8_t modrm_reg;
- uint8_t modrm_rm;
- uint8_t sib;
- uint8_t sib_scale;
- uint8_t sib_index;
- uint8_t sib_base;
- union {
- uint8_t imm8;
- uint16_t imm16;
- uint32_t imm32;
- } imm;
- union {
- uint8_t disp8;
- uint16_t disp16;
- uint32_t disp32;
- } disp;
- uint32_t flags;
-} hde32s;
-
-#pragma pack(pop)
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* __cdecl */
-unsigned int hde32_disasm(const void *code, hde32s *hs);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _HDE32_H_ */
diff --git a/lib/MinHook/src/hde/hde64.c b/lib/MinHook/src/hde/hde64.c
deleted file mode 100644
index ce773b1..0000000
--- a/lib/MinHook/src/hde/hde64.c
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * Hacker Disassembler Engine 64 C
- * Copyright (c) 2008-2009, Vyacheslav Patkov.
- * All rights reserved.
- *
- */
-
-#if defined(_M_X64) || defined(__x86_64__)
-
-#include
-#include "hde64.h"
-#include "table64.h"
-
-unsigned int hde64_disasm(const void *code, hde64s *hs)
-{
- uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0;
- uint8_t *ht = hde64_table, m_mod, m_reg, m_rm, disp_size = 0;
- uint8_t op64 = 0;
-
- memset(hs, 0, sizeof(hde64s));
-
- for (x = 16; x; x--)
- switch (c = *p++) {
- case 0xf3:
- hs->p_rep = c;
- pref |= PRE_F3;
- break;
- case 0xf2:
- hs->p_rep = c;
- pref |= PRE_F2;
- break;
- case 0xf0:
- hs->p_lock = c;
- pref |= PRE_LOCK;
- break;
- case 0x26: case 0x2e: case 0x36:
- case 0x3e: case 0x64: case 0x65:
- hs->p_seg = c;
- pref |= PRE_SEG;
- break;
- case 0x66:
- hs->p_66 = c;
- pref |= PRE_66;
- break;
- case 0x67:
- hs->p_67 = c;
- pref |= PRE_67;
- break;
- default:
- goto pref_done;
- }
- pref_done:
-
- hs->flags = (uint32_t)pref << 23;
-
- if (!pref)
- pref |= PRE_NONE;
-
- if ((c & 0xf0) == 0x40) {
- hs->flags |= F_PREFIX_REX;
- if ((hs->rex_w = (c & 0xf) >> 3) && (*p & 0xf8) == 0xb8)
- op64++;
- hs->rex_r = (c & 7) >> 2;
- hs->rex_x = (c & 3) >> 1;
- hs->rex_b = c & 1;
- if (((c = *p++) & 0xf0) == 0x40) {
- opcode = c;
- goto error_opcode;
- }
- }
-
- if ((hs->opcode = c) == 0x0f) {
- hs->opcode2 = c = *p++;
- ht += DELTA_OPCODES;
- } else if (c >= 0xa0 && c <= 0xa3) {
- op64++;
- if (pref & PRE_67)
- pref |= PRE_66;
- else
- pref &= ~PRE_66;
- }
-
- opcode = c;
- cflags = ht[ht[opcode / 4] + (opcode % 4)];
-
- if (cflags == C_ERROR) {
- error_opcode:
- hs->flags |= F_ERROR | F_ERROR_OPCODE;
- cflags = 0;
- if ((opcode & -3) == 0x24)
- cflags++;
- }
-
- x = 0;
- if (cflags & C_GROUP) {
- uint16_t t;
- t = *(uint16_t *)(ht + (cflags & 0x7f));
- cflags = (uint8_t)t;
- x = (uint8_t)(t >> 8);
- }
-
- if (hs->opcode2) {
- ht = hde64_table + DELTA_PREFIXES;
- if (ht[ht[opcode / 4] + (opcode % 4)] & pref)
- hs->flags |= F_ERROR | F_ERROR_OPCODE;
- }
-
- if (cflags & C_MODRM) {
- hs->flags |= F_MODRM;
- hs->modrm = c = *p++;
- hs->modrm_mod = m_mod = c >> 6;
- hs->modrm_rm = m_rm = c & 7;
- hs->modrm_reg = m_reg = (c & 0x3f) >> 3;
-
- if (x && ((x << m_reg) & 0x80))
- hs->flags |= F_ERROR | F_ERROR_OPCODE;
-
- if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) {
- uint8_t t = opcode - 0xd9;
- if (m_mod == 3) {
- ht = hde64_table + DELTA_FPU_MODRM + t*8;
- t = ht[m_reg] << m_rm;
- } else {
- ht = hde64_table + DELTA_FPU_REG;
- t = ht[t] << m_reg;
- }
- if (t & 0x80)
- hs->flags |= F_ERROR | F_ERROR_OPCODE;
- }
-
- if (pref & PRE_LOCK) {
- if (m_mod == 3) {
- hs->flags |= F_ERROR | F_ERROR_LOCK;
- } else {
- uint8_t *table_end, op = opcode;
- if (hs->opcode2) {
- ht = hde64_table + DELTA_OP2_LOCK_OK;
- table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK;
- } else {
- ht = hde64_table + DELTA_OP_LOCK_OK;
- table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK;
- op &= -2;
- }
- for (; ht != table_end; ht++)
- if (*ht++ == op) {
- if (!((*ht << m_reg) & 0x80))
- goto no_lock_error;
- else
- break;
- }
- hs->flags |= F_ERROR | F_ERROR_LOCK;
- no_lock_error:
- ;
- }
- }
-
- if (hs->opcode2) {
- switch (opcode) {
- case 0x20: case 0x22:
- m_mod = 3;
- if (m_reg > 4 || m_reg == 1)
- goto error_operand;
- else
- goto no_error_operand;
- case 0x21: case 0x23:
- m_mod = 3;
- if (m_reg == 4 || m_reg == 5)
- goto error_operand;
- else
- goto no_error_operand;
- }
- } else {
- switch (opcode) {
- case 0x8c:
- if (m_reg > 5)
- goto error_operand;
- else
- goto no_error_operand;
- case 0x8e:
- if (m_reg == 1 || m_reg > 5)
- goto error_operand;
- else
- goto no_error_operand;
- }
- }
-
- if (m_mod == 3) {
- uint8_t *table_end;
- if (hs->opcode2) {
- ht = hde64_table + DELTA_OP2_ONLY_MEM;
- table_end = ht + sizeof(hde64_table) - DELTA_OP2_ONLY_MEM;
- } else {
- ht = hde64_table + DELTA_OP_ONLY_MEM;
- table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM;
- }
- for (; ht != table_end; ht += 2)
- if (*ht++ == opcode) {
- if ((*ht++ & pref) && !((*ht << m_reg) & 0x80))
- goto error_operand;
- else
- break;
- }
- goto no_error_operand;
- } else if (hs->opcode2) {
- switch (opcode) {
- case 0x50: case 0xd7: case 0xf7:
- if (pref & (PRE_NONE | PRE_66))
- goto error_operand;
- break;
- case 0xd6:
- if (pref & (PRE_F2 | PRE_F3))
- goto error_operand;
- break;
- case 0xc5:
- goto error_operand;
- }
- goto no_error_operand;
- } else
- goto no_error_operand;
-
- error_operand:
- hs->flags |= F_ERROR | F_ERROR_OPERAND;
- no_error_operand:
-
- c = *p++;
- if (m_reg <= 1) {
- if (opcode == 0xf6)
- cflags |= C_IMM8;
- else if (opcode == 0xf7)
- cflags |= C_IMM_P66;
- }
-
- switch (m_mod) {
- case 0:
- if (pref & PRE_67) {
- if (m_rm == 6)
- disp_size = 2;
- } else
- if (m_rm == 5)
- disp_size = 4;
- break;
- case 1:
- disp_size = 1;
- break;
- case 2:
- disp_size = 2;
- if (!(pref & PRE_67))
- disp_size <<= 1;
- break;
- }
-
- if (m_mod != 3 && m_rm == 4) {
- hs->flags |= F_SIB;
- p++;
- hs->sib = c;
- hs->sib_scale = c >> 6;
- hs->sib_index = (c & 0x3f) >> 3;
- if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1))
- disp_size = 4;
- }
-
- p--;
- switch (disp_size) {
- case 1:
- hs->flags |= F_DISP8;
- hs->disp.disp8 = *p;
- break;
- case 2:
- hs->flags |= F_DISP16;
- hs->disp.disp16 = *(uint16_t *)p;
- break;
- case 4:
- hs->flags |= F_DISP32;
- hs->disp.disp32 = *(uint32_t *)p;
- break;
- }
- p += disp_size;
- } else if (pref & PRE_LOCK)
- hs->flags |= F_ERROR | F_ERROR_LOCK;
-
- if (cflags & C_IMM_P66) {
- if (cflags & C_REL32) {
- if (pref & PRE_66) {
- hs->flags |= F_IMM16 | F_RELATIVE;
- hs->imm.imm16 = *(uint16_t *)p;
- p += 2;
- goto disasm_done;
- }
- goto rel32_ok;
- }
- if (op64) {
- hs->flags |= F_IMM64;
- hs->imm.imm64 = *(uint64_t *)p;
- p += 8;
- } else if (!(pref & PRE_66)) {
- hs->flags |= F_IMM32;
- hs->imm.imm32 = *(uint32_t *)p;
- p += 4;
- } else
- goto imm16_ok;
- }
-
-
- if (cflags & C_IMM16) {
- imm16_ok:
- hs->flags |= F_IMM16;
- hs->imm.imm16 = *(uint16_t *)p;
- p += 2;
- }
- if (cflags & C_IMM8) {
- hs->flags |= F_IMM8;
- hs->imm.imm8 = *p++;
- }
-
- if (cflags & C_REL32) {
- rel32_ok:
- hs->flags |= F_IMM32 | F_RELATIVE;
- hs->imm.imm32 = *(uint32_t *)p;
- p += 4;
- } else if (cflags & C_REL8) {
- hs->flags |= F_IMM8 | F_RELATIVE;
- hs->imm.imm8 = *p++;
- }
-
- disasm_done:
-
- if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) {
- hs->flags |= F_ERROR | F_ERROR_LENGTH;
- hs->len = 15;
- }
-
- return (unsigned int)hs->len;
-}
-
-#endif // defined(_M_X64) || defined(__x86_64__)
diff --git a/lib/MinHook/src/hde/hde64.h b/lib/MinHook/src/hde/hde64.h
deleted file mode 100644
index ecbf4df..0000000
--- a/lib/MinHook/src/hde/hde64.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Hacker Disassembler Engine 64
- * Copyright (c) 2008-2009, Vyacheslav Patkov.
- * All rights reserved.
- *
- * hde64.h: C/C++ header file
- *
- */
-
-#ifndef _HDE64_H_
-#define _HDE64_H_
-
-/* stdint.h - C99 standard header
- * http://en.wikipedia.org/wiki/stdint.h
- *
- * if your compiler doesn't contain "stdint.h" header (for
- * example, Microsoft Visual C++), you can download file:
- * http://www.azillionmonkeys.com/qed/pstdint.h
- * and change next line to:
- * #include "pstdint.h"
- */
-#include "pstdint.h"
-
-#define F_MODRM 0x00000001
-#define F_SIB 0x00000002
-#define F_IMM8 0x00000004
-#define F_IMM16 0x00000008
-#define F_IMM32 0x00000010
-#define F_IMM64 0x00000020
-#define F_DISP8 0x00000040
-#define F_DISP16 0x00000080
-#define F_DISP32 0x00000100
-#define F_RELATIVE 0x00000200
-#define F_ERROR 0x00001000
-#define F_ERROR_OPCODE 0x00002000
-#define F_ERROR_LENGTH 0x00004000
-#define F_ERROR_LOCK 0x00008000
-#define F_ERROR_OPERAND 0x00010000
-#define F_PREFIX_REPNZ 0x01000000
-#define F_PREFIX_REPX 0x02000000
-#define F_PREFIX_REP 0x03000000
-#define F_PREFIX_66 0x04000000
-#define F_PREFIX_67 0x08000000
-#define F_PREFIX_LOCK 0x10000000
-#define F_PREFIX_SEG 0x20000000
-#define F_PREFIX_REX 0x40000000
-#define F_PREFIX_ANY 0x7f000000
-
-#define PREFIX_SEGMENT_CS 0x2e
-#define PREFIX_SEGMENT_SS 0x36
-#define PREFIX_SEGMENT_DS 0x3e
-#define PREFIX_SEGMENT_ES 0x26
-#define PREFIX_SEGMENT_FS 0x64
-#define PREFIX_SEGMENT_GS 0x65
-#define PREFIX_LOCK 0xf0
-#define PREFIX_REPNZ 0xf2
-#define PREFIX_REPX 0xf3
-#define PREFIX_OPERAND_SIZE 0x66
-#define PREFIX_ADDRESS_SIZE 0x67
-
-#pragma pack(push,1)
-
-typedef struct {
- uint8_t len;
- uint8_t p_rep;
- uint8_t p_lock;
- uint8_t p_seg;
- uint8_t p_66;
- uint8_t p_67;
- uint8_t rex;
- uint8_t rex_w;
- uint8_t rex_r;
- uint8_t rex_x;
- uint8_t rex_b;
- uint8_t opcode;
- uint8_t opcode2;
- uint8_t modrm;
- uint8_t modrm_mod;
- uint8_t modrm_reg;
- uint8_t modrm_rm;
- uint8_t sib;
- uint8_t sib_scale;
- uint8_t sib_index;
- uint8_t sib_base;
- union {
- uint8_t imm8;
- uint16_t imm16;
- uint32_t imm32;
- uint64_t imm64;
- } imm;
- union {
- uint8_t disp8;
- uint16_t disp16;
- uint32_t disp32;
- } disp;
- uint32_t flags;
-} hde64s;
-
-#pragma pack(pop)
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* __cdecl */
-unsigned int hde64_disasm(const void *code, hde64s *hs);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _HDE64_H_ */
diff --git a/lib/MinHook/src/hde/pstdint.h b/lib/MinHook/src/hde/pstdint.h
deleted file mode 100644
index 84d82a0..0000000
--- a/lib/MinHook/src/hde/pstdint.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * MinHook - The Minimalistic API Hooking Library for x64/x86
- * Copyright (C) 2009-2017 Tsuda Kageyu. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include
-
-// Integer types for HDE.
-typedef INT8 int8_t;
-typedef INT16 int16_t;
-typedef INT32 int32_t;
-typedef INT64 int64_t;
-typedef UINT8 uint8_t;
-typedef UINT16 uint16_t;
-typedef UINT32 uint32_t;
-typedef UINT64 uint64_t;
diff --git a/lib/MinHook/src/hde/table32.h b/lib/MinHook/src/hde/table32.h
deleted file mode 100644
index 7b3e12e..0000000
--- a/lib/MinHook/src/hde/table32.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Hacker Disassembler Engine 32 C
- * Copyright (c) 2008-2009, Vyacheslav Patkov.
- * All rights reserved.
- *
- */
-
-#define C_NONE 0x00
-#define C_MODRM 0x01
-#define C_IMM8 0x02
-#define C_IMM16 0x04
-#define C_IMM_P66 0x10
-#define C_REL8 0x20
-#define C_REL32 0x40
-#define C_GROUP 0x80
-#define C_ERROR 0xff
-
-#define PRE_ANY 0x00
-#define PRE_NONE 0x01
-#define PRE_F2 0x02
-#define PRE_F3 0x04
-#define PRE_66 0x08
-#define PRE_67 0x10
-#define PRE_LOCK 0x20
-#define PRE_SEG 0x40
-#define PRE_ALL 0xff
-
-#define DELTA_OPCODES 0x4a
-#define DELTA_FPU_REG 0xf1
-#define DELTA_FPU_MODRM 0xf8
-#define DELTA_PREFIXES 0x130
-#define DELTA_OP_LOCK_OK 0x1a1
-#define DELTA_OP2_LOCK_OK 0x1b9
-#define DELTA_OP_ONLY_MEM 0x1cb
-#define DELTA_OP2_ONLY_MEM 0x1da
-
-unsigned char hde32_table[] = {
- 0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,
- 0xa8,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xac,0xaa,0xb2,0xaa,0x9f,0x9f,
- 0x9f,0x9f,0xb5,0xa3,0xa3,0xa4,0xaa,0xaa,0xba,0xaa,0x96,0xaa,0xa8,0xaa,0xc3,
- 0xc3,0x96,0x96,0xb7,0xae,0xd6,0xbd,0xa3,0xc5,0xa3,0xa3,0x9f,0xc3,0x9c,0xaa,
- 0xaa,0xac,0xaa,0xbf,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0x90,
- 0x82,0x7d,0x97,0x59,0x59,0x59,0x59,0x59,0x7f,0x59,0x59,0x60,0x7d,0x7f,0x7f,
- 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x9a,0x88,0x7d,
- 0x59,0x50,0x50,0x50,0x50,0x59,0x59,0x59,0x59,0x61,0x94,0x61,0x9e,0x59,0x59,
- 0x85,0x59,0x92,0xa3,0x60,0x60,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,
- 0x59,0x59,0x9f,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xcc,0x01,0xbc,0x03,0xf0,
- 0x10,0x10,0x10,0x10,0x50,0x50,0x50,0x50,0x14,0x20,0x20,0x20,0x20,0x01,0x01,
- 0x01,0x01,0xc4,0x02,0x10,0x00,0x00,0x00,0x00,0x01,0x01,0xc0,0xc2,0x10,0x11,
- 0x02,0x03,0x11,0x03,0x03,0x04,0x00,0x00,0x14,0x00,0x02,0x00,0x00,0xc6,0xc8,
- 0x02,0x02,0x02,0x02,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0xca,
- 0x01,0x01,0x01,0x00,0x06,0x00,0x04,0x00,0xc0,0xc2,0x01,0x01,0x03,0x01,0xff,
- 0xff,0x01,0x00,0x03,0xc4,0xc4,0xc6,0x03,0x01,0x01,0x01,0xff,0x03,0x03,0x03,
- 0xc8,0x40,0x00,0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00,
- 0x00,0x00,0x00,0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00,
- 0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0xff,0xff,0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x7f,0x00,0x00,0xff,0x4a,0x4a,0x4a,0x4a,0x4b,0x52,0x4a,0x4a,0x4a,0x4a,0x4f,
- 0x4c,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x55,0x45,0x40,0x4a,0x4a,0x4a,
- 0x45,0x59,0x4d,0x46,0x4a,0x5d,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,
- 0x4a,0x4a,0x4a,0x4a,0x4a,0x61,0x63,0x67,0x4e,0x4a,0x4a,0x6b,0x6d,0x4a,0x4a,
- 0x45,0x6d,0x4a,0x4a,0x44,0x45,0x4a,0x4a,0x00,0x00,0x00,0x02,0x0d,0x06,0x06,
- 0x06,0x06,0x0e,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x00,0x06,0x06,0x02,0x06,
- 0x00,0x0a,0x0a,0x07,0x07,0x06,0x02,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04,
- 0x04,0x04,0x00,0x00,0x00,0x0e,0x05,0x06,0x06,0x06,0x01,0x06,0x00,0x00,0x08,
- 0x00,0x10,0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01,
- 0x86,0x00,0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba,
- 0xf8,0xbb,0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00,
- 0xc4,0xff,0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00,
- 0x13,0x09,0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07,
- 0xb2,0xff,0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf,
- 0xe7,0x08,0x00,0xf0,0x02,0x00
-};
diff --git a/lib/MinHook/src/hde/table64.h b/lib/MinHook/src/hde/table64.h
deleted file mode 100644
index 01d4541..0000000
--- a/lib/MinHook/src/hde/table64.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Hacker Disassembler Engine 64 C
- * Copyright (c) 2008-2009, Vyacheslav Patkov.
- * All rights reserved.
- *
- */
-
-#define C_NONE 0x00
-#define C_MODRM 0x01
-#define C_IMM8 0x02
-#define C_IMM16 0x04
-#define C_IMM_P66 0x10
-#define C_REL8 0x20
-#define C_REL32 0x40
-#define C_GROUP 0x80
-#define C_ERROR 0xff
-
-#define PRE_ANY 0x00
-#define PRE_NONE 0x01
-#define PRE_F2 0x02
-#define PRE_F3 0x04
-#define PRE_66 0x08
-#define PRE_67 0x10
-#define PRE_LOCK 0x20
-#define PRE_SEG 0x40
-#define PRE_ALL 0xff
-
-#define DELTA_OPCODES 0x4a
-#define DELTA_FPU_REG 0xfd
-#define DELTA_FPU_MODRM 0x104
-#define DELTA_PREFIXES 0x13c
-#define DELTA_OP_LOCK_OK 0x1ae
-#define DELTA_OP2_LOCK_OK 0x1c6
-#define DELTA_OP_ONLY_MEM 0x1d8
-#define DELTA_OP2_ONLY_MEM 0x1e7
-
-unsigned char hde64_table[] = {
- 0xa5,0xaa,0xa5,0xb8,0xa5,0xaa,0xa5,0xaa,0xa5,0xb8,0xa5,0xb8,0xa5,0xb8,0xa5,
- 0xb8,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xac,0xc0,0xcc,0xc0,0xa1,0xa1,
- 0xa1,0xa1,0xb1,0xa5,0xa5,0xa6,0xc0,0xc0,0xd7,0xda,0xe0,0xc0,0xe4,0xc0,0xea,
- 0xea,0xe0,0xe0,0x98,0xc8,0xee,0xf1,0xa5,0xd3,0xa5,0xa5,0xa1,0xea,0x9e,0xc0,
- 0xc0,0xc2,0xc0,0xe6,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0xab,
- 0x8b,0x90,0x64,0x5b,0x5b,0x5b,0x5b,0x5b,0x92,0x5b,0x5b,0x76,0x90,0x92,0x92,
- 0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x6a,0x73,0x90,
- 0x5b,0x52,0x52,0x52,0x52,0x5b,0x5b,0x5b,0x5b,0x77,0x7c,0x77,0x85,0x5b,0x5b,
- 0x70,0x5b,0x7a,0xaf,0x76,0x76,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,
- 0x5b,0x5b,0x86,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xd5,0x03,0xcc,0x01,0xbc,
- 0x03,0xf0,0x03,0x03,0x04,0x00,0x50,0x50,0x50,0x50,0xff,0x20,0x20,0x20,0x20,
- 0x01,0x01,0x01,0x01,0xc4,0x02,0x10,0xff,0xff,0xff,0x01,0x00,0x03,0x11,0xff,
- 0x03,0xc4,0xc6,0xc8,0x02,0x10,0x00,0xff,0xcc,0x01,0x01,0x01,0x00,0x00,0x00,
- 0x00,0x01,0x01,0x03,0x01,0xff,0xff,0xc0,0xc2,0x10,0x11,0x02,0x03,0x01,0x01,
- 0x01,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x10,
- 0x10,0x10,0x10,0x02,0x10,0x00,0x00,0xc6,0xc8,0x02,0x02,0x02,0x02,0x06,0x00,
- 0x04,0x00,0x02,0xff,0x00,0xc0,0xc2,0x01,0x01,0x03,0x03,0x03,0xca,0x40,0x00,
- 0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00,0x00,0x00,0x00,
- 0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0xff,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,
- 0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x00,0x00,
- 0xff,0x40,0x40,0x40,0x40,0x41,0x49,0x40,0x40,0x40,0x40,0x4c,0x42,0x40,0x40,
- 0x40,0x40,0x40,0x40,0x40,0x40,0x4f,0x44,0x53,0x40,0x40,0x40,0x44,0x57,0x43,
- 0x5c,0x40,0x60,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
- 0x40,0x40,0x64,0x66,0x6e,0x6b,0x40,0x40,0x6a,0x46,0x40,0x40,0x44,0x46,0x40,
- 0x40,0x5b,0x44,0x40,0x40,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x06,0x01,0x06,
- 0x06,0x02,0x06,0x06,0x00,0x06,0x00,0x0a,0x0a,0x00,0x00,0x00,0x02,0x07,0x07,
- 0x06,0x02,0x0d,0x06,0x06,0x06,0x0e,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04,
- 0x04,0x04,0x05,0x06,0x06,0x06,0x00,0x00,0x00,0x0e,0x00,0x00,0x08,0x00,0x10,
- 0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01,0x86,0x00,
- 0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba,0xf8,0xbb,
- 0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00,0xc4,0xff,
- 0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00,0x13,0x09,
- 0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07,0xb2,0xff,
- 0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf,0xe7,0x08,
- 0x00,0xf0,0x02,0x00
-};
diff --git a/lib/MinHook/src/hook.c b/lib/MinHook/src/hook.c
deleted file mode 100644
index abb2397..0000000
--- a/lib/MinHook/src/hook.c
+++ /dev/null
@@ -1,923 +0,0 @@
-/*
- * MinHook - The Minimalistic API Hooking Library for x64/x86
- * Copyright (C) 2009-2017 Tsuda Kageyu.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
- * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include
-#include
-#include
-
-#include "MinHook.h"
-#include "buffer.h"
-#include "trampoline.h"
-
-#ifndef ARRAYSIZE
- #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
-#endif
-
-// Initial capacity of the HOOK_ENTRY buffer.
-#define INITIAL_HOOK_CAPACITY 32
-
-// Initial capacity of the thread IDs buffer.
-#define INITIAL_THREAD_CAPACITY 128
-
-// Special hook position values.
-#define INVALID_HOOK_POS UINT_MAX
-#define ALL_HOOKS_POS UINT_MAX
-
-// Freeze() action argument defines.
-#define ACTION_DISABLE 0
-#define ACTION_ENABLE 1
-#define ACTION_APPLY_QUEUED 2
-
-// Thread access rights for suspending/resuming threads.
-#define THREAD_ACCESS \
- (THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION | THREAD_SET_CONTEXT)
-
-// Hook information.
-typedef struct _HOOK_ENTRY
-{
- LPVOID pTarget; // Address of the target function.
- LPVOID pDetour; // Address of the detour or relay function.
- LPVOID pTrampoline; // Address of the trampoline function.
- UINT8 backup[8]; // Original prologue of the target function.
-
- UINT8 patchAbove : 1; // Uses the hot patch area.
- UINT8 isEnabled : 1; // Enabled.
- UINT8 queueEnable : 1; // Queued for enabling/disabling when != isEnabled.
-
- UINT nIP : 4; // Count of the instruction boundaries.
- UINT8 oldIPs[8]; // Instruction boundaries of the target function.
- UINT8 newIPs[8]; // Instruction boundaries of the trampoline function.
-} HOOK_ENTRY, *PHOOK_ENTRY;
-
-// Suspended threads for Freeze()/Unfreeze().
-typedef struct _FROZEN_THREADS
-{
- LPDWORD pItems; // Data heap
- UINT capacity; // Size of allocated data heap, items
- UINT size; // Actual number of data items
-} FROZEN_THREADS, *PFROZEN_THREADS;
-
-//-------------------------------------------------------------------------
-// Global Variables:
-//-------------------------------------------------------------------------
-
-// Spin lock flag for EnterSpinLock()/LeaveSpinLock().
-volatile LONG g_isLocked = FALSE;
-
-// Private heap handle. If not NULL, this library is initialized.
-HANDLE g_hHeap = NULL;
-
-// Hook entries.
-struct
-{
- PHOOK_ENTRY pItems; // Data heap
- UINT capacity; // Size of allocated data heap, items
- UINT size; // Actual number of data items
-} g_hooks;
-
-//-------------------------------------------------------------------------
-// Returns INVALID_HOOK_POS if not found.
-static UINT FindHookEntry(LPVOID pTarget)
-{
- UINT i;
- for (i = 0; i < g_hooks.size; ++i)
- {
- if ((ULONG_PTR)pTarget == (ULONG_PTR)g_hooks.pItems[i].pTarget)
- return i;
- }
-
- return INVALID_HOOK_POS;
-}
-
-//-------------------------------------------------------------------------
-static PHOOK_ENTRY AddHookEntry()
-{
- if (g_hooks.pItems == NULL)
- {
- g_hooks.capacity = INITIAL_HOOK_CAPACITY;
- g_hooks.pItems = (PHOOK_ENTRY)HeapAlloc(
- g_hHeap, 0, g_hooks.capacity * sizeof(HOOK_ENTRY));
- if (g_hooks.pItems == NULL)
- return NULL;
- }
- else if (g_hooks.size >= g_hooks.capacity)
- {
- PHOOK_ENTRY p = (PHOOK_ENTRY)HeapReAlloc(
- g_hHeap, 0, g_hooks.pItems, (g_hooks.capacity * 2) * sizeof(HOOK_ENTRY));
- if (p == NULL)
- return NULL;
-
- g_hooks.capacity *= 2;
- g_hooks.pItems = p;
- }
-
- return &g_hooks.pItems[g_hooks.size++];
-}
-
-//-------------------------------------------------------------------------
-static VOID DeleteHookEntry(UINT pos)
-{
- if (pos < g_hooks.size - 1)
- g_hooks.pItems[pos] = g_hooks.pItems[g_hooks.size - 1];
-
- g_hooks.size--;
-
- if (g_hooks.capacity / 2 >= INITIAL_HOOK_CAPACITY && g_hooks.capacity / 2 >= g_hooks.size)
- {
- PHOOK_ENTRY p = (PHOOK_ENTRY)HeapReAlloc(
- g_hHeap, 0, g_hooks.pItems, (g_hooks.capacity / 2) * sizeof(HOOK_ENTRY));
- if (p == NULL)
- return;
-
- g_hooks.capacity /= 2;
- g_hooks.pItems = p;
- }
-}
-
-//-------------------------------------------------------------------------
-static DWORD_PTR FindOldIP(PHOOK_ENTRY pHook, DWORD_PTR ip)
-{
- UINT i;
-
- if (pHook->patchAbove && ip == ((DWORD_PTR)pHook->pTarget - sizeof(JMP_REL)))
- return (DWORD_PTR)pHook->pTarget;
-
- for (i = 0; i < pHook->nIP; ++i)
- {
- if (ip == ((DWORD_PTR)pHook->pTrampoline + pHook->newIPs[i]))
- return (DWORD_PTR)pHook->pTarget + pHook->oldIPs[i];
- }
-
-#if defined(_M_X64) || defined(__x86_64__)
- // Check relay function.
- if (ip == (DWORD_PTR)pHook->pDetour)
- return (DWORD_PTR)pHook->pTarget;
-#endif
-
- return 0;
-}
-
-//-------------------------------------------------------------------------
-static DWORD_PTR FindNewIP(PHOOK_ENTRY pHook, DWORD_PTR ip)
-{
- UINT i;
- for (i = 0; i < pHook->nIP; ++i)
- {
- if (ip == ((DWORD_PTR)pHook->pTarget + pHook->oldIPs[i]))
- return (DWORD_PTR)pHook->pTrampoline + pHook->newIPs[i];
- }
-
- return 0;
-}
-
-//-------------------------------------------------------------------------
-static VOID ProcessThreadIPs(HANDLE hThread, UINT pos, UINT action)
-{
- // If the thread suspended in the overwritten area,
- // move IP to the proper address.
-
- CONTEXT c;
-#if defined(_M_X64) || defined(__x86_64__)
- DWORD64 *pIP = &c.Rip;
-#else
- DWORD *pIP = &c.Eip;
-#endif
- UINT count;
-
- c.ContextFlags = CONTEXT_CONTROL;
- if (!GetThreadContext(hThread, &c))
- return;
-
- if (pos == ALL_HOOKS_POS)
- {
- pos = 0;
- count = g_hooks.size;
- }
- else
- {
- count = pos + 1;
- }
-
- for (; pos < count; ++pos)
- {
- PHOOK_ENTRY pHook = &g_hooks.pItems[pos];
- BOOL enable;
- DWORD_PTR ip;
-
- switch (action)
- {
- case ACTION_DISABLE:
- enable = FALSE;
- break;
-
- case ACTION_ENABLE:
- enable = TRUE;
- break;
-
- default: // ACTION_APPLY_QUEUED
- enable = pHook->queueEnable;
- break;
- }
- if (pHook->isEnabled == enable)
- continue;
-
- if (enable)
- ip = FindNewIP(pHook, *pIP);
- else
- ip = FindOldIP(pHook, *pIP);
-
- if (ip != 0)
- {
- *pIP = ip;
- SetThreadContext(hThread, &c);
- }
- }
-}
-
-//-------------------------------------------------------------------------
-static BOOL EnumerateThreads(PFROZEN_THREADS pThreads)
-{
- BOOL succeeded = FALSE;
-
- HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
- if (hSnapshot != INVALID_HANDLE_VALUE)
- {
- THREADENTRY32 te;
- te.dwSize = sizeof(THREADENTRY32);
- if (Thread32First(hSnapshot, &te))
- {
- succeeded = TRUE;
- do
- {
- if (te.dwSize >= (FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(DWORD))
- && te.th32OwnerProcessID == GetCurrentProcessId()
- && te.th32ThreadID != GetCurrentThreadId())
- {
- if (pThreads->pItems == NULL)
- {
- pThreads->capacity = INITIAL_THREAD_CAPACITY;
- pThreads->pItems
- = (LPDWORD)HeapAlloc(g_hHeap, 0, pThreads->capacity * sizeof(DWORD));
- if (pThreads->pItems == NULL)
- {
- succeeded = FALSE;
- break;
- }
- }
- else if (pThreads->size >= pThreads->capacity)
- {
- pThreads->capacity *= 2;
- LPDWORD p = (LPDWORD)HeapReAlloc(
- g_hHeap, 0, pThreads->pItems, pThreads->capacity * sizeof(DWORD));
- if (p == NULL)
- {
- succeeded = FALSE;
- break;
- }
-
- pThreads->pItems = p;
- }
- pThreads->pItems[pThreads->size++] = te.th32ThreadID;
- }
-
- te.dwSize = sizeof(THREADENTRY32);
- } while (Thread32Next(hSnapshot, &te));
-
- if (succeeded && GetLastError() != ERROR_NO_MORE_FILES)
- succeeded = FALSE;
-
- if (!succeeded && pThreads->pItems != NULL)
- {
- HeapFree(g_hHeap, 0, pThreads->pItems);
- pThreads->pItems = NULL;
- }
- }
- CloseHandle(hSnapshot);
- }
-
- return succeeded;
-}
-
-//-------------------------------------------------------------------------
-static MH_STATUS Freeze(PFROZEN_THREADS pThreads, UINT pos, UINT action)
-{
- MH_STATUS status = MH_OK;
-
- pThreads->pItems = NULL;
- pThreads->capacity = 0;
- pThreads->size = 0;
- if (!EnumerateThreads(pThreads))
- {
- status = MH_ERROR_MEMORY_ALLOC;
- }
- else if (pThreads->pItems != NULL)
- {
- UINT i;
- for (i = 0; i < pThreads->size; ++i)
- {
- HANDLE hThread = OpenThread(THREAD_ACCESS, FALSE, pThreads->pItems[i]);
- if (hThread != NULL)
- {
- SuspendThread(hThread);
- ProcessThreadIPs(hThread, pos, action);
- CloseHandle(hThread);
- }
- }
- }
-
- return status;
-}
-
-//-------------------------------------------------------------------------
-static VOID Unfreeze(PFROZEN_THREADS pThreads)
-{
- if (pThreads->pItems != NULL)
- {
- UINT i;
- for (i = 0; i < pThreads->size; ++i)
- {
- HANDLE hThread = OpenThread(THREAD_ACCESS, FALSE, pThreads->pItems[i]);
- if (hThread != NULL)
- {
- ResumeThread(hThread);
- CloseHandle(hThread);
- }
- }
-
- HeapFree(g_hHeap, 0, pThreads->pItems);
- }
-}
-
-//-------------------------------------------------------------------------
-static MH_STATUS EnableHookLL(UINT pos, BOOL enable)
-{
- PHOOK_ENTRY pHook = &g_hooks.pItems[pos];
- DWORD oldProtect;
- SIZE_T patchSize = sizeof(JMP_REL);
- LPBYTE pPatchTarget = (LPBYTE)pHook->pTarget;
-
- if (pHook->patchAbove)
- {
- pPatchTarget -= sizeof(JMP_REL);
- patchSize += sizeof(JMP_REL_SHORT);
- }
-
- if (!VirtualProtect(pPatchTarget, patchSize, PAGE_EXECUTE_READWRITE, &oldProtect))
- return MH_ERROR_MEMORY_PROTECT;
-
- if (enable)
- {
- PJMP_REL pJmp = (PJMP_REL)pPatchTarget;
- pJmp->opcode = 0xE9;
- pJmp->operand = (UINT32)((LPBYTE)pHook->pDetour - (pPatchTarget + sizeof(JMP_REL)));
-
- if (pHook->patchAbove)
- {
- PJMP_REL_SHORT pShortJmp = (PJMP_REL_SHORT)pHook->pTarget;
- pShortJmp->opcode = 0xEB;
- pShortJmp->operand = (UINT8)(0 - (sizeof(JMP_REL_SHORT) + sizeof(JMP_REL)));
- }
- }
- else
- {
- if (pHook->patchAbove)
- memcpy(pPatchTarget, pHook->backup, sizeof(JMP_REL) + sizeof(JMP_REL_SHORT));
- else
- memcpy(pPatchTarget, pHook->backup, sizeof(JMP_REL));
- }
-
- VirtualProtect(pPatchTarget, patchSize, oldProtect, &oldProtect);
-
- // Just-in-case measure.
- FlushInstructionCache(GetCurrentProcess(), pPatchTarget, patchSize);
-
- pHook->isEnabled = enable;
- pHook->queueEnable = enable;
-
- return MH_OK;
-}
-
-//-------------------------------------------------------------------------
-static MH_STATUS EnableAllHooksLL(BOOL enable)
-{
- MH_STATUS status = MH_OK;
- UINT i, first = INVALID_HOOK_POS;
-
- for (i = 0; i < g_hooks.size; ++i)
- {
- if (g_hooks.pItems[i].isEnabled != enable)
- {
- first = i;
- break;
- }
- }
-
- if (first != INVALID_HOOK_POS)
- {
- FROZEN_THREADS threads;
- status = Freeze(&threads, ALL_HOOKS_POS, enable ? ACTION_ENABLE : ACTION_DISABLE);
- if (status == MH_OK)
- {
- for (i = first; i < g_hooks.size; ++i)
- {
- if (g_hooks.pItems[i].isEnabled != enable)
- {
- status = EnableHookLL(i, enable);
- if (status != MH_OK)
- break;
- }
- }
-
- Unfreeze(&threads);
- }
- }
-
- return status;
-}
-
-//-------------------------------------------------------------------------
-static VOID EnterSpinLock(VOID)
-{
- SIZE_T spinCount = 0;
-
- // Wait until the flag is FALSE.
- while (InterlockedCompareExchange(&g_isLocked, TRUE, FALSE) != FALSE)
- {
- // No need to generate a memory barrier here, since InterlockedCompareExchange()
- // generates a full memory barrier itself.
-
- // Prevent the loop from being too busy.
- if (spinCount < 32)
- Sleep(0);
- else
- Sleep(1);
-
- spinCount++;
- }
-}
-
-//-------------------------------------------------------------------------
-static VOID LeaveSpinLock(VOID)
-{
- // No need to generate a memory barrier here, since InterlockedExchange()
- // generates a full memory barrier itself.
-
- InterlockedExchange(&g_isLocked, FALSE);
-}
-
-//-------------------------------------------------------------------------
-MH_STATUS WINAPI MH_Initialize(VOID)
-{
- MH_STATUS status = MH_OK;
-
- EnterSpinLock();
-
- if (g_hHeap == NULL)
- {
- g_hHeap = HeapCreate(0, 0, 0);
- if (g_hHeap != NULL)
- {
- // Initialize the internal function buffer.
- InitializeBuffer();
- }
- else
- {
- status = MH_ERROR_MEMORY_ALLOC;
- }
- }
- else
- {
- status = MH_ERROR_ALREADY_INITIALIZED;
- }
-
- LeaveSpinLock();
-
- return status;
-}
-
-//-------------------------------------------------------------------------
-MH_STATUS WINAPI MH_Uninitialize(VOID)
-{
- MH_STATUS status = MH_OK;
-
- EnterSpinLock();
-
- if (g_hHeap != NULL)
- {
- status = EnableAllHooksLL(FALSE);
- if (status == MH_OK)
- {
- // Free the internal function buffer.
-
- // HeapFree is actually not required, but some tools detect a false
- // memory leak without HeapFree.
-
- UninitializeBuffer();
-
- HeapFree(g_hHeap, 0, g_hooks.pItems);
- HeapDestroy(g_hHeap);
-
- g_hHeap = NULL;
-
- g_hooks.pItems = NULL;
- g_hooks.capacity = 0;
- g_hooks.size = 0;
- }
- }
- else
- {
- status = MH_ERROR_NOT_INITIALIZED;
- }
-
- LeaveSpinLock();
-
- return status;
-}
-
-//-------------------------------------------------------------------------
-MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal)
-{
- MH_STATUS status = MH_OK;
-
- EnterSpinLock();
-
- if (g_hHeap != NULL)
- {
- if (IsExecutableAddress(pTarget) && IsExecutableAddress(pDetour))
- {
- UINT pos = FindHookEntry(pTarget);
- if (pos == INVALID_HOOK_POS)
- {
- LPVOID pBuffer = AllocateBuffer(pTarget);
- if (pBuffer != NULL)
- {
- TRAMPOLINE ct;
-
- ct.pTarget = pTarget;
- ct.pDetour = pDetour;
- ct.pTrampoline = pBuffer;
- if (CreateTrampolineFunction(&ct))
- {
- PHOOK_ENTRY pHook = AddHookEntry();
- if (pHook != NULL)
- {
- pHook->pTarget = ct.pTarget;
-#if defined(_M_X64) || defined(__x86_64__)
- pHook->pDetour = ct.pRelay;
-#else
- pHook->pDetour = ct.pDetour;
-#endif
- pHook->pTrampoline = ct.pTrampoline;
- pHook->patchAbove = ct.patchAbove;
- pHook->isEnabled = FALSE;
- pHook->queueEnable = FALSE;
- pHook->nIP = ct.nIP;
- memcpy(pHook->oldIPs, ct.oldIPs, ARRAYSIZE(ct.oldIPs));
- memcpy(pHook->newIPs, ct.newIPs, ARRAYSIZE(ct.newIPs));
-
- // Back up the target function.
-
- if (ct.patchAbove)
- {
- memcpy(
- pHook->backup,
- (LPBYTE)pTarget - sizeof(JMP_REL),
- sizeof(JMP_REL) + sizeof(JMP_REL_SHORT));
- }
- else
- {
- memcpy(pHook->backup, pTarget, sizeof(JMP_REL));
- }
-
- if (ppOriginal != NULL)
- *ppOriginal = pHook->pTrampoline;
- }
- else
- {
- status = MH_ERROR_MEMORY_ALLOC;
- }
- }
- else
- {
- status = MH_ERROR_UNSUPPORTED_FUNCTION;
- }
-
- if (status != MH_OK)
- {
- FreeBuffer(pBuffer);
- }
- }
- else
- {
- status = MH_ERROR_MEMORY_ALLOC;
- }
- }
- else
- {
- status = MH_ERROR_ALREADY_CREATED;
- }
- }
- else
- {
- status = MH_ERROR_NOT_EXECUTABLE;
- }
- }
- else
- {
- status = MH_ERROR_NOT_INITIALIZED;
- }
-
- LeaveSpinLock();
-
- return status;
-}
-
-//-------------------------------------------------------------------------
-MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget)
-{
- MH_STATUS status = MH_OK;
-
- EnterSpinLock();
-
- if (g_hHeap != NULL)
- {
- UINT pos = FindHookEntry(pTarget);
- if (pos != INVALID_HOOK_POS)
- {
- if (g_hooks.pItems[pos].isEnabled)
- {
- FROZEN_THREADS threads;
- status = Freeze(&threads, pos, ACTION_DISABLE);
- if (status == MH_OK)
- {
- status = EnableHookLL(pos, FALSE);
-
- Unfreeze(&threads);
- }
- }
-
- if (status == MH_OK)
- {
- FreeBuffer(g_hooks.pItems[pos].pTrampoline);
- DeleteHookEntry(pos);
- }
- }
- else
- {
- status = MH_ERROR_NOT_CREATED;
- }
- }
- else
- {
- status = MH_ERROR_NOT_INITIALIZED;
- }
-
- LeaveSpinLock();
-
- return status;
-}
-
-//-------------------------------------------------------------------------
-static MH_STATUS EnableHook(LPVOID pTarget, BOOL enable)
-{
- MH_STATUS status = MH_OK;
-
- EnterSpinLock();
-
- if (g_hHeap != NULL)
- {
- if (pTarget == MH_ALL_HOOKS)
- {
- status = EnableAllHooksLL(enable);
- }
- else
- {
- UINT pos = FindHookEntry(pTarget);
- if (pos != INVALID_HOOK_POS)
- {
- if (g_hooks.pItems[pos].isEnabled != enable)
- {
- FROZEN_THREADS threads;
- status = Freeze(&threads, pos, ACTION_ENABLE);
- if (status == MH_OK)
- {
- status = EnableHookLL(pos, enable);
-
- Unfreeze(&threads);
- }
- }
- else
- {
- status = enable ? MH_ERROR_ENABLED : MH_ERROR_DISABLED;
- }
- }
- else
- {
- status = MH_ERROR_NOT_CREATED;
- }
- }
- }
- else
- {
- status = MH_ERROR_NOT_INITIALIZED;
- }
-
- LeaveSpinLock();
-
- return status;
-}
-
-//-------------------------------------------------------------------------
-MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget)
-{
- return EnableHook(pTarget, TRUE);
-}
-
-//-------------------------------------------------------------------------
-MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget)
-{
- return EnableHook(pTarget, FALSE);
-}
-
-//-------------------------------------------------------------------------
-static MH_STATUS QueueHook(LPVOID pTarget, BOOL queueEnable)
-{
- MH_STATUS status = MH_OK;
-
- EnterSpinLock();
-
- if (g_hHeap != NULL)
- {
- if (pTarget == MH_ALL_HOOKS)
- {
- UINT i;
- for (i = 0; i < g_hooks.size; ++i)
- g_hooks.pItems[i].queueEnable = queueEnable;
- }
- else
- {
- UINT pos = FindHookEntry(pTarget);
- if (pos != INVALID_HOOK_POS)
- {
- g_hooks.pItems[pos].queueEnable = queueEnable;
- }
- else
- {
- status = MH_ERROR_NOT_CREATED;
- }
- }
- }
- else
- {
- status = MH_ERROR_NOT_INITIALIZED;
- }
-
- LeaveSpinLock();
-
- return status;
-}
-
-//-------------------------------------------------------------------------
-MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget)
-{
- return QueueHook(pTarget, TRUE);
-}
-
-//-------------------------------------------------------------------------
-MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget)
-{
- return QueueHook(pTarget, FALSE);
-}
-
-//-------------------------------------------------------------------------
-MH_STATUS WINAPI MH_ApplyQueued(VOID)
-{
- MH_STATUS status = MH_OK;
- UINT i, first = INVALID_HOOK_POS;
-
- EnterSpinLock();
-
- if (g_hHeap != NULL)
- {
- for (i = 0; i < g_hooks.size; ++i)
- {
- if (g_hooks.pItems[i].isEnabled != g_hooks.pItems[i].queueEnable)
- {
- first = i;
- break;
- }
- }
-
- if (first != INVALID_HOOK_POS)
- {
- FROZEN_THREADS threads;
- status = Freeze(&threads, ALL_HOOKS_POS, ACTION_APPLY_QUEUED);
- if (status == MH_OK)
- {
- for (i = first; i < g_hooks.size; ++i)
- {
- PHOOK_ENTRY pHook = &g_hooks.pItems[i];
- if (pHook->isEnabled != pHook->queueEnable)
- {
- status = EnableHookLL(i, pHook->queueEnable);
- if (status != MH_OK)
- break;
- }
- }
-
- Unfreeze(&threads);
- }
- }
- }
- else
- {
- status = MH_ERROR_NOT_INITIALIZED;
- }
-
- LeaveSpinLock();
-
- return status;
-}
-
-//-------------------------------------------------------------------------
-MH_STATUS WINAPI MH_CreateHookApiEx(
- LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour,
- LPVOID *ppOriginal, LPVOID *ppTarget)
-{
- HMODULE hModule;
- LPVOID pTarget;
-
- hModule = GetModuleHandleW(pszModule);
- if (hModule == NULL)
- return MH_ERROR_MODULE_NOT_FOUND;
-
- pTarget = (LPVOID)GetProcAddress(hModule, pszProcName);
- if (pTarget == NULL)
- return MH_ERROR_FUNCTION_NOT_FOUND;
-
- if(ppTarget != NULL)
- *ppTarget = pTarget;
-
- return MH_CreateHook(pTarget, pDetour, ppOriginal);
-}
-
-//-------------------------------------------------------------------------
-MH_STATUS WINAPI MH_CreateHookApi(
- LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal)
-{
- return MH_CreateHookApiEx(pszModule, pszProcName, pDetour, ppOriginal, NULL);
-}
-
-//-------------------------------------------------------------------------
-const char * WINAPI MH_StatusToString(MH_STATUS status)
-{
-#define MH_ST2STR(x) \
- case x: \
- return #x;
-
- switch (status) {
- MH_ST2STR(MH_UNKNOWN)
- MH_ST2STR(MH_OK)
- MH_ST2STR(MH_ERROR_ALREADY_INITIALIZED)
- MH_ST2STR(MH_ERROR_NOT_INITIALIZED)
- MH_ST2STR(MH_ERROR_ALREADY_CREATED)
- MH_ST2STR(MH_ERROR_NOT_CREATED)
- MH_ST2STR(MH_ERROR_ENABLED)
- MH_ST2STR(MH_ERROR_DISABLED)
- MH_ST2STR(MH_ERROR_NOT_EXECUTABLE)
- MH_ST2STR(MH_ERROR_UNSUPPORTED_FUNCTION)
- MH_ST2STR(MH_ERROR_MEMORY_ALLOC)
- MH_ST2STR(MH_ERROR_MEMORY_PROTECT)
- MH_ST2STR(MH_ERROR_MODULE_NOT_FOUND)
- MH_ST2STR(MH_ERROR_FUNCTION_NOT_FOUND)
- }
-
-#undef MH_ST2STR
-
- return "(unknown)";
-}
diff --git a/lib/MinHook/src/trampoline.c b/lib/MinHook/src/trampoline.c
deleted file mode 100644
index 617baf3..0000000
--- a/lib/MinHook/src/trampoline.c
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- * MinHook - The Minimalistic API Hooking Library for x64/x86
- * Copyright (C) 2009-2017 Tsuda Kageyu.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
- * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include
-
-#ifdef _MSC_VER
- #include
-#endif
-
-#ifndef ARRAYSIZE
- #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
-#endif
-
-#if defined(_M_X64) || defined(__x86_64__)
- #include "./hde/hde64.h"
- typedef hde64s HDE;
- #define HDE_DISASM(code, hs) hde64_disasm(code, hs)
-#else
- #include "./hde/hde32.h"
- typedef hde32s HDE;
- #define HDE_DISASM(code, hs) hde32_disasm(code, hs)
-#endif
-
-#include "trampoline.h"
-#include "buffer.h"
-
-// Maximum size of a trampoline function.
-#if defined(_M_X64) || defined(__x86_64__)
- #define TRAMPOLINE_MAX_SIZE (MEMORY_SLOT_SIZE - sizeof(JMP_ABS))
-#else
- #define TRAMPOLINE_MAX_SIZE MEMORY_SLOT_SIZE
-#endif
-
-//-------------------------------------------------------------------------
-static BOOL IsCodePadding(LPBYTE pInst, UINT size)
-{
- UINT i;
-
- if (pInst[0] != 0x00 && pInst[0] != 0x90 && pInst[0] != 0xCC)
- return FALSE;
-
- for (i = 1; i < size; ++i)
- {
- if (pInst[i] != pInst[0])
- return FALSE;
- }
- return TRUE;
-}
-
-//-------------------------------------------------------------------------
-BOOL CreateTrampolineFunction(PTRAMPOLINE ct)
-{
-#if defined(_M_X64) || defined(__x86_64__)
- CALL_ABS call = {
- 0xFF, 0x15, 0x00000002, // FF15 00000002: CALL [RIP+8]
- 0xEB, 0x08, // EB 08: JMP +10
- 0x0000000000000000ULL // Absolute destination address
- };
- JMP_ABS jmp = {
- 0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6]
- 0x0000000000000000ULL // Absolute destination address
- };
- JCC_ABS jcc = {
- 0x70, 0x0E, // 7* 0E: J** +16
- 0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6]
- 0x0000000000000000ULL // Absolute destination address
- };
-#else
- CALL_REL call = {
- 0xE8, // E8 xxxxxxxx: CALL +5+xxxxxxxx
- 0x00000000 // Relative destination address
- };
- JMP_REL jmp = {
- 0xE9, // E9 xxxxxxxx: JMP +5+xxxxxxxx
- 0x00000000 // Relative destination address
- };
- JCC_REL jcc = {
- 0x0F, 0x80, // 0F8* xxxxxxxx: J** +6+xxxxxxxx
- 0x00000000 // Relative destination address
- };
-#endif
-
- UINT8 oldPos = 0;
- UINT8 newPos = 0;
- ULONG_PTR jmpDest = 0; // Destination address of an internal jump.
- BOOL finished = FALSE; // Is the function completed?
-#if defined(_M_X64) || defined(__x86_64__)
- UINT8 instBuf[16];
-#endif
-
- ct->patchAbove = FALSE;
- ct->nIP = 0;
-
- do
- {
- HDE hs;
- UINT copySize;
- LPVOID pCopySrc;
- ULONG_PTR pOldInst = (ULONG_PTR)ct->pTarget + oldPos;
- ULONG_PTR pNewInst = (ULONG_PTR)ct->pTrampoline + newPos;
-
- copySize = HDE_DISASM((LPVOID)pOldInst, &hs);
- if (hs.flags & F_ERROR)
- return FALSE;
-
- pCopySrc = (LPVOID)pOldInst;
- if (oldPos >= sizeof(JMP_REL))
- {
- // The trampoline function is long enough.
- // Complete the function with the jump to the target function.
-#if defined(_M_X64) || defined(__x86_64__)
- jmp.address = pOldInst;
-#else
- jmp.operand = (UINT32)(pOldInst - (pNewInst + sizeof(jmp)));
-#endif
- pCopySrc = &jmp;
- copySize = sizeof(jmp);
-
- finished = TRUE;
- }
-#if defined(_M_X64) || defined(__x86_64__)
- else if ((hs.modrm & 0xC7) == 0x05)
- {
- // Instructions using RIP relative addressing. (ModR/M = 00???101B)
-
- // Modify the RIP relative address.
- PUINT32 pRelAddr;
-
- // Avoid using memcpy to reduce the footprint.
-#ifndef _MSC_VER
- memcpy(instBuf, (LPBYTE)pOldInst, copySize);
-#else
- __movsb(instBuf, (LPBYTE)pOldInst, copySize);
-#endif
- pCopySrc = instBuf;
-
- // Relative address is stored at (instruction length - immediate value length - 4).
- pRelAddr = (PUINT32)(instBuf + hs.len - ((hs.flags & 0x3C) >> 2) - 4);
- *pRelAddr
- = (UINT32)((pOldInst + hs.len + (INT32)hs.disp.disp32) - (pNewInst + hs.len));
-
- // Complete the function if JMP (FF /4).
- if (hs.opcode == 0xFF && hs.modrm_reg == 4)
- finished = TRUE;
- }
-#endif
- else if (hs.opcode == 0xE8)
- {
- // Direct relative CALL
- ULONG_PTR dest = pOldInst + hs.len + (INT32)hs.imm.imm32;
-#if defined(_M_X64) || defined(__x86_64__)
- call.address = dest;
-#else
- call.operand = (UINT32)(dest - (pNewInst + sizeof(call)));
-#endif
- pCopySrc = &call;
- copySize = sizeof(call);
- }
- else if ((hs.opcode & 0xFD) == 0xE9)
- {
- // Direct relative JMP (EB or E9)
- ULONG_PTR dest = pOldInst + hs.len;
-
- if (hs.opcode == 0xEB) // isShort jmp
- dest += (INT8)hs.imm.imm8;
- else
- dest += (INT32)hs.imm.imm32;
-
- // Simply copy an internal jump.
- if ((ULONG_PTR)ct->pTarget <= dest
- && dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL)))
- {
- if (jmpDest < dest)
- jmpDest = dest;
- }
- else
- {
-#if defined(_M_X64) || defined(__x86_64__)
- jmp.address = dest;
-#else
- jmp.operand = (UINT32)(dest - (pNewInst + sizeof(jmp)));
-#endif
- pCopySrc = &jmp;
- copySize = sizeof(jmp);
-
- // Exit the function if it is not in the branch.
- finished = (pOldInst >= jmpDest);
- }
- }
- else if ((hs.opcode & 0xF0) == 0x70
- || (hs.opcode & 0xFC) == 0xE0
- || (hs.opcode2 & 0xF0) == 0x80)
- {
- // Direct relative Jcc
- ULONG_PTR dest = pOldInst + hs.len;
-
- if ((hs.opcode & 0xF0) == 0x70 // Jcc
- || (hs.opcode & 0xFC) == 0xE0) // LOOPNZ/LOOPZ/LOOP/JECXZ
- dest += (INT8)hs.imm.imm8;
- else
- dest += (INT32)hs.imm.imm32;
-
- // Simply copy an internal jump.
- if ((ULONG_PTR)ct->pTarget <= dest
- && dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL)))
- {
- if (jmpDest < dest)
- jmpDest = dest;
- }
- else if ((hs.opcode & 0xFC) == 0xE0)
- {
- // LOOPNZ/LOOPZ/LOOP/JCXZ/JECXZ to the outside are not supported.
- return FALSE;
- }
- else
- {
- UINT8 cond = ((hs.opcode != 0x0F ? hs.opcode : hs.opcode2) & 0x0F);
-#if defined(_M_X64) || defined(__x86_64__)
- // Invert the condition in x64 mode to simplify the conditional jump logic.
- jcc.opcode = 0x71 ^ cond;
- jcc.address = dest;
-#else
- jcc.opcode1 = 0x80 | cond;
- jcc.operand = (UINT32)(dest - (pNewInst + sizeof(jcc)));
-#endif
- pCopySrc = &jcc;
- copySize = sizeof(jcc);
- }
- }
- else if ((hs.opcode & 0xFE) == 0xC2)
- {
- // RET (C2 or C3)
-
- // Complete the function if not in a branch.
- finished = (pOldInst >= jmpDest);
- }
-
- // Can't alter the instruction length in a branch.
- if (pOldInst < jmpDest && copySize != hs.len)
- return FALSE;
-
- // Trampoline function is too large.
- if ((newPos + copySize) > TRAMPOLINE_MAX_SIZE)
- return FALSE;
-
- // Trampoline function has too many instructions.
- if (ct->nIP >= ARRAYSIZE(ct->oldIPs))
- return FALSE;
-
- ct->oldIPs[ct->nIP] = oldPos;
- ct->newIPs[ct->nIP] = newPos;
- ct->nIP++;
-
- // Avoid using memcpy to reduce the footprint.
-#ifndef _MSC_VER
- memcpy((LPBYTE)ct->pTrampoline + newPos, pCopySrc, copySize);
-#else
- __movsb((LPBYTE)ct->pTrampoline + newPos, (LPBYTE)pCopySrc, copySize);
-#endif
- newPos += copySize;
- oldPos += hs.len;
- }
- while (!finished);
-
- // Is there enough place for a long jump?
- if (oldPos < sizeof(JMP_REL)
- && !IsCodePadding((LPBYTE)ct->pTarget + oldPos, sizeof(JMP_REL) - oldPos))
- {
- // Is there enough place for a short jump?
- if (oldPos < sizeof(JMP_REL_SHORT)
- && !IsCodePadding((LPBYTE)ct->pTarget + oldPos, sizeof(JMP_REL_SHORT) - oldPos))
- {
- return FALSE;
- }
-
- // Can we place the long jump above the function?
- if (!IsExecutableAddress((LPBYTE)ct->pTarget - sizeof(JMP_REL)))
- return FALSE;
-
- if (!IsCodePadding((LPBYTE)ct->pTarget - sizeof(JMP_REL), sizeof(JMP_REL)))
- return FALSE;
-
- ct->patchAbove = TRUE;
- }
-
-#if defined(_M_X64) || defined(__x86_64__)
- // Create a relay function.
- jmp.address = (ULONG_PTR)ct->pDetour;
-
- ct->pRelay = (LPBYTE)ct->pTrampoline + newPos;
- memcpy(ct->pRelay, &jmp, sizeof(jmp));
-#endif
-
- return TRUE;
-}
diff --git a/lib/MinHook/src/trampoline.h b/lib/MinHook/src/trampoline.h
deleted file mode 100644
index bdffdac..0000000
--- a/lib/MinHook/src/trampoline.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * MinHook - The Minimalistic API Hooking Library for x64/x86
- * Copyright (C) 2009-2017 Tsuda Kageyu.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
- * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#pragma pack(push, 1)
-
-// Structs for writing x86/x64 instructions.
-
-// 8-bit relative jump.
-typedef struct _JMP_REL_SHORT
-{
- UINT8 opcode; // EB xx: JMP +2+xx
- UINT8 operand;
-} JMP_REL_SHORT, *PJMP_REL_SHORT;
-
-// 32-bit direct relative jump/call.
-typedef struct _JMP_REL
-{
- UINT8 opcode; // E9/E8 xxxxxxxx: JMP/CALL +5+xxxxxxxx
- UINT32 operand; // Relative destination address
-} JMP_REL, *PJMP_REL, CALL_REL;
-
-// 64-bit indirect absolute jump.
-typedef struct _JMP_ABS
-{
- UINT8 opcode0; // FF25 00000000: JMP [+6]
- UINT8 opcode1;
- UINT32 dummy;
- UINT64 address; // Absolute destination address
-} JMP_ABS, *PJMP_ABS;
-
-// 64-bit indirect absolute call.
-typedef struct _CALL_ABS
-{
- UINT8 opcode0; // FF15 00000002: CALL [+6]
- UINT8 opcode1;
- UINT32 dummy0;
- UINT8 dummy1; // EB 08: JMP +10
- UINT8 dummy2;
- UINT64 address; // Absolute destination address
-} CALL_ABS;
-
-// 32-bit direct relative conditional jumps.
-typedef struct _JCC_REL
-{
- UINT8 opcode0; // 0F8* xxxxxxxx: J** +6+xxxxxxxx
- UINT8 opcode1;
- UINT32 operand; // Relative destination address
-} JCC_REL;
-
-// 64bit indirect absolute conditional jumps that x64 lacks.
-typedef struct _JCC_ABS
-{
- UINT8 opcode; // 7* 0E: J** +16
- UINT8 dummy0;
- UINT8 dummy1; // FF25 00000000: JMP [+6]
- UINT8 dummy2;
- UINT32 dummy3;
- UINT64 address; // Absolute destination address
-} JCC_ABS;
-
-#pragma pack(pop)
-
-typedef struct _TRAMPOLINE
-{
- LPVOID pTarget; // [In] Address of the target function.
- LPVOID pDetour; // [In] Address of the detour function.
- LPVOID pTrampoline; // [In] Buffer address for the trampoline and relay function.
-
-#if defined(_M_X64) || defined(__x86_64__)
- LPVOID pRelay; // [Out] Address of the relay function.
-#endif
- BOOL patchAbove; // [Out] Should use the hot patch area?
- UINT nIP; // [Out] Number of the instruction boundaries.
- UINT8 oldIPs[8]; // [Out] Instruction boundaries of the target function.
- UINT8 newIPs[8]; // [Out] Instruction boundaries of the trampoline function.
-} TRAMPOLINE, *PTRAMPOLINE;
-
-BOOL CreateTrampolineFunction(PTRAMPOLINE ct);
diff --git a/lib/Sig/Sig.hpp b/lib/Sig/Sig.hpp
deleted file mode 100644
index 6802596..0000000
--- a/lib/Sig/Sig.hpp
+++ /dev/null
@@ -1,1142 +0,0 @@
-#pragma once
-
-#include
-
-
-#if (__cplusplus >= 202002) || _HAS_CXX20
-# define sig_has_cxx20 (1)
-#else
-# define sig_has_cxx20 (0)
-#endif
-
-
-struct Sig
-{
- enum class Tag
- {
- val,
- any,
- pkg,
- str,
- raw,
- rep,
- set,
- range,
- compound
- };
-
-
- struct Cmp
- {
- template
- struct Eq
- {
- static bool cmp(const void* const pos)
- {
- return *static_cast(pos) == val;
- }
- };
-
- template
- struct Gr
- {
- static bool cmp(const void* const pos)
- {
- return *static_cast(pos) > val;
- }
- };
-
- template
- struct GrEq
- {
- static bool cmp(const void* const pos)
- {
- return *static_cast(pos) >= val;
- }
- };
-
- template
- struct Le
- {
- static bool cmp(const void* const pos)
- {
- return *static_cast(pos) < val;
- }
- };
-
- template
- struct LeEq
- {
- static bool cmp(const void* const pos)
- {
- return *static_cast(pos) <= val;
- }
- };
-
- template
- struct NotEq
- {
- static bool cmp(const void* const pos)
- {
- return *static_cast(pos) != val;
- }
- };
-
- template
- struct OneOf
- {
- static bool cmp(const void* const pos)
- {
- return (*static_cast(pos) & val) != 0;
- }
- };
-
- template
- struct AllOf
- {
- static bool cmp(const void* const pos)
- {
- return (*static_cast(pos) & val) == val;
- }
- };
- };
-
- template
- struct PackageHolder
- {
- };
-
-
- template typename Comparator, Type... values>
- struct Holder
- {
- using BaseType = Type;
- using Package = PackageHolder...>;
-
- static constexpr auto k_tag = Tag::pkg;
- static constexpr auto k_count = sizeof...(values);
- static constexpr auto k_size = k_count * sizeof(Type);
- };
- static_assert(Holder::k_tag == Tag::pkg);
-
- template typename Comparator>
- struct Holder
- {
- using BaseType = Type;
-
- static constexpr auto k_tag = Tag::any;
- static constexpr auto k_count = 1;
- static constexpr auto k_size = sizeof(Type);
- };
- static_assert(Holder::k_tag == Tag::any);
-
- template typename Comparator, Type val>
- struct Holder
- {
- using BaseType = Type;
- using Cmp = Comparator;
-
- static constexpr auto k_tag = Tag::val;
- static constexpr auto k_count = 1;
- static constexpr auto k_size = sizeof(Type);
- };
- static_assert(Holder::k_tag == Tag::val);
-
- template
- struct RawCmp
- {
- using BaseType = Type;
-
- static constexpr auto k_tag = Tag::raw;
- static constexpr auto k_count = count;
- static constexpr auto k_size = sizeof(Type) * k_count;
- };
-
- template
- struct Rep
- {
- using Type = Repeatable;
- static constexpr auto k_tag = Tag::rep;
- static constexpr auto k_count = count;
- static constexpr auto k_size = k_count * Type::k_size;
- };
-
- template
- struct Set
- {
- template
- static constexpr auto maxof()
- {
- constexpr decltype(val) k_arr[sizeof...(values) + 1]{ val, values... };
- auto maxval = k_arr[0];
- for (size_t i = 1; i < sizeof...(values); ++i)
- {
- if (k_arr[i] > maxval)
- {
- maxval = k_arr[i];
- }
- }
- return maxval;
- }
-
- static constexpr auto k_tag = Tag::set;
- static constexpr auto k_size = maxof();
- static constexpr auto k_count = sizeof...(Entries);
- };
-
- template typename Entry, auto from, auto to>
- struct Range
- {
- using BaseType = typename Entry::BaseType;
-
- template
- using EntryType = Entry;
-
- static constexpr auto k_from = from;
- static constexpr auto k_to = to;
-
- static constexpr auto k_tag = Tag::range;
- static constexpr auto k_size = Entry::k_size;
- };
-
- template
- struct Compound
- {
- static constexpr auto k_tag = Tag::compound;
- static constexpr auto k_size = (Entries::k_size + ...);
- static constexpr auto k_count = sizeof...(Entries);
- };
-
-
-#if sig_has_cxx20
- template
- struct Arr
- {
- using Type = T;
- static constexpr auto k_len = len;
- Type buf[k_len]{};
- };
-
- template
- struct String
- {
- using Type = T;
- static constexpr auto k_len = len;
-
- Arr str;
-
- consteval String(const Type* const string)
- {
- for (size_t i = 0; i < k_len; ++i)
- {
- str.buf[i] = string[i];
- }
- }
- };
-
- template
- String(const Type(&)[len])->String;
-
- template
- struct Str
- {
- using Type = typename decltype(string)::Type;
- static constexpr auto k_tag = Tag::str;
- static constexpr auto k_size = sizeof(Type) * string.k_len;
- static constexpr auto k_count = string.k_len;
- };
-#endif
-
- template
- struct Comparator;
-
- struct PackedCmp
- {
- template typename Package, typename... Entries>
- static bool cmp(const Package&, const void* const pos)
- {
- return Comparator::cmp(pos);
- }
- };
-
- template
- struct RepCmp
- {
- static bool cmp(const void* const pos)
- {
- for (size_t i = 0; i < Rep::k_count; ++i)
- {
- const bool matches = Comparator::cmp(&static_cast(pos)[i]);
- if (!matches)
- {
- return false;
- }
- }
-
- return true;
- }
- };
-
- template
- struct SetComparator;
-
- template
- struct SetComparator
- {
- static size_t equals(const void* const pos)
- {
- const bool matches = Comparator::cmp(pos);
- if (matches)
- {
- return Entry::k_size;
- }
- return SetComparator::equals(pos);
- }
- };
-
-
-
- struct SetCmp
- {
- template typename Set, typename... Entries>
- static size_t cmp(const Set&, const void* const pos)
- {
- return SetComparator::equals(pos);
- }
- };
-
- struct RangeCmp
- {
- template typename Entry, auto val, auto end>
- static bool equals(const void* const pos)
- {
- using Cmp = typename Entry::Cmp;
-
- constexpr auto from = val;
- constexpr auto to = end;
-
- if constexpr (from < to)
- {
- const bool matches = Cmp::cmp(pos);
- return matches || equals(pos);
- }
- else
- {
- return Cmp::cmp(pos);
- }
- }
-
- template
- static bool cmp(const void* const pos)
- {
- const auto from = Range::k_from;
- const auto to = Range::k_to;
- return equals(pos);
- }
- };
-
- struct CompoundCmp
- {
- template typename Compound, typename... Entries>
- static bool cmp(const Compound&, const void* const pos)
- {
- return Comparator::cmp(pos);
- }
- };
-
- template
- struct Comparator
- {
- static bool cmp(const void* const pos)
- {
- if constexpr ((Entry::k_tag == Tag::val) || (Entry::k_tag == Tag::raw) || (Entry::k_tag == Tag::str))
- {
- const bool matches = Comparator::cmp(pos);
- return matches && Comparator::cmp(static_cast(pos) + Entry::k_size);
- }
- else if constexpr (Entry::k_tag == Tag::pkg)
- {
- const bool matches = PackedCmp::cmp(typename Entry::Package{}, pos);
- return matches && Comparator::cmp(static_cast(pos) + Entry::k_size);
- }
- else if constexpr (Entry::k_tag == Tag::rep)
- {
- const bool matches = RepCmp::cmp(pos);
- return matches && Comparator::cmp(static_cast(pos) + Entry::k_size);
- }
- else if constexpr (Entry::k_tag == Tag::set)
- {
- const size_t size = SetCmp::cmp(Entry{}, pos);
- return size && Comparator::cmp(static_cast(pos) + size);
- }
- else if constexpr (Entry::k_tag == Tag::range)
- {
- const bool matches = RangeCmp::cmp(pos);
- return matches && Comparator::cmp(static_cast(pos) + Entry::k_size);
- }
- else if constexpr (Entry::k_tag == Tag::compound)
- {
- const bool matches = CompoundCmp::cmp(Entry{}, pos);
- return matches && Comparator::cmp(static_cast(pos) + Entry::k_size);
- }
- else
- {
- return Comparator::cmp(static_cast(pos) + Entry::k_size);
- }
- }
- };
-
- template
- struct Comparator
- {
- static bool cmp(const void* const pos)
- {
- if constexpr (Entry::k_tag == Tag::val)
- {
- using Cmp = typename Entry::Cmp;
- return Cmp::cmp(pos);
- }
- else if constexpr (Entry::k_tag == Tag::pkg)
- {
- return PackedCmp::cmp(typename Entry::Package{}, pos);
- }
- else if constexpr (Entry::k_tag == Tag::raw)
- {
- return Entry::cmp(pos);
- }
- else if constexpr (Entry::k_tag == Tag::str)
- {
- return Entry::cmp(pos);
- }
- else if constexpr (Entry::k_tag == Tag::rep)
- {
- return RepCmp::cmp(pos);
- }
- else if constexpr (Entry::k_tag == Tag::set)
- {
- return SetCmp::cmp(Entry{}, pos) != 0;
- }
- else if constexpr (Entry::k_tag == Tag::range)
- {
- return RangeCmp::cmp(pos);
- }
- else if constexpr (Entry::k_tag == Tag::compound)
- {
- return CompoundCmp::cmp(Entry{}, pos);
- }
- else if constexpr (Entry::k_tag == Tag::any)
- {
- return true;
- }
- else
- {
- static_assert("Invalid entry");
- }
- }
- };
-
-
- // Pattern format in a template way:
- // Sig::find, Sig::Char<'t', 'e', 'x', 't'>, Sig::Dword<>, Sig::Byte<0xFF>>(arr, sizeof(arr));
- template
- static const void* find(const void* const buf, const size_t size)
- {
- constexpr auto k_patternSize = (Entries::k_size + ...);
-
- const auto* pos = static_cast(buf);
- const auto* const end = static_cast(buf) + size - k_patternSize + 1;
- while (pos < end)
- {
- const bool equals = Comparator::cmp(pos);
- if (equals)
- {
- return pos;
- }
-
- ++pos;
- }
-
- return nullptr;
- }
-
-
-#if sig_has_cxx20
- template
- struct StrEq : Str
- {
- static bool cmp(const void* const pos)
- {
- const auto* const mem = static_cast(pos);
- for (size_t i = 0; i < decltype(str)::k_len; ++i)
- {
- if (mem[i] != str.str.buf[i])
- {
- return false;
- }
- }
-
- return true;
- }
- };
-
- template
- struct StrEqNoCase : Str
- {
- static bool cmp(const void* const pos)
- {
- using Char = typename decltype(str)::Type;
-
- const auto* const mem = static_cast(pos);
- for (size_t i = 0; i < decltype(str)::k_len; ++i)
- {
- const auto low = [](const Char ch) -> Char
- {
- return ((ch >= static_cast('A')) && (ch <= static_cast('Z')))
- ? (ch + static_cast('a' - 'A'))
- : (ch);
- };
-
- const auto left = low(mem[i]);
- const auto right = low(str.str.buf[i]);
-
- if (left != right)
- {
- return false;
- }
- }
-
- return true;
- }
- };
-#endif
-
-
- template
- struct BitMask : RawCmp
- {
- static bool cmp(const void* const pos)
- {
- return (*static_cast(pos) & mask) == (value & mask);
- }
- };
-
-
- template typename Comparator, char... values>
- using CmpChar = Holder;
-
- template
- using Char = CmpChar;
-
-
- template typename Comparator, wchar_t... values>
- using CmpWChar = Holder;
-
- template
- using WChar = CmpWChar;
-
-
- template typename Comparator, unsigned char... values>
- using CmpByte = Holder;
-
- template
- using Byte = CmpByte;
-
-
- template typename Comparator, unsigned short... values>
- using CmpWord = Holder;
-
- template
- using Word = CmpWord;
-
-
- template typename Comparator, unsigned int... values>
- using CmpDword = Holder;
-
- template
- using Dword = CmpDword;
-
-
- template typename Comparator, unsigned long long... values>
- using CmpQword = Holder;
-
- template
- using Qword = CmpQword;
-
-
- template typename Comparator, short... values>
- using CmpShort = Holder;
-
- template
- using Short = CmpShort;
-
-
- template typename Comparator, unsigned short... values>
- using CmpUShort = Holder;
-
- template
- using UShort = CmpUShort;
-
-
- template typename Comparator, long... values>
- using CmpLong = Holder;
-
- template
- using Long = CmpLong;
-
-
- template typename Comparator, unsigned long... values>
- using CmpULong = Holder;
-
- template
- using ULong = CmpULong;
-
-
- template typename Comparator, long long... values>
- using CmpLongLong = Holder;
-
- template
- using LongLong = CmpLongLong;
-
-
- template typename Comparator, unsigned long long... values>
- using CmpULongLong = Holder;
-
- template
- using ULongLong = CmpULongLong;
-
-
- template typename Comparator, int... values>
- using CmpInt = Holder;
-
- template
- using Int = CmpInt;
-
-
- template typename Comparator, unsigned int... values>
- using CmpUInt = Holder;
-
- template
- using UInt = CmpUInt;
-
-
- template typename Comparator, long long... values>
- using CmpInt64 = Holder;
-
- template
- using Int64 = CmpInt64;
-
-
- template typename Comparator, unsigned long long... values>
- using CmpUInt64 = Holder;
-
- template
- using UInt64 = CmpUInt64;
-
-
-
- template
- using ByteMask = BitMask;
-
- template
- using WordMask = BitMask;
-
- template
- using DwordMask = BitMask;
-
- template
- using QwordMask = BitMask;
-
-
-
- struct Mask
- {
- enum class CmpType
- {
- basic,
- extended
- };
-
- template
- struct MaskCmp
- {
- static constexpr auto k_char = ch;
- static constexpr auto k_type = CmpType::basic;
- };
-
- template
- struct MaskCmpEx
- {
- static constexpr auto k_char = ch;
- static constexpr auto k_type = CmpType::extended;
- };
-
- template
- struct Eq : MaskCmp
- {
- static bool cmp(const char data, const char pattern)
- {
- return data == pattern;
- }
- };
-
- template
- struct NotEq : MaskCmp
- {
- static bool cmp(const char data, const char pattern)
- {
- return data != pattern;
- }
- };
-
- template
- struct Gr : MaskCmp
- {
- static bool cmp(const char data, const char pattern)
- {
- return data > pattern;
- }
- };
-
- template
- struct GrEq : MaskCmp
- {
- static bool cmp(const char data, const char pattern)
- {
- return data >= pattern;
- }
- };
-
- template
- struct Le : MaskCmp
- {
- static bool cmp(const char data, const char pattern)
- {
- return data < pattern;
- }
- };
-
- template
- struct LeEq : MaskCmp
- {
- static bool cmp(const char data, const char pattern)
- {
- return data <= pattern;
- }
- };
-
- template
- struct OneOf : MaskCmp
- {
- static bool cmp(const char data, const char pattern)
- {
- return (data & pattern) != 0;
- }
- };
-
- template
- struct AllOf : MaskCmp
- {
- static bool cmp(const char data, const char pattern)
- {
- return (data & pattern) == pattern;
- }
- };
-
- template
- struct BitMask : MaskCmpEx
- {
- static bool cmp(const char data, const char pattern, const char subpattern)
- {
- return (data & subpattern) == (pattern & subpattern);
- }
- };
-
- template
- struct Any : MaskCmp
- {
- static bool cmp(const char, const char)
- {
- return true;
- }
- };
- };
-
- template
- struct MaskComparator
- {
- };
-
- template
- struct MaskComparator
- {
- static bool cmp(const char data, const char pattern, const char mask)
- {
- if (mask == Entry::k_char)
- {
- return Entry::cmp(data, pattern);
- }
- else
- {
- return MaskComparator::cmp(data, pattern, mask);
- }
- }
-
- static bool cmp(const char data, const char pattern, const char subpattern, const char mask)
- {
- if (mask == Entry::k_char)
- {
- if constexpr (Entry::k_type == Mask::CmpType::basic)
- {
- return Entry::cmp(data, pattern);
- }
- else if constexpr (Entry::k_type == Mask::CmpType::extended)
- {
- return Entry::cmp(data, pattern, subpattern);
- }
- else
- {
- static_assert("Unknown type of comparator");
- }
- }
- else
- {
- return MaskComparator::cmp(data, pattern, subpattern, mask);
- }
- }
- };
-
-
-
- // Pattern format: "\x11\x2\x00text" + "..?....", meaning of mask chars is customizable by Sig:Mask::* types
- template
- static const void* find(const void* const buf, const size_t size, const char* const sig, const char* const mask, const size_t sigsize)
- {
- if (!size || !sig || !mask)
- {
- return nullptr;
- }
-
- const auto* pos = static_cast(buf);
- const auto* const end = static_cast(buf) + size - sigsize + 1;
- while (pos < end)
- {
- bool result = true;
- for (size_t i = 0; i < sigsize; ++i)
- {
- const bool matches = MaskComparator::cmp(pos[i], sig[i], mask[i]);
- result &= matches;
- if (!result)
- {
- break;
- }
- }
-
- if (result)
- {
- return pos;
- }
-
- ++pos;
- }
-
- return nullptr;
- }
-
- // Pattern format: "\x11\x2\x00text" + "..?....", meaning of mask chars is customizable by Sig::Mask::* types
- template
- static const void* find(const void* const buf, const size_t size, const char* const sig, const char* const mask)
- {
- if (!mask)
- {
- return nullptr;
- }
-
- return find(buf, size, sig, mask, strlen(mask));
- }
-
- // Pattern format: "\x11\x2\x00text" + nullptr/"....\x1C\x03." + "..?.mm.", meaning of mask chars is customizable by Sig:Mask::* types
- template
- static const void* find(const void* const buf, const size_t size, const char* const sig, const char* const subsig, const char* const mask, const size_t sigsize)
- {
- if (!sig || !subsig || !mask)
- {
- return nullptr;
- }
-
- const auto* pos = static_cast(buf);
- const auto* const end = static_cast(buf) + size - sigsize + 1;
- while (pos < end)
- {
- bool result = true;
- for (size_t i = 0; i < sigsize; ++i)
- {
- const bool matches = MaskComparator::cmp(pos[i], sig[i], subsig[i], mask[i]);
- result &= matches;
- if (!result)
- {
- break;
- }
- }
-
- if (result)
- {
- return pos;
- }
-
- ++pos;
- }
-
- return nullptr;
- }
-
- // Pattern format: "\x11\x2\x00text" + "..?....", meaning of mask chars is customizable by Sig::Mask::* types
- template
- static const void* find(const void* const buf, const size_t size, const char* const sig, const char* const subsig, const char* const mask)
- {
- if (!mask)
- {
- return nullptr;
- }
-
- return find(buf, size, sig, subsig, mask, strlen(mask));
- }
-
- // Pattern format: sig ("\x0D\xCB\xFF") + valuable bits in the sig that must match ("\x0D\xFF\x03")
- static const void* bitmask(const void* const buf, const size_t size, const void* const sig, const void* const mask, size_t sigsize)
- {
- if (!sig || !mask || !sigsize)
- {
- return nullptr;
- }
-
- const auto* const val = static_cast(sig);
- const auto* const msk = static_cast(mask);
-
- const auto* pos = static_cast(buf);
- const auto* const end = static_cast(buf) + size - sigsize + 1;
- while (pos < end)
- {
- bool result = true;
- for (size_t i = 0; i < sigsize; ++i)
- {
- const bool matches = ((pos[i] & msk[i]) == (val[i] & msk[i]));
- result &= matches;
- if (!result)
- {
- break;
- }
- }
-
- if (result)
- {
- return pos;
- }
-
- ++pos;
- }
-
- return nullptr;
- }
-
- // Pattern format: "11 22 ? 44 ?? ?? 66 aa bB Cc DD ee FF" ('?' and '??' have the same meaning: any byte)
- static const void* find(const void* const buf, const size_t size, const char* const sig)
- {
- if (!sig)
- {
- return nullptr;
- }
-
- const auto skipSpace = [](const char* const str) -> const char*
- {
- const char* pos = str;
- while ((*pos == ' ') || (*pos == '\t'))
- {
- ++pos;
- }
-
- return pos;
- };
-
- const auto calcTokenLen = [](const char* const str) -> size_t
- {
- size_t size = 0;
- while ((str[size]) && (str[size] != ' ') && (str[size] != '\t'))
- {
- ++size;
- }
- return size;
- };
-
- const auto calcSigBytes = [&skipSpace, &calcTokenLen](const char* const sig) -> size_t
- {
- const char* pos = sig;
- size_t bytes = 0;
-
- const auto isHexChar = [](const char ch) -> bool
- {
- return ((ch >= '0') && (ch <= '9')) || ((ch >= 'A') && (ch <= 'F')) || ((ch >= 'a') && (ch <= 'f'));
- };
-
- while (*(pos = skipSpace(pos)) != '\0')
- {
- ++bytes;
- const size_t entryLen = calcTokenLen(pos);
- constexpr auto k_maxTokenSize = (sizeof("xx") - sizeof('\0'));
- if (entryLen > k_maxTokenSize)
- {
- return 0;
- }
-
- if (entryLen == k_maxTokenSize)
- {
- if ((pos[0] == '?') || (pos[1] == '?'))
- {
- if (pos[0] != pos[1])
- {
- return 0;
- }
- }
- else
- {
- if (!isHexChar(pos[0]) || !isHexChar(pos[1]))
- {
- return 0;
- }
- }
- }
- else if (entryLen == sizeof('x'))
- {
- if ((pos[0] != '?') && !isHexChar(pos[0]))
- {
- return 0;
- }
- }
-
- pos += entryLen;
- }
-
- return bytes;
- };
-
- const auto testPattern = [&skipSpace, &calcTokenLen](const void* const buf, const char* const sig) -> bool
- {
- const char* sigPos = sig;
- const unsigned char* bufPos = static_cast(buf);
-
- const auto tokenToByte = [](const char* const token, size_t size) -> unsigned char
- {
- const auto charToByte = [](const char ch) -> unsigned char
- {
- if (ch >= '0' && ch <= '9')
- {
- return static_cast(ch - '0');
- }
-
- if (ch >= 'A' && ch <= 'F')
- {
- return static_cast(ch - 'A' + 10);
- }
-
- if (ch >= 'a' && ch <= 'f')
- {
- return static_cast