You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用C++获取Linux进程列表及状态的最优方案问询

Linux Process Enumeration for Antivirus: Avoiding Short-Lived Process Leaks

Hey there! Let's tackle this process enumeration problem for your Linux antivirus project—super cool that you've already nailed the math models and heuristic methods, by the way. Recursively scanning /proc is a common first approach, but as you've noticed, it misses short-lived processes that start and exit between directory scans. Here are two modern, clean C++ solutions to fix this:

1. Use libproc2 for Fast, Reliable One-Shot Scans

libproc2 is the updated, maintained successor to the old libproc library, built for modern Linux kernels. It's efficient and avoids many pitfalls of manual /proc parsing.

Step-by-Step Implementation

First, install the library (package names vary by distro: libproc2-dev on Debian/Ubuntu, procps-ng-devel on RHEL/CentOS).

Here's a concise C++ example that enumerates all processes, grabs their state, and writes to a file:

#include <iostream>
#include <fstream>
#include <cstring>
#include <proc/readproc.h>

int main() {
    // Open output file with RAII-style management
    std::ofstream out_file("process_snapshot.txt");
    if (!out_file.is_open()) {
        std::cerr << "Failed to open output file\n";
        return 1;
    }

    // Configure proc reader to fetch core process details + state
    proc_t proc_info{};
    PROCTAB* proc_tab = openproc(PROC_FILLSTAT | PROC_FILLSTATUS);

    if (!proc_tab) {
        std::cerr << "Failed to initialize proc table reader\n";
        return 1;
    }

    // Iterate through all process entries
    while (readproc(proc_tab, &proc_info) != nullptr) {
        out_file << "PID: " << proc_info.tgid 
                 << " | Name: " << proc_info.cmd 
                 << " | State: " << proc_info.state << "\n";
    }

    // Cleanup resources
    closeproc(proc_tab);
    out_file.close();

    return 0;
}

Compile with:

g++ -o proc_snapshot proc_snapshot.cpp -lps

This method is faster than manual /proc traversal and handles edge cases like zombie processes or kernel threads more reliably.

To catch short-lived processes that might escape a one-shot scan, use the Linux kernel's netlink PROC_EVENT interface. This lets your program receive real-time notifications when processes are created, exited, or modified.

This code sets up a netlink socket to listen for process events and appends them to your output file:

#include <iostream>
#include <fstream>
#include <cstring>
#include <unistd.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <linux/connector.h>
#include <linux/cn_proc.h>

#define BUFFER_SIZE 1024

void handle_proc_event(const struct proc_event* event, std::ofstream& out_file) {
    switch (event->what) {
        case PROC_EVENT_FORK:
            out_file << "[NEW PROCESS] Child PID: " << event->event_data.fork.child_tgid 
                     << " | Parent PID: " << event->event_data.fork.parent_tgid << "\n";
            break;
        case PROC_EVENT_EXIT:
            out_file << "[PROCESS EXIT] PID: " << event->event_data.exit.process_tgid 
                     << " | Exit Code: " << (event->event_data.exit.exit_code >> 8) << "\n";
            break;
        default:
            break;
    }
}

int main() {
    std::ofstream out_file("process_events.txt", std::ios::app);
    if (!out_file.is_open()) {
        std::cerr << "Failed to open events log file\n";
        return 1;
    }

    int sock_fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
    if (sock_fd < 0) {
        std::cerr << "Failed to create netlink socket\n";
        return 1;
    }

    struct sockaddr_nl sa_nl{};
    sa_nl.nl_family = AF_NETLINK;
    sa_nl.nl_groups = CN_IDX_PROC;
    sa_nl.nl_pid = getpid();

    if (bind(sock_fd, (struct sockaddr*)&sa_nl, sizeof(sa_nl)) < 0) {
        std::cerr << "Failed to bind netlink socket\n";
        close(sock_fd);
        return 1;
    }

    // Send subscription request for process events
    struct cn_msg msg{};
    struct proc_event_mc mc{};
    msg.id.idx = CN_IDX_PROC;
    msg.id.val = CN_VAL_PROC;
    msg.len = sizeof(mc);
    mc.cmd = PROC_MC_LISTEN;

    if (send(sock_fd, &msg, sizeof(msg) + sizeof(mc), 0) < 0) {
        std::cerr << "Failed to subscribe to process events\n";
        close(sock_fd);
        return 1;
    }

    // Listen for incoming events
    char buffer[BUFFER_SIZE];
    while (true) {
        ssize_t recv_len = recv(sock_fd, buffer, BUFFER_SIZE, 0);
        if (recv_len < 0) {
            std::cerr << "Failed to receive netlink message\n";
            break;
        }

        struct nlmsghdr* nl_hdr = (struct nlmsghdr*)buffer;
        while (NLMSG_OK(nl_hdr, recv_len)) {
            struct cn_msg* cn_msg = (struct cn_msg*)NLMSG_DATA(nl_hdr);
            struct proc_event* event = (struct proc_event*)cn_msg->data;
            handle_proc_event(event, out_file);

            nl_hdr = NLMSG_NEXT(nl_hdr, recv_len);
        }
    }

    close(sock_fd);
    out_file.close();
    return 0;
}

Compile with:

g++ -o proc_monitor proc_monitor.cpp

Optimal Workflow for Your Antivirus

For complete host fingerprinting:

  1. Run the libproc2 snapshot first to capture all currently running processes.
  2. Start the netlink monitor immediately after to track any new/exited processes, appending them to your file. This combination ensures you won't miss short-lived processes that start after your initial scan.

Both solutions use modern Linux APIs and clean C++ practices, avoiding outdated code patterns.

内容的提问来源于stack exchange,提问作者Mihai

火山引擎 最新活动