大三时的笔记了,当时有一段时间觉得闲,正好网上对进程与端口关联也炒得比较热,自己也就看了看别人的代码,本来想自己搞一个试试,但是由于自己的水平不济,有加上遇上了期末考试,最后就不了了之了。这里是当时的一些函数记录。
调用了NTDLL.dll的几个未公开API,NtQuerySystemInfomation,NtQueryInfomationProcess
调用函数获得访问网络的程序的句柄然后从这些句柄中得到所用的套接字,从而得到该程序和端口的对应关系NtQuerySystemInfomation函数就提供了一个路径来完成操作。函数原型为:
DWORD NtQuerySystemInformation(
DWORD dwRecordType, //制定索要查询的系统信息类型,为了查询系统信息的handle列表,定义常量 #define NT_HANDLE_LIST 16
在SDK中指出该参数是一个指定的SYSTEM_INFORMATION_CLASS的一
个值,在该程序中我认为应该指定为SystemProcessInformation,该选项将返
回一个SYSTEM_PROCESS_INFORMATION结构在该结构中有关于改进程的
内存,线程数等信息。
PDWORD pdwHandleList, //一个指针用来返回系统句柄的列表,必须在调用函数之前为其申请一个做够大的缓冲区,不然会出错
DWORD dwNumBytes, //指定你为上面的句柄分配的内存的空间大小,单位byte
PDWORD pdwNumBytesRet //返回的句柄列表的大小
返回的结构的大小为该字段,如果返回的结构大小小于第三个参数,那么将返回这个结构的实际大小,否则返回错误代码。
该函数如果成功调用会返回0,否则可由GetLastError获得详细的错误代码。
一旦NtQuerySystemInformation函数调用成功,系统中所有的句柄将被存放在pdwHandleList所指向内存空间中,其中,pdwHandleList所指向的第一个32位数,是这个buf所包含的句柄数量,之后是顺序排列的句柄指针pHandleInfo,指向的是HANDLEINFO结构:
typedef struct _HandleInfo
{
USHORT dwPid;
USHORT CreatorBackTraceIndex;
BYTE ObjType;
BYTE HandleAttributes;
USHORT HndlOffset;
DWORDdwKeObject;
ULONG GrantedAccess;
}HANDLEINFO, *PHANDLEINFO;
一点疑问:在上面函数中那个NT_HANDLE_LIST 如何而来,怎么知道返回的HandleInfo这个结构体,这个结构好像是自己定义的。
句柄信息中包括了句柄所属进程的PID,这样我们就可以关联进程和SOCKET了,可是,在NT中有各种各样的句柄:进程句柄、令牌句柄、文件句柄、窗口句柄……我们怎样才能判断一个句柄究竟是不是SOCKET呢?这就要靠HANDLEINFO结构中的ObjType属性了,经过分析,我们发现,SOCKET句柄的类型值为0x1A,所以,我们将所有类型为0x1A的句柄取出,进行getsockname操作就可以得到当前的进程/端口对应列表,实际上并不然,要知道,我们得到的句柄都属于其他的进程,在NT中根据进程保护的原则,一个进程没有办法直接得到其他进程的各种信息,特别是句柄,不同进程中的同一句柄(句柄的数值相同)根本就不是同样的东西,因此,我们还必须进行一次转换,将其他进程的句柄转换为本进程的句柄,这个转换工作只要简单地调用DuplicateHandle函数就可以完成了:
DuplicateHandle( //复制一个句柄对象,其实就是将其他进程转换为本进程句柄
hSourceProc, //要被复制的原进程的句柄 进程必须要有PROCESS_DUP_HANDLE 权限
e
(HANDLE)pHandleInfo->HndlOffset,
//MSDN中对该参数的描述hSourceHandle,handle to duplicate(复制)
和前面有点重复
hCurrentProc, //用来存放复制了的句柄的句柄Handle to duplicate. This is an open object handle that is valid in the context of the source process
&hMyHandle, //用来接收复制的句柄的,本地进程的句柄,对本地进程必须有 PROCESS_DUP_HANDLE access.
STANDARD_RIGHTS_REQUIRED,
//true,本进程可以继承原进程,否则不行0可选择的动作,比如关闭复制的原进程句柄
);
int getsockname ( //得到一个本地套接字的名字
SOCKET s, //识别一个将要操作的套接字的标识符
struct sockaddr FAR* name,
//输出,接受操作的套接字的名字的地址
int FAR* namelen //名字缓冲区的大小
);
成功的话返回0,否则的话返回SOCKET_ERROR
int getsockopt ( //得到一个套接字的选项信息
SOCKET s, //套接字标识符
int level, //协议被定义的标准
int optname, //在上面的标准中的要得到的值 详解查 MSDN
char FAR* optval, //指向所请求的选项所返回的值得缓冲区
int FAR* optlen //指向上面参数长度的指针
);
成功的话返回
SOCKET socket (
int af, //
int type,
int protocol
);
Parameters
af
[in] An address family specification.
type
[in] A type specification for the new socket.
The following are the only two type specifications supported for Windows Sockets 1.1: Type Explanation
SOCK_STREAM Provides sequenced, reliable, two-way, connection-based byte streams with an out-of-band data transmission mechanism. Uses TCP for the Internet address family. 面向连接的套接字
SOCK_DGRAM Supports datagrams, which are connectionless, unreliable buffers of a fixed (typically small) maximum length. Uses UDP for the Internet address family.
面向无连接的套接字
In Windows Sockets 2, many new socket types will be introduced and don' need to be specified now because an application can dynamically discover the attributes of each available transport protocol through the WSAEnumProtocols function. Socket type definitions will appear in WINSOCK2.H, which will be periodically updated as new socket types, address families and protocols are defined.
protocol
[in] A particular protocol to be used with the socket that is specific to the indicated address family.
SOCKADDR_IN Structure
The SOCKADDR_IN structure has the following form:
struct sockaddr_in{
short sin_family;
unsigned short sin_port;
Struct in_addr in_addr;
char sin_zero[8];
};
In the Internet address family, the SOCKADDR_IN structure is used by Windows Sockets to specify a local or remote endpoint(端点) address to which to connect a socket. This is the form of the SOCKADDR structure specific to the Internet address family and can be cast to SOCKADDR.
Members
sin_family
Address family (must be AF_INET).指明地址是 Internet Address
sin_port
IP port.
sin_addr
IP address.
sin_zero //填充物使该结构的大小接近于 SOCKADDR
Padding to make structure the same size as SOCKADDR.
WSADATA windows socket 执行的信息
typedef struct WSAData {
WORD wVersion;
WORD wHighVersion;
char szDescription[WSADESCRIPTION_LEN+1];
char szSystemStatus[WSASYS_STATUS_LEN+1];
unsigned short iMaxSockets;
unsigned short iMaxUdpDg;
char FAR * lpVendorInfo;
} WSADATA, FAR * LPWSADATA;
The members of this structure are:
Parameters
wVersion
The version of the Windows Sockets specification that the WS2_32.DLL expects the caller to use. 在WS2_32.dll中描述的windows Socket的版本
wHighVersion
The highest version of the Windows Sockets specification that this DLL can support (also encoded as above). Normally this will be the same as wVersion. 该动态链接库支持的最高的windows socket 版本,一般和上面的版本一致
szDescription
A null-terminated ASCII string into which the WS2_32.DLL copies a description of the Windows Sockets implementation. The text (up to 256 characters in length) can contain any characters except control and formatting characters: the most likely use that an application will put this to is to display it (possibly truncated) in a status message.
szSystemStatus
A null-terminated ASCII string into which the WS2_32.DLL copies relevant (有关)status or configuration (结构,构造) information. The WS2_32.DLL should use this field only if the information might be useful to the user or support staff: it should not be considered as an extension of the szDescription field.
iMaxSockets
This field is retained保留 for backward compatibility, but should be ignored for version 2 and later as no single value can be appropriate for all underlying service providers.
iMaxUdpDg
This value should be ignored忽视 for version 2 and onward. It is retained for compatibility with Windows Sockets specification 1.1, but should not be used when developing new applications. For the actual maximum message size specific to a particular Windows Sockets service provider and socket type, applications should use getsockopt to retrieve the value of option SO_MAX_MSG_SIZE after a socket has been created.
lpVendorInfo
This value should be ignored for version 2 and onward. It is retained for compatibility with Windows Sockets specification 1.1. Applications needing to access vendor-specific configuration information should use getsockopt to retrieve the value of option PVD_CONFIG. The definition of this value (if utilized) is beyond the scope of this specification.
Note An application should ignore the iMaxsockets, iMaxUdpDg, and lpVendorInfo fields in WSAData if the value in wVersion after a successful call to WSAStartup is at least 2. This is because the architecture of Windows Sockets has been changed in version 2 to support multiple providers, and WSAData no longer applies to a single vendor's stack. Two new socket options are introduced to supply provider-specific information: SO_MAX_MSG_SIZE (replaces the iMaxUdpDg element) and PVD_CONFIG (allows any other provider-specific configuration to occur).
到现在我还是对作者东西一头雾水,因为在技术上还不够了解,如在NT下的权限提升以及对进程的控制等等,对了英语太差导致对msdn之中的注释好久才可以看懂,得加把有啊!!
需要了解的几个函数
1:NTQUERYSYSTEMINFORMATION 包含在Ntdll中是微软没有公布的函数之一
在SDK中可以查到。
2:了解Socket Socket_in 等几个常用的结构的含义及各个域的含义
3:在nt 下的权限的提高,三个函数有OpenProcessToken、 LookupPrivilegeValue 和 AdjustTokenPrivileges
OpenProcessToken
OpenProcessToken function opens the access token associated with a process.打开与进程相关联的权限
BOOL OpenProcessToken(
HANDLE ProcessHandle, //所要打开权限的进程句柄
DWORD DesiredAccess, //所要改变的权限的描述
PHANDLE TokenHandle //指向打开后返回的句柄的指针
);
ProcessHandle:
[in] Handle to the process whose access token is opened. The process must have the PROCESS_QUERY_INFORMATION access permission.
DesiredAccess
[in] Specifies an access mask that specifies the requested types of access to the access token. These requested access types are compared with the token's discretionary access control list (DACL) to determine which accesses are granted or denied.
TokenHandle
[out] Pointer to a handle that identifies the newly opened access token when the function returns
LookupPrivilegeValue
function retrieves the locally unique identifier (LUID)本地唯一标识 used on a specified system to locally represent the specified privilege name.返回在本地的输入特权的描述
BOOL LookupPrivilegeValue(
LPCTSTR lpSystemName, // address of string specifying the system一个指针指向一个零结尾 的字符串,该字符串的名字是您想要在系统中提升的权限的名字,如果指定的非空字符串存在,程序将在本地系统中找到这个权限一般为空
LPCTSTR lpName, // address of string specifying the privilege一个指针指向您要提升的权限的名字,该名字已经在winnt.h中定义,例如:SE_SECURITY_NAME 等等,即最后想拥有的权限的名字
PLUID lpLuid // address of locally unique identifier一个指向本地唯一关于由第一个参数需要描述的本系统权限的指针 LUID TOKEN_PRIVILEGES结构中的一项
);
该函数如果成功运行,将返回一个非零值,如果不成功将返回一个零,用GetLastError可以得到根详细的错误说明
一个重要的结构
TOKEN_PRIVILEGES
The TOKEN_PRIVILEGES structure contains information about a set of privileges for an access token.
这个结构包含了关于存取权限的信息
typedef struct TOKEN_PRIVILEGES { // tp
DWORD PrivilegeCount; 输入的特权在特权队列中的序号
LUID_AND_ATTRIBUTES Privileges[ANYSIZE_ARRAY]; 一个在其他结构中定义过的结构
} TOKEN_PRIVILEGES;
下面是LUID_AND_ATTRIBUTES Privileges[ANYSIZE_ARRAY];的一些取值 SE_PRIVILEGE_ENABLED_BY_DEFAULT 默认被激活的权限 SE_PRIVILEGE_ENABLED 被激活的权现
SE_PRIVILEGE_USED_FOR_ACCESS 权限用于提升某个服务或对象,该标志用于识别一个客户应用程序已经通过的但是这个权限可能是不必要的
AdjustTokenPrivileges
The AdjustTokenPrivileges function enables or disables privileges in the specified access token. Enabling or disabling privileges in an access token requires TOKEN_ADJUST_PRIVILEGES access. 提升权限的关键函数调用
BOOL AdjustTokenPrivileges(
HANDLE TokenHandle, 鉴别含有被修改的权限的表识的局柄
BOOL DisableAllPrivileges, 标识是否使全县无效,如果该值为 TURE 那么函数将不会理睬新的权限或是该权现无效,如果改值为 FALSE 那么函数将按照新的指定修改权限
PTOKEN_PRIVILEGES NewState, 指向标识权限以及其他信息的TOKEN_PRIVILEGES结构
DisableAllPrivileges parameter is FALSE, AdjustTokenPrivileges enables or disables these privileges for the token. If you set the SE_PRIVILEGE_ENABLED attribute for a privilege, the function enables that privilege; otherwise, it disables the privilege.
DWORD BufferLength, 以字节表示下一个参数指向的缓冲区的大小 如果下一个参数为空,那么它的值也可以为空
PTOKEN_PRIVILEGES PreviousState, 接收权限的初始状态,如果该缓冲区过小将导致函数运行失败// receives original state of changed privileges
PDWORD ReturnLength 字节的数量,上面参数的缓冲区的大小,如果上面参数为空,那么该参数也可以为空// receives required size of the PreviousState buffer
);
以上两函数要十分注意,在以前写2000下的关机程序是用过,但是没有解决问题,这次还要从以前的程序入手搞清楚这两个函数的用法和含义
4:Dacl:
discretionary access-control list (DACL)
An access-control list that is controlled by the owner of an object and that specifies the access particular users or groups can have to the object.
5: SID:
The SID structure is a variable-length structure used to uniquely identify users or groups. SID stands for security identifier.
Applications are not to modify the SID structure directly. To create and manipulate a security identifier, use the functions listed in the See Also section.
typedef PVOID PSID;
6:SetEntriesInAcl
7:SetSecurityInfo
8:WSADATA
9:OpenProcessToken
10:getsockname //取得套接字的本地名字
int getsockname (
SOCKET s, 一个封装好的套接字描述符
struct sockaddr FAR* name, 接收套接字的地址(名字)
int FAR* namelen 存放名字的缓冲区的大小
);
成功执行便会返回 0 否则返回错误码
11:WSAStartup
The Windows Sockets WSAStartup function initiates use of WS2_32.DLL by a process.
int WSAStartup (
WORD wVersionRequested, 指定用户可以使用的套接字的字最高版本,
LPWSADATA lpWSAData 指向 WSADATA 结构的指针用来接收系统执行的套接字的详细信息
);
相关结构: WSADATA
typedef struct WSAData {
WORD wVersion;
WORD wHighVersion;
char szDescription[WSADESCRIPTION_LEN+1];
char szSystemStatus[WSASYS_STATUS_LEN+1];
unsigned short iMaxSockets;
unsigned short iMaxUdpDg;
char FAR * lpVendorInfo;
} WSADATA, FAR * LPWSADATA;
函数和思路都是从安全焦点的文章中摘出来的,只是自己查MSDN学习了一下,见笑了