不敢说是原创的呀,只能算分享
。因为都是取之看雪,还之看雪嘛
。
下面是我写的一个SYS中的2个方法,作用是遍历内核当前模块信息,并可以打印出关注的模块的IAT,是否全部模块都适用没有测试,但查看我自己的SYS及ntkrnlpa是可以的。集合了几位大牛的代码,在这里谢谢大牛们,谢谢看雪
#include <winnt.h>
IMAGE_DOS_HEADER* pDosHeader;
IMAGE_OPTIONAL_HEADER * pOptHeader;
IMAGE_IMPORT_DESCRIPTOR * pImportDesc;
HANDLE hanSection = NULL;
HANDLE hFile = NULL;
PVOID MapFileBaseAddress = NULL;
NTSTATUS FUNC_TEST_EVENT(){
NTSTATUS _statu = STATUS_SUCCESS;
ULONG _size;
ULONG cbBuffer = 0x10000;
ULONG dwCount = 0;
PSYSTEM_MODULE_INFORMATION mList = NULL;
IMAGE_THUNK_DATA * pFirstThunk ;
IMAGE_THUNK_DATA * pOriginalFirstThunk;
IMAGE_IMPORT_BY_NAME * pImpName;
char* pimFuncName;
ULONG * pThuk;
ULONG * funcRva;
UNICODE_STRING ptrDriverName;
ANSI_STRING anStrPath;
/*ZwQuerySystemInformation获取系统信息,第一个参数指定要获取的信息类型。
先调用一次函数是为了为了获取size*/
_statu = ZwQuerySystemInformation(SystemModuleInformation,&_size,0,&_size);
KdPrint(("[FindModuleByAddress] size:0x%x\n",_size));
//堆中开辟一块大小为size的不分页内存
mList = (PSYSTEM_MODULE_INFORMATION)ExAllocatePool(NonPagedPool, _size);
if(mList == NULL){
KdPrint(("ExAllocatePool error \n"));
return STATUS_DATA_ERROR;
}
//获取系统内核模块信息
_statu = ZwQuerySystemInformation(SystemModuleInformation,mList,_size,NULL);
if(!NT_SUCCESS(_statu)){
KdPrint(("ZwQuerySystemInformation error status: 0x%x\n",_statu));
//填充失败就释放内存
ExFreePool(mList);
return STATUS_DATA_ERROR;
}
for (dwCount = 0;dwCount < mList->ModulesCount;dwCount++)
{
/*KdPrint(("The address of %s is %8X \n",
(mList->Modules[dwCount].ImageName),
mList->Modules[dwCount].ImageBaseAddress));*/
/*找到关注的模块,提取模块在内存中的基址。
ImageName是带路径的,ImageNameOffset是路径部分的长度*/
if(strcmp((mList->Modules[dwCount].ImageName + mList->Modules[dwCount].ImageNameOffset)
,"ntkrnlpa.exe") == 0){
PNTKRNLPABASE = mList->Modules[dwCount].ImageBaseAddress;
KdPrint(("The address of %s is %8X \n",
(mList->Modules[dwCount].ImageName + mList->Modules[dwCount].ImageNameOffset),
mList->Modules[dwCount].ImageBaseAddress));
}
}
ExFreePool(mList);
/*这里别人使用的是上面得到的ImageName,不过在我的电脑上BSOD咯,
无奈下这里用了硬编码,BSOD的问题有时间再解决*/
RtlInitUnicodeString(&ptrDriverName,L"\\??\\C:\\WINDOWS\\system32\\ntkrnlpa.exe");
_statu = MAPFILE_AND_GETBASE(&ptrDriverName);
if(!NT_SUCCESS(_statu)){
KdPrint((" NTSTATUS = %X \n",_statu));
return _statu;
}
KdPrint((" PNTKRNLPABASE->%0X ;",PNTKRNLPABASE));
KdPrint((" pImportDesc->%0X \n",pImportDesc));
KdPrint((" MapFileBaseAddress->%0X \n",MapFileBaseAddress));
dwCount = 1;
/*这个地方写的时候很纠结,蓝了无数次,最后还是看雪大大们的文章解决了问题,也才会有今天这一篇。*/
while(pImportDesc->OriginalFirstThunk != 0){
KdPrint((" DLL NAME -> %s \n",
(char*)((BYTE*)PNTKRNLPABASE + pImportDesc->Name)));
/*由于ntkrnlpa在加载后移除了IMAGE_IMPORT_DESCRIPTOR结构,
所以这里才使用了双向比较的方法获取THUNK,也就是为什么这段看起来这么纠结。
如果是其他的exe或sys的话,上面映射文件那步可以省略,直接在加载的模块
里找就可以。*/
pThuk = (ULONG*)((BYTE*)MapFileBaseAddress + pImportDesc->OriginalFirstThunk);
funcRva = (ULONG*)((BYTE*)PNTKRNLPABASE +pImportDesc->FirstThunk);
KdPrint((" OriginalFirstThunk->%0X ; FirstThunk->%0X \n",pThuk,funcRva));
while(*pThuk != 0){
//这里要小心,内存映射中的pThuk是偏移不是地址
pImpName = (IMAGE_IMPORT_BY_NAME *)((BYTE*)PNTKRNLPABASE + *pThuk);
KdPrint((" No. %d : Hint->%d; Name->%s; Address->%0X\n",
dwCount,
pImpName->Hint,
(char*)pImpName->Name1,
*funcRva));
pThuk++;
dwCount++;
funcRva++;
}
pImportDesc++;
}
ZwUnmapViewOfSection(ZwCurrentProcess(),MapFileBaseAddress);
ZwClose(hanSection);
ZwClose(hFile);
KdPrint((" step->5->CloseFileHandle \n"));
return _statu;
}
NTSTATUS MAPFILE_AND_GETBASE(PUNICODE_STRING pDriverName){
SIZE_T size=0;
IO_STATUS_BLOCK stataus;
OBJECT_ATTRIBUTES oa ;
NTSTATUS _stu;
IMAGE_DOS_HEADER * ptrDosHeader;
IMAGE_OPTIONAL_HEADER * ptrOptHeader;
InitializeObjectAttributes(&oa,pDriverName,OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,NULL,NULL);
KdPrint((" step->1 \n"));
_stu = ZwOpenFile(&hFile, GENERIC_ALL, &oa, &stataus,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_NONALERT);
/*_stu = ZwCreateFile(&hFile,FILE_GENERIC_WRITE,&oa,&stataus,NULL,
FILE_ATTRIBUTE_NORMAL,FILE_SHARE_READ,FILE_OPEN_IF,
FILE_SYNCHRONOUS_IO_NONALERT,NULL,0);*/
if (!NT_SUCCESS(_stu))
{
KdPrint(("<==============ZwOpenFile STATUS->ERROR : %0X \n",_stu));
return _stu;
}
KdPrint((" step->2->hFile->%0X \n",hFile));
oa.ObjectName = 0;
_stu = ZwCreateSection(&hanSection,SECTION_ALL_ACCESS,&oa,0,
PAGE_EXECUTE_READWRITE, SEC_IMAGE, hFile);
if (!NT_SUCCESS(_stu))
{
KdPrint(("<==============ZwCreateSection STATUS->ERROR : %0X \n",_stu));
ZwClose(hFile);
return _stu;
}
KdPrint((" step->3->hanSection->%0X \n",hanSection));
_stu = ZwMapViewOfSection(hanSection,ZwCurrentProcess(),
&MapFileBaseAddress, 0, 1024,0, &size,
ViewShare,MEM_TOP_DOWN, PAGE_READWRITE);
if (!NT_SUCCESS(_stu))
{
KdPrint(("<==============ZwMapViewOfSection STATUS->ERROR : %0X \n",_stu));
ZwClose(hFile);
ZwClose(hanSection);
return _stu;
}
__try{
/*由于我还很菜,所以这个地方代码写的丑*/
if ((ULONG)MapFileBaseAddress < 0x80000000L)
{
ProbeForRead(MapFileBaseAddress,size,1L);
}
}__except(EXCEPTION_EXECUTE_HANDLER){
KdPrint((" MapFileBaseAddress can not read \n"));
ZwUnmapViewOfSection(ZwCurrentProcess(),MapFileBaseAddress);
ZwClose(hFile);
ZwClose(hanSection);
return STATUS_ACCESS_DENIED;
}
KdPrint((" step->4->mapFileBase->%0X \n",MapFileBaseAddress));
/*基址就是PE的IMAGE_DOS_HEADER*/
ptrDosHeader = (IMAGE_DOS_HEADER *)MapFileBaseAddress;
KdPrint((" ptrDosHeader.e_magic-> %8X,ptrDosHeader.e_lfanew-> %8X \n",
ptrDosHeader->e_magic,ptrDosHeader->e_lfanew));
//定位到PE HEADER
//基址hMod加上IMAGE_DOS_HEADER结构的e_lfanew成员到达IMAGE_NT_HEADERS
//NT文件头的前4字节是文件签名("PE00" 字符串),然后是20字节的IMAGE_FILE_HEADER结构
//即到达IMAGE_OPTIONAL_HEADER结构的地址,获取了一个指向IMAGE_OPTIONAL_HEADER结构体的指针
ptrOptHeader = (IMAGE_OPTIONAL_HEADER *)((BYTE*)MapFileBaseAddress + ptrDosHeader->e_lfanew + 24);
//定位到导入表
//通过IMAGE_OPTIONAL_HEADER结构中的DataDirectory结构数组中的第二个成员中的
//VirturalAddress字段定位到IMAGE_IMPORT_DESCRIPTOR结构的起始地址
//即获得导入表中第一个IMAGE_IMPORT_DESCRIPTOR结构的指针(导入表首地址)
//DataDirectory[0]是导出表
pImportDesc = (IMAGE_IMPORT_DESCRIPTOR*)
((BYTE*)MapFileBaseAddress + ptrOptHeader->DataDirectory[1].VirtualAddress);
return _stu;
}
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)