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.
usbFilter_Cpp/usbFilter.cpp

468 lines
16 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "usbFilter.h"
using json = nlohmann::json;
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
}