首页
社区
课程
招聘
[分享]遍历内核导入模块及导出IAT的方法
发表于: 2011-7-29 16:19 8362

[分享]遍历内核导入模块及导出IAT的方法

2011-7-29 16:19
8362
不敢说是原创的呀,只能算分享。因为都是取之看雪,还之看雪嘛
下面是我写的一个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期)

收藏
免费 0
支持
分享
最新回复 (4)
雪    币: 39
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
沙发自己坐啦
2011-7-29 16:26
0
雪    币: 54
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
支持代码分享!
2011-7-29 16:40
0
雪    币: 130
活跃值: (1005)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
LZ能把完整代码发出来吗
2011-12-15 00:52
0
雪    币: 227
活跃值: (66)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
5
能检测原始地址的话会更好~
2011-12-17 14:17
0
游客
登录 | 注册 方可回帖
返回
//