Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
391d7f25af | ||
|
|
6cfb84a443 | ||
|
|
a5dc2d9578 | ||
|
|
f095b5836b | ||
|
|
a669340c91 |
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,2 +1,3 @@
|
||||
upper/build
|
||||
upper/upper.pro.*
|
||||
upper/upper.pro.*
|
||||
.vscode
|
||||
12
README.md
Normal file
12
README.md
Normal 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
223
ida/crack_ida90_beta.py
Executable 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
BIN
ida/idapro_90_x64linux.run
Executable file
Binary file not shown.
23
testMod/libusb/Makefile
Normal file
23
testMod/libusb/Makefile
Normal 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
106
testMod/libusb/libusbMod.c
Normal 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
16
testMod/netlink/Makefile
Normal 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
|
||||
54
testMod/netlink/netlink_logger.c
Normal file
54
testMod/netlink/netlink_logger.c
Normal 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);
|
||||
@ -1,7 +1,7 @@
|
||||
#include "mainwindow.h"
|
||||
#include <QApplication>
|
||||
|
||||
FILE* log_output=stdout;
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
@ -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());
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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">
|
||||
|
||||
@ -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
|
||||
|
||||
459
usbFilter.cpp
459
usbFilter.cpp
@ -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
|
||||
}
|
||||
31
usbFilter.h
31
usbFilter.h
@ -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);
|
||||
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user