如何检查rootkit?

如何检查rootkit?

rootkit本来一直都是*nix系统中流行的一种后门,但现在win下也开始流行rootkit了,由于rootkit一般具有隐藏自己的特性,所以并不是象一般后门那样可以轻易的找出来.现在win下最流行的后门是国外的那个hxdef,代码也已经发放了.hxdef一个不足是主程序在隐藏自己的进程上做得不好,已经有多种方法可以将它本身的隐藏进程查出来,但将来的rootkit会在隐藏进程方面做得更好,或者会使用没有进程的方法另这种查隐藏进程去检测rootkit的方法失效.已知新版的hxdef(还没开始写),已要开始使用另类的隐藏进程方法,也已经有人开发出第三方的工具去隐藏其它程序的进程,而且这种方法可以令klister也无法查到其隐藏的进程.自然还有其它多种方法可以检测rootkit的,我也介绍一种可行的,但会有限制的检查方法.一般的rootkit都无法将隐远程session的,hxdef和国产的ntrootkit都一样,这样就我们只要使用远程枚举的方法,就应该能够检测到rootkit的存在.

原理是远程枚举系统的服务,hxdef和ntrootkit隐藏的服务都是无法对于远程的枚举服务进行隐藏的,那我们只要对比一下远程枚举出来的服务和本地枚举出来的服务,就能得到rootkit隐藏了的服务了.这种方法的限制在于需要远程系统允许远程的验证(ipc,rpc等).

以下代码是可以进行远程和本地的枚举WIN32类型的所有正在运行的服务,改变枚举的服务类型的话,可以枚举所有的服务(WIN32+Driver),通过比较远程和本地枚举结果,就应该能查出是否存在隐藏了的服务了.远程枚举需要远程系统允许ipc远程验证.

 

//********************************************************************************

// Version: V1.0
// Coder: WinEggDrop
// Date Release: NULL
// Purpose: To View Local Or Remote WIN32 Service(A Way
To Detect Some Rookits)
// Test PlatForm: Win 2K Pro And Server SP4
// Compiled On: VC++ 6.0
// Others:
// A Way To Detect Rootkit By Comparing The
Results Of Listing Service
// Locally And Remotely Since Most Rootkit
Doesn't Hide Service In Remote
// Session.
// The Code Only List WIN32 Service;Modifying The
ServiceType Can List All
// Services(WIN32 + Driver)
// Limitation:
// IPC Connection Is Enabled
//********************************************************************************

#include <stdio.h>
#include <windows.h>
#include <Winnetwk.h>
#include <Shlwapi.h>
#include <Winsvc.h>

#pragma comment(lib, "Advapi32.lib")
#pragma comment(lib, "Mpr.lib")

// Function ProtoType Declaration
//------------------------------------------------------------------------------------------------------

BOOL ListRemoteService(const char *RemoteIP,const char
*UserName,const char *Password);
BOOL ListSpecifiedTypeService(const char *RemoteIP,const
DWORD dwServiceType);
BOOL EstablishIPCConnection(const char *RemoteIP,const
char *UserName,const char *Password);
BOOL DisconnectIPC(const char *RemoteIP);
//------------------------------------------------------------------------------------------------------

// End Of Fucntion ProtoType Declaration

int main(int argc,char *argv[])
{
if (argc != 4 && argc != 2) // Argument Number Is
Wrong, Display Usage And Exit
{
printf("Usage: %s Local / RemoteIP UserName
Password/n",argv[0]);
printf("Example: %s
//12.12.12.12 test
test/n",argv[0]);
printf("Example: %s Local/n",argv[0]);
return -1;
}

if (argc == 4)
{
ListRemoteService(argv[1],argv[2],argv[3]);
// Let's List The RemoteIP Service
}
else
{
if (strcmpi(argv[1],"Local") == 0) // List
Local Service
{
ListSpecifiedTypeService(NULL,SERVICE_WIN32);

}
}
return 0;
}// End Of Main();

//------------------------------------------------------------------------------------

// Purpose: To List Service Remotely
// Return Type: BOOLEAN
// Parameters:
// In: const char *RemoteIP --> Remote IP To
Connect
// In: const char *UserName --> User Name
For IPC Connection
// In: const char *Password --> Password For
IPC Connection
//------------------------------------------------------------------------------------

BOOL ListRemoteService(const char *RemoteIP,const char
*UserName,const char *Password)
{
char RemoteAddress[128] = {0};

if (strncmp(RemoteIP,"//",2) != 0) // Check
Whether It's In
//IP Form
{
sprintf(RemoteAddress,"
//%s/ipc$",RemoteIP);
// Add // If It's Not In
//IP Form
}
else
{
sprintf(RemoteAddress,"%s/ipc$",RemoteIP);
}

printf("Connecting IPC....../r");
if
(!EstablishIPCConnection(RemoteAddress,UserName,Password))
// Fail To Connect IP
{
printf("Fail To Establish IPC Connection/n");
return FALSE;
}
printf("Connecting IPC OK /n");
DWORD dwServiceType = SERVICE_WIN32;
ListSpecifiedTypeService(RemoteIP,dwServiceType);
// List Service RemoteLY
return DisconnectIPC(RemoteAddress);
}// End of ListRemoteService()

//------------------------------------------------------------------------------------

// Purpose: To List Service Based On The ServiceType
// Return Type: BOOLEAN
// Parameters:
// In: const char *RemoteIP --> Remote
IP To Connect
// In: const DWORD dwServiceType --> The
Service Type
//------------------------------------------------------------------------------------

BOOL ListSpecifiedTypeService(const char *RemoteIP,const
DWORD dwServiceType)
{
char RemoteAddress[128] = {0};
LPENUM_SERVICE_STATUS lpServices = NULL;
DWORD nSize = 0;
DWORD nServicesReturned;
DWORD nResumeHandle = 0;
SC_HANDLE schSCManager = NULL;
BOOL Flag = FALSE;
DWORD i = 0;
UINT j = 0;

if (RemoteIP != NULL) // List Service Remotely
{
if (strncmp(RemoteIP,"
//",2) != 0) // Check
Whether It's In
//IP Form
{
sprintf (RemoteAddress, "
//%s",RemoteIP);
// Add // If It's Not In
//IP Form
}
else
{
sprintf (RemoteAddress, "%s",RemoteIP);
}
}

if (RemoteIP != NULL)
{
schSCManager = OpenSCManager(RemoteAddress, NULL,
SC_MANAGER_ALL_ACCESS);
}
else
{
schSCManager = OpenSCManager(NULL, NULL,
SC_MANAGER_ALL_ACCESS);
}

if (schSCManager == NULL) // Fail To Open SCM
{
printf("Fail To Open SCM/n");
return FALSE;
}

lpServices = (LPENUM_SERVICE_STATUS) LocalAlloc(LPTR, 64
* 1024); // Allocate Ram

if (lpServices == NULL) // Fail To Allocate Ram
{
printf("Fail To Allocate Ram/n");
goto CleanUP;
}

// Enum All Service Based On Service Type
if (EnumServicesStatus(schSCManager,
dwServiceType,
SERVICE_ACTIVE,

(LPENUM_SERVICE_STATUS)lpServices,
64 * 1024,
&nSize,
&nServicesReturned,
&nResumeHandle) == NULL)

 


{
printf("Fail To Enum Service/n");
goto CleanUP;
}

// Display The Services
printf("%-34s%s/n/n","ServiceName","DisplayName");
for (i = 0; i < nServicesReturned; i++)
{
if (lpServices[i].ServiceStatus.dwCurrentState ==
SERVICE_RUNNING)
{

printf("%d:%-32s%s/n",++j,lpServices[i].lpServiceName,
lpServices[i].lpDisplayName);
}
}
Flag = TRUE;

// Close Service Handle,Free Allocated Ram And Return To
The Caller
CleanUP:
CloseServiceHandle(schSCManager);
if (lpServices != NULL)
{
LocalFree(lpServices);
}
return Flag;
}// End Of ListSpecifiedTypeService()

//------------------------------------------------------------------------------------

// Purpose: To Establish IPC Connection
// Return Type: BOOLEAN
// Parameters:
// In: const char *RemoteIP --> Remote IP To
Connect
// In: const char *UserName --> User Name
For IPC Connection
// In: const char *Password --> Password For
IPC Connection
// This Is Too Simple,I Won't Comment It
//------------------------------------------------------------------------------------

BOOL EstablishIPCConnection(const char *RemoteIP,const
char *UserName,const char *Password)
{
NETRESOURCE NET;

NET.lpLocalName = NULL;
NET.lpRemoteName = (char *)RemoteIP;
NET.dwType = RESOURCETYPE_ANY;
NET.lpProvider = NULL;
return (WNetAddConnection2(&NET, Password,UserName,
CONNECT_INTERACTIVE) == NO_ERROR);
}// End Of EstablishIPCConnection()

//------------------------------------------------------------------------------------

// Purpose: To Disconnect IPC Connection
// Return Type: BOOLEAN
// Parameters:
// In: const char *RemoteIP --> Remote IP To
Connect
// This Is Too Simple,I Won't Comment It
//------------------------------------------------------------------------------------

BOOL DisconnectIPC(const char *RemoteIP)
{
return (WNetCancelConnection2(RemoteIP,NULL,TRUE) ==
NO_ERROR);
}// End Of DisconnectIPC()
// End Of File


其实不需要写程序也可以,有现成的程序可以做到的了,sc.exe可以查看到远程的服务,只不过sc.exe列出来一个服务的信息太多了,我们关心的只是正在运行的服务的服务名和显示名,而且给每个服务前加个编号,比较起来也比较容易.例如远程枚举时最后的服务编号是40,但本地枚举时最后的服务编号是35,那么你已经可以知道有5个服务是被隐藏的了.