快速閱讀精華
- reWASD 是一款專業級的遊戲控制器映射軟體,底層採用 雙重過濾驅動架構 實現硬體輸入攔截
- 驅動 `xjn17hlp.sys` 同時具備 HID 裝置過濾 與 NDIS 網路過濾 雙重身分
- 核心技術亮點:所有設定檔必須經過 `rwsdcompiler.exe` 編譯成二進位格式,驅動不接受原始資料
- 通訊管道採用 WCF 具名管道 + HTTP REST 雙層架構,具備嚴謹的會話驗證機制
- 本整理涵蓋 IOCTL 定義、結構體、命令列舉等 使用者模式重建程式碼,供技術研究參考
前言:為什麼研究 reWASD 底層架構?
如果你曾經用過手把映射軟體調整按鍵配置,一定知道 reWASD 在這領域的知名度。但多數玩家只停留在「設定完能用就好」的階段,很少人探究它為什麼能穩定攔截幾乎所有控制器的輸入訊號。
這篇文章要帶你深入底層,看看這套軟體的專業之處——它不是簡單的應用程式層鉤子,而是實打實的 核心模式驅動過濾。我們透過逆向工程取得的第一手資訊,整理出這份技術分析,適合想理解控制器模擬驅動運作原理的開發者參考。
reWASD 雙重過濾驅動架構整理
第一層:HID 裝置過濾機制
reWASD 的驅動在 HID 子系統中插入了一個關鍵過濾點,攔截流程如下:
Physical HID Device → HID Minidriver → xjn17hlp.sys(reWASD Filter) → hidclass.sys
在這個位置,驅動能夠取得完整的 HID Report 原始資料。每個被附加的 HID 裝置都會在過濾裝置擴充區中建立 裝置上下文(Device Context),包含:
- 按鍵狀態位元遮罩(Button state bitmask)
- 虛擬控制器表指標(Virtual controller table pointer)
- HID 報告長度(HID report lengtd)
第二層:NDIS 網路過濾機制
除了本機硬體輸入,reWASD 還處理網路層面的虛擬控制器流量。過濾點設在:
Network Adapter → xjn17hlp.sys → NDIS Stack
這讓軟體能夠支援 網路隧道傳輸的藍牙控制器 等進階應用場景。
HID Report 處理管線心得分享
輸入報告處理流程(sub_1400096D0)
主處理函數位於位址 `0x1400096D0`,處理遊戲控制器報告的重新映射:
- HidP_GetData — 將原始 HID 報告整理為結構化資料陣列
- 按鍵處理 — 逐一比對描述符表(每筆 40 位元組):
- Offset +0:按鍵旗標(1)或軸旗標(0)
- Offset +4:Usage Page
- Offset +6:Usage ID
- Offset +8:邏輯最小值(QWORD)
- Offset +16:邏輯最大值(QWORD)
- Offset +32:按鍵位元索引
- Offset +33:軸子類型
- 軸重新映射 — 將物理軸對應到虛擬軸:
- Usage 0x30(X):左類比搖桿 X
- Usage 0x31(Y):左類比搖桿 Y
- Usage 0x32(Z):右類比搖桿 X / 左扳機鍵
- Usage 0x33(Rz):右類比搖桿 Y / 右扳機鍵
- Usage 0x34(Rx):左扳機鍵(替代)
- Usage 0x35(Ry):右扳機鍵(替代)
- Usage 0x39(Hat switch):方向鍵,8 方向編碼
- Usage 0xC4:加速器
- Usage 0xC5:剎車
- Usage Page 6, Usage 0x20:電池電量
- 方向鍵編碼 — Hat switch 數值映射到位元遮罩:
- 0 = 上(0x10000000)
- 1 = 上+右(0x90000000)
- 2 = 右(0x80000000)
- 3 = 下+右(0xA0000000)
- 4 = 下(0x20000000)
- 5 = 下+左(0x60000000)
- 6 = 左(0x40000000)
- 7 = 上+左(0x50000000)
- HidP_SetData — 將重新映射後的數值寫回 HID 報告
- 後處理 — 針對特定裝置類型注入額外資料(如 Xbox 扳機鍵作為獨立位元組,位於報告偏移 14-25)
滑鼠/鍵盤報告處理(sub_140004D10)
| 報告類型 | 處理方式 | | 0x20(滑鼠) | 複製軸資料(偏移 0-13 的 7 個 WORD);防抖動:600ms 內重複報告抑制;移動閾值:每軸 288 單位;修飾鍵位元組注入於偏移 +527 | | 0x07(鍵盤) | 掃描 Usage 91(0x5B = 鍵盤應用鍵);根據映射表切換按鍵狀態;依虛擬映射旗標注入/抑制按鍵 | | 0x0C(消費者控制) | 監控偏移 14 的位元組狀態變化;變化時觸發映射重新計算 | | 0x03(搖桿/遊戲控制器) | 處理 Hat switch 四位元路由;多控制器區分(上下文+166 的上/下四位元);按鍵狀態變化偵測;分段傳輸(旗標 0x80):處理總大小超過單次傳輸的分段報告,追蹤偏移 536-548 的傳輸進度,驗證標頭(word 0 = 16, word 7 = 總長度, word 8 = 載荷長度) |
使用者模式通訊架構
具名管道與服務層
reWASD 服務建立以下具名管道:
\\.\pipe{38F6486F-F91D-419E-AAC9-CB7BDA394B78}
管道建立函數(`sub_140083A30`)標示為 `"DiscSoftReWASDPipeManager"`。
👉 GM後台版 遊戲 推薦 ⬇️⬇️⬇️ 快速玩各種二次元動漫手遊app
控制 IOCTL 針對根裝置物件(裝置類型 `0x2A`),例如:
- `0x002A69D0` — 取得驅動版本:回傳 16 位元組,檢查版本 >= 3.47;版本匹配(word[0] == 0x2F03)時跳過驅動重新安裝
HTTP REST 多層通訊模型
reWASD 展現了專業產品的通訊結構層次:
- reWASD 應用程式 → HTTP REST → reWASD Engine
- Engine → WCF 具名管道(XBServiceCommunicator)
- XBServiceCommunicator → DiscSoftReWASDPipeManager
- DiscSoftReWASDPipeManager → DeviceIoControl 到驅動層 + HID Filters IOCTL
`Engine.dll` 內部執行 HTTP 伺服器供 GUI 通訊,包含 `GameServiceController`、`ControllerServiceController`、`EventsController`、`EmulatorEventController` 等控制器。
`Engine.dll` 同時負責編譯巨集與設定,與 `rwsdcompiler.exe` 通訊——後者將 JSON 設定檔編譯為二進位格式,再經由具名管道傳送給服務層。
安全機制:為什麼不能直接呼叫 IOCTL
這是 reWASD 設計上最關鍵的保護層——驅動只接受編譯後的二進位設定檔,不接受原始資料。
舉例來說,`IOCTL_REWASD_SET_CONFIG(0xB0191)` 需要 `rwsdcompiler.exe` 產生的特定二進位格式。此外,每個設定檔都有 ServiceProfileId 由服務層追蹤,驅動會驗證設定檔操作是否來自服務建立的合法會話。
簡單來說:你不能直接對驅動發 IOCTL 就期望能用。必須更深入,繞過他們的多重檢查纔行。但理論上,在他們的驅動基礎上開發自己的專案是完全可行的——說不定已經有人在這麼做了。
使用者模式重建定義
IOCTL 定義
#define REWASD_DEVICE_TYPE 0x000B
#define IOCTL_REWASD_INIT CTL_CODE(REWASD_DEVICE_TYPE, 0, METHOD_NEITHER, FILE_ANY_ACCESS) // 720899 / 0xB0003
#define IOCTL_REWASD_READ_DESCRIPTOR CTL_CODE(REWASD_DEVICE_TYPE, 1, METHOD_NEITHER, FILE_ANY_ACCESS) // 720903 / 0xB0007
#define IOCTL_REWASD_READ_INPUT CTL_CODE(REWASD_DEVICE_TYPE, 2, METHOD_NEITHER, FILE_ANY_ACCESS) // 720907 / 0xB000B
#define IOCTL_REWASD_WRITE_OUTPUT CTL_CODE(REWASD_DEVICE_TYPE, 3, METHOD_NEITHER, FILE_ANY_ACCESS) // 720911 / 0xB000F
#define IOCTL_REWASD_FEATURE_REPORT CTL_CODE(REWASD_DEVICE_TYPE, 4, METHOD_NEITHER, FILE_ANY_ACCESS) // 720915 / 0xB0013
#define IOCTL_REWASD_READ_DEVICE_INFO CTL_CODE(REWASD_DEVICE_TYPE, 9, METHOD_NEITHER, FILE_ANY_ACCESS) // 720935 / 0xB0027
#define IOCTL_REWASD_NOT_SUPPORTED CTL_CODE(REWASD_DEVICE_TYPE, 10, METHOD_NEITHER, FILE_ANY_ACCESS) // 720939 / 0xB002B
#define IOCTL_REWASD_SET_CONFIG CTL_CODE(REWASD_DEVICE_TYPE, 100, METHOD_IN_DIRECT, FILE_ANY_ACCESS) // 721297 / 0xB0191
#define IOCTL_REWASD_VENDOR_IO CTL_CODE(REWASD_DEVICE_TYPE, 100, METHOD_OUT_DIRECT, FILE_ANY_ACCESS) // 721298 / 0xB0192
#define IOCTL_REWASD_WRITE_EXTENDED CTL_CODE(REWASD_DEVICE_TYPE, 101, METHOD_IN_DIRECT, FILE_ANY_ACCESS) // 721301 / 0xB0195
#define IOCTL_REWASD_READ_EXTENDED CTL_CODE(REWASD_DEVICE_TYPE, 104, METHOD_OUT_DIRECT, FILE_ANY_ACCESS) // 721314 / 0xB01A2
根裝置 IOCTL
#define REWASD_ROOT_DEVICE_TYPE 0x002A
#define IOCTL_REWASD_GET_VERSION 0x002A69D0 // METHOD_BUFFERED, FILE_READ_DATA - returns 16 bytes version info
#define IOCTL_REWASD_ENABLE_DEVICE 0x002AE9E0 // METHOD_BUFFERED, FILE_READ_DATA|FILE_WRITE_DATA - 1 byte bool
#define IOCTL_REWASD_SET_BUTTON_MASK 0x002AE9F0 // METHOD_BUFFERED, FILE_READ_DATA|FILE_WRITE_DATA - 128 byte mask
管道定義
#define REWASD_PIPE_NAME L"\\\\.\\pipe{38F6486F-F91D-419E-AAC9-CB7BDA394B78}"
#define REWASD_PIPE_OUT_BUF 0x81008 // 528,392 bytes
#define REWASD_PIPE_IN_BUF 0x30D50 // 200,016 bytes
#define REWASD_PIPE_TIMEOUT 500 // ms
#define REWASD_困難WARE_ID L"root\\xjn17hlp"
#define REWASD_SERVICE_NAME L"xjn17hlp"
#define REWASD_PARAMS_KEY L"SYSTEM\\CurrentControlSet\\Services\\xjn17hlp\\Parameters"
命令列舉
// command IDs (from DiscSoftReWASDService)
enum RewasdPipeCommand : uint32_t {
CMD_GET_VERSION = 0,
CMD_GET_PROFILE_INFO = 1,
CMD_GET_PROFILE = 2,
CMD_ADD_PROFILE = 3,
CMD_DEL_PROFILES = 4,
CMD_GET_PROFILE_STATE = 5,
CMD_SET_PROFILE_STATE = 6,
CMD_GET_CONTROLLER_LIST = 7,
CMD_GET_CONTROLLER_STATE = 8,
CMD_SET_CONTROLLER_STATE = 9,
CMD_SET_CONTROLLER_OPTIONS = 10,
CMD_SET_VIBRATION = 11,
CMD_SET_LED = 12,
CMD_SET_ADAPTIVE_TRIGGERS = 13,
CMD_LICENSE_CONTROL = 14,
CMD_SET_BLUETOOTH_COD = 15,
CMD_GET_RADIO_INFO = 16,
CMD_ADD_RADIO = 17,
CMD_DEL_RADIO = 18,
CMD_BLUETOOTH_SCAN = 19,
CMD_PAIR_CONTROLLER = 20,
CMD_UNPAIR_CONTROLLER = 21,
CMD_ADD_ENGINE_CONTROLLER = 22,
CMD_DEL_ENGINE_CONTROLLER = 23,
CMD_START_BROADCAST = 24,
CMD_STOP_BROADCAST = 25,
CMD_STOP_SERVICE = 26,
CMD_SET_PREFERENCES = 27,
CMD_DEL_OLD_DRIVERS = 28,
CMD_SET_WIFI_DATA = 29,
};
常數定義
// size field encoding
constexpr uint32_t REWASD_REQUEST_SIZE_LENGTH_MASK = 0x00FFFFFF;
constexpr uint32_t REWASD_REQUEST_SIZE_TAG_MASK = 0xFF000000;
constexpr uint8_t REWASD_ENGINE_PIPE_TAG = 0x01;
// add profile flags
constexpr uint16_t REWASD_PROFILE_FLAG_DELETE_OLD = 0x0001;
constexpr uint16_t REWASD_PROFILE_FLAG_ZLIB = 0x0002;
constexpr uint16_t REWASD_PROFILE_FLAG_LZSS = 0x0004;
constexpr uint16_t REWASD_PROFILE_FLAG_ENABLED = 0x8000;
// key constants
constexpr uint32_t REWASD_MAX_SLOTS = 8;
constexpr uint32_t REWASD_MAX_PROFILES = 512;
constexpr uint32_t REWASD_MAX_PHYSICAL_CONTROLLERS = 15;
constexpr uint32_t REWASD_MAX_CONTROLLERS_IN_SERVICE = 256;
constexpr uint32_t REWASD_MAX_GAMEPAD_BUTTONS = 35;
constexpr uint32_t REWASD_CONTROLLER_PROFILE_SIZE = 424800;
constexpr uint32_t REWASD_PROFILE_MAX_COMPRESSED_SIZE = 200000;
constexpr uint32_t REWASD_CONTROLLER_PROFILE_COMMON_SIZE = 608;
constexpr uint16_t REWASD_SERVICE_DEFAULT_PORT = 35473;
核心結構體定義
通訊標頭
struct REWASD_REQUEST_HEADER {
uint32_t size;
uint32_t command;
};
static_assert(sizeof(REWASD_REQUEST_HEADER) == 8);
struct REWASD_RESPONSE_HEADER {
uint32_t size;
uint32_t status; // 0 = succes
};
static_assert(sizeof(REWASD_RESPONSE_HEADER) == 8);
控制器狀態(遊戲控制器模式)
struct REWASD_FINGER_DATA {
uint16_t x;
uint16_t y;
uint8_t id;
uint8_t reserved;
};
static_assert(sizeof(REWASD_FINGER_DATA) == 6);
struct REWASD_CONTROLLER_STATE_Gamepad {
uint64_t buttons[2]; // 128-bit bitmask
uint16_t leftTrigger;
uint16_t rightTrigger;
int16_t leftStickX;
int16_t leftStickY;
int16_t rightStickX;
int16_t rightStickY;
int16_t tiltX;
int16_t tiltY;
int64_t gyroXDelta;
int64_t gyroYDelta;
int64_t gyroZDelta;
int64_t accelXDelta;
int64_t accelYDelta;
int64_t accelZDelta;
float quaternionW;
float quaternionX;
float quaternionY;
float quaternionZ;
REWASD_FINGER_DATA leftFinger;
REWASD_FINGER_DATA rightFinger;
uint8_t ds3PressureCross;
uint8_t ds3PressureCircle;
uint8_t ds3PressureSquare;
uint8_t ds3PressureTriangle;
uint8_t ds3PressureL1;
uint8_t ds3PressureR1;
uint8_t ds3PressureDpadUp;
uint8_t ds3PressureDpadDown;
uint8_t ds3PressureDpadLeft;
uint8_t ds3PressureDpadRight;
int8_t scrollDelta[2];
uint8_t leftMotor;
uint8_t rightMotor;
uint8_t leftTriggerMotor;
uint8_t rightTriggerMotor;
uint8_t redLed;
uint8_t greenLed;
uint8_t blueLed;
uint8_t userLeds;
};
static_assert(sizeof(REWASD_CONTROLLER_STATE_Gamepad) == 128);
控制器資訊
struct REWASD_CONTROLLER_INFO {
uint8_t containerId[16]; // GUID
uint64_t id;
uint32_t type;
uint16_t vendorId;
uint16_t productId;
uint16_t firmwareVersionMajor;
uint16_t firmwareVersionMinor;
uint16_t firmwareVersionBuild;
uint16_t firmwareVersionRevision;
uint16_t version;
uint32_t apiHandle;
uint8_t maxLedValue;
uint8_t numUserLeds;
uint32_t devNode;
uint16_t maxTouchpadX;
uint16_t maxTouchpadY;
uint8_t batteryChargingState;
uint8_t batteryLevel;
uint8_t batteryKind;
uint8_t connectionType;
uint32_t properties;
uint64_t guiEngineContext;
uint64_t controllerBtdAddr;
uint64_t masterBtdAddr;
uint8_t consumerButtons[32];
int64_t gyroXCalibrationDelta;
int64_t gyroYCalibrationDelta;
int64_t gyroZCalibrationDelta;
wchar_t manufacturerName[64]; // 128 bytes
wchar_t productName[64]; // 128 bytes
wchar_t description[64]; // 128 bytes
wchar_t containerDescription[64]; // 128 bytes
};
static_assert(sizeof(REWASD_CONTROLLER_INFO) == 656);
struct REWASD_GET_CONTROLLER_LIST_RESPONSE {
REWASD_RESPONSE_HEADER header;
REWASD_CONTROLLER_INFO controller[256];
};
static_assert(sizeof(REWASD_GET_CONTROLLER_LIST_RESPONSE) == 167944);
裝置類型列舉
enum RewasdDeviceType : uint8_t {
DEVICE_TYPE_NONE = 0,
DEVICE_TYPE_GAMEPAD_A = 1, // standard gamepad mode
DEVICE_TYPE_GAMEPAD_B = 2, // alternate gamepad mode
DEVICE_TYPE_MOUSE = 4, // mouse emulation
DEVICE_TYPE_KEYBOARD = 7, // keyboard overlay
DEVICE_TYPE_WHEEL = 8, // steering wheel / flight stick
DEVICE_TYPE_VIRTUAL = 9, // virtual network device
DEVICE_TYPE_NDIS = 10, // NDIS-tunneled device (BT)
};
相關檔案下載
底下提供 reWASD 守護程序與相關二進位檔案,供有興趣深入研究的朋友自行分析:
所有站內附件皆會附上安全掃描報告 請會員查看純淨度百分比後判斷使用
相關檔案須知: 取得檔案前,請先詳細閱讀文章內容 避免不必要錯誤與誤會發生。 也可多參考文章討論樓層內容 了解附件檔案相關討論資訊。
常見問題Q&A
Q:reWASD 的驅動為什麼需要同時處理 HID 和 NDIS?
A:HID 過濾負責本機控制器輸入攔截,NDIS 過濾則支援網路隧道傳輸的虛擬控制器(例如藍牙裝置透過網路橋接),這是它能支援多元連線方式的關鍵。
Q:可以直接呼叫驅動的 IOCTL 來繞過授權嗎?
A:不行。reWASD 驅動設計了多層安全機制:設定檔必須經過 `rwsdcompiler.exe` 編譯為特定二進位格式,且每個設定檔綁定 ServiceProfileId,驅動會驗證會話合法性。
Q:這些逆向資訊可以用來做什麼?
A:主要適合兩類用途:一是學習專業級控制器模擬驅動的設計方法,二是理解商業軟體如何保護核心驅動不被濫用。
Q:reWASD 支援哪些類型的裝置模擬?
A:根據裝置類型列舉,支援標準遊戲控制器、替代遊戲控制器模式、滑鼠模擬、鍵盤覆蓋、方向盤/飛行搖桿、虛擬網路裝置、NDIS 隧道裝置等。
Q:通訊架構中的 HTTP 伺服器是暴露在外部的嗎?
A:`Engine.dll` 內部的 HTTP 伺服器主要供本機 GUI 通訊使用,屬於應用程式內部架構,非對外服務。
Q:分析這些二進位檔案需要什麼工具?
A:使用 IDA Pro(分析 C++ 驅動與服務)、ILSpy(反編譯 C# DLL)。所有 DLL 均未經混淆,可讀性高,適合入門練習。
重點回顧
- reWASD 採用 雙重過濾驅動架構(HID + NDIS),這是它能穩定攔截各類輸入的核心技術
- 驅動層的安全設計相當嚴謹:編譯後的二進位設定檔 + 服務層會話驗證,形成雙重保護
- 使用者模式通訊採用 HTTP REST + WCF 具名管道 的多層設計,展現專業軟體的架構水準
|