From a9506ab74d53092fd0d7787f508e6232f9701214 Mon Sep 17 00:00:00 2001 From: lumos Date: Sun, 22 Jun 2025 13:42:41 +0800 Subject: [PATCH] init --- .gitignore | 2 + log.h | 80 ++++++++++++++++++ .../frida_hook_libusb_basic_Version2.js | 53 ++++++++++++ .../frida_hook_libusb_modify_data_Version2.js | 84 +++++++++++++++++++ .../frida_hook_libusb_replay_Version2.js | 83 ++++++++++++++++++ upper/main.cpp | 12 +++ upper/mainwindow.cpp | 20 +++++ upper/mainwindow.h | 27 ++++++ upper/mainwindow.ui | 67 +++++++++++++++ upper/upper.pro | 26 ++++++ usbFilter.cpp | 11 +++ usbFilter.h | 14 ++++ 12 files changed, 479 insertions(+) create mode 100644 .gitignore create mode 100644 log.h create mode 100755 testScripts/frida_hook_libusb_basic_Version2.js create mode 100755 testScripts/frida_hook_libusb_modify_data_Version2.js create mode 100755 testScripts/frida_hook_libusb_replay_Version2.js create mode 100644 upper/main.cpp create mode 100644 upper/mainwindow.cpp create mode 100644 upper/mainwindow.h create mode 100644 upper/mainwindow.ui create mode 100644 upper/upper.pro create mode 100644 usbFilter.cpp create mode 100644 usbFilter.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5397813 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +upper/build +upper/upper.pro.* \ No newline at end of file diff --git a/log.h b/log.h new file mode 100644 index 0000000..04b8a90 --- /dev/null +++ b/log.h @@ -0,0 +1,80 @@ +#ifndef LOG_H +#define LOG_H + +#include // 使用 std::time 和 std::strftime +#include // 使用 printf +#include // 使用 va_list 和 va_start +#include // 使用 std::mutex + +// 定义打印等级 +#define LOG_LEVEL_DEBUG 0 +#define LOG_LEVEL_INFO 1 +#define LOG_LEVEL_WARN 2 +#define LOG_LEVEL_ERROR 3 + +// 默认日志等级为INFO +#ifndef LOG_LEVEL +#define LOG_LEVEL LOG_LEVEL_DEBUG +#endif + +// 颜色配置:用户空间启用颜色 +#define LOG_COLOR true + +// 颜色宏定义 +#if LOG_COLOR +#define RESET_COLOR "\033[0m" +#define COLOR_DEBUG "\033[34m" // 蓝色 +#define COLOR_INFO "\033[32m" // 绿色 +#define COLOR_WARN "\033[33m" // 黄色 +#define COLOR_ERROR "\033[31m" // 红色 +#else +#define RESET_COLOR "" +#define COLOR_DEBUG "" +#define COLOR_INFO "" +#define COLOR_WARN "" +#define COLOR_ERROR "" +#endif + +// 获取当前时间的字符串(用户空间实现) +inline const char* current_time() { + static char buffer[64]; + std::time_t now = std::time(nullptr); + std::tm* tm_now = std::localtime(&now); + + std::strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", tm_now); + return buffer; +} + +// 定义一个静态互斥锁,保证线程安全 +static std::mutex log_mutex; + +// 定义一个外部 FILE 变量,可以用来切换输出目标 +extern FILE* log_output; // 默认为 stdout + +// 用户空间打印日志 +#define LOG(level, format, ...) do {\ +if (level >= LOG_LEVEL) {\ + std::lock_guard lock(log_mutex); /* 自动锁住互斥锁 */\ + const char *level_str;\ + const char *color;\ + switch (level) {\ + case LOG_LEVEL_DEBUG: level_str = "[DEBUG]"; color = COLOR_DEBUG; break;\ + case LOG_LEVEL_INFO: level_str = "[INFO]"; color = COLOR_INFO; break;\ + case LOG_LEVEL_WARN: level_str = "[WARN]"; color = COLOR_WARN; break;\ + case LOG_LEVEL_ERROR: level_str = "[ERROR]"; color = COLOR_ERROR; break;\ + default: level_str = "[UNKNOWN]"; color = ""; break;\ + }\ + fprintf(log_output, "%s%s %s %s:%d - ", color, current_time(), level_str, __FILE__, __LINE__);\ + fprintf(log_output, format, ##__VA_ARGS__); /* 打印日志信息 */\ + fprintf(log_output, "%s\n", RESET_COLOR);\ + fflush(log_output); /* 强制刷新到指定输出目标 */\ +}\ +} while (0) + +// 简便宏,用于各个等级的日志 +#define LOG_DEBUG(format, ...) LOG(LOG_LEVEL_DEBUG, format, ##__VA_ARGS__) +#define LOG_INFO(format, ...) LOG(LOG_LEVEL_INFO, format, ##__VA_ARGS__) +#define LOG_WARN(format, ...) LOG(LOG_LEVEL_WARN, format, ##__VA_ARGS__) +#define LOG_ERROR(format, ...) LOG(LOG_LEVEL_ERROR, format, ##__VA_ARGS__) + +#endif // LOG_H diff --git a/testScripts/frida_hook_libusb_basic_Version2.js b/testScripts/frida_hook_libusb_basic_Version2.js new file mode 100755 index 0000000..95b2642 --- /dev/null +++ b/testScripts/frida_hook_libusb_basic_Version2.js @@ -0,0 +1,53 @@ +const symbol = DebugSymbol.fromName("libusb_bulk_transfer"); +console.log("libusb_bulk_transfer symbol info:", symbol); + +if (symbol && symbol.address) { + Interceptor.replace(symbol.address, new NativeCallback(function( + dev_handle, endpoint, data, length, transferred, timeout + ) { + console.log('[!] libusb_bulk_transfer 被阻断'); + console.log('dev_handle:', dev_handle); + console.log('endpoint:', endpoint); + console.log('data pointer:', data); + console.log('length:', length); + console.log('transferred pointer:', transferred); + console.log('timeout:', timeout); + + try { + var nLen = length.toInt32 ? length.toInt32() : parseInt(length); + var bytesToPrint = Math.min(nLen, 64); // 只输出前64字节 + + if (data && nLen > 0) { + console.log("数据十六进制输出(前" + bytesToPrint + "字节):"); + + // 最原始的读取方法 + var hexOutput = ""; + for (var i = 0; i < bytesToPrint; i++) { + try { + // 尝试使用ptr对象的属性 + var byteValue = data.add(i).readU8(); + var hexByte = byteValue.toString(16).padStart(2, "0"); + hexOutput += hexByte + " "; + if ((i + 1) % 16 === 0) { + hexOutput += "\n"; + } + } catch (readErr) { + console.log("读取字节" + i + "时出错:", readErr); + break; + } + } + console.log(hexOutput); + } else { + console.log('data 指针无效 或 length <= 0'); + } + } catch (e) { + console.log('读取data时出错:', e); + console.log('错误详情:', e.stack || e.toString()); + } + + return -1; // 阻断原函数 + }, 'int', ['pointer', 'uchar', 'pointer', 'int', 'pointer', 'uint'])); + console.log("已成功 Hook libusb_bulk_transfer at:", symbol.address); +} else { + console.log("找不到符号 libusb_bulk_transfer,请确认程序未被 strip,且符号可见。"); +} \ No newline at end of file diff --git a/testScripts/frida_hook_libusb_modify_data_Version2.js b/testScripts/frida_hook_libusb_modify_data_Version2.js new file mode 100755 index 0000000..98a1b62 --- /dev/null +++ b/testScripts/frida_hook_libusb_modify_data_Version2.js @@ -0,0 +1,84 @@ +const symbol = DebugSymbol.fromName("libusb_bulk_transfer"); +console.log("libusb_bulk_transfer symbol info:", symbol); + +if (symbol && symbol.address) { + Interceptor.attach(symbol.address, { + onEnter: function(args) { + this.dev_handle = args[0]; + this.endpoint = args[1]; + this.data = args[2]; + this.length = args[3]; + this.transferred = args[4]; + this.timeout = args[5]; + + console.log('[+] libusb_bulk_transfer 被拦截'); + console.log('dev_handle:', this.dev_handle); + console.log('endpoint:', this.endpoint); + console.log('data pointer:', this.data); + console.log('length:', this.length); + console.log('transferred pointer:', this.transferred); + console.log('timeout:', this.timeout); + + try { + var nLen = parseInt(this.length); + if (this.data && nLen > 0) { + console.log(`[+] 正在修改 ${nLen} 字节数据,全部修改为0`); + + // 先记录前16个字节用于展示修改前后差异 + var previewBytes = 16; + var bytesToPreview = Math.min(nLen, previewBytes); + var originalHex = ""; + + for (var i = 0; i < bytesToPreview; i++) { + try { + var byteValue = this.data.add(i).readU8(); + originalHex += byteValue.toString(16).padStart(2, "0") + " "; + } catch (readErr) { + console.log("读取原始数据时出错:", readErr); + break; + } + } + console.log("修改前前16字节:", originalHex); + + // 修改数据为全0 + for (var j = 0; j < nLen; j++) { + try { + this.data.add(j).writeU8(0); + } catch (writeErr) { + console.log("写入数据时出错:", writeErr); + break; + } + } + + // 校验修改结果 + var modifiedHex = ""; + for (var k = 0; k < bytesToPreview; k++) { + try { + var newByteValue = this.data.add(k).readU8(); + modifiedHex += newByteValue.toString(16).padStart(2, "0") + " "; + } catch (verifyErr) { + console.log("验证修改后数据时出错:", verifyErr); + break; + } + } + console.log("修改后前16字节:", modifiedHex); + + console.log('[+] 数据修改完成'); + } else { + console.log('[-] data 指针无效 或 length <= 0,无法修改数据'); + } + } catch (e) { + console.log('[-] 处理数据时出错:', e); + console.log('错误详情:', e.stack || e.toString()); + } + }, + + onLeave: function(retval) { + console.log(`[+] libusb_bulk_transfer 返回值: ${retval}`); + // 如果想修改返回值,可以使用 retval.replace(0) + } + }); + console.log("已成功 Hook libusb_bulk_transfer at:", symbol.address); +} else { + console.log("找不到符号 libusb_bulk_transfer,请确认程序未被 strip,且符号可见。"); +} \ No newline at end of file diff --git a/testScripts/frida_hook_libusb_replay_Version2.js b/testScripts/frida_hook_libusb_replay_Version2.js new file mode 100755 index 0000000..da66d82 --- /dev/null +++ b/testScripts/frida_hook_libusb_replay_Version2.js @@ -0,0 +1,83 @@ +const symbol = DebugSymbol.fromName("libusb_bulk_transfer"); +console.log("libusb_bulk_transfer symbol info:", symbol); + +if (symbol && symbol.address) { + Interceptor.attach(symbol.address, { + onEnter: function(args) { + // 保存原始参数 + this.dev_handle = args[0]; + this.endpoint = parseInt(args[1]); // 转换为整数 + this.data = args[2]; + this.length = parseInt(args[3]); // 转换为整数 + this.transferred = args[4]; + this.timeout = parseInt(args[5]); // 转换为整数 + + // 记录原始函数和参数,以便后续重放 + this.original_function = symbol.address; + + console.log('[+] libusb_bulk_transfer 被拦截'); + console.log('dev_handle:', this.dev_handle); + console.log('endpoint:', this.endpoint, '(', args[1], ')'); + console.log('data pointer:', this.data); + console.log('length:', this.length, '(', args[3], ')'); + console.log('transferred pointer:', this.transferred); + console.log('timeout:', this.timeout, '(', args[5], ')'); + + // 显示部分原始数据(前16字节) + try { + if (this.data && this.length > 0) { + var bytesToPreview = Math.min(this.length, 16); + var originalHex = ""; + + for (var i = 0; i < bytesToPreview; i++) { + try { + var byteValue = this.data.add(i).readU8(); + originalHex += byteValue.toString(16).padStart(2, "0") + " "; + } catch (readErr) { + console.log("读取原始数据时出错:", readErr); + break; + } + } + console.log("数据前16字节:", originalHex); + } + } catch (e) { + console.log('读取数据时出错:', e, e.stack); + } + }, + + onLeave: function(retval) { + console.log(`[+] libusb_bulk_transfer 原始调用返回值: ${retval}`); + + // 重放次数设置 + const replayCount = 3; // 设置重放次数,这里重放3次 + console.log(`[*] 开始重放 libusb_bulk_transfer ${replayCount} 次`); + + // 重放函数 + try { + const originalFunction = new NativeFunction(this.original_function, 'int', + ['pointer', 'int', 'pointer', 'int', 'pointer', 'int']); + + for (let i = 0; i < replayCount; i++) { + console.log(`[*] 正在重放第 ${i + 1}/${replayCount} 次`); + const replayResult = originalFunction( + this.dev_handle, + this.endpoint, + this.data, + this.length, + this.transferred, + this.timeout + ); + console.log(`[+] 重放 #${i + 1} 返回值: ${replayResult}`); + } + + console.log('[+] 重放完成'); + } catch (err) { + console.log('[!] 重放时发生错误: ', err, err.stack); + } + } + }); + + console.log("已成功 Hook libusb_bulk_transfer at:", symbol.address); +} else { + console.log("找不到符号 libusb_bulk_transfer,请确认程序未被 strip,且符号可见。"); +} \ No newline at end of file diff --git a/upper/main.cpp b/upper/main.cpp new file mode 100644 index 0000000..31867f3 --- /dev/null +++ b/upper/main.cpp @@ -0,0 +1,12 @@ +#include "mainwindow.h" +#include + +FILE* log_output=stdout; + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + return a.exec(); +} diff --git a/upper/mainwindow.cpp b/upper/mainwindow.cpp new file mode 100644 index 0000000..f192a33 --- /dev/null +++ b/upper/mainwindow.cpp @@ -0,0 +1,20 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" +#include "QDateTime" +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent) + , ui(new Ui::MainWindow) +{ + ui->setupUi(this); +} + +MainWindow::~MainWindow() +{ + delete ui; +} + +void MainWindow::onPrint(QString &msg){ + QDateTime cur = QDateTime::currentDateTime(); + QString tmp =cur.toString("yyyy-MM-dd HH:mm:ss"); + ui->textBrowser->append(tmp+" --> "+msg); +} diff --git a/upper/mainwindow.h b/upper/mainwindow.h new file mode 100644 index 0000000..b39332c --- /dev/null +++ b/upper/mainwindow.h @@ -0,0 +1,27 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include + + +QT_BEGIN_NAMESPACE +namespace Ui { +class MainWindow; +} +QT_END_NAMESPACE + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + MainWindow(QWidget *parent = nullptr); + ~MainWindow(); +public slots: + void onPrint(QString &msg); + + +private: + Ui::MainWindow *ui; +}; +#endif // MAINWINDOW_H diff --git a/upper/mainwindow.ui b/upper/mainwindow.ui new file mode 100644 index 0000000..845c204 --- /dev/null +++ b/upper/mainwindow.ui @@ -0,0 +1,67 @@ + + + MainWindow + + + + 0 + 0 + 800 + 600 + + + + MainWindow + + + + + + + Stop Srv + + + + + + + Start Srv + + + + + + + Log + + + + + + + + + + + + Enum Drivers And Devices + + + + + + + + + 0 + 0 + 800 + 22 + + + + + + + + diff --git a/upper/upper.pro b/upper/upper.pro new file mode 100644 index 0000000..7e54a58 --- /dev/null +++ b/upper/upper.pro @@ -0,0 +1,26 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++17 + +# You can make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + ../usbFilter.cpp \ + main.cpp \ + mainwindow.cpp + +HEADERS += \ + ../usbFilter.h \ + mainwindow.h + +FORMS += \ + mainwindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/usbFilter.cpp b/usbFilter.cpp new file mode 100644 index 0000000..652c4c0 --- /dev/null +++ b/usbFilter.cpp @@ -0,0 +1,11 @@ +#include "usbFilter.h" + + +usbFilter::usbFilter(/* args */) +{ +} + +usbFilter::~usbFilter() +{ +} + \ No newline at end of file diff --git a/usbFilter.h b/usbFilter.h new file mode 100644 index 0000000..7c80a4e --- /dev/null +++ b/usbFilter.h @@ -0,0 +1,14 @@ +#include "log.h" + +class usbFilter +{ +private: + /* data */ +public: + usbFilter(/* args */); + ~usbFilter(); + void StarSrv(); + void StopSrv(); + +}; +