Support Forums

Full Version: [VB.Net] Local/Remote TCP info from process [Source]
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hey,

I never really intended to release it as I had some crap with this getting it to work. Though I had lots of help with this since I liked it more then WireShark and I got all the info I needed without searching.
I've used this for packet logging of: HWID applications, games and other things you will find out while using this.

Screenshot:
[Image: jcNZU2.png]

We are going to use iphlpapi.dll (GetExtendedTcpTable) to get the information.

First, declare the API and some structures we need:

Code:
<DllImport("iphlpapi.dll", SetLastError:=True)> _
    Private Function GetExtendedTcpTable(ByVal pTcpTable As IntPtr, ByRef OutBufLen As Integer, ByVal sort As Boolean, ByVal ipVersion As Integer, ByVal tblClass As Integer, ByVal reserved As Integer) As UInteger
    End Function

    Private Structure tcprows
        Public LocalAddress As Integer
        Public LocalPort As Integer
        Public RemoteAddress As Integer
        Public RemotePort As Integer
        Public ProcessID As Integer
    End Structure

    Private Structure tcptable
        Public NumEntries As Integer
    End Structure

Now comes the most important function of this, the part where we get all the connections.

Code:
Private Function GetAllTcpConnections() As tcprows()
        Const NO_ERROR As Integer = 0
        Const IP_v4 As Integer = 2
        Dim tTable As tcprows() = Nothing
        Dim buffSize As Integer = 0
        GetExtendedTcpTable(IntPtr.Zero, buffSize, True, IP_v4, 5, 0)
        Dim buffTable As IntPtr = Marshal.AllocHGlobal(buffSize)
        Try
            If NO_ERROR <> GetExtendedTcpTable(buffTable, buffSize, True, IP_v4, 5, 0) Then
                Return Nothing
            End If
            Dim tab As tcptable = Marshal.PtrToStructure(buffTable, GetType(tcptable))
            Dim rowPtr As IntPtr = CLng(buffTable) + Marshal.SizeOf(tab.NumEntries)
            tTable = New tcprows(tab.NumEntries - 1) {}

            Dim rowSize As Integer = Marshal.SizeOf(GetType(tcprows))
            For i As Integer = 0 To tab.NumEntries - 1
                Dim tcpRow As tcprows = Marshal.PtrToStructure(rowPtr, GetType(tcprows))
                tTable(i) = tcpRow
                rowPtr = CInt(rowPtr) + rowSize
            Next
        Finally
            Marshal.FreeHGlobal(buffTable)
        End Try
        Return tTable
    End Function

As I'm using a Command Application I made this:

Code:
Public Sub CheckProcess_Tcp(ByVal procname As String)
        Dim allTcpConns As tcprows() = GetAllTcpConnections()
        For Each row As tcprows In allTcpConns
            For Each p As Process In Process.GetProcessesByName(procname)
                If row.ProcessID = p.Id Then
                    Console.ForegroundColor = ConsoleColor.White
                    Console.Write("---------------------------------------------" & vbNewLine)
                    Console.Write("Remote:   " & tIP(row.RemoteAddress) & ":" & tPort(row.RemotePort) & vbNewLine)
                    Console.Write("Local:    " & tIP(row.LocalAddress) & ":" & tPort(row.LocalPort) & vbNewLine)
                    Console.Write("Process:  " & procname & "(" & row.ProcessID & ")" & vbNewLine)
                    Try
                        For Each pm As ProcessModule In p.Modules
                            If pm.FileName.Contains(procname) Then
                                Console.Write("Location: " & pm.FileName() & vbNewLine)
                                Exit For
                            End If
                        Next
                    Catch
                        Console.Write("Location: Error - 32 bit process could not been read" & vbNewLine)
                    End Try
                    Console.Write("---------------------------------------------" & vbNewLine)
                End If
            Next
        Next
    End Sub

This will check if a row in the table contains the matched ID of the process we are looking for.

As you see there are some errors. We need to translate the port and IP.

Code:
Private Function tPort(ByVal port As Integer) As Integer
        Return ((port And &HFF) << 8 Or (port And &HFF00) >> 8)
    End Function
    Public Function tIP(ByVal LongIP As Double) As String
        Dim ByteIP(4) As String
        Dim x As Byte = Nothing
        Dim IP As String

        If LongIP < 4294967296.0# And LongIP >= 0 Then
            ByteIP(0) = Fix(LongIP / (256 ^ 3))
            ByteIP(1) = Fix(((LongIP - (ByteIP(0) * (256 ^ 3))) / (256 ^ 2)))
            ByteIP(2) = Fix(((LongIP - (ByteIP(0) * (256 ^ 3)) - (ByteIP(1) * (256 ^ 2))) / 256))
            ByteIP(3) = ((LongIP - (ByteIP(0) * (256 ^ 3)) - (ByteIP(1) * (256 ^ 2)) - (ByteIP(2) * 256)))
            IP = ByteIP(3) & "." & ByteIP(2) & "." & ByteIP(1) & "." & ByteIP(0)
            tIP = IP
        Else
            tIP = -1
        End If
    End Function

Enjoy, any questions can be asked below. I'd appreciate if you reply below Big Grin
I created something same long time ago.
Only think mine was getting all ip's.

Nice..
(06-04-2011, 01:17 PM)goranpilkic Wrote: [ -> ]I created something same long time ago.
Only think mine was getting all ip's.

Nice..

No problem, thanks for the first response and rate.
I hope someone is still monitoring this thread. I'm trying to get a process name if a port is found to be in use. I'm hoping someone can help me leverage the information here to get the job done.

My current code (installer custom action) works to detect if the port is in use, but I want to take it a step further and get the process name of the port user. If is a certain value I will allow the use of that port in the install dialog. If not, I will notify that port is in use.

Anyway, here's my code...

Code:
Dim hostname As String = "127.0.0.1"
Dim port As Integer
Dim ipa As IPAddress = DirectCase(Dns.GetHostAddresses(hostname)(0), IPAddress)
Dim sock as New System.Net.Sockets.Socket(System.Net.Sockets.AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp)

sock.Connect(ipa, port)
If sock.Connected = True Then
     session.item("PORT_VALID") = "" 'Property value returned to installer.
End If

sock.Close

Like I said, this code works pretty well or so it seems. I just want to add a layer to it to check the process by PID I guess, grab the name and if = to or contains "MyValue" then allow the in use port to be selected or used during the install.

I hope someone can help.
Looks pretty nice. Do you plan on ever switching it into a windows form instead of console?
Awesome, thanks for sharing. c: