注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

yeye55的博客

编程就象品一杯清茶,清淡却又深厚。

 
 
 

日志

 
 
关于我

宅男一只,喜欢编程。没事的时候就喜欢抱着电脑看看电影、看看动漫、听听音乐、打打网游、逛逛论坛。清静的时候喜欢专研编程技术,但是发现自己至今仍然只是一只三脚猫。

网易考拉推荐

Delphi下获取进程连接端口  

2011-11-03 13:54:20|  分类: 默认分类 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

  本文最早于2008年2月25日在编程论坛(programbbs.com)上发表,页面地址:http://programbbs.com/bbs/view12-9312-1.htm 。

  PS:本文末尾附可执行文件和项目源程序文件的下载。

  Windows操作系统提供了一个iphlpapi.dll文件,全称IP帮助API,通过这个函数库可以获取和修改电脑的网络配置、获取网络状态信息、管理网络活动,利用这个文件中两个未公开的函数AllocateAndGetTcpExTableFromStack和AllocateAndGetUdpExTableFromStack可以获得一个TCP连接表和一个UDP连接表,这两个连接表中包含了正在使用当前连接的进程ID号。

  有的资料称只有Windows XP及以上操作系统才提供了这些扩展IP帮助函数,但是在我的系统(Windows 2000+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';

  在调用函数前还要自己定义几个结构,及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;

  最后做出来的程序如图所示:

图1

  这个程序可以获取当前系统中的网络活动,可以看到有哪些TCP和UDP连接,是哪些进程在进行这些活动,还可以看到进程ID、可执行文件名、文件路径、文件说明、公司名称。单击“保存”按纽可以将当前连接表的信息保存到文件中,完整的源代码可以参考项目文件。

  项目文件下载(点这里

  可执行文件下载(点这里

  评论这张
 
阅读(718)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017