無進程DLL木馬

protoin layerid=protoin WSCGetProviderPath(&protoin

簡介

最近新型木馬有向無進程DLL木馬方向發展的趨勢。雖然,編程方法多種多樣,但原理基本上是相通的。我們特組織了這篇文章,使大家對此有更多的了解:

一)Windows下進程的隱藏

在M$的32位作業系統中,有許許多多的辦法可以實現進程隱藏的功能。在Win98下將程式註冊為系統服務就可以實現在進程列表里的隱藏,但是在NT/2000下,由於作業系統添加了許多特性使得進程的隱藏提到了一個新的高度。其中,DLL木馬是非常流行的一種形式,它將自己添加到其他執行檔的進程里,這樣在任務管理器里就不會出現我們的DLL檔案,而是我們DLL的載體EXE檔案。在Jeffrey Richter大師的文章里提到了好幾種插入DLL的方式,比如說在註冊表的AppInit_DLLs里添加木馬DLL,特洛伊DLL方式,使用Windows掛鈎和遠程執行緒的插入等等,在此我就不做詳細介紹了。現在給大家介紹一種隱藏進程的新方法,它仍然是以DLL的形式存在的(同樣需要由其他執行檔來載入),而且還具有無連線埠的特性。它就是使用了windows socket 2的新特性,服務提供者接口(Service Provider Interface),SPI試圖支持所有的32位Windows作業系統,當然也包括Windows95。

二)Windows Socket 2 SPI技術概述

Winsock 2 SPI是一個新特性,是為書寫服務提供者的人員提供的。Winsock 2不僅提供了一個供應用程式訪問網路服務的Windows socket應用程式編程接口(API),還包含了由傳輸服務提供者和名字解析服務提供者實現的Winsock服務提供者接口(SPI)和ws2_32.dll。在此以傳輸服務提供者為例來實現進程的隱藏。如下是應用程式,Ws2_32.dll和傳輸服務提供者接口之間的層次關係:

----------------------------
 Windows socket 2 應用程式 
----------------------------Windows socket 2 API
  WS2_32.DLL  
----------------------------Windows socket 2 傳輸SPI
  傳輸服務提供者(DLL)  
----------------------------

傳輸服務提供者是以DLL的形式存在的,它向外只有一個入口函式,那就是WSPStartup,其中的參數LPWSAPRTOCOL_INFOW結構指針決定了服務提供者的類型,其他的30個傳輸服務提供者函式是以分配表的方式調用的。當網路應用程式調用WSASocket/socket函式創建套接字時,會有三個參數:地址族,套接字類型和協定,正是這三個參數共同決定了是由哪一個類型的傳輸服務提供者來實現本應用程式的功能。在整個層次結構中,Ws2_32.dll只是起到了媒介的作用,應用程式則是對用戶功能的實現,而真正實現網路傳輸功能的是傳輸服務提供者接口。當前系統中有一些默認的服務提供者,它們已經實現了大部分基本的功能,所以我們自己在書寫服務提供者程式時,只須對數據報進行“修飾”後,將數據報傳送給系統服務提供者來實現剩下的功能。

在服務提供者中有三種協定:分層協定,基礎協定和協定鏈。區分它們的方法是通過結構WSAPROTOCOL_INFOW中的Protocolchain結構的ChainLen值來實現的。分層協定的ChainLen值為0,基礎協定的值為1,而協定鏈的值是大於1。其實分層協定和基礎協定在功能實現上沒有太大的區別(均可通過調用系統服務提供者實現數據轉發),但是在安裝上卻有很大的不同。安裝基礎協定時我們把所有的基礎服務提供者的DLL檔案名稱和路徑都替換為我們自定義的基礎協定;而安裝分層協定後,我們還必須將和分層協定有關的各個協定組成協定鏈,然後再安裝協定鏈。在所有的服務提供者都安裝完後,我們還必須重新排列它們的安裝順序,這一點很重要。當我們的WSASocket/socket創建套接字時,Ws2_32.dll就會在服務提供者資料庫中按順序搜尋和WSASTARTUP/socket提供的三個參數相匹配的服務提供者,如果同時有兩個相同類型的服務提供者存在於服務提供者資料庫中,那么順序在前的那個服務提供者就會被調用。通常,在我們安裝完自己的服務提供者後,都會將自己的服務提供者重新排列在最前面。在實例instBD.exe中,我們以分層協定為例,展示如何安裝傳輸服務提供者。

Ws2_32.dll是使用標準的動態程式庫來載入服務提供者接口的DLL到系統中去的,並調用WSPStartup來初始化。WSPStartup是Windows Socket 2應用程式調用SPI程式的初始化函式,也就是入口函式。WSPStartup的參數LPWSAPROTOCOL_INFOW指針提供應用程式所期望的協定信息,然後通過這個結構指針我們可以獲得所保存的系統服務提供者的DLL名稱和路徑,載入系統服務提供者後查找到系統SPI程式的WSPStartup函式的指針,通過這個指針我們就可以將自己服務提供者的WSPStartup函式和系統SPI程式的WSPStartup函式相關聯,進而調用系統的各個服務提供者函式。在數據傳輸服務提供者的實現中,我們需要兩個程式,一個是執行檔用來安裝傳輸服務提供者;另一個就是DLL形式的數據傳輸服務提供者。

三)基於SPI的DLL木馬技術

上面我們已經介紹了傳輸服務提供者的特性,現在讓我們來看看如果將這種技術運用於木馬進程隱藏的。在每個作業系統中都有系統網路服務,它們是在系統啟動時自動載入,而且很多是基於IP協定的。如果我們書寫了一個IP協定的傳輸服務提供者,並安裝在服務提供者資料庫的最前端,系統網路服務就會載入我們的服務提供者。如果將木馬程式嵌入到服務提供者的DLL檔案之中,在啟動系統網路服務時我們的木馬程式也會被啟動。這種形式的DLL木馬只須被安裝一次,而後就會被自動載入到執行檔的進程中,還有一個特點就是它會被多個網路服務載入。通常在系統關閉時,系統網路服務才會結束,所以我們的木馬程式同樣可以在系統運行時保持激活狀態。

在傳輸服務提供者中,有30個SPI函式是以分配表的形式存在的。在Ws2_32.dll中的大多數函式都有與之對應的傳輸服務提供者函式。如WSPRecv和WSPSend,它們在Ws2_32.dll中的對應函式是WSARecv和WSASend。我們假設自己編寫了一個基於IP協定的服務提供者並安裝於系統之中,當系統重啟時它被svchost.exe程式載入了,而且svchost.exe在135/TCP監聽,完事具備了。在我們的傳輸服務提供者中,自己重新編寫了WSPRecv函式,對接收到的數據進行分析,如果其中含有客戶端傳送過來的暗號,就執行相應的命令獲得期望的動作,之後我們可以調用WSPSend函式將結果傳送到客戶端,這樣不僅隱藏了進程,而且還重用了已有的連線埠。

四)主要代碼分析

1.instBD.exe

可執行程式instBD.exe的主要功能是安裝我們自己的分層傳輸服務提供者,並重新排列所有傳輸服務提供者的順序,使我們的服務提供者位於協定鏈的頂端,這樣相應類型的應用程式就會首先進入我們的傳輸服務提供者接口。本程式只有一個參數,就是安裝(-install)或卸載(-remove)。作為演示,本程式只安裝了IP分層協定及與TCP相關的協定鏈。在backdoor.dll中,我們不對數據報進行任何修飾,只是在啟動我們的木馬進程。

自定義函式:

BOOL getfilter(); //獲得所有已經安裝的傳輸服務提供者
void freefilter(); //釋放存儲空間
void installfilter(); //安裝分層協定,協定鏈及排序
void removefilter(); //卸載分層協定和協定鏈

代碼分析:

protoinfo=(LPWSAPROTOCOL_INFOW)GlobalAlloc(GPTR,protoinfosize);
//分配WSAPROTOCOL_INFOW結構的存儲空間
totalprotos=WSCEnumProtocols(NULL,protoinfo,&protoinfosize,&errorcode);
//獲得系統中已安裝的所有服務提供者
GetCurrentDirectory(max_path,filter_path);
//得到當前的路徑
_tcscpy(filter_name,_T("\\backdoor.dll"));
//構造服務提供者檔案backdoor.dll的路徑全名
WSCInstallProvider(&filterguid,filter_path,&iplayerinfo,1,&errorcode);
//安裝自定義的IP分層協定
iplayercataid=protoinfo.dwCatalogEntryId;
//獲得已安裝自定義IP分層協定的由Ws2_32.dll分配的唯一標誌
udpchaininfo.ProtocolChain.ChainEntries[0]=iplayercataid;
//將自定義的IP分層協定作為自定義UDP協定鏈的根分層服務提供者安裝在協定鏈的頂端
WSCInstallProvider(&filterchainguid,filter_path,chainarray,provcnt,&errorcode);
//安裝協定鏈
WSCWriteProviderOrder(cataentries,totalprotos);
//更新所有服務提供者的安裝順序,把自定義的服務提供者排在所有協定的最前列
WSCDeinstallProvider(&filterguid,&errorcode);
//卸載IP分層協定
WSCDeinstallProvider(&filterchainguid,&errorcode);
//卸載協定鏈

2.backdoor.dll

傳輸服務提供者都是以動態程式庫的形式存在的,在應用程式需要時由Ws2_32.dll載入,在用完之後就被卸載。傳輸服務提供者只有一個入口函式就是WSPStartup,它是Windows Socket 應用程式調用SPI的初始化函式,其他SPI函式的調用都是通過WSPStartup的參數WSPUPCALLTABLE來實現的。其中有個全局變數,可共所有調用DLL的程式讀取與修改。在首次載入服務提供者時,我們啟動木馬進程。演示中木馬進程沒有任何特別的功能,當客戶端和監聽的伺服器連線埠連線後,如果客戶端傳送了特定的暗號,服務端就會回送特定的訊息。

自定義函式:

int WSPAPI WSPStartup( WORD wversionrequested,LPWSPDATA lpwspdata,LPWSAPROTOCOL_INFOW
lpprotoinfo,
WSPUPCALLTABLE upcalltable,LPWSPPROC_TABLE lpproctable);
//SPI函式WSPStartup和Windows Socket 2的API函式WSAStartup相對應,WSPStartup是唯一的入口函
數,剩下的30個SPI函式則是通過參數upcalltable來實現的,它們只能在內部調用,不向外提供入口

代碼分析:

hthread=CreateThread(NULL,0,backdoor,NULL,0,NULL);
//創建木馬進程,它只是展示數據的流通
GetModuleFileName(NULL,processname,MAX_PATH);
//獲得調用本服務提供者動態程式庫的執行檔的全名
OutputDebugString(_T("Start the backdoor ..."));
//輸出調試信息
layerid=protoinfo.dwCatalogEntryId;
//獲得已安裝自定義IP分層協定的由Ws2_32.dll分配的唯一標誌
nextlayerid=lpprotoinfo->ProtocolChain.ChainEntries[i+1];
//獲得下一層傳輸服務提供者的標誌信息
WSCGetProviderPath(&protoinfo.ProviderId,filterpath,&filterpathlen,&errorcode);
//獲得下一層傳輸服務提供者的安裝路徑
ExpandEnvironmentStrings(filterpath,filterpath,MAX_PATH);
//擴展環境變數
hfilter=LoadLibrary(filterpath));
//裝載下一層傳輸服務提供者
wspstartupfunc=(LPWSPSTARTUP)GetProcAddress(hfilter,"WSPStartup"));
//獲得下一層傳輸服務提供者的入口函式WSPStartup,以便調用
wspstartupfunc(wversionrequested,lpwspdata,lpprotoinfo,upcalltable,lpproctable);
//調用下一層傳輸服務提供者的WSPStartup函式,實現鉤子功能
nextproctable=*lpproctable;
//保存下一層服務提供者的30個服務函式指針
由於以動態程式庫形式的服務提供者要向外提供一個入口函式,因此還須一個配置檔案backdoor.def:
EXPORTS WSPStartup
//向外提供入口函式WSPStartup

3.testBD.exe

這是一個測試程式,用來檢測木馬的伺服器端是否正常工作。在它傳送特定的訊息到伺服器端後,如果伺服器正常工作就會回送特定的訊息,反之則不會收到任何訊息。由於木馬的伺服器在TCP的12345連線埠監聽,所以我們的客戶端也是基於TCP協定的。

五)小結與後記

本文的目的在於向大家介紹一種編程思路,固不是任何的木馬教程。其實只有在不斷的對抗中,技術和思路才會不斷的提高。我們只有充分的了解了各種技術,甚至有前瞻的能力才能維護好網路秩序,促進網路安全的發展。最後送給大家一句老話:知己知彼,百戰不殆。

相關詞條

相關搜尋

熱門詞條

聯絡我們