簡單說,即調用第11號功能,枚舉一下內核中已加載的模塊。
部分代碼如下:
//功能號爲11,先獲取所需的緩衝區大小
ZwQuerySystemInformation(SystemModuleInformation,NULL,0,&needlen);
//申請內存
ZwAllocateVirtualMemory(NtCurrentProcess(),(PVOID*)&pBuf,0,&needlen,MEM_COMMIT,PAGE_READWRITE);
//再次調用
ZwQuerySystemInformation(SystemModuleInformation,(PVOID)pBuf,truelen,&needlen);
......
//最後,釋放內存
ZwFreeVirtualMemory(NtCurrentProcess(),(PVOID*)&pBuf,&needlen,MEM_RELEASE);
突出過程,省略了錯誤判斷,和調用其它的功能時操作並沒有什麼區別。
關鍵在返回的內容中,緩衝區pBuf的前四個字節是已加載的模塊總數,記爲ModuleCnt,接下來就是共有ModuleCnt個元素的模塊信息數組了。
該結構如下:
typedef struct _SYSTEM_MODULE_INFORMATION {
ULONG Count;
SYSTEM_MODULE_INFORMATION_ENTRY Module[1];
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;
模塊詳細信息結構如下:
typedef struct _SYSTEM_MODULE_INFORMATION_ENTRY {
HANDLE Section;
PVOID MappedBase;
PVOID Base;
ULONG Size;
ULONG Flags;
USHORT LoadOrderIndex;
USHORT InitOrderIndex;
USHORT LoadCount;
USHORT PathLength;
CHAR ImageName[256];
} SYSTEM_MODULE_INFORMATION_ENTRY, *PSYSTEM_MODULE_INFORMATION_ENTRY;
一個for循環,循環ModuleCnt次就OK了。
基於此,寫了三個簡單的函數。
void ShowAllModules(char *pBuf)
{
//函數功能:輸出所有模塊信息
//參數pBuf:ZwQuerySystemInformation返回的緩衝區首址
PSYSTEM_MODULE_INFORMATION_ENTRY pSysModuleInfo;
DWORD Modcnt=0;
Modcnt=*(DWORD*)pBuf;
pSysModuleInfo=(PSYSTEM_MODULE_INFORMATION_ENTRY)(pBuf+sizeof(DWORD));
for (DWORD i=0;i<Modcnt;i++)
{
printf("%d\t0x%08X 0x%08X %s\n",pSysModuleInfo->LoadOrderIndex,pSysModuleInfo->Base,pSysModuleInfo->Size,pSysModuleInfo->ImageName);
pSysModuleInfo++;
}
}
void GetOSKrnlInfo(char *pBuf,DWORD *KernelBase,char *szKrnlPath)
{
//函數功能:返回系統內核(ntoskrnl.exe或ntkrnlpa.exe)的基址和路徑
//參數pBuf:ZwQuerySystemInformation返回的緩衝區首址
//參數KernelBase:接收返回的系統內核的基址
//參數szKrnlPath:接收返回的內核文件的路徑
PSYSTEM_MODULE_INFORMATION_ENTRY pSysModuleInfo;
DWORD Modcnt=0;
*KernelBase=0;
Modcnt=*(DWORD*)pBuf;
pSysModuleInfo=(PSYSTEM_MODULE_INFORMATION_ENTRY)(pBuf+sizeof(DWORD));
//其實第一個模塊就是了,還是驗證一下吧
if (strstr((strlwr(pSysModuleInfo->ImageName),pSysModuleInfo->ImageName),"nt"))
{
*KernelBase=(DWORD)pSysModuleInfo->Base;
GetSystemDirectory(szKrnlPath,MAX_PATH);
lstrcat(szKrnlPath,strrchr(pSysModuleInfo->ImageName,'\\'));
}
}
void DetectModule(char *pBuf,DWORD dwAddress,char *ModulePath)
{
//函數功能:找出給定地址所在的模塊
//參數pBuf:緩衝區地址,同上
//參數dwAddress:要查詢的內核地址
//參數ModulePath:接收返回的模塊路徑
PSYSTEM_MODULE_INFORMATION_ENTRY pSysModuleInfo;
DWORD Modcnt=0;
Modcnt=*(DWORD*)pBuf;
pSysModuleInfo=(PSYSTEM_MODULE_INFORMATION_ENTRY)(pBuf+sizeof(DWORD));
for (DWORD i=0;i<Modcnt;i++)
{
if ((dwAddress>=(DWORD)pSysModuleInfo->Base)&&(dwAddress<(DWORD)pSysModuleInfo->Base+pSysModuleInfo->Size))
{
lstrcpy(ModulePath,pSysModuleInfo->ImageName);
}
pSysModuleInfo++;
}
}
該功能是通過遍歷PsLoadedModuleList實現的,所以要隱藏的話,最簡單的方法還是斷鏈~~
更高級的方法比如抹DriveObject,抹PE信息等等,以後再玩~
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1.接口說明
NTKERNELAPI NTSTATUS ZwQuerySystemInformation(
IN ULONG SystemInformationClass,
IN OUT PVOID SystemInformation,
IN ULONG SystemInformationLength,
IN PULONG ReturnLength OPTIONAL );
第一個參數是一個枚舉類型,傳入的是你需要查詢的信息的類型以下是這個enmu類型的定義。
typedef enum _SYSTEM_INFORMATION_CLASS {
SystemBasicInformation, // 0 Y N
SystemProcessorInformation, // 1 Y N
SystemPerformanceInformation, // 2 Y N
SystemTimeOfDayInformation, // 3 Y N
SystemNotImplemented1, // 4 Y N
SystemProcessesAndThreadsInformation, // 5 Y N
SystemCallCounts, // 6 Y N
SystemConfigurationInformation, // 7 Y N
SystemProcessorTimes, // 8 Y N
SystemGlobalFlag, // 9 Y Y
SystemNotImplemented2, // 10 Y N
SystemModuleInformation, // 11 Y N 枚舉內核模塊時用
SystemLockInformation, // 12 Y N
SystemNotImplemented3, // 13 Y N
SystemNotImplemented4, // 14 Y N
SystemNotImplemented5, // 15 Y N
SystemHandleInformation, // 16 Y N
SystemObjectInformation, // 17 Y N
SystemPagefileInformation, // 18 Y N
SystemInstructionEmulationCounts, // 19 Y N
SystemInvalidInfoClass1, // 20
SystemCacheInformation, // 21 Y Y
SystemPoolTagInformation, // 22 Y N
SystemProcessorStatistics, // 23 Y N
SystemDpcInformation, // 24 Y Y
SystemNotImplemented6, // 25 Y N
SystemLoadImage, // 26 N Y
SystemUnloadImage, // 27 N Y
SystemTimeAdjustment, // 28 Y Y
SystemNotImplemented7, // 29 Y N
SystemNotImplemented8, // 30 Y N
SystemNotImplemented9, // 31 Y N
SystemCrashDumpInformation, // 32 Y N
SystemExceptionInformation, // 33 Y N
SystemCrashDumpStateInformation, // 34 Y Y/N
SystemKernelDebuggerInformation, // 35 Y N
SystemContextSwitchInformation, // 36 Y N
SystemRegistryQuotaInformation, // 37 Y Y
SystemLoadAndCallImage, // 38 N Y
SystemPrioritySeparation, // 39 N Y
SystemNotImplemented10, // 40 Y N
SystemNotImplemented11, // 41 Y N
SystemInvalidInfoClass2, // 42
SystemInvalidInfoClass3, // 43
SystemTimeZoneInformation, // 44 Y N
SystemLookasideInformation, // 45 Y N
SystemSetTimeSlipEvent, // 46 N Y
SystemCreateSession, // 47 N Y
SystemDeleteSession, // 48 N Y
SystemInvalidInfoClass4, // 49
SystemRangeStartInformation, // 50 Y N
SystemVerifierInformation, // 51 Y Y
SystemAddVerifier, // 52 N Y
SystemSessionProcessesInformation // 53 Y N
}SYSTEM_INFORMATION_CLASS;
2.調用方式:
(1).功能號爲11,先獲取所需的緩衝區大小
(1).功能號爲11,先獲取所需的緩衝區大小
ZwQuerySystemInformation(SystemModuleInformation,NULL,0,&needlen);
(2).申請內存
Ring3層 ZwAllocateVirtualMemory(NtCurrentProcess(),(PVOID*)&pBuf,0,&needlen,MEM_COMMIT,PAGE_READWRITE);
Ring0層 ExAllocatePool( NonPagedPool, NeedSize );
(3).再次調用
ZwQuerySystemInformation(SystemModuleInformation,(PVOID)pBuf,truelen,&needlen);
......
(4).最後,釋放內存
Ring3層 ZwFreeVirtualMemory(NtCurrentProcess(),(PVOID*)&pBuf,&needlen,MEM_RELEASE);
Ring0層 ExFreePool(pBuffer);
3.返回數據:
緩衝區pBuf的前四個字節是已加載的模塊總數,記爲ModuleCnt。接下來就是共有ModuleCnt個元素的模塊信息數組了。
該結構如下:
typedef struct _SYSTEM_MODULE_INFORMATION {
ULONG Count;
SYSTEM_MODULE_INFORMATION_ENTRY Module[1];
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;
模塊詳細信息結構如下:
typedef struct _SYSTEM_MODULE_INFORMATION_ENTRY {
HANDLE Section;
PVOID MappedBase;
PVOID Base;
ULONG Size;
ULONG Flags;
USHORT LoadOrderIndex;
USHORT InitOrderIndex;
USHORT LoadCount;
USHORT PathLength;
CHAR ImageName[256];
}SYSTEM_MODULE_INFORMATION_ENTRY, *PSYSTEM_MODULE_INFORMATION_ENTRY;
4.基於pBuf的幾個函數封裝:
//函數功能:輸出所有模塊信息
//參數pBuf:ZwQuerySystemInformation返回的緩衝區首址
void ShowAllModules(char *pBuf)
{
PSYSTEM_MODULE_INFORMATION_ENTRY pSysModuleInfo;
DWORD Modcnt=0;
Modcnt=*(DWORD*)pBuf; //模塊數量
pSysModuleInfo=(PSYSTEM_MODULE_INFORMATION_ENTRY)(pBuf+sizeof(DWORD));
for (DWORD i=0;i<Modcnt;i++)
{
DbgPrint("%d/t0x%08X 0x%08X %s/n",pSysModuleInfo->LoadOrderIndex,pSysModuleInfo->Base,pSysModuleInfo->Size,pSysModuleInfo->ImageName);
pSysModuleInfo++;
}
}
//函數功能:返回系統內核(ntoskrnl.exe或ntkrnlpa.exe)的基址和路徑
//參數pBuf:ZwQuerySystemInformation返回的緩衝區首址
//參數KernelBase:接收返回的系統內核的基址
//參數szKrnlPath:接收返回的內核文件的路徑
void GetOSKrnlInfo(char *pBuf,DWORD *KernelBase,char *szKrnlPath)
{
PSYSTEM_MODULE_INFORMATION_ENTRY pSysModuleInfo;
DWORD Modcnt=0;
*KernelBase=0;
Modcnt=*(DWORD*)pBuf;
pSysModuleInfo=(PSYSTEM_MODULE_INFORMATION_ENTRY)(pBuf+sizeof(DWORD));
//其實第一個模塊就是了,還是驗證一下吧
if (strstr((strlwr(pSysModuleInfo->ImageName),pSysModuleInfo->ImageName),"nt"))
{
*KernelBase=(DWORD)pSysModuleInfo->Base;
GetSystemDirectory(szKrnlPath,MAX_PATH);
lstrcat(szKrnlPath,strrchr(pSysModuleInfo->ImageName,'//'));
}
}
//函數功能:找出給定地址所在的模塊
//參數pBuf:緩衝區地址,同上
//參數dwAddress:要查詢的內核地址
//參數ModulePath:接收返回的模塊路徑
void DetectModule(char *pBuf,DWORD dwAddress,char *ModulePath)
{
PSYSTEM_MODULE_INFORMATION_ENTRY pSysModuleInfo;
DWORD Modcnt=0;
Modcnt=*(DWORD*)pBuf;
pSysModuleInfo=(PSYSTEM_MODULE_INFORMATION_ENTRY)(pBuf+sizeof(DWORD));
for(DWORD i=0;i<Modcnt;i++)
{
if((dwAddress>=(DWORD)pSysModuleInfo->Base)&&(dwAddress<(DWORD)pSysModuleInfo->Base+pSysModuleInfo->Size))
{
lstrcpy(ModulePath,pSysModuleInfo->ImageName);
}
pSysModuleInfo++;
}
}