设为首页 加入收藏

TOP

VC++实现恢复SSDT(四)
2013-05-03 18:09:51 来源: 作者: 【 】 浏览:161
Tags:实现 恢复 SSDT

 

  status=ZwQuerySystemInformation(SystemModuleInformation,List,size,0);

  if(!NT_SUCCESS(status))

  {

  KdPrint(("[FindModuleByAddress] query failed\n"));

  //打印错误

  KdPrint(("[FindModuleByAddress] status: 0x%x\n",status));

  ExFreePool( List );

  return ;

  }

  //得到了模块链表

  //判断模块名

  for( i=0; i<List->ulCount; i++)

  {

  //得到模块的范围

  minAddress = (ULONG)List->smi[i].Base;

  maxAddress = minAddress + List->smi[i].Size;

  //判断地址

  if( Address >= minAddress && Address <= maxAddress )

  {

  memcpy( buffer, List->smi[i].ImageName,sizeof(List->smi[i].ImageName));

  KdPrint(("[FindModuleByAddress] modulename: %s\n",buffer));

  //释放内存

  ExFreePool(List);

  break;

  }

  }

  }

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

  *

  *   函数名:GetOriFunctionAddress

  *   功能描述:得到原始SSDT表中函数地址

  *

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

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

  *

  *   原理: 找到内核文件,获取基址BaseAddress

  *           根据内核文件查找SSDT表的文件偏移SSDTFileOffset = SSDTRVA-(节RVA-节Offset)

  *           读取函数的文件偏移FunctionFileOffset

  *           VA=BaseAddress+FunctionFileOffset-00400000=800d8000 + FunctionFileOffset

  *

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

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

  *

  *   根据RVA查找所在的文件偏移:FileOffset = Rva- (节Rva - 节Offset)

  *   找到区块表

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

  ULONG FindFileOffsetByRva( ULONG ModuleAddress,ULONG Rva)

  {

  PIMAGE_DOS_HEADER dos;

  PIMAGE_FILE_HEADER file;

  PIMAGE_SECTION_HEADER section;

  //区块数目

  ULONG number;

  ULONG i;

  ULONG minAddress;

  ULONG maxAddress;

  ULONG SeFileOffset;

  ULONG FileOffset;

  dos = (PIMAGE_DOS_HEADER)ModuleAddress;

  file = (PIMAGE_FILE_HEADER)( ModuleAddress + dos->e_lfanew + 4 );

  //得到区块数量

  number = file->NumberOfSections;

  KdPrint(("[FindFileOffsetByRva] number :0x%x\n",number));

  //得到第一个区块地址

  section = (PIMAGE_SECTION_HEADER)(ModuleAddress + dos->e_lfanew + 4 + sizeof(IMAGE_FILE_HEADER) + file->SizeOfOptionalHeader);

  for( i=0;i<number;i++)

  {

  minAddress = section[i].VirtualAddress;

  maxAddress = minAddress + section[i].SizeOfRawData;

  SeFileOffset = section[i].PointerToRawData;

  if( Rva > minAddress && Rva < maxAddress)

  {

  KdPrint(("[FindFileOffsetByRva] minAddress :0x%x\n",minAddress));

  KdPrint(("[FindFileOffsetByRva] SeFileOffset :0x%x\n",SeFileOffset));

  FileOffset = Rva - ( minAddress - SeFileOffset);

  KdPrint(("[FindFileOffsetByRva] FileOffset :0x%x\n",FileOffset));

  break ;

  }

  }

  return FileOffset;

  }

  //路径解析出子进程名

  void  GetModuleName( char *ProcessPath, char *ProcessName)

  {

  ULONG n = strlen( ProcessPath) - 1;

  ULONG i = n;

  KdPrint(("%d",n));

  while( ProcessPath[i] != '\\')

  {

  i = i-1;

  }

  strncpy( ProcessName, ProcessPath+i+1,n-i);

  }

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

  *

  *   根据传入的服务号得到函数原始地址

  *

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

  ULONG FindOriAddress( ULONG index )

  {

  //根据传入的index得到函数VA地址

  //重定位函数地址

  //BaseAddress - 0x00400000 + *(PULONG)(FileOffset+(index*4))

  //ZwQuerySystemInformation得到内核文件基地址

  //得到SSDT表的地址

  //得到SSDT RVA 查找SSDT RVA所在的节

  NTSTATUS status;

  ULONG size;

  ULONG BaseAddress;

  ULONG SsdtRva;

  ULONG FileOffset = 0;

  PSYSMODULELIST list;

  char Name[32]={0};

  char PathName[256] = "\\SystemRoot\\system32\\";

  ANSI_STRING name;

  UNICODE_STRING modulename;

  OBJECT_ATTRIBUTES  object_attributes;

  IO_STATUS_BLOCK io_status = {0};

  HANDLE hFile;

  //读取的位置

  ULONG location;

  LARGE_INTEGER offset;

  ULONG address;

  //得到需要申请的内存大小

  ZwQuerySystemInformation( SystemModuleInformation,&size,0,&size );

  //申请内存

  list = (PSYSMODULELIST) ExAllocatePool( NonPagedPool,size );

  //验证是否申请成功

  if( list == NULL)

  {

  //申请失败

  KdPrint(("[FindOriAddress] malloc memory failed\n"));

  ExFreePool(list);

  return 0;

  }

  status = ZwQuerySystemInformation( SystemModuleInformation,list,size,0);

  if( !NT_SUCCESS( status ))

  {

  //获取信息失败

  KdPrint(("[FindOriAddress] query failed\n"));

  KdPrint(("[FindOriAddress] status:0x%x\n",status));

  ExFreePool(list);

  return 0;

  }

  //得到模块基址,第一个模块为内核文件

  BaseAddress = (ULONG )list->smi[0].Base;

  KdPrint(("[FindOriAddress] BaseAddress:0x%x\n",BaseAddress));

  //分离出内核文件名

  GetModuleName(list->smi[0].ImageName,Name);

  KdPrint(("[FindOriAddress] processname:%s\n",Name));

  strcat(PathName,Name);

  RtlInitAnsiString(&name,PathName);

  RtlAnsiStringToUnicodeString(&modulename,&name,TRUE);

  KdPrint(("[FindOriAddress] modulename: %wZ\n",&modulename));

  ExFreePool(list);

  //经验证地址正确

  //得到SSDT表的Rva

  SsdtRva = (ULONG)KeServiceDescriptorTable->ServiceTableBase - BaseAddress;

  //验证

  KdPrint(("[FindOriAddress] SsdtRva:0x%x\n",SsdtRva));

  //根据RVA查找文件偏移,//得到文件偏移了

  FileOffset= FindFileOffsetByRva( BaseAddress,SsdtRva);

  KdPrint(("[FindOriAddress] FileOffset:0x%x\n",FileOffset));

  //读取的位置

  location = FileOffset + index * 4;

  offset.QuadPart =location;

  KdPrint(("[FindOriAddress] location:0x%x\n",location));

  //利用ZwReadFile读取文件

  //初始化OBJECT_ATTRIBUTES结构

  InitializeObjectAttributes(

  &object_attributes,

  &modulename,

  OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,

  NULL,

  NULL);

  //打开文件

  status = ZwCreateFile(

  &hFile,

  FILE_EXECUTE | SYNCHRONIZE,

  &object_attributes,

  &io_status,

  NULL,

  FILE_ATTRIBUTE_NORMAL,

  FILE_SHARE_READ,

  FILE_OPEN,

  FILE_NON_DIRECTORY_FILE |

  FILE_RANDOM_ACCESS |

  FILE_SYNCHRONOUS_IO_NONALERT,

  NULL,

  0);

  if( !NT_SUCCESS( status ))

  {

  KdPrint(("[FindOriAddress] open error\n"));

  KdPrint(("[FindOriAddress] status = 0x%x\n", status));

  ZwClose( hFile );

  return 0;

  }

  status = ZwReadFile(

  hFile,

  NULL,

  NULL,

  NULL,

  NULL,

  &address,

  sizeof(ULONG),

  &offset,

  NULL);

  if( !NT_SUCCESS( status ))

  {

  KdPrint(("[FindOriAddress] read error\n"));

  KdPrint(("[FindOriAddress] status = 0x%x\n", status));

  ZwClose( hFile );

  return 0;

  }

  KdPrint(("[FindOriAddress] address:0x%x\n",address));

  //重定位

  address = BaseAddress - 0x00400000 + address;

  KdPrint(("[FindOriAddress] Oriaddress:0x%x\n",address));

  //释放动态分配的内存

  RtlFreeUnicodeString(&modulename);

  ZwClose( hFile );

  return address;

  }

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

  *

  *   得到SSDT Shadow当前地址

  *   1、KeServiceDescriptorTable -  0x40 + 0x10

  *   2、搜索KeAddSystemServiceTable函数,特征码

  *   3、Kthread->ServiceTable指向

  *   4、MJ提出的搜索特定内存

  *

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

  //方式1,XP下-0x40;

  ULONG GetSSDTShadowAddress1()

  {

  ULONG address;

  ULONG ssdt;

  ssdt = (ULONG)KeServiceDescriptorTable;

  address = ssdt - 0x30;

  KdPrint(("[GetSSDTShadowAddress] ssdt:0x%x\n",ssdt));

  KdPrint(("[GetSSDTShadowAddress] address:0x%x\n",address));

  return address;

  }

  //方式2

  ULONG GetSSDTShadowAddress2()

  {

  ULONG address;

  PUCHAR addr;

  PUCHAR p;

  addr = (PUCHAR)KeAddSystemServiceTable;

  for( p=addr; p<addr+PAGE_SIZE; p++)

  {

  if(*(PUSHORT)p == 0x888D)

  {

  address = *(PULONG)((ULONG)p+2);

  break;

  }

  }

  address = address + 0x10;

  KdPrint(("[GetSSDTShadowAddress] address:0x%x\n",address));

  return address;

  }

        

首页 上一页 1 2 3 4 5 下一页 尾页 4/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇VC++实现枚举进程与模块 下一篇char [] 和 char * 区别

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: