技術要點:
1。通過NTQuerySystemInforamtion函數獲得系統所有控制代碼,來獲得SOCKET控制代碼。
2.通過CreateToolhelp32Snapshot函數獲得系統進程快照,獲得進程詳細資料。
實現細節1
NTQuerySystemInformation(DWORD,PDWORD,DWORD,PDWORD)是Windows未公開的API函數,它包含四個參數第一個參數指定了我們所查詢的系統資訊類型,它能夠查詢56種系統資訊,為了查詢系統HANDLE列表,我們定義一個常量
#define NT_HANDLE_LIST 16(這個數值我是查資料得到的);
第二個參數是一個指標,這個指標用來返回系統控制代碼列表,在調用NtQuerySystemInformation函數之前,必須為這個指標分配足夠的記憶體空間,否則函數調用會出錯;
第三個參數是指定你為系統控制代碼列表所分配的記憶體空間大小,單位是byte;
第四個參數是NtQuerySystemInformation返回的系統控制代碼列表的大小;
一旦NtQuerySystemInformation函數調用成功,系統中所有的控制代碼將被存放在第二個參數所指向記憶體空間中,其中,第二個參數所指向的第一個32位元,是這個buf所包含的控制代碼計數,之後是順序排列的控制代碼指標pHandleInfo,指向的是_HANDLEINFO結構:
typedef struct _HandleInfo
{
USHORT dwPid;
USHORT CreatorBackTraceIndex;
BYTE ObjType;
BYTE HandleAttributes;
USHORT HndlOffset;
DWORD dwKeObject;
ULONG GrantedAccess;
}HandleInfo, *pHandleInfo;
控制代碼資訊中包括了控制代碼所屬進程的PID,這樣就可以關聯進程和SOCKET了,SOCKET控制代碼的類型值為0x1A(26),所以,將所有類型為0x1A的控制代碼取出
方法:SOCKET s = (SOCKET)handle;
進行getsockname操作就可以得到當前的進程/連接埠對應列表,實際上並不然,得到的控制代碼都屬於其他的進程,在NT中根據進程保護的原則,一個進程沒有辦法直接得到其他進程的各種資訊,特別是控制代碼,不同進程中的同一控制代碼(控制代碼的數值相同)根本就不是同樣的東西,因此,還必須進行一次轉換,將其他進程的控制代碼轉換為本進程的控制代碼,這個轉換工作只要簡單地調用DuplicateHandle函數就可以完成了:
DuplicateHandle(HANDLE,HANDLE,HANDLE,LPHANDLE,DWORD,BOOL,DWORD);
之後就可以通過getsockname、getsockopt等函數來獲得SOCKET的各種屬性了.
至此,進程和連接埠關聯的工作已經基本完成,可是,還有一些不足的地方,因為許可權問題所以不能夠查看系統進程
附代碼:
void GetSocketHandle(){
HANDLE hCurrentProcess = GetCurrentProcess();
HANDLE hToken;
/*獲得當前進程層級控制代碼*/
if(!::OpenProcessToken(hCurrentProcess,TOKEN_QUERY|TOKEN_ADJUST_PRIVILEGES,&hToken)){
MessageBox("Open Process Token Failed!","ERROR",0);
return FALSE;
}
if(!RaisePrivileges(hToken,SE_DEBUG_NAME)){//提升進程層級
MessageBox("Raise Process Failed!","ERROR");
return FALSE;
}
if(hToken) CloseHandle(hToken);
//////////////////////////////////////////////////////////////////////////////////////////////////
PDWORD pdwHandleList = (PDWORD)malloc(MAX_HANDLE_LIST_BUF);//臨時緩衝區
if(!pdwHandleList){
MessageBox("No Enough Memory for Handle List!","ERROR");
return FALSE;
}
DWORD dwNumBytesRet = 0;
//獲得系統所有控制代碼
if(NtQuerySystemInformation(NT_HANDLE_LIST,pdwHandleList,MAX_HANDLE_LIST_BUF,&dwNumBytesRet)){
MessageBox("NtQuerySystemInformation Return Error!","ERROR");
return FALSE;
}
//////////////////////////////////////////////////////////////////////////////////////////////////
DWORD dwNumEntries;//控制代碼數
HANDLE hProc;
pHandleInfo pHandle;
dwNumEntries = pdwHandleList[0];//緩衝區的第一項為控制代碼數
pHandle = (pHandleInfo)(pdwHandleList+1);
/////////////////////////////枚舉控制代碼獲得相應資訊////////////////////////////////////////////////
//獲得各個進程的資訊
for(DWORD i=0;i<dwNumEntries;i++){//1
if((pHandle->objType == OBJECT_TYPE_SOCKET) && (pHandle->dwPid) ){//2//判斷是否為
//SOCKET類型
//OBJECT_TYPE_SOCKET 是定義的常量值為0x1a
if(pHandle->dwPid == m_nMyPID){//如果是本進程跳過
//獲得進程的控制代碼
hProc = OpenProcess(WRITE_DAC,FALSE,pHandle->dwPid);
if(hProc){//3
AdjustDacl(hProc);//調整目標控制代碼的存取控制屬性
CloseHandle(hProc);
}//3
else{//4
break;
}//4
HANDLE hMyHandle = NULL;
hProc = OpenProcess(PROCESS_DUP_HANDLE,TRUE,pHandle->dwPid);
if(hProc){//5
//將獲得進程控制代碼複製到本進程控制代碼
DuplicateHandle(hProc,(HANDLE)pHandle->HandOffset,hCurrentProcess,
&hMyHandle,STANDARD_RIGHTS_REQUIRED,TRUE,0);
if(hMyHandle != NULL){//6
SocketInfo(hMyHandle,pHandle);//獲得SOCKET資訊
}//6
CloseHandle(hMyHandle);
}//5
//CloseHandle(hProc);
}
}//2
pHandle++;
}//1
if(pdwHandleList){
free(pdwHandleList);
}
if(hCurrentProcess){
CloseHandle(hCurrentProcess);
}
return TRUE;
}
void SocketInfo(HANDLE RequireHandle,pHandleInfo pHandleBuf)
{
sockaddr_in name = ;
name.sin_family = AF_INET;
int namelen = sizeof(sockaddr_in);
SOCKET s = (SOCKET)RequireHandle;
//獲得SOCKET進程的詳細訊息,由Process ID通過系統快照找到Process的詳細資料
//系統快照可以在kernel32.dll裡調用,此功能稍後補加
if(getsockname(s,(sockaddr*)&name,&namelen) != SOCKET_ERROR){//7
TargetHandle[++THIndex].m_hHandle = *pHandleBuf;
TargetHandle[THIndex].m_addr = name;
TargetHandle[THIndex].sockettype = 4;
int optlen = 4;
getsockopt(s,SOL_SOCKET,SO_TYPE,(char*)&TargetHandle[THIndex].sockettype,&optlen);
}//7
else CloseHandle(RequireHandle);
}
void AdjustDacl(HANDLE hProcess)//調整目標進程的DACL,資料結構,函數定義參考AclAPI.h
{
SID world = ;
LPTSTR ptstrName = (LPTSTR)&world;
EXPLICIT_ACCESS ea={//進程存取控制資訊
STANDARD_RIGHTS_ALL|SPECIFIC_RIGHTS_ALL,
SET_ACCESS,
NO_INHERITANCE,
{
0,NO_MULTIPLE_TRUSTEE,
TRUSTEE_IS_SID,
TRUSTEE_IS_USER,
ptstrName
}
};
ACL *pdacl = 0;
if(SetEntriesInAcl(1,&ea,0,&pdacl)!=ERROR_SUCCESS){
MessageBox("SetEntriesInAcl Failed!","ERROR");
return;
}
if(SetSecurityInfo(hProcess,SE_KERNEL_OBJECT,DACL_SECURITY_INFORMATION,0,0,pdacl,0)){
MessageBox("SetSecurity Failed!","ERROR");
}
LocalFree(pdacl);
}
BOOL CLocalscanDlg::RaisePrivileges(HANDLE hToken,char *pPriv)//提升自己的進程層級
{
TOKEN_PRIVILEGES tkp;
if(!::LookupPrivilegeValue(NULL,pPriv,&tkp.Privileges[0].Luid)){//獲得當前層級
MessageBox("Look Up PrivilegeValue Failed!","NULL");
return FALSE;
}//修改進程層級
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if(!::AdjustTokenPrivileges(hToken,FALSE,&tkp,0,NULL,NULL)){//調整進程層級
MessageBox("Adjust Privileges Failed!","ERROR");
return FALSE;
}
return TRUE;
}
2.
從第一步已經可以獲得開啟的視窗和及佔用連接埠進程的PID,可以通過Kernel32.dll中的CreateToolhelp32Snapshot(DWORD dwFlags,DWORD th32ProcessID)來獲得系統中進程快照,進一步獲得詳細資料(需包含標頭檔tlhelp32.h)
第一個參數是系統快照的類型在這裡選擇TH32CS_SNAPPROCESS,此時第二個參數必須為NULL.
若調用成功便返回系統快照的控制代碼,然後通過
Process32First(HANDLE hSnapshot,LPPROCESSENTRY32 lppe)和
Process32Next(HANDLE hSnapshot,LPPROCESSENTRY32 lppe)函數獲得進程的詳細資料
LPPROCESSENTRY32的結構
typedef struct tagPROCESSENTRY32 {
DWORD dwSize; //此為結構大小,使用上面兩函數前必須先賦值sizeof(PROCESSENTRY32)
DWORD cntUsage;
DWORD th32ProcessID; //進程PID
DWORD th32DefaultHeapID;
DWORD th32ModuleID;
DWORD cntThreads; //線程數
DWORD th32ParentProcessID;
LONG pcPriClassBase;
DWORD dwFlags;
char szExeFile[MAX_PATH]; //進程名
} PROCESSENTRY32;
typedef PROCESSENTRY32 * PPROCESSENTRY32;
typedef PROCESSENTRY32 * LPPROCESSENTRY32;
附代碼:
BOOL GetSocketProcInfo()
{
int i;
HANDLE hSnapShot;
PROCESSENTRY32 lppe;
hSnapShot = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);//獲得系統快照
lppe.dwSize = sizeof(lppe);//賦值
int ret = ::Process32First(hSnapShot,&lppe);
if(ret){
do {
for(i=0;i<=THIndex;i++){
if(TargetHandle[ i ].m_hHandle.dwPid == lppe.th32ProcessID){
strcpy(TargetHandle[ i ].m_hProcList.ExeName,lppe.szExeFile);
TargetHandle[ i ].m_hProcList.cntThreads = lppe.cntThreads;
}
}
}while(::Process32Next(hSnapShot,&lppe));
}
CloseHandle(hSnapShot);
return TRUE;
}
不足:
因為重新整理時不斷將目標進程的控制代碼複製所以會造成系統控制代碼增多.會佔用系統記憶體,和將事先給結構分配給的記憶體用完,會導致NTQuerySystemInformation函數錯誤
解決:
建立PID鏈表,將PID記錄下來,對出現的PID賦於不同的屬性BOOL isNew,來防止重複復制。