Compare commits

...
This repository has been archived on 2025-07-08. You can view files and clone it, but cannot push or open issues or pull requests.

5 Commits
main ... dev

17 changed files with 26526 additions and 20 deletions

3
.gitignore vendored
View File

@ -1,2 +1,3 @@
upper/build
upper/upper.pro.*
upper/upper.pro.*
.vscode

12
README.md Normal file
View File

@ -0,0 +1,12 @@
# 目录说明
- `scripts` 为`Frida`注入脚本;
- `testScripts` 为常规测试时所使用的测试脚本,主要为了寻找函数入口和验证功能;
- `testMod`为常规测试时用所使用的内核模块,主要查看到内核处的数据如何;
- `upper`为动态库的上位机调试程序;
- `usbFilter.h/cpp`为动态库实际实现代码;
- `ida` 中包括ida pro的程序和破解脚本安装安成后将破解脚本放在ida pro的目录下运行替换运行库即可
# 软件需求
- Frida
- libudev用于查找设备

223
ida/crack_ida90_beta.py Executable file
View File

@ -0,0 +1,223 @@
import json
import hashlib
import os
license = {
"header": {"version": 1},
"payload": {
"name": "meow :3",
"email": "hi@hex-rays.com",
"licenses": [
{
"id": "48-2137-ACAB-99",
"license_type": "named",
"product": "IDA",
"seats": 1,
"start_date": "2024-08-10 00:00:00",
"end_date": "2033-12-31 23:59:59", # This can't be more than 10 years!
"issued_on": "2024-08-10 00:00:00",
"owner": "cracked by alula :3",
"add_ons": [
# {
# "id": "48-1337-DEAD-01",
# "code": "HEXX86L",
# "owner": "48-0000-0000-00",
# "start_date": "2024-08-10 00:00:00",
# "end_date": "2033-12-31 23:59:59",
# },
# {
# "id": "48-1337-DEAD-02",
# "code": "HEXX64L",
# "owner": "48-0000-0000-00",
# "start_date": "2024-08-10 00:00:00",
# "end_date": "2033-12-31 23:59:59",
# },
],
"features": [],
}
],
},
}
def add_every_addon(license):
platforms = [
"W", # Windows
"L", # Linux
"M", # macOS
]
addons = [
"HEXX86",
"HEXX64",
"HEXARM",
"HEXARM64",
"HEXMIPS",
"HEXMIPS64",
"HEXPPC",
"HEXPPC64",
"HEXRV64",
"HEXARC",
"HEXARC64",
# Probably cloud?
# "HEXCX86",
# "HEXCX64",
# "HEXCARM",
# "HEXCARM64",
# "HEXCMIPS",
# "HEXCMIPS64",
# "HEXCPPC",
# "HEXCPPC64",
# "HEXCRV",
# "HEXCRV64",
# "HEXCARC",
# "HEXCARC64",
]
i = 0
for addon in addons:
i += 1
license["payload"]["licenses"][0]["add_ons"].append(
{
"id": f"48-1337-DEAD-{i:02}",
"code": addon,
"owner": license["payload"]["licenses"][0]["id"],
"start_date": "2024-08-10 00:00:00",
"end_date": "2033-12-31 23:59:59",
}
)
# for addon in addons:
# for platform in platforms:
# i += 1
# license["payload"]["licenses"][0]["add_ons"].append(
# {
# "id": f"48-1337-DEAD-{i:02}",
# "code": addon + platform,
# "owner": license["payload"]["licenses"][0]["id"],
# "start_date": "2024-08-10 00:00:00",
# "end_date": "2033-12-31 23:59:59",
# }
# )
add_every_addon(license)
def json_stringify_alphabetical(obj):
return json.dumps(obj, sort_keys=True, separators=(",", ":"))
def buf_to_bigint(buf):
return int.from_bytes(buf, byteorder="little")
def bigint_to_buf(i):
return i.to_bytes((i.bit_length() + 7) // 8, byteorder="little")
# Yup, you only have to patch 5c -> cb in libida64.so
pub_modulus_hexrays = buf_to_bigint(
bytes.fromhex(
"edfd425cf978546e8911225884436c57140525650bcf6ebfe80edbc5fb1de68f4c66c29cb22eb668788afcb0abbb718044584b810f8970cddf227385f75d5dddd91d4f18937a08aa83b28c49d12dc92e7505bb38809e91bd0fbd2f2e6ab1d2e33c0c55d5bddd478ee8bf845fcef3c82b9d2929ecb71f4d1b3db96e3a8e7aaf93"
)
)
pub_modulus_patched = buf_to_bigint(
bytes.fromhex(
"edfd42cbf978546e8911225884436c57140525650bcf6ebfe80edbc5fb1de68f4c66c29cb22eb668788afcb0abbb718044584b810f8970cddf227385f75d5dddd91d4f18937a08aa83b28c49d12dc92e7505bb38809e91bd0fbd2f2e6ab1d2e33c0c55d5bddd478ee8bf845fcef3c82b9d2929ecb71f4d1b3db96e3a8e7aaf93"
)
)
private_key = buf_to_bigint(
bytes.fromhex(
"77c86abbb7f3bb134436797b68ff47beb1a5457816608dbfb72641814dd464dd640d711d5732d3017a1c4e63d835822f00a4eab619a2c4791cf33f9f57f9c2ae4d9eed9981e79ac9b8f8a411f68f25b9f0c05d04d11e22a3a0d8d4672b56a61f1532282ff4e4e74759e832b70e98b9d102d07e9fb9ba8d15810b144970029874"
)
)
def decrypt(message):
decrypted = pow(buf_to_bigint(message), exponent, pub_modulus_patched)
decrypted = bigint_to_buf(decrypted)
return decrypted[::-1]
def encrypt(message):
encrypted = pow(buf_to_bigint(message[::-1]), private_key, pub_modulus_patched)
encrypted = bigint_to_buf(encrypted)
return encrypted
exponent = 0x13
def sign_hexlic(payload: dict) -> str:
data = {"payload": payload}
data_str = json_stringify_alphabetical(data)
buffer = bytearray(128)
# first 33 bytes are random
for i in range(33):
buffer[i] = 0x42
# compute sha256 of the data
sha256 = hashlib.sha256()
sha256.update(data_str.encode())
digest = sha256.digest()
# copy the sha256 digest to the buffer
for i in range(32):
buffer[33 + i] = digest[i]
# encrypt the buffer
encrypted = encrypt(buffer)
return encrypted.hex().upper()
def generate_patched_dll(filename):
if not os.path.exists(filename):
print(f"Didn't find {filename}, skipping patch generation")
return
with open(filename, "rb") as f:
data = f.read()
if data.find(bytes.fromhex("EDFD42CBF978")) != -1:
print(f"{filename} looks to be already patched :)")
return
if data.find(bytes.fromhex("EDFD425CF978")) == -1:
print(f"{filename} doesn't contain the original modulus.")
return
data = data.replace(
bytes.fromhex("EDFD425CF978"), bytes.fromhex("EDFD42CBF978")
)
patched_filename = f"{filename}.patched"
with open(patched_filename, "wb") as f:
f.write(data)
print(f"Generated modulus patch to {patched_filename}! To apply the patch, replace the original file with the patched file")
# message = bytes.fromhex(license["signature"])
# print(decrypt(message).hex())
# print(encrypt(decrypt(message)).hex())
license["signature"] = sign_hexlic(license["payload"])
serialized = json_stringify_alphabetical(license)
# write to ida.hexlic
filename = "ida.hexlic"
with open(filename, "w") as f:
f.write(serialized)
print(f"Saved new license to {filename}!")
generate_patched_dll("ida.dll")
generate_patched_dll("ida64.dll")
generate_patched_dll("libida.so")
generate_patched_dll("libida64.so")
generate_patched_dll("libida.dylib")
generate_patched_dll("libida64.dylib")

BIN
ida/idapro_90_x64linux.run Executable file

Binary file not shown.

25526
json.hpp Normal file

File diff suppressed because it is too large Load Diff

2
log.cpp Normal file
View File

@ -0,0 +1,2 @@
#include "log.h"
FILE* log_output = stdout; // 只定义一次

23
testMod/libusb/Makefile Normal file
View File

@ -0,0 +1,23 @@
obj-m += libusbMod.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
# 默认目标:只编译内核模块
all: libusbMod.ko
# 编译内核模块
libusbMod.ko:
make -C $(KDIR) M=$(PWD) modules
# 清理所有生成文件
clean:
make -C $(KDIR) M=$(PWD) clean
# 加载模块
load:
sudo insmod libusbMod.ko
# 卸载模块
unload:
sudo rmmod libusbMod

106
testMod/libusb/libusbMod.c Normal file
View File

@ -0,0 +1,106 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kprobes.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <linux/usb.h>
#include <linux/slab.h>
#include <linux/version.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Leo");
MODULE_DESCRIPTION("Monitor usb_submit_urb() data submission only");
static struct kprobe kp;
// 兼容 x86_64 和 arm64 获取第一个参数
static struct urb *get_urb_from_regs(struct pt_regs *regs)
{
#if defined(CONFIG_ARM64)
return (struct urb *)regs->regs[0];
#elif defined(CONFIG_X86_64)
return (struct urb *)regs->di;
#else
#error "Unsupported architecture"
#endif
}
static int handler_pre(struct kprobe *p, struct pt_regs *regs)
{
struct urb *urb_kern = get_urb_from_regs(regs);
if (!urb_kern)
return 0;
pr_info("[usbFilter] 提交URB进程: %s (pid: %d)\n", current->comm, current->pid);
if (urb_kern->dev) {
pr_info("[usbFilter] USB设备: busnum=%d, devnum=%d, VID=0x%04x, PID=0x%04x\n",
urb_kern->dev->bus->busnum,
urb_kern->dev->devnum,
urb_kern->dev->descriptor.idVendor,
urb_kern->dev->descriptor.idProduct);
}
pr_info("[usbFilter] URB: %p, pipe=0x%x, flags=0x%x\n",
urb_kern, urb_kern->pipe, urb_kern->transfer_flags);
pr_info("[usbFilter] pipe: 端点=%d, 方向=%s, 类型=%s\n",
usb_pipeendpoint(urb_kern->pipe),
usb_pipein(urb_kern->pipe) ? "IN" : "OUT",
usb_pipetype(urb_kern->pipe) == PIPE_CONTROL ? "CONTROL" :
usb_pipetype(urb_kern->pipe) == PIPE_ISOCHRONOUS ? "ISO" :
usb_pipetype(urb_kern->pipe) == PIPE_BULK ? "BULK" :
usb_pipetype(urb_kern->pipe) == PIPE_INTERRUPT ? "INTERRUPT" : "UNKNOWN");
// 打印控制传输的setup包内容
if (usb_pipetype(urb_kern->pipe) == PIPE_CONTROL && urb_kern->setup_packet) {
char setup_hex[3 * 8 + 1] = {0};
int i;
unsigned char *setup = (unsigned char *)urb_kern->setup_packet;
for (i = 0; i < 8; ++i) {
snprintf(setup_hex + i * 3, sizeof(setup_hex) - i * 3, "%02X ", setup[i]);
}
pr_info("[usbFilter] 控制传输setup包(8字节hex): %s\n", setup_hex);
}
// 打印控制传输的数据内容
if (urb_kern->transfer_buffer && urb_kern->transfer_buffer_length > 0) {
unsigned int to_copy = min(32U, (unsigned int)urb_kern->transfer_buffer_length);
unsigned char data[32] = {0};
memcpy(data, urb_kern->transfer_buffer, to_copy);
char hex[3 * 32 + 1] = {0};
int i;
for (i = 0; i < to_copy; ++i) {
snprintf(hex + i * 3, sizeof(hex) - i * 3, "%02X ", data[i]);
}
pr_info("[usbFilter] 提交数据(前32字节hex): %s\n", hex);
}
return 0;
}
static int __init usb_hook_init(void)
{
kp.symbol_name = "usb_submit_urb";
kp.pre_handler = handler_pre;
if (register_kprobe(&kp) < 0)
{
pr_err("[usbFilter] 无法注册 kprobe\n");
return -1;
}
pr_info("[usbFilter] 成功 hook usb_submit_urb()\n");
return 0;
}
static void __exit usb_hook_exit(void)
{
unregister_kprobe(&kp);
pr_info("[usbFilter] 已卸载 usb_submit_urb hook\n");
}
module_init(usb_hook_init);
module_exit(usb_hook_exit);

16
testMod/netlink/Makefile Normal file
View File

@ -0,0 +1,16 @@
obj-m += netlink_logger.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KDIR) M=$(PWD) clean
load:
sudo insmod netlink_logger.ko
unload:
sudo rmmod netlink_logger

View File

@ -0,0 +1,54 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/netlink.h>
#include <net/sock.h>
#include <linux/skbuff.h>
#define NETLINK_USER_CUSTOM 31
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Leo");
MODULE_DESCRIPTION("Netlink message logger for custom protocol");
static struct sock *nl_sk = NULL;
static void netlink_recv_msg(struct sk_buff *skb)
{
struct nlmsghdr *nlh;
char *payload;
if (!skb)
return;
nlh = nlmsg_hdr(skb);
payload = (char *)nlmsg_data(nlh);
pr_info("[netlink_logger] Received netlink msg: %s\n", payload); //此处打印信息
}
static int __init netlink_logger_init(void)
{
struct netlink_kernel_cfg cfg = {
.input = netlink_recv_msg,
};
nl_sk = netlink_kernel_create(&init_net, NETLINK_USER_CUSTOM, &cfg);
if (!nl_sk) {
pr_err("[netlink_logger] Failed to create netlink socket\n");
return -ENOMEM;
}
pr_info("[netlink_logger] Netlink logger module loaded (protocol: %d)\n", NETLINK_USER_CUSTOM);
return 0;
}
static void __exit netlink_logger_exit(void)
{
if (nl_sk)
netlink_kernel_release(nl_sk);
pr_info("[netlink_logger] Module unloaded\n");
}
module_init(netlink_logger_init);
module_exit(netlink_logger_exit);

View File

@ -1,7 +1,7 @@
#include "mainwindow.h"
#include <QApplication>
FILE* log_output=stdout;
int main(int argc, char *argv[])
{

View File

@ -1,11 +1,13 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "QDateTime"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
uf = new usbFilter();
}
MainWindow::~MainWindow()
@ -13,8 +15,29 @@ MainWindow::~MainWindow()
delete ui;
}
void MainWindow::onPrint(QString &msg){
void MainWindow::onPrint(const QString &msg){
QDateTime cur = QDateTime::currentDateTime();
QString tmp =cur.toString("yyyy-MM-dd HH:mm:ss");
ui->textBrowser->append(tmp+" --> "+msg);
}
void MainWindow::on_pushButton_3_clicked()
{
string tmp =uf->EnumDriversAndDevices();
this->onPrint(QString::fromStdString(tmp));
auto jsonList = json::parse(tmp);
ui->comboBox->clear();
for(auto i :jsonList){
if(i.contains("DevPath")){
ui->comboBox->addItem(QString::fromStdString(i["DevPath"].get<string>()));
}
}
}
void MainWindow::on_pushButton_4_clicked()
{
QString tmp = ui->comboBox->currentText();
uf->open(tmp.toStdString());
}

View File

@ -2,7 +2,12 @@
#define MAINWINDOW_H
#include <QMainWindow>
#include "../usbFilter.h"
#include "QDebug"
#include "QDateTime"
#include "../json.hpp"
using json = nlohmann::json;
QT_BEGIN_NAMESPACE
namespace Ui {
@ -18,10 +23,16 @@ public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
public slots:
void onPrint(QString &msg);
void onPrint(const QString &msg);
private slots:
void on_pushButton_3_clicked();
void on_pushButton_4_clicked();
private:
Ui::MainWindow *ui;
usbFilter *uf;
};
#endif // MAINWINDOW_H

View File

@ -15,21 +15,45 @@
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout">
<item row="2" column="0">
<widget class="QPushButton" name="pushButton_2">
<item row="4" column="1">
<widget class="QPushButton" name="pushButton_4">
<property name="text">
<string>Stop Srv</string>
<string>Open</string>
</property>
</widget>
</item>
<item row="1" column="0">
<item row="4" column="0">
<widget class="QComboBox" name="comboBox"/>
</item>
<item row="1" column="0" colspan="2">
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>Start Srv</string>
</property>
</widget>
</item>
<item row="4" column="0">
<item row="2" column="0" colspan="2">
<widget class="QPushButton" name="pushButton_2">
<property name="text">
<string>Stop Srv</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QPushButton" name="pushButton_3">
<property name="text">
<string>Enum Drivers And Devices</string>
</property>
</widget>
</item>
<item row="5" column="0" colspan="2">
<widget class="QPushButton" name="pushButton_5">
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
<item row="6" column="0" colspan="2">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Log</string>
@ -41,13 +65,6 @@
</layout>
</widget>
</item>
<item row="3" column="0">
<widget class="QPushButton" name="pushButton_3">
<property name="text">
<string>Enum Drivers And Devices</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">

View File

@ -11,15 +11,21 @@ CONFIG += c++17
SOURCES += \
../usbFilter.cpp \
main.cpp \
../log.cpp \
mainwindow.cpp
HEADERS += \
../json.hpp \
../usbFilter.h \
mainwindow.h
mainwindow.h\
../log.h
FORMS += \
mainwindow.ui
LIBS += -ludev
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin

View File

@ -1,6 +1,8 @@
#include "usbFilter.h"
using json = nlohmann::json;
usbFilter::usbFilter(/* args */)
{
}
@ -8,4 +10,459 @@ usbFilter::usbFilter(/* args */)
usbFilter::~usbFilter()
{
}
string usbFilter::EnumDriversAndDevices()
{
json list = json::array();
// 1. 获取USB设备libudev
{
udev* udev_ctx = udev_new();
if (udev_ctx) {
udev_enumerate* enumerate = udev_enumerate_new(udev_ctx);
udev_enumerate_add_match_subsystem(enumerate, "usb");
udev_enumerate_scan_devices(enumerate);
udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate);
udev_list_entry* dev_list_entry;
udev_list_entry_foreach(dev_list_entry, devices) {
const char* path = udev_list_entry_get_name(dev_list_entry);
udev_device* dev = udev_device_new_from_syspath(udev_ctx, path);
const char* vendor = udev_device_get_sysattr_value(dev, "idVendor");
const char* product = udev_device_get_sysattr_value(dev, "idProduct");
const char* devpath = udev_device_get_syspath(dev);
const char* devname = udev_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE");
if (!devname) devname = udev_device_get_property_value(dev, "ID_MODEL");
if (!devname) devname = udev_device_get_property_value(dev, "ID_VENDOR_FROM_DATABASE");
if (!devname) devname = devpath ? devpath : "";
if (vendor && product) {
json item;
item["VendorId"] = vendor;
item["ProductId"] = product;
item["DeviceName"] = devname ? devname : "";
item["DevPath"] = devpath ? devpath : "";
item["Subsystem"] = "USB";
list.push_back(item);
}
udev_device_unref(dev);
}
udev_enumerate_unref(enumerate);
udev_unref(udev_ctx);
}
}
// 2. 获取PCI/PCIe设备libudev
{
udev* udev_ctx = udev_new();
if (udev_ctx) {
udev_enumerate* enumerate = udev_enumerate_new(udev_ctx);
udev_enumerate_add_match_subsystem(enumerate, "pci");
udev_enumerate_scan_devices(enumerate);
udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate);
udev_list_entry* dev_list_entry;
udev_list_entry_foreach(dev_list_entry, devices) {
const char* path = udev_list_entry_get_name(dev_list_entry);
udev_device* dev = udev_device_new_from_syspath(udev_ctx, path);
const char* vendor = udev_device_get_sysattr_value(dev, "vendor");
const char* product = udev_device_get_sysattr_value(dev, "device");
// 尝试多种方式获取设备名
const char* devpath = udev_device_get_syspath(dev);
const char* devname = udev_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE");
if (!devname) devname = udev_device_get_property_value(dev, "ID_MODEL");
if (!devname) devname = udev_device_get_property_value(dev, "ID_VENDOR_FROM_DATABASE");
if (!devname) devname = devpath ? devpath : "";
if (vendor && product) {
// vendor和device通常是0x开头的16进制去掉0x
string vendor_id = vendor;
string product_id = product;
if (vendor_id.find("0x") == 0) vendor_id = vendor_id.substr(2);
if (product_id.find("0x") == 0) product_id = product_id.substr(2);
json item;
item["VendorId"] = vendor_id;
item["ProductId"] = product_id;
item["DeviceName"] = devname ? devname : "";
item["DevPath"] = devpath ? devpath : "";
item["Subsystem"] = "PCI";
list.push_back(item);
}
udev_device_unref(dev);
}
udev_enumerate_unref(enumerate);
udev_unref(udev_ctx);
}
}
return list.dump();
}
bool usbFilter::open(const string &devPath)
{
// 检查设备路径是否为空
if (devPath.empty()) {
return false;
}
// 检查设备路径是否存在
string devPathTrans = sysfsToDevPath(devPath);
if (devPathTrans.empty()) {
LOG_ERROR("Device path does not exist" );
return false;
}else{
LOG_DEBUG("Opening device: %s", devPathTrans.c_str());
}
int pid = getDeviceUserPID(devPathTrans);
if (pid < 0) {
LOG_ERROR("No process is using the device: %s", devPathTrans.c_str());
return false;
} else {
LOG_DEBUG("Device %s is being used by process with PID: %d", devPathTrans.c_str(), pid);
}
//获取当前目录
string currendDir = CURRENTDIR;
// string scriptPath = currentDir + "/scripts";
string scriptPath = currendDir + "/testScripts";
LOG_INFO("Ready to run frida scripts. The scripts are located in %s.",scriptPath.c_str());
// 构造命令行
// string cmd = "frida -p " + to_string(pid) + " -l " + scriptPath + "/frida_hook_libusb_basic_Version2.js &";
string cmd = "frida -p " + to_string(pid) + " -l " + scriptPath + "/frida_hook_libusb_basic_Version2.js &";
LOG_DEBUG("Running command: %s", cmd.c_str());
// 执行命令
int result = system(cmd.c_str());
if (result != 0) {
LOG_ERROR("Failed to run command: %s", cmd.c_str());
return false;
}
LOG_INFO("Command executed successfully.");
return true;
}
string usbFilter::sysfsToDevPath(const string& sysfs_path) {
struct stat st;
// Check if the sysfs path exists
if (stat(sysfs_path.c_str(), &st) != 0 || !S_ISDIR(st.st_mode)) {
return ""; // Path doesn't exist or is not a directory
}
// Check if this is a USB device path
if (sysfs_path.find("/usb") != string::npos) {
return convertUsbSysfsPath(sysfs_path);
}
// Check if this is a PCI/PCIe device path
if (sysfs_path.find("/pci") != string::npos) {
return convertPciSysfsPath(sysfs_path);
}
// Unknown device type
return "";
}
// Helper function to convert USB sysfs path
string usbFilter::convertUsbSysfsPath(const string& sysfs_path) {
// Construct paths to busnum and devnum files
string busnum_path = sysfs_path + "/busnum";
string devnum_path = sysfs_path + "/devnum";
// Read bus number
ifstream bus_file(busnum_path);
if (!bus_file.is_open()) {
return "";
}
int busnum = 0;
bus_file >> busnum;
bus_file.close();
if (busnum <= 0) {
return "";
}
// Read device number
ifstream dev_file(devnum_path);
if (!dev_file.is_open()) {
return "";
}
int devnum = 0;
dev_file >> devnum;
dev_file.close();
if (devnum <= 0) {
return "";
}
// Construct the /dev path with proper zero-padding
ostringstream dev_path;
dev_path << "/dev/bus/usb/"
<< setfill('0') << setw(3) << busnum
<< "/"
<< setfill('0') << setw(3) << devnum;
string result = dev_path.str();
// Check if the /dev node actually exists
if (access(result.c_str(), F_OK) != 0) {
return ""; // Device node doesn't exist
}
return result;
}
// Helper function to convert PCI/PCIe sysfs path
string usbFilter::convertPciSysfsPath(const string& sysfs_path) {
// First check if there are any special device nodes (e.g., for graphics cards, network cards)
// 1. Check for graphics card
string device_path = sysfs_path + "/drm";
DIR* dir = opendir(device_path.c_str());
if (dir) {
// Found DRM device (likely a graphics card)
closedir(dir);
// Look for card* entries in /dev/dri/
dir = opendir("/dev/dri");
if (dir) {
struct dirent *entry;
regex card_regex("card[0-9]+");
while ((entry = readdir(dir)) != NULL) {
string name = entry->d_name;
if (regex_match(name, card_regex)) {
// For each card, check if it corresponds to our PCI device
string cardpath = "/dev/dri/" + name;
// Need to check if this card corresponds to our PCI device
// One way is to check the device node major/minor numbers against sys/dev entries
struct stat card_stat;
if (stat(cardpath.c_str(), &card_stat) == 0) {
ostringstream dev_path;
dev_path << sysfs_path << "/drm/" << name << "/dev";
ifstream dev_file(dev_path.str());
if (dev_file.is_open()) {
string dev_numbers;
getline(dev_file, dev_numbers);
dev_file.close();
// Format is major:minor
size_t colon_pos = dev_numbers.find(':');
if (colon_pos != string::npos) {
int major = stoi(dev_numbers.substr(0, colon_pos));
int minor = stoi(dev_numbers.substr(colon_pos + 1));
if (major == major(card_stat.st_rdev) &&
minor == minor(card_stat.st_rdev)) {
closedir(dir);
return cardpath;
}
}
}
}
}
}
closedir(dir);
}
}
// 2. Check for network interfaces
device_path = sysfs_path + "/net";
dir = opendir(device_path.c_str());
if (dir) {
// Found network interface
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
if (entry->d_type == DT_DIR &&
strcmp(entry->d_name, ".") != 0 &&
strcmp(entry->d_name, "..") != 0) {
closedir(dir);
// Network interfaces don't have /dev entries, but we can return the interface name
return "/sys/class/net/" + string(entry->d_name);
}
}
closedir(dir);
}
// 3. Check for NVMe devices
if (sysfs_path.find("nvme") != string::npos) {
// Extract the NVMe controller number (e.g., nvme0)
regex nvme_regex("nvme([0-9]+)");
smatch match;
if (regex_search(sysfs_path, match, nvme_regex) && match.size() > 1) {
string nvme_num = match[1].str();
string nvme_dev = "/dev/nvme" + nvme_num;
if (access(nvme_dev.c_str(), F_OK) == 0) {
return nvme_dev;
}
}
}
// 4. Check for SCSI/SATA devices that might be connected via PCIe
string block_path = sysfs_path + "/block";
dir = opendir(block_path.c_str());
if (dir) {
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
if (entry->d_type == DT_DIR &&
strcmp(entry->d_name, ".") != 0 &&
strcmp(entry->d_name, "..") != 0) {
string dev_name = entry->d_name;
string block_dev = "/dev/" + dev_name;
if (access(block_dev.c_str(), F_OK) == 0) {
closedir(dir);
return block_dev;
}
}
}
closedir(dir);
}
// 5. Generic way to find PCI device - try to use the device's resource file
ifstream resource_file(sysfs_path + "/resource");
if (resource_file.is_open()) {
// This is more complex and would require parsing the resource file
// and checking if it maps to any character device
resource_file.close();
}
// 6. Check for udev links in /dev/char/ directory
string dev_content;
ifstream dev_file(sysfs_path + "/dev");
if (dev_file.is_open()) {
getline(dev_file, dev_content); // Format is "major:minor"
dev_file.close();
if (!dev_content.empty()) {
// Check in /dev/char/ directory
string char_dev_path = "/dev/char/" + dev_content;
if (access(char_dev_path.c_str(), F_OK) == 0) {
// This is a character device
return char_dev_path;
}
// Check in /dev/block/ directory
string block_dev_path = "/dev/block/" + dev_content;
if (access(block_dev_path.c_str(), F_OK) == 0) {
// This is a block device
return block_dev_path;
}
}
}
// If we reach here, couldn't find a corresponding /dev node
return "";
}
// 修复getDeviceUserPID函数中的错误和警告
int usbFilter::getDeviceUserPID(const string& devpath) {
// First check if the device path exists
struct stat st;
if (stat(devpath.c_str(), &st) != 0) {
return -1; // Device path doesn't exist
}
// Use lsof command to find processes using this device
string cmd = "lsof -t " + devpath + " 2>/dev/null";
array<char, 128> buffer;
string result;
unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"), pclose);
if (!pipe) {
return -1; // Failed to run command
}
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
result += buffer.data();
}
// Trim whitespace and newlines
result.erase(result.find_last_not_of(" \n\r\t") + 1);
// If result is empty, no process is using the device
if (result.empty()) {
return -1;
}
// Parse the PID from the result (may have multiple lines if multiple processes)
regex pid_regex("^(\\d+)$", regex::multiline);
smatch match;
if (regex_search(result, match, pid_regex) && match.size() > 1) {
try {
return stoi(match[1].str());
} catch (const invalid_argument& e) {
return -1;
} catch (const out_of_range& e) {
return -1;
}
}
// Alternative approach using /proc filesystem if lsof fails or isn't available
if (access("/proc", F_OK) == 0) {
// Iterate through all processes
string proc_dir = "/proc";
array<char, 256> cmd;
// 修复这行错误
FILE* fp = popen("ls -d /proc/[0-9]*", "r");
if (fp) {
while (fgets(cmd.data(), cmd.size(), fp) != nullptr) {
string pid_dir = cmd.data();
pid_dir.erase(pid_dir.find_last_not_of("\n\r") + 1);
// Check process fd directory
string fd_dir = pid_dir + "/fd";
FILE* fd_fp = popen(("ls -l " + fd_dir + " 2>/dev/null").c_str(), "r");
if (fd_fp) {
array<char, 512> fd_info;
bool found = false;
while (fgets(fd_info.data(), fd_info.size(), fd_fp) != nullptr) {
string line = fd_info.data();
// Check if this fd points to our device
if (line.find(devpath) != string::npos) {
found = true;
break;
}
}
pclose(fd_fp);
if (found) {
pclose(fp);
// Extract PID from path /proc/[0-9]*
regex proc_regex("/proc/(\\d+)");
if (regex_search(pid_dir, match, proc_regex) && match.size() > 1) {
try {
return stoi(match[1].str());
} catch (...) {
return -1;
}
}
}
}
}
pclose(fp);
}
}
return -1; // No process found using the device
}

View File

@ -1,4 +1,25 @@
#include "log.h"
#include "json.hpp"
#include <string>
#include <cstdio>
#include <memory>
#include <stdexcept>
#include <array>
#include <sstream>
#include <regex>
#include <libudev.h>
#include <fstream>
#include <iomanip>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <cstring>
#include <fcntl.h>
#define CURRENTDIR "/home/leo/devCode/outer/USBFilter_30/usbFilter"
using namespace std;
using json = nlohmann::json;
class usbFilter
{
@ -7,8 +28,16 @@ private:
public:
usbFilter(/* args */);
~usbFilter();
void StarSrv();
void StartSrv();
void StopSrv();
string EnumDriversAndDevices();
bool open(const string &devPath);
private:
string sysfsToDevPath(const string& sysfs_path);
string convertUsbSysfsPath(const string& sysfs_path);
string convertPciSysfsPath(const string& sysfs_path);
int getDeviceUserPID(const string& devpath);
};