端口号的总结
端口号---具有网络功能的应用软件的标识号。注意,端口号是不固定的,即可以由用户手工可以分配(当然,一般在软件编写时就已经定义)。当然,有很多应用软件有公认的默认的端口,比如FTP:20和21,HTTP:80,TELNET:23等等,这里就不一一列举了。一个软件可以拥有多个端口号,这证明这个软件拥有不止一个网络功能。
0-1023是公认端口号,即已经公认定义或为将要公认定义的软件保留的,而1024-65535是并没有公共定义的端口号,用户可以自己定义这些端口的作用。
那么端口号到底有什么作用呢?请大家继续往下看。
当一台电脑启动了一个可以让远程其他电脑访问的程序,那么它就要开启至少一个端口号来让外界访问。我们可以把没有开启端口号的电脑看作是一个密封的房间,密封的房间当然不可能接受外界的访问,所以当系统开启了一个可以让外界访问的程序后它自然需要在房间上开一个窗口来接受来自外界的访问,这个窗口就是端口。
那么为什么要给端口编号来区分它们呢,既然一个程序开了一个端口,那么不是外部信息都可以通过这个开启的端口来访问了吗?答案是不可以。为什么呢?因为数据是用端口号来通知传输层协议送给哪个软件来处理的,数据是没有智慧的,如果很多的程序共用一个端口来接受数据的话,那么当外界的一个数据包送来后传输层就不知道该送给哪一个软件来处理,这样势必将导致混乱。
上一次提到提到在一个经过OSI第四层传输层封装的数据段的第四层报头里包含两个端口号,既源端口号和目的端口号,目的端口号的作用上面已经介绍了,下面让我们了解一下原端口号吧。
源端口号一般是由系统自己动态生成的一个从1024-65535的号码,当一台计算机A通过网络访问计算机B时,如果它需要对方返回数据的话,它也会随机创建一个大于1023的端口,告诉B返回数据时把数据送到自己的哪个端口,然后软件开始侦听这个端口,等待数据返回。而B收到数据后会读取数据包的源端口号和目的端口号,然后记录下来,当软件创建了要返回的数据后就把原来数据包中的原端口号作为目的端口号,而把自己的端口号作为原端口号,也就是说把收到的数据包中的原和目的反过来,然后再送回A,A再重复这个过程如此反复直到数据传输完成。当数据全部传输完A就把源端口释放出来,所以同一个软件每次传输数据时不一定是同一个源端口号。
IP协议是由TCP、UDP、ARP、ICMP等一系列子协议组成的。其中,主要用来做传输数据使用的是TCP和UDP协议。在TCP和UDP协议中,都有端口号的概念存在。端口号的作用,主要是区分服务类别和在同一时间进行多个会话。
http://bbs.chinaunix.net/thread-1460809-2-1.html
请教一个问题,我正在写一个linux上ftp客户端程序,遇到一个问题,请各位大侠帮助。
根据ftp协议,客户端将会通过port命令将客户端建立的一个监听端口发给ftp服务器,然后ftp服务器将connect到该端口上,如果在客户端程序中强制设置一个端口,当然可以,但是我希望由内核自动分配一个可用端口。我们知道通常设置sockaddr_in的sin_port字段为0,就是告诉内核自己分配,但是这样在客户端代码中就无法正确得到这个端口值了,因为客户端代码中总是0,谁能提醒下俺呢? 谢谢!
getsockname()
getsockname函数不行
我已经试过getsockname函数,该函数返回的端口仍然是0(printf函数中返回的值仍然是0),如下代码所示: --------------------------------------------------------------------------------------- 155 memset (&local_addr, 0, sizeof local_addr); 156 local_addr.sin_family = AF_INET; 157 local_addr.sin_addr.s_addr = htonl (INADDR_ANY); 158 local_addr.sin_port = 0; 159 160 /* bind client's passive process to server listening socket */ 161 if ((bind 162 (sockfd_data, (struct sockaddr *) (&local_addr), 163 sizeof local_addr)) == -1) 164 { 165 fprintf (stderr, "Bind error: %s\a\n", strerror (errno)); 166 exit (1); 167 } 168 169 /* concat port to parm */ 170 getsockname(sockfd_data, (struct sockaddr*)&local_addr, &sin_size); 171 port=ntohs(local_addr.sin_port); 172 173 printf("in child process port is: %d\n", port); |
我这里的strace结果
|
---------------------------------------------------------------
172 if (listen (sockfd_data, 5))
173 {
174 fprintf (stderr, "Listen error: %s\n\a", strerror (errno));
175 exit (1);
176 }
177
178 getsockname(sockfd_data, (struct sockaddr*)&local_addr, &sin_size);
179 port=ntohs(local_addr.sin_port);
180
181 printf("in child process port is: %d\n", port);
非常感谢风行者!
// 作者 beiyu http://beiyu.bokee.com
// 内核态实现进程和端口关联,在WINDOWS2000.xp,2003下可以用。
// 感谢Leven公布了他的代码,增加了区分tcp,udp,增加了操作系统的兼容性
// 可以在Windows 2000, xp, 2003下面正常使用,编译环境Win2000DDK
// 使用妳的sys loader加载,使用Dbgview查看
// 如果你有什么改进,请email我: beiyuly@gmail.com
//
//
#include <ntddk.h>
#include <string.h>
#define SystemHandleInformation 16
#define TCPUDP_FLAG 100
#define WIN2K_SOCKET_FLAG 0x1a //2k
#define WINXP_SOCKET_FLAG 0x1c //xp
#define WIN2K3_SOCKET_FLAG 0x1a //2k3
#define WIN2K_EPROCESS_NAMEOFFSET 0x1fc //2k
#define WINXP_EPROCESS_NAMEOFFSET 0x174 //xp
#define WIN2K3_EPROCESS_NAMEOFFSET 0x1fc //2k3
#define ObjectNameInformation 1
#define ObjectAllTypesInformation 3
/*
typedef struct _OBJECT_NAME_INFORMATION {
UNICODE_STRING Name;
} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION;
typedef struct _OBJECT_TYPE_INFORMATION {
UNICODE_STRING Name;
ULONG ObjectCount;
ULONG HandleCount;
ULONG Reserved1[4];
ULONG PeakObjectCount;
ULONG PeakHandleCount;
ULONG Reserved2[4];
ULONG InvalidAttributes;
GENERIC_MAPPING GenericMapping;
ULONG ValidAccess;
UCHAR Unknown;
BOOLEAN MaintainHandleDatabase;
POOL_TYPE PoolType;
ULONG PagedPoolUsage;
ULONG NonPagedPoolUsage;
} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;
typedef struct _OBJECT_ALL_TYPES_INFORMATION {
ULONG NumberOfTypes;
OBJECT_TYPE_INFORMATION TypeInformation;
} OBJECT_ALL_TYPES_INFORMATION, *POBJECT_ALL_TYPES_INFORMATION;
*/
#define ntohs(s) /
( ( ((s) >> 8) & 0x00FF ) | /
( ((s) << 8) & 0xFF00 ) )
typedef struct _TDI_CONNECTION_INFO {
ULONG State;
ULONG Event;
ULONG TransmittedTsdus;
ULONG ReceivedTsdus;
ULONG TransmissionErrors;
ULONG ReceiveErrors;
LARGE_INTEGER Throughput;
LARGE_INTEGER Delay;
ULONG SendBufferSize;
ULONG ReceiveBufferSize;
BOOLEAN Unreliable;
} TDI_CONNECTION_INFO, *PTDI_CONNECTION_INFO;
typedef struct _TDI_CONNECTION_INFORMATION {
LONG UserDataLength;
PVOID UserData;
LONG OptionsLength;
PVOID Options;
LONG RemoteAddressLength;
PVOID RemoteAddress;
} TDI_CONNECTION_INFORMATION, *PTDI_CONNECTION_INFORMATION;
typedef struct _SYSTEM_HANDLE_INFORMATION
{
ULONG ProcessID; //进程的标识ID
UCHAR ObjectTypeNumber; //对象类型
UCHAR Flags; //0x01 = PROTECT_FROM_CLOSE,0x02 = INHERIT
USHORT Handle; //对象句柄的数值
PVOID Object; //对象句柄所指的内核对象地址 WinNT4/Windows2000是0x1A xp中是0x1c 2003中是
ACCESS_MASK GrantedAccess; //创建句柄时所准许的对象的访问权
}SYSTEM_HANDLE_INFORMATION, * PSYSTEM_HANDLE_INFORMATION;
NTSYSAPI
NTSTATUS
NTAPI
ZwQuerySystemInformation(
IN ULONG SystemInformationClass,
IN OUT PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength);
NTSYSAPI
NTSTATUS
NTAPI
NtDeviceIoControlFile(
IN HANDLE FileHandle,
IN HANDLE Event OPTIONAL,
IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
IN PVOID ApcContext OPTIONAL,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN ULONG IoControlCode,
IN PVOID InputBuffer OPTIONAL,
IN ULONG InputBufferLength,
OUT PVOID OutputBuffer OPTIONAL,
IN ULONG OutputBufferLength
);
NTSYSAPI
NTSTATUS
NTAPI
ZwQueryObject(
IN HANDLE ObjectHandle,
IN ULONG ObjectInformationClass,
OUT PVOID ObjectInformation,
IN ULONG ObjectInformationLength,
OUT PULONG ReturnLength OPTIONAL
);
NTSYSAPI
BOOLEAN
NTAPI
NtDuplicateObject(
IN HANDLE hSourceProcessHandle,
IN HANDLE hSourceHandle,
IN HANDLE hTargetProcessHandle,
OUT HANDLE * lpTargetHandle,
IN ULONG dwDesiredAccess,
IN BOOLEAN bInheritHandle,
IN ULONG dwOptions
);
NTSYSAPI
NTSTATUS
NTAPI
PsLookupProcessByProcessId(
IN ULONG ulProcId,
OUT PEPROCESS * pEProcess
);
NTSTATUS
DriverEntry(IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath);
void DriverUnload(IN PDRIVER_OBJECT DriverObject);
//几个全局变量,记录端口相关信息,最后列印出来
ULONG g_pid[1000];
ULONG g_port[1000];
ULONG g_handle[1000];
ULONG g_tcpudp[1000];
ULONG g_num =0 ;
ULONG g_tu[1000]; //g_tu=0 tcp, g_tu=1 udp
//获得所有句柄
ULONG GetHandleList()
{
ULONG n;
ULONG pBuffer;
NTSTATUS status;
DbgPrint("GetHandleList/n");
pBuffer =(ULONG)ExAllocatePool(PagedPool,0x1000);
status = ZwQuerySystemInformation(SystemHandleInformation,(PVOID)pBuffer,0x1000,&n);
ExFreePool((PVOID)pBuffer);
if(STATUS_INFO_LENGTH_MISMATCH == status)
{
pBuffer =(ULONG)ExAllocatePool(NonPagedPool,n);
ZwQuerySystemInformation(SystemHandleInformation,(PVOID)pBuffer,n,NULL);
return pBuffer;
}
else
return 0;
}
//根据句柄得到端口信息
void GetOpenPort(ULONG dwProcessesID,ULONG Handle,int NoCache,ULONG tcpudp)
{
HANDLE hProc,DupHandle=NULL;
USHORT openport;
ULONG i=0;
NTSTATUS status;
TDI_CONNECTION_INFO TdiConnInfo={0};
TDI_CONNECTION_INFORMATION TdiConnInformation={0};
ULONG dwRetu=0;
IO_STATUS_BLOCK IoStatusBlock={0};
CLIENT_ID id;
OBJECT_ATTRIBUTES objatt = {0};
POBJECT_NAME_INFORMATION ObjectName;
char ObjectNameBuf[512];
// char ObjectNameMBS[261];
ULONG ReturnLen;
ObjectName = (POBJECT_NAME_INFORMATION)ObjectNameBuf;
ObjectName->Name.MaximumLength = 500;
//DbgPrint("GetOpenPort/n");
id.UniqueProcess = (HANDLE)dwProcessesID;
id.UniqueThread = 0;
//打开对方进程
NtOpenProcess(&hProc,PROCESS_DUP_HANDLE,&objatt,&id);
//复制句柄
NtDuplicateObject(hProc,
(HANDLE)Handle,
(HANDLE)0xffffffff,
&DupHandle,
0,
FALSE,
2);
//根据object的数据得到端口信息
if(NoCache==0x2)
{
//取得句柄关联的对象的信息
ZwQueryObject(DupHandle, ObjectNameInformation, ObjectName, sizeof(ObjectNameBuf), &ReturnLen);
TdiConnInformation.RemoteAddressLength= 4;
status = NtDeviceIoControlFile((HANDLE)DupHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
0x210012, // Command code
&TdiConnInformation,
sizeof(TdiConnInformation),
&TdiConnInfo,
sizeof(TdiConnInfo));
//进行TDI查询,得到连接的相关信息
if(status == 0)
{
openport = ntohs((USHORT)TdiConnInfo.ReceivedTsdus);
if(openport == 0)
return;
for(i=0;i {
if(g_pid == dwProcessesID && g_port == openport)
if(tcpudp >= TCPUDP_FLAG && g_tcpudp >= TCPUDP_FLAG || tcpudp < TCPUDP_FLAG && g_tcpudp < TCPUDP_FLAG)
return;
}
g_pid = dwProcessesID;
g_port = openport;
g_handle = Handle;
g_tcpudp = tcpudp;
g_num++;
if (wcscmp(ObjectName->Name.Buffer, L"//Device//Tcp") == 0)
{
g_tu = 0;
}
if (wcscmp(ObjectName->Name.Buffer, L"//Device//Udp") == 0)
{
g_tu = 1;
}
}
}
if(NoCache==0x1)
{
ZwQueryObject(DupHandle, ObjectNameInformation, ObjectName, sizeof(ObjectNameBuf), &ReturnLen);
TdiConnInformation.RemoteAddressLength= 3;
status = NtDeviceIoControlFile((HANDLE)DupHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
0x210012, // Command code
&TdiConnInformation,
sizeof(TdiConnInformation),
&TdiConnInfo,
sizeof(TdiConnInfo));
//进行TDI查询,得到连接的相关信息
if(status == 0)
{
openport = ntohs((USHORT)TdiConnInfo.ReceivedTsdus);
if(openport == 0)
return;
for(i=0;i {
if(g_pid == dwProcessesID && g_port == openport)
if(tcpudp >= TCPUDP_FLAG && g_tcpudp >= TCPUDP_FLAG || tcpudp < TCPUDP_FLAG && g_tcpudp < TCPUDP_FLAG)
return;
}
g_pid = dwProcessesID;
g_port = openport;
g_handle = Handle;
g_tcpudp = tcpudp;
g_num++;
if (wcscmp(ObjectName->Name.Buffer, L"//Device//Tcp") == 0)
{
g_tu = 0;
}
if (wcscmp(ObjectName->Name.Buffer, L"//Device//Udp") == 0)
{
g_tu = 1;
}
}
}
}
void Start(ULONG pBuffer)
{
ULONG i;
//头4个字节是所有的句柄的数目UNONG 32位
//从第5个字节开始就是结构体了
PSYSTEM_HANDLE_INFORMATION pProcesses = (PSYSTEM_HANDLE_INFORMATION)(pBuffer+4);
ULONG nocache;
ULONG tcpudp;
PEPROCESS epro;
char *p;
ULONG uMajorVersion;
ULONG uMinorVersion;
ULONG uBuildNumber;
ULONG uOsVer;
DbgPrint("Start11/n");
PsGetVersion(&uMajorVersion, &uMinorVersion, &uBuildNumber, NULL);
if(uMajorVersion == 5)
{
if(uMinorVersion == 0)
{
DbgPrint("2k/n");
uOsVer = 0;//2k
}
else if(uMinorVersion == 1)
{
uOsVer = 1;//xp
DbgPrint("xp/n");
}
else if(uMinorVersion == 2)
{
uOsVer = 2;//2k3
DbgPrint("2k3/n");
}
else
{
uOsVer = 3;//nt
DbgPrint("NT/n");
}
}
else
{
uOsVer = 99;
DbgPrint("Unknow OS/n");
}
for (i=0;i<((ULONG)(*(ULONG*)pBuffer));i++)
{
//2000 xp 2003 三种操作系统
if(pProcesses.ObjectTypeNumber == WIN2K_SOCKET_FLAG
|| pProcesses.ObjectTypeNumber == WINXP_SOCKET_FLAG
|| pProcesses.ObjectTypeNumber == WIN2K3_SOCKET_FLAG)
{
//得到SYSTEM_HANDLE_INFORMATION.object的相关数据
//这里要密切注意内存情况,一不小心就蓝屏。因为句柄经常变化,有些可能已经被销毁了
nocache = (ULONG)pProcesses.Object;
if(!MmIsAddressValid((VOID*)nocache))
continue;
nocache = (ULONG)(*((ULONG*)(nocache)+4));
tcpudp = (ULONG)(*((ULONG*)(pProcesses.Object)+1));
if(!MmIsAddressValid((VOID*)tcpudp))
continue;
tcpudp = (ULONG)(*((ULONG*)(tcpudp)+1));
if(nocache == 2 || nocache == 1)
{
GetOpenPort(pProcesses.ProcessID,pProcesses.Handle,nocache,tcpudp);
}
}
}
for(i=0;i {
//根据PID得到进程名
PsLookupProcessByProcessId(g_pid,&epro);
if(uOsVer == 0)
{ //2k中进程名在EPROCESS结构中的位置
p = (char*)epro + WIN2K_EPROCESS_NAMEOFFSET;
//DbgPrint("2k/n");
}
if(uOsVer == 1)
{ //xp中进程名在EPROCESS结构中的位置
p = (char*)epro + WINXP_EPROCESS_NAMEOFFSET;
//DbgPrint("xp/n");
}
if(uOsVer == 2)
{ //2k3中进程名在EPROCESS结构中的位置
p = (char*)epro + WIN2K3_EPROCESS_NAMEOFFSET;
//DbgPrint("2k3/n");
}
if(uOsVer == 3)
{
p = (char*)epro + WIN2K_EPROCESS_NAMEOFFSET; //NT
//DbgPrint("nt/n");
}
if(uOsVer == 99)
{
//DbgPrint("Unknow OS/n");
break;
}
if(g_tu == 0)
DbgPrint("TCP:/tProcName=%s/tPID=%d/tport=%d/t%d/n",p,g_pid,g_port,g_tcpudp);
if(g_tu == 1)
DbgPrint("UDP:/tProcName=%s/tPID=%d/tport=%d/t%d/n",p,g_pid,g_port,g_tcpudp);
}
return;
}
//
NTSTATUS
DriverEntry(IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath)
{
ULONG pbuf;
DbgPrint("DriverEntry/n");
DriverObject->DriverUnload = DriverUnload;
pbuf = GetHandleList();
Start(pbuf);
return STATUS_SUCCESS;
}
void DriverUnload(IN PDRIVER_OBJECT pDriverObject)
{
NTSTATUS status;
//ResumeDestFunction();
if(pDriverObject->DeviceObject != NULL)
{
IoDeleteDevice( pDriverObject->DeviceObject );
}
DbgPrint("DriverUnload/n");
}
参考文献:
1 Windows DDK
2 http://coffeeqiqi.blogchina.com
3 Leven-端口关联进程-在核心态的实现方法
4 Msdn
5 port/connection hiding http://dev.csdn.net/Develop/article/28/84294.shtm
6 在NT系列操作系统里让自己“消失”
7 http://www.rootkit.com
-
顶