Win2K下關聯進程/埠之代碼初步分析 |
|
conundrum
尊榮會員 發表:893 回覆:1272 積分:643 註冊:2004-01-06 發送簡訊給我 |
Win2K下關聯進程/埠之代碼初步分析 關鍵字 進程/埠 原作者姓名 Shotgun[Shotgun@xici.net] 文章原始出處 http://shotgun.patching.net/bbs.htm 讀者評分 3 評分次數 1 正文 在西祠或者中綠的BBS中,經常見到網友問:如何才能關聯我的進程和埠呀? 沒錯,關聯進程和埠是一個非常有用的功能,你可以清楚地知道哪些程式在使用 哪些埠,對於查殺木馬很有幫助。可是我們雖然可以使用任務管理器流覽進程列 表,使用Netstat查看埠的使用狀況,卻沒有一個命令可以直接關聯進程和埠 (WinXP上增加了新的NetStat功能,支援直接查看埠進程狀況),今年年初的時 候,國外出了一個有名的軟體Fport,它可以顯示當前所有的埠及他們所屬的進 程,可是,這個軟體並沒有公開源代碼,(太不符合自由軟體精神了吧?), 我根據對這個軟體的逆向工程,做了一個類似的工具,在這裏和大家探討一下它的原理。 一拿到Fport的時候,我就對它進行了API分析,發現除了一些基本的API以外, 它還調用了NTDLL.dll的幾個未公開API,如NtQuerySystemInfomation, NtQueryInfomationProcess,直覺告訴我,關鍵應該在這兩個函數中,特別是前者。 為了能夠理解Fport的運行機理,我們首先要來復習一下SOCKET。 SOCKET究竟是什麼?它的中文名稱叫做套介面,但是,實際上我們所謂的 SOCKET資料結構只是一個32位元的無符號整數(在UNIX中是16位的), 它對於Windows作業系統來說其實是一個檔控制碼(SOCKET是檔?奇怪麼? 作業系統在底層實現的時候,常常使用檔的概念來完成一些基本的功能), 這樣的話問題就明朗了,如果我們能夠枚舉系統所有的控制碼,從中獲得屬性為 SOCKET的,不就可以完成Fport的功能?現在你應該想到了,為什麼Fport 要調用NtQuerySystemInfomation這個API,實際上,NtQuerySystemInfomation 這個函數提供了一個簡單的途徑以獲得系統所有的HANDLE, 我們先來看看這個函數的原型: DWORD NtQuerySystemInformation( DWORD dwRecordType, PDWORD pdwHandleList, DWORD dwNumBytes, PDWORD pdwNumBytesRet ); 我來解釋一下,NtQuerySystemInformation這個函數有四個參數,第一個參數是 dwRecordType,這個參數指定了我們所查詢的系統資訊類型,為了查詢系統 HANDLE列表,我們定義一個常量#defineNT_HANDLE_LIST 16(這個數值我是查資料得到的,如果誰有更詳細的資料,也請讓我共用一下); 第二個參數是一個指標,這個指標用來返回系統控制碼列表, 在調用NtQuerySystemInformation函數之前,必須為這個指標分配足夠的記憶體 空間,否則函數調用會出錯;第三個參數是指定你為HandleList所分配的記憶體 空間大小,單位是byte; 第四個參數是NtQuerySystemInformation返回的HandleList的大小; 如果NtQuerySystemInformation函數調用成功,返回值將是0, 否則可以使用GetLastError()獲得詳細的錯誤代碼。 一旦NtQuerySystemInformation函數調用成功,系統中所有的控制碼將被存放在 pdwHandleList所指向記憶體空間中,其中,pdwHandleList所指向的第一個32 位數,是這個buf所包含的控制碼數量,之後是順序排列的控制碼指標 pHandleInfo,指向的是HANDLEINFO結構: typedef struct _HandleInfo { USHORTdwPid; USHORTCreatorBackTraceIndex; BYTE ObjType; BYTE HandleAttributes; USHORT HndlOffset; DWORD dwKeObject; ULONG GrantedAccess; }HANDLEINFO, *PHANDLEINFO; 看到這個結構,我們心中就有底了,控制碼資訊中包括了控制碼所屬進程的 PID,這樣我們就可以關聯進程和SOCKET了,可是,在NT中有各種各樣的控 制碼:進程控制碼、權杖控制碼、檔控制碼、視窗控制碼……我們怎樣才能判斷 一個控制碼究竟是不是SOCKET呢? 這就要靠HANDLEINFO結構中的ObjType屬性了,經過分析,我們發現, SOCKET控制碼的類型值為0x1A,所以,我們將所有類型為0x1A的控制碼取 出,進行getsockname操作就可以得到當前的進程/埠對應列表,實際上並不然, 要知道,我們得到的控制碼都屬於其他的進程,在NT中根據進程保護的原則, 一個進程沒有辦法直接得到其他進程的各種資訊,特別是控制碼,不同進程中的 同一控制碼(控制碼的數值相同)根本就不是同樣的東西,因此,我們還必須進行 一次轉換,將其他進程的控制碼轉換為本進程的控制碼,這個轉換工作只要簡單地調用DuplicateHandle函數就可以完成了: DuplicateHandle(hSourceProc, (HANDLE)pHandleInfo->HndlOffset, hCurrentProc, &hMyHandle, STANDARD_RIGHTS_REQUIRED, true, 0 ); 之後我們就可以通過getsockname、getsockopt等函數來獲得SOCKET的各種屬 性了(使我困惑的是,Fport並沒有調用getsockname,這說明,應該有更簡單的 方法來得到SOCKET控制碼的各種屬性,看來我對SOCKET控制碼的瞭解程度 還是很膚淺呀) sockaddr_in name = {0}; name.sin_family = AF_INET; int namelen = sizeof(sockaddr_in); SOCKET s = (SOCKET)hMyHandle; char szSockType[6][6] = { "NUL", "TCP", "UDP", "RAW", "RDM","SEQ" }; iRet = getsockname( s, (sockaddr*)&name, &namelen ); if ( iRet != SOCKET_ERROR ) { int sockType = 0; int optlen = 4; iRet = getsockopt( s,SOL_SOCKET, SO_TYPE, (char*)&sockType, &optlen ); printf("PID=M PORT=] %s\n",pHandleInfo->dwPid, ntohs( name.sin_port ), szSockType[sockType] ); } 至此,進程和埠關聯的工作已經基本完成,可是,還有一些不足的地方,首先, 這個軟體不像Fport一樣能夠查看system進程(就是那個著名的8#進程)的 SOCKET,錯誤代碼是5(accessdenied),一個簡單的解決方法是將自己做成 service,這樣就有了對LocalSystem進程的訪問許可權,不過似乎Fport並不是 這麼做的,此為疑點一;其次,由於我對HANDLE屬性的膚淺認識,有的時候 會出現誤報或漏報的現象,即使沒有誤報,將所有屬性為0x1A的控制碼都進行 getsockname效率也略微低了一點,這裏應該有更好的解決方案,此為疑點二; 最後,Fport並沒有調用socket函數來獲得socket屬性,這說明有一個更簡單直 接的方法可以從SOCKET控制碼中得到埠、協定等資訊,可惜我不知道,此為 疑點三。不過令人欣慰的是,我寫出來的Gport可以在Win2K的非管理員用戶 下運行,此時,僅能獲得本用戶所有進程的埠,這大概是Fport所沒有具備的功 能。 寫本文的目的,一方面是為了解答某些網友對Fport原理的疑問,另一方面也是 為了抛磚引玉,希望能解答我心中的這些疑點,望各位高手能不吝賜教。 最後附上Gport的代碼,Gport的測試版和代碼檔可以在我的主頁上下載,位址為: http://shotgun.patching.net/Gport.zip 正文完 附件: • Gport的測試版和代碼檔 Gport.zip發表人 - conundrum 於 2004/07/24 17:12:13 |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |