Se me planteó la necesidad de tener que matar un proceso a la escucha en un determinado puerto. Para ello desarrollé un código en C++ que me permitiese localizar el proceso que pone un socket a la escucha en un determinado puerto y luego matarlo.
Pensando que este truco puede ser de utilidad a atros, he implementado un ejemplo para socket TCP y UDP pudiendo elegir entre uno, otro o los dos.
El código que expongo está escrito en C++ Builder 5 y delphi 7. Para ambos compiladores he tenido que declarar ciertas estructuras y constantes que no estaban incluidas en ellos, pero es posible que en versiones mas modernas lo estén. Con objeto de dejar el código compatible con esas versiones modernas, las declaraciones que he añadido están extraídas de http://msdn.microsoft.com. En el caso de delphi es posible que los nombres varíen un poco, en ese caso no será difícil adaptar el código. En el caso de C++ no habrá ningún problema.
Como último apunte decir que para matar algunos procesos y aquellos pertenecientes a otro usuario, es necesario desponer de privilegio "SeDebugPrivilege", con lo que habrá que ajustar dicho privilegio previamente al uso de la función objeto del presente truco.
Comienzo con la versión C++ del código.
#include <windows.h> #include <winsock2.h> #include <iphlpapi.h> // TCP typedef struct _MIB_TCPROW_OWNER_PID { DWORD dwState; DWORD dwLocalAddr; DWORD dwLocalPort; DWORD dwRemoteAddr; DWORD dwRemotePort; DWORD dwOwningPid; } MIB_TCPROW_OWNER_PID, *PMIB_TCPROW_OWNER_PID; typedef struct { DWORD dwNumEntries; MIB_TCPROW_OWNER_PID table[ANY_SIZE]; } MIB_TCPTABLE_OWNER_PID, *PMIB_TCPTABLE_OWNER_PID; typedef enum { TCP_TABLE_BASIC_LISTENER, TCP_TABLE_BASIC_CONNECTIONS, TCP_TABLE_BASIC_ALL, TCP_TABLE_OWNER_PID_LISTENER, TCP_TABLE_OWNER_PID_CONNECTIONS, TCP_TABLE_OWNER_PID_ALL, TCP_TABLE_OWNER_MODULE_LISTENER, TCP_TABLE_OWNER_MODULE_CONNECTIONS, TCP_TABLE_OWNER_MODULE_ALL } TCP_TABLE_CLASS, *PTCP_TABLE_CLASS; //UDP typedef enum { UDP_TABLE_BASIC, UDP_TABLE_OWNER_PID, UDP_TABLE_OWNER_MODULE } UDP_TABLE_CLASS, *PUDP_TABLE_CLASS; typedef struct _MIB_UDPROW_OWNER_PID { DWORD dwLocalAddr; DWORD dwLocalPort; DWORD dwOwningPid; } MIB_UDPROW_OWNER_PID, *PMIB_UDPROW_OWNER_PID; typedef struct _MIB_UDPTABLE_OWNER_PID { DWORD dwNumEntries; MIB_UDPROW_OWNER_PID table[ANY_SIZE]; } MIB_UDPTABLE_OWNER_PID, *PMIB_UDPTABLE_OWNER_PID; typedef DWORD (__stdcall *PGetExtendedTcpTable)(PVOID pTcpTable, PDWORD pdwSize, BOOL bOrder, ULONG ulAf, TCP_TABLE_CLASS TableClass, ULONG Reserved); typedef DWORD (__stdcall *PGetExtendedUdpTable)(PVOID pUdpTable, PDWORD pdwSize, BOOL bOrder, ULONG ulAf, UDP_TABLE_CLASS TableClass, ULONG Reserved); #define TCP 0x1 #define UDP 0x2 // Termina un proceso a la escucha de un determinado puerto bool TerminateProcessByPort(int Port, int IPProto) { PMIB_TCPTABLE_OWNER_PID TCPTablePID; PMIB_UDPTABLE_OWNER_PID UDPTablePID; DWORD Size = 0; bool Result = false; // TCP PGetExtendedTcpTable GetExtendedTcpTable = (PGetExtendedTcpTable)GetProcAddress(LoadLibrary("Iphlpapi.dll"), "GetExtendedTcpTable"); if(GetExtendedTcpTable && (IPProto & TCP)){ GetExtendedTcpTable(0, &Size, TRUE, AF_INET, TCP_TABLE_OWNER_PID_LISTENER, 0); TCPTablePID = (PMIB_TCPTABLE_OWNER_PID)VirtualAlloc(0, Size, MEM_COMMIT, PAGE_READWRITE); GetExtendedTcpTable(TCPTablePID, &Size, TRUE, AF_INET, TCP_TABLE_OWNER_PID_LISTENER, 0); for(DWORD i = 0; i< TCPTablePID->dwNumEntries; i++){ if(ntohs((u_short)TCPTablePID->table[i].dwLocalPort) == Port && TCPTablePID->table.dwState == MIB_TCP_STATE_LISTEN){ HANDLE Process = OpenProcess(PROCESS_TERMINATE, false, TCPTablePID->table.dwOwningPid); Result |= TerminateProcess(Process, 0); CloseHandle(Process); break; } } VirtualFree(TCPTablePID, 0, MEM_RELEASE); } // UDP PGetExtendedUdpTable GetExtendedUdpTable = (PGetExtendedUdpTable)GetProcAddress(LoadLibrary("Iphlpapi.dll"), "GetExtendedUdpTable"); if(GetExtendedUdpTable && (IPProto & UDP)){ GetExtendedUdpTable(0, &Size, TRUE, AF_INET, UDP_TABLE_OWNER_PID, 0); UDPTablePID = (PMIB_UDPTABLE_OWNER_PID)VirtualAlloc(0, Size, MEM_COMMIT, PAGE_READWRITE); GetExtendedUdpTable(UDPTablePID, &Size, TRUE, AF_INET, UDP_TABLE_OWNER_PID, 0); for(DWORD i = 0; i< UDPTablePID->dwNumEntries; i++){ if(ntohs((u_short)UDPTablePID->table.dwLocalPort) == Port){ HANDLE Process = OpenProcess(PROCESS_TERMINATE, false, UDPTablePID->table.dwOwningPid); Result |= TerminateProcess(Process, 0); CloseHandle(Process); break; } } VirtualFree(UDPTablePID, 0, MEM_RELEASE); } return Result; }
Un ejemplo de uso:
TerminateProcessByPort(5000, TCP | UDP);
Por organizar un poco el tema y no mezclar mucho termino aquí este mensaje y dejo para el siguiente la versión delphi.
Espero que este truco sea de utilidad como lo ha sido para mi.
Saludos.