19.12 Boost Asio 获取远程进程

发布时间 2023-11-09 14:02:05作者: lyshark

远程进程遍历功能实现原理与远程目录传输完全一致,唯一的区别在于远程进程枚举中使用EnumProcess函数枚举当前系统下所有活动进程,枚举结束后函数返回一个PROCESSENTRY32类型的容器,其中的每一个成员都是一个进程信息,只需要对该容器进行动态遍历即可得到所有的远程主机列表。

服务端代码如下所示,首先代码中通过read_some第一次接收到对端进程数量,接着通过第一个循环,将接收到的字符串数据强制转换为PROCESSENTRY32类型的结构,并将结构存入vector容器内,第二个循环则用于枚举输出我们整理好的容器列表。

#include <iostream>
#include <string>
#include <boost/asio.hpp>
#include <vector>
#include <Windows.h>
#include <tlhelp32.h>
#include <boost/lexical_cast.hpp>

using namespace boost;
using namespace boost::asio;
using namespace std;

int main(int argc, char* argv[])
{
  io_service io_service;
  ip::tcp::acceptor acceptor(io_service, ip::tcp::endpoint(ip::tcp::v4(), 6666));
  ip::tcp::socket socket(io_service);
  acceptor.accept(socket);
  boost::system::error_code error_code;

  // 接收客户端的进程数量
  char process_count[32] = { 0 };
  socket.read_some(boost::asio::buffer(process_count), error_code);
  std::cout << "接收到的进程数量: " << process_count << std::endl;

  std::vector<PROCESSENTRY32> recv_process_list;

  // 循环接收客户端进程结构体
  for (int x = 0; x < lexical_cast<int>(process_count); x++)
  {
    // 接收字节序,并存入本地列表中
    char recv_buffer[sizeof(PROCESSENTRY32)] = { 0 };
    socket.read_some(boost::asio::buffer(recv_buffer, sizeof(PROCESSENTRY32)), error_code);

    // 强转指针
    PROCESSENTRY32 *ptr = (PROCESSENTRY32 *)recv_buffer;
    // 将每一个 PROCESSENTRY32 结构存入vector容器
    recv_process_list.push_back(*ptr);
  }

  // 循环输出 PROCESSENTRY32 测试是否可读取
  for (int x = 0; x < recv_process_list.size(); x++)
  {
    std::cout << "进程PID: " << recv_process_list[x].th32ProcessID 
      << "父进程PID: " << recv_process_list[x].th32ParentProcessID 
      << "进程名称: " << recv_process_list[x].szExeFile << std::endl;
  }

  std::system("pause");
  return 0;
}

客户端代码如下所示,其实现原理与文件传输功能完全一致,此处只是更换了一个EnumProcess函数,其传输方式此处就不在赘述。

#include <iostream>
#include <string>
#include <boost/asio.hpp>
#include <vector>
#include <Windows.h>
#include <tlhelp32.h>
#include <boost/lexical_cast.hpp>

using namespace boost;
using namespace boost::asio;
using namespace std;

// 输出系统进程信息,并出入vector容器中返回给调用者
std::vector<PROCESSENTRY32> EnumProcess()
{
  std::vector<PROCESSENTRY32> process_info;

  PROCESSENTRY32 pe32 = { 0 };
  pe32.dwSize = sizeof(PROCESSENTRY32);

  // 获取全部进程快照
  HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  if (INVALID_HANDLE_VALUE != hProcessSnap)
  {
    // 获取快照中第一条信息
    BOOL bRet = Process32First(hProcessSnap, &pe32);
    while (bRet)
    {
      // 将进程快照到的列表加入到容器中
      process_info.push_back(pe32);

      // 获取快照中下一条信息
      bRet = Process32Next(hProcessSnap, &pe32);
    }
    CloseHandle(hProcessSnap);
  }
  return process_info;
}

int main(int argc, char * argv[])
{
  io_service io_service;
  ip::tcp::socket socket(io_service);
  ip::tcp::endpoint ep(ip::address_v4::from_string("127.0.0.1"), 6666);

  boost::system::error_code error_code;
  socket.connect(ep, error_code);

  // send_process_list 存储需要发送的结构体
  std::vector<PROCESSENTRY32> send_process_list = EnumProcess();

  // 首先将当前进程数量发送给服务端
  std::string process_count = lexical_cast<std::string>(send_process_list.size());
  std::cout << "当前进程数量: " << process_count << std::endl;
  socket.write_some(boost::asio::buffer(process_count));

  // 循环发送每一个进程结构
  for (int x = 0; x < send_process_list.size(); x++)
  {
    // 定义发送字节序缓冲区
    char send_buffer[sizeof(PROCESSENTRY32)] = { 0 };

    // 拷贝字节序并发送字节序
    memcpy(send_buffer, &send_process_list[x], sizeof(PROCESSENTRY32));
    socket.write_some(boost::asio::buffer(send_buffer, sizeof(PROCESSENTRY32)));
  }

  std::system("pause");
  return 0;

}

读者可自行编译上述代码片段,并依次运行服务端与客户端,此时读者可清晰的看到目标主机中所运行的完整进程列表。