Delphi下获取进程连接端口
[]
Windows操作系统提供了一个iphlpapi.dll文件,全称IP帮助API,通过这个函数库可以获取和修改电脑的网络配置、获取网络状态信息、管理网络活动,利用这个文件中两个未公开的函数AllocateAndGetTcpExTableFromStackAllocateAndGetUdpExTableFromStack可以获得一个TCP连接表和一个UDP连接表,这两个连接表中包含了正在使用当前连接的进程ID号。
  有的资料称只有Windows XP及以上操作系统才提供了这些扩展IP帮助函数,但是在我的系统(Windows2000+SP4)中程序可以正常运行,我系统中的iphlpapi.dll文件版本号为5.0.2195.7097,程序使用Delphi7.0编写,对于不同的系统这个程序不知是否可以正常运行。
  网上查到的很多例子都是VC++的,在VC++中调用这两个函数需要动态的从DLL文件中载入,因为对应的iphlpapi.lib文件中没有对这两个函数进行声明,但是在Delphi下没必要这么复杂,Delphi下调用DLL文件中的函数不需要对应的LIB文件,只要对函数进行声明再进行调用就可以了。这两个函数的声明如下:
//获取TCP连接表的IP帮助函数声明
function AllocateAndGetTcpExTableFromStack(
    var pTcpTable;
    bOrder : Bool;
    heap : THandle;
    zero : DWORD;
    flags : DWORD
    ): DWORD; stdcall; external 'iphlpapi.dll'
    name 'AllocateAndGetTcpExTableFromStack';
//获取UDP连接表的IP帮助函数声明
function AllocateAndGetUdpExTableFromStack(
    var pUdpTable;
    bOrder : Bool;
    heap : THandle;
    zero : DWORD;
    flags : DWORD
    ): DWORD; stdcall; external 'iphlpapi.dll'
    name 'AllocateAndGetUdpExTableFromStack';
  在调用函数前还要自己定义几个结构,及enum函数TCP连接表和UDP连接表,代码如下:
//相关数据结构的定义
const
    ANY_SIZE=256;
type
    MIB_TCPEXROW = record
        dwState : DWORD;      //连接状态
        dwLocalAddr : DWORD;  //本地地址
        dwLocalPort : DWORD;  //本地端口
        dwRemoteAddr : DWORD; //远程地址
        dwRemotePort : DWORD; //远程端口
        dwProcessId : DWORD;  //进程ID
    end;
    MIB_TCPEXTABLE = record
        dwNumEntries : DWORD; //端口数量
        table : array [0..ANY_SIZE-1] of MIB_TCPEXROW;
    end;
    PMIB_TCPEXTABLE = ^MIB_TCPEXTABLE;
    MIB_UDPEXROW = record
        dwLocalAddr : DWORD; //本地地址
        dwLocalPort : DWORD; //本地端口
        dwProcessId : DWORD; //进程ID
    end;
    MIB_UDPEXTABLE = record
        dwNumEntries : DWORD; //端口数量
        table : array [0..ANY_SIZE-1] of MIB_UDPEXROW;
    end;
    PMIB_UDPEXTABLE = ^MIB_UDPEXTABLE;
  这两个函数的调用代码如下:
AllocateAndGetTcpExTableFromStack(pTcpTab,true,GetProcessHeap(),2,2); //获取TCP连接表
AllocateAndGetUdpExTableFromStack(pUdpTab,true,GetProcessHeap(),2,2); //获取UDP连接表
  仅有进程ID号是不够的,还要获得进程对应可执行文件名,这个可以使用CreateToolhelp32Snapshot函数获得系统进程快照,利用Process32First函数和Process32Next函数从中查出对应的进程,在Delphi中调用这几个函数要引用TlHelp32.pas单元,相关代码如下:
//根据进程ID查可执行文件名
function IdToExeFile(hSnapshot : THandle; dwProcessId : DWORD): String;
var
    lppe : TProcessEntry32;
    b : BOOL;
begin
    lppe.dwSize:=SizeOf(lppe);
    //取第1个进程数据
    b:=Process32First(hSnapshot,lppe);
    result:='';
    while b do
    begin
        if lppe.th32ProcessID=dwProcessId then
        begin
            result:=lppe.szExeFile;
            break;
        end;
        //取下一个进程
        b:=Process32Next(hSnapshot,lppe);
    end;
end;
  利用上面这个方法只能获得单一的可执行文件名,而无法获得可执行文件的路径,最好是获得可执行文件完整的路径,以判断可执行文件到底位于哪个文件夹,利用EnumProcessModules函数返回一个进程中的句柄,再调用GetModuleFileNameEx函数就可以获得可执行文件完整的路径,在Delphi下调用这两个函数要引用PsAPI.pas单元,相关代码如下:
//根据进程ID查可执行文件路径
function IdToExeDir(dwProcessId : DWORD): String;
var
    cbNeeded : DWORD;
    hProcess : THandle;
    hModules : HMODULE;
    lpFilename : array [0..1024-1] of Char;
begin
    result:='';
    hProcess:=OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ,false,dwProcessId);
    if hProcess=0 then exit;
    EnumProcessModules(hProcess,@hModules,sizeof(hModule),cbNeeded);
    GetModuleFileNameEx(hProcess,hModules,lpFilename,1024);
    result:=lpFilename;
    CloseHandle(hProcess);
end;
  获得了可执行文件完整的路径最好还要获得文件版本的相关信息,这样才能更好的判断文件是系统文件、应用程序文件、还是木马。获得文件版本信息可以调用GetFileVersionInfo函数和VerQueryValue函数,以下代码只提取文件版本信息中的文件说明和公司名称,用以对可执行文件的判断,相关代码如下:
//根据文件名查文件信息
function ExeDirToFileInfo(Filename : String): String;
var
    NameLen,BufLen,ValLen : DWORD;
    pBuf,pVal : Pointer;
    LangCode : String;
begin
    result:='';
    NameLen:=Length(Filename);
    if NameLen=0 then exit;
    //获取版本信息
    BufLen:=GetFileVersionInfoSize(PChar(Filename),NameLen);
    pBuf:=AllocMem(BufLen);
    if pBuf=nil then exit;
    if GetFileVersionInfo(PChar(Filename),0,BufLen,pBuf)=false then
    begin
        FreeMem(pBuf);
        exit;
    end;
    //获取代码页信息
    if VerQueryValue(pBuf,'\VarFileInfo\Translation',pVal,ValLen)=false then
    begin
        FreeMem(pBuf);
        exit;
    end;
    LangCode:=Format('%.2x%.2x%.2x%.2x',[
        BYTE(PChar(pVal)[1]),
        BYTE(PChar(pVal)[0]),
        BYTE(PChar(pVal)[3]),
        BYTE(PChar(pVal)[2])]);
    //获取文件说明
    if VerQueryValue(pBuf,PChar('\StringFileInfo\'+LangCode+'\FileDescription'),pVal,ValLen)=false then
    begin
        FreeMem(pBuf);
        exit;
    end;
    result:=PChar(pVal);
    //获取公司名称
    if VerQueryValue(pBuf,PChar('\StringFileInfo\'+LangCode+'\CompanyName'),pVal,ValLen)=false then
    begin
        FreeMem(pBuf);
        exit;
    end;
    result:=result+' / '+PChar(pVal);
    FreeMem(pBuf);
end;
  最后做出来的程序如图所示:
  这个程序可以获取当前系统中的网络活动,可以看到有哪些TCPUDP连接,是哪些进程在进行这些活动,还可以看到进程ID、可执行文件名、文件路径、文件说明、公司名称。单击保存按纽可以将当前连接表的信息保存到文件中,完整的源代码可以参考项目文件。
项目下载:点击下载

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。