#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 buffer; string result; unique_ptr 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 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 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 }