Search code examples
delphisocketsipc

Kill a Delphi app based on which socket it is using


Lets assume you have a app that opens a socket port for communication purposes. How can I get the path of this app only by knowing its port?

I want to do what netstat -b does. It lists all socket ports opened and the app that opened the socket.

I am using delphi 2010. By knowing which app opened which port I am able to kill the app.

Note that I need a delphi code, not an Dos command or an explanation of how to use netstat.


Solution

  • Rafael, you can use the GetExtendedTcpTable function, this function retrieves a table that contains a list of TCP connections availables.

    first you must inspect the records returned by this function, and check the dwLocalPortor dwRemotePort (depending of what port your need to check), then you can get the pid of the application checking the dwOwningPid field and resolve the exe name using a windows api function like GetModuleFileNameEx

    Check this sample application which show all tcp connections like netstat. you can modify this sample to fit with your requirements.

    uses
          PsAPI,
          WinSock,
          Windows,
          SysUtils;
    
        const
           ANY_SIZE = 1;
           iphlpapi = 'iphlpapi.dll';
           TCP_TABLE_OWNER_PID_ALL = 5;
    
           MIB_TCP_STATE:
           array[1..12] of string = ('CLOSED', 'LISTEN', 'SYN-SENT ','SYN-RECEIVED', 'ESTABLISHED', 'FIN-WAIT-1',
                                     'FIN-WAIT-2', 'CLOSE-WAIT', 'CLOSING','LAST-ACK', 'TIME-WAIT', 'delete TCB');
    
        type
           TCP_TABLE_CLASS = Integer;
    
          PMibTcpRowOwnerPid = ^TMibTcpRowOwnerPid;
          TMibTcpRowOwnerPid  = packed record
            dwState     : DWORD;
            dwLocalAddr : DWORD;
            dwLocalPort : DWORD;
            dwRemoteAddr: DWORD;
            dwRemotePort: DWORD;
            dwOwningPid : DWORD;
            end;
    
    
          PMIB_TCPTABLE_OWNER_PID  = ^MIB_TCPTABLE_OWNER_PID;
          MIB_TCPTABLE_OWNER_PID = packed record
           dwNumEntries: DWord;
           table: array [0..ANY_SIZE - 1] OF TMibTcpRowOwnerPid;
          end;
    
        var
           GetExtendedTcpTable:function  (pTcpTable: Pointer; dwSize: PDWORD; bOrder: BOOL; lAf: ULONG; TableClass: TCP_TABLE_CLASS; Reserved: ULONG): DWord; stdcall;
    
    
    
    
        function GetPathPID(PID: DWORD): string;
        var
          Handle: THandle;
        begin
          Result := '';
          Handle := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, PID);
          if Handle <> 0 then
            try
              SetLength(Result, MAX_PATH);
                if GetModuleFileNameEx(Handle, 0, PChar(Result), MAX_PATH) > 0 then
                  SetLength(Result, StrLen(PChar(Result)))
                else
                  Result := '';
            finally
              CloseHandle(Handle);
            end;
        end;
    
    
        procedure ShowCurrentTCPConnections;
        var
           Error        : DWORD;
           TableSize    : DWORD;
           i            : integer;
           IpAddress    : in_addr;
           RemoteIp     : string;
           LocalIp      : string;
           FExtendedTcpTable : PMIB_TCPTABLE_OWNER_PID;
        begin
          TableSize := 0;
          Error := GetExtendedTcpTable(nil, @TableSize, False, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0);
          if Error <> ERROR_INSUFFICIENT_BUFFER then
             Exit;
    
          GetMem(FExtendedTcpTable, TableSize);
          try
           if GetExtendedTcpTable(FExtendedTcpTable, @TableSize, TRUE, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0) = NO_ERROR then
              for i := 0 to FExtendedTcpTable.dwNumEntries - 1 do
              if {(FExtendedTcpTable.Table[i].dwOwningPid=Pid) and} (FExtendedTcpTable.Table[i].dwRemoteAddr<>0) then //here you can check the particular port
              begin
                 IpAddress.s_addr := FExtendedTcpTable.Table[i].dwRemoteAddr;
                 RemoteIp  := string(inet_ntoa(IpAddress));
                 IpAddress.s_addr := FExtendedTcpTable.Table[i].dwLocalAddr;
                 LocalIp          := string(inet_ntoa(IpAddress));
                 Writeln(GetPathPID(FExtendedTcpTable.Table[i].dwOwningPid));
                 Writeln(Format('%-16s %-6d %-16s %-6d %s',[LocalIp,FExtendedTcpTable.Table[i].dwLocalPort,RemoteIp,FExtendedTcpTable.Table[i].dwRemotePort,MIB_TCP_STATE[FExtendedTcpTable.Table[i].dwState]]));
              end;
          finally
             FreeMem(FExtendedTcpTable);
          end;
        end;
    
        var
           libHandle : THandle;
        begin
          try
            ReportMemoryLeaksOnShutdown:=DebugHook<>0;
            libHandle           := LoadLibrary(iphlpapi);
            GetExtendedTcpTable := GetProcAddress(libHandle, 'GetExtendedTcpTable');
            ShowCurrentTCPConnections;
          except
            on E: Exception do
              Writeln(E.ClassName, ': ', E.Message);
          end;
    
          readln;
        end.