转贴-XiaoP,系统信息

来源:互联网 发布:淘宝手机上传宝贝 编辑:程序博客网 时间:2024/04/29 00:25

最近在准备一个进程查看(当然不只进程查看功能了)的工具,总结了在用户态下查找进程的几种方法。

当然,如果想要真正做到进程查看,还是要进入核心态中,因为在用户态是查不到什么东西的,但是可以用来和

核心态结果进行比较找出隐藏进程。(内核级病毒、木马在Ring0中可以很容易的做到隐藏而是用户态程序检测不到)。

//write by jingzhongrong

1、利用ToolHelp API

首先创建一个系统快照,然后通过对系统快照的访问完成进程的枚举

获取系统快照使用 CreateToolhelp32Snapshot 函数

函数原型声明如下:

HANDLE WINAPI CreateToolhelp32Snapshot(
  DWORD dwFlags,
  DWORD th32ProcessID
);

将dwFlags设置为TH32CS_SNAPPROCESS用于获取进程快照。

函数调用成功后会返回一个快照的句柄,便可以使用Process32First、Process32Next进行枚举了              

函数原型声明如下:

BOOL WINAPI Process32First(
  HANDLE hSnapshot,
  LPPROCESSENTRY32 lppe
);

BOOL WINAPI Process32Next(  HANDLE hSnapshot,  LPPROCESSENTRY32 lppe);

下面是相关代码:

 

#include <windows.h>
#include 
<tlhelp32.h>
#include 
<stdio.h>

void useToolHelp()
{
    HANDLE procSnap 
= CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0
);
    
if(procSnap ==
 INVALID_HANDLE_VALUE)
    {
        printf(
"CreateToolhelp32Snapshot failed, %d "
,GetLastError());
        
return
;
    }
    
//
    PROCESSENTRY32 procEntry = { 0
 };
    procEntry.dwSize 
= sizeof
(PROCESSENTRY32);
    BOOL bRet 
= Process32First(procSnap,&
procEntry);
    
while
(bRet)
    {
        wprintf(L
"PID: %d (%s) "
,procEntry.th32ProcessID, procEntry.szExeFile);                                                   
        bRet 
= Process32Next(procSnap,&
procEntry);
    }
    CloseHandle(procSnap);
}

void
 main()
{
    useToolHelp();
    getchar();
}

用此方法可以在进程ID和进程名称间进行转换,即通过进程名称获得进程ID,通过进程ID获取进程名称。

 

2、通过psapi.dll提供的函数

通过psapi.dll提供的EnumProcesses、EnumProcessModules实现

函数原型声明如下:

BOOL EnumProcesses(  DWORD* pProcessIds,  DWORD cb,  DWORD* pBytesReturned);
BOOL EnumProcessModules(  HANDLE hProcess,  HMODULE* lphModule,  DWORD cb,  LPDWORD lpcbNeeded);
相关代码如下:(参考MSDN)
#include <windows.h>
#include 
<stdio.h>
#include 
<tchar.h>
#include 
"psapi.h"
#pragma comment(lib,"psapi.lib")


void PrintProcessNameAndID(DWORD processID)
{
    TCHAR szProcessName[MAX_PATH] 
= _T("<unknown>");
  HANDLE hProcess 
= OpenProcess(PROCESS_ALL_ACCESS/* | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ*/,FALSE,processID);     
    
//Process name.
  if(NULL!=hProcess)
  {
        HMODULE hMod;
    DWORD cbNeeded;
    
if(EnumProcessModules(hProcess,&hMod,sizeof(hMod), &cbNeeded))         
    {
            GetModuleBaseName(hProcess,hMod,szProcessName,
sizeof(szProcessName)/sizeof(TCHAR));                        
    }
  }
    wprintf(_T(
"PID: %d (%s) "),processID,szProcessName);
  CloseHandle(hProcess);
}

void main( )
{
    DWORD aProcesses[
1024], cbNeeded, cProcesses;
  unsigned 
int i;
  
if(!EnumProcesses(aProcesses,sizeof(aProcesses),&cbNeeded))
        
return;
  cProcesses 
= cbNeeded/sizeof(DWORD);
  
for(i=0;i<cProcesses;i++)
        PrintProcessNameAndID(aProcesses[i]);
    getchar();
}

此方法由于需要进行OpenProcess操作,所以需要一定的权限,当权限不够时,有些进程将不能被打开。

下面给出提升权限的相关代码:

void RaisePrivilege()
{
    HANDLE hToken;
    TOKEN_PRIVILEGES tp;
    tp.PrivilegeCount 
= 1
;
    tp.Privileges[
0].Attributes =
 SE_PRIVILEGE_ENABLED;
    
if(OpenProcessToken(GetCurrentProcess(),TOKEN_ALL_ACCESS,&
hToken))
    {
        
if(LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&tp.Privileges[0
].Luid))
        {
            AdjustTokenPrivileges(hToken,FALSE,
&tp,NULL,NULL,0
);
        }
    }
    
if
(hToken)
        CloseHandle(hToken);
}

3、通过ntdll.dll提供的Native API

使用Native API 中的ZwQuerySystemInformation的SystemProcessesAndThreadsInformation系统调用枚举进程

由于该函数没有被导出,所以首先定义要使用到的结构和常量

 

typedef DWORD (WINAPI *ZWQUERYSYSTEMINFORMATION)(DWORD, PVOID, DWORD, PDWORD);

typedef 
struct
 _SYSTEM_PROCESS_INFORMATION
{
    DWORD NextEntryDelta;
    DWORD ThreadCount;
    DWORD Reserved1[
6
];
    FILETIME ftCreateTime;
    FILETIME ftUserTime;
    FILETIME ftKernelTime;
    UNICODE_STRING ProcessName;
    DWORD BasePriority;
    DWORD ProcessId;
    DWORD InheritedFromProcessId;
    DWORD HandleCount;
    DWORD Reserved2[
2
];
    DWORD VmCounters;
    DWORD dCommitCharge;
    PVOID ThreadInfos[
1
];
}SYSTEM_PROCESS_INFORMATION, 
*
PSYSTEM_PROCESS_INFORMATION;

#define SystemProcessesAndThreadsInformation 5

然后动态加载ntdll.dll,获得函数的地址。

便可以进行进程的枚举

相关代码如下:

 

#include <windows.h>
#include 
<ntsecapi.h>
#include 
<stdio.h>

typedef DWORD (WINAPI 
*ZWQUERYSYSTEMINFORMATION)(DWORD, PVOID, DWORD, PDWORD);

typedef 
struct
 _SYSTEM_PROCESS_INFORMATION
{
    DWORD NextEntryDelta;
    DWORD ThreadCount;
    DWORD Reserved1[
6
];
    FILETIME ftCreateTime;
    FILETIME ftUserTime;
    FILETIME ftKernelTime;
    UNICODE_STRING ProcessName;
    DWORD BasePriority;
    DWORD ProcessId;
    DWORD InheritedFromProcessId;
    DWORD HandleCount;
    DWORD Reserved2[
2
];
    DWORD VmCounters;
    DWORD dCommitCharge;
    PVOID ThreadInfos[
1
];
}SYSTEM_PROCESS_INFORMATION, 
*
PSYSTEM_PROCESS_INFORMATION;

#define SystemProcessesAndThreadsInformation 5


void main()
{
    HMODULE hNtDll 
= GetModuleHandle(L"ntdll.dll"
);
    
if(!
hNtDll)
        
return
;
    ZWQUERYSYSTEMINFORMATION ZwQuerySystemInformation 
= (ZWQUERYSYSTEMINFORMATION)GetProcAddress(hNtDll,"ZwQuerySystemInformation"
);
    ULONG cbBuffer 
= 0x10000
;
    LPVOID pBuffer 
=
 NULL;
    pBuffer 
=
 malloc(cbBuffer);
    
if(pBuffer ==
 NULL)
        
return
;
    ZwQuerySystemInformation(SystemProcessesAndThreadsInformation,pBuffer,cbBuffer,NULL);
    PSYSTEM_PROCESS_INFORMATION pInfo 
=
 (PSYSTEM_PROCESS_INFORMATION)pBuffer;
    
for
(;;)
    {
        wprintf(L
"PID: %d (%ls) ",pInfo->ProcessId,pInfo->
ProcessName.Buffer);
        
if(pInfo->NextEntryDelta == 0
)
            
break
;
        pInfo 
= (PSYSTEM_PROCESS_INFORMATION)(((PUCHAR)pInfo) + pInfo->
NextEntryDelta);
    }
    free(pBuffer);
    getchar();
}

代码在VS2005 release + XP SP2调试通过

4、通过进程打开的句柄来枚举进程

同样使用ZwQuerySystemInformation函数,使用SystemHandleInformation系统调用

相关代码如下:

 

#include <windows.h>
#include 
<ntsecapi.h>
#include 
<ntstatus.h>
#include 
<stdio.h>

typedef NTSTATUS (WINAPI 
*ZWQUERYSYSTEMINFORMATION)(DWORD, PVOID, DWORD, PDWORD);

typedef 
struct
 _SYSTEM_HANDLE_INFORMATION 
{
    ULONG ProcessId;
    UCHAR ObjectTypeNumber;
    UCHAR Flags;
    USHORT Handle;
    PVOID Object;
    ACCESS_MASK GrantedAccess;
}SYSTEM_HANDLE_INFORMATION, 
*
PSYSTEM_HANDLE_INFORMATION;

typedef 
struct
 _SYSTEM_HANDLE_INFORMATION_EX 
{
    ULONG NumberOfHandles;
    SYSTEM_HANDLE_INFORMATION Information[
1
];
}SYSTEM_HANDLE_INFORMATION_EX, 
*
PSYSTEM_HANDLE_INFORMATION_EX;

#define SystemHandleInformation 0x10   //16


void main()
{
    HMODULE hNtDll 
= LoadLibrary(L"ntdll.dll"
);
    
if(!
hNtDll)
        
return
;
    ZWQUERYSYSTEMINFORMATION ZwQuerySystemInformation 
= (ZWQUERYSYSTEMINFORMATION)GetProcAddress(hNtDll,"ZwQuerySystemInformation"
);
    ULONG cbBuffer 
= 0x4000
;
    LPVOID pBuffer 
=
 NULL;
    NTSTATUS s;
    
do

    {
        pBuffer 
= malloc(cbBuffer);
        
if(pBuffer ==
 NULL)
            
return
;
        memset(pBuffer,
0
,cbBuffer);
        s 
=
 ZwQuerySystemInformation(SystemHandleInformation,pBuffer,cbBuffer,NULL);
        
if(s ==
 STATUS_INFO_LENGTH_MISMATCH)
        {
            free(pBuffer);
            cbBuffer 
= cbBuffer * 2
;
        }
    }
while(s ==
 STATUS_INFO_LENGTH_MISMATCH);

    PSYSTEM_HANDLE_INFORMATION_EX pInfo 
=
 (PSYSTEM_HANDLE_INFORMATION_EX)pBuffer;
    ULONG OldPID 
= 0
;
    
for(DWORD i = 0;i<pInfo->NumberOfHandles;i++
)
    {
        
if(OldPID != pInfo->
Information[i].ProcessId)
        {
            OldPID 
= pInfo->
Information[i].ProcessId;
            wprintf(L
"PID: %d "
,OldPID);
        }
    }
    free(pBuffer);
    FreeLibrary(hNtDll);
    getchar();
}

另外,在进行进程“隐藏”工作的时候,此处的句柄是一件容易被忽略的地方,因此需要注意隐藏由程序打开的相关句柄,由于系统中句柄数量经常变换,所以没有什么必要修改其中的NumberOfHandles域,因为如果修改此处的值,则需要不停对句柄的变化进行维护,开销比较大。

 

在用户态下的进程枚举已经变得不可靠,因为一个内核级的Rootkit很容易就能够更改这些函数的返回结果,因此进程的可靠枚举应在内核态中实现,可以通过编写驱动来实现

 
原创粉丝点击