当前位置: 代码迷 >> Access >> 模拟键盘鼠标操作——IoAccessMap引见
  详细解决方案

模拟键盘鼠标操作——IoAccessMap引见

热度:3753   发布时间:2013-02-26 00:00:00.0
模拟键盘鼠标操作——IoAccessMap介绍
键词:I/O Permission Bit Map、按键精灵、模拟键盘鼠标

今天又被恶心了,上班不想工作。来谈谈IoAccessMap相关的一些东西吧。

我在上一篇XTrap驱动分析的文章里面提到过,现在的一些模拟键盘鼠标输入的程序使用了一种所谓硬件模式的东西,例如按键精灵。其实就是使用了WinIo这样一些打开进程在Ring3访问端口权限的库。这里会详细分析一下他们的实现机制,以及对付这些工具的推荐方法。

首先摘抄一段WinIo驱动里面的代码:

case IOCTL_WINIO_ENABLEDIRECTIO:

          OutputDebugString(“IOCTL_WINIO_ENABLEDIRECTIO”);

          pIOPM = MmAllocateNonCachedMemory(sizeof(IOPM));

          if (pIOPM)

          {

            RtlZeroMemory(pIOPM, sizeof(IOPM));

            Ke386IoSetAccessProcess(PsGetCurrentProcess(), 1);

            Ke386SetIoAccessMap(1, pIOPM);

          }

          else

            Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;

        break;



ok,打开端口权限的所有秘密就在这里了。不过我们要先介绍一下Inter CPU对IoAccessMap的定义。

I386架构下,每个进程拥有的TSS块包含一个I/O Permission Bit Map,其中定义了该进程对各个端口的读写权限。I/O Permission Bit Map的每一位对应一个端口。例如和鼠标键盘相关的端口对应于bit60和bit64。另外,在EFLAGS寄存器中的bit12、bit13指示了IN, INS, OUT, OUTS, CLI, STI这几条指令需要的IOPL。当CPL大于IOPL时,IO访问时就会再查询I/O Permission Bit Map里面对应bit是否为0,如果为0则允许IO访问,否则会触发general-protection exception (#GP)。

所以,如果要打开某个进程的IO权限,只需要修改它的I/O Permission Bit Map就可以了。

Windows为每个进程保存的TSS结构如下:

typedef struct _KTSS {

    USHORT Backlink;

    USHORT Reserved0;

    ULONG   Esp0;

    USHORT Ss0;

    USHORT Reserved1;

    ULONG   NotUsed1[4];

    ULONG   CR3;

    ULONG   Eip;

    ULONG   EFlags;

    ULONG   Eax;

    ULONG   Ecx;

    ULONG   Edx;

    ULONG   Ebx;

    ULONG   Esp;

    ULONG   Ebp;

    ULONG   Esi;

    ULONG   Edi;

    USHORT Es;

    USHORT Reserved2;

    USHORT Cs;

    USHORT Reserved3;

    USHORT Ss;

    USHORT Reserved4;

    USHORT Ds;

    USHORT Reserved5;

    USHORT Fs;

    USHORT Reserved6;

    USHORT Gs;

    USHORT Reserved7;

    USHORT LDT;

    USHORT Reserved8;

    USHORT Flags;

    USHORT IoMapBase;

    KIIO_ACCESS_MAP IoMaps[IOPM_COUNT];

    //

    // This is the Software interrupt direction bitmap associated with

    // IO_ACCESS_MAP_NONE

    //

    KINT_DIRECTION_MAP IntDirectionMap;

} KTSS, *PKTSS;



其中的IOPM_COUNT定义为1。貌似本来Windows想为每个Process保存多个IoAccessMap,默认只保存了一个。在访问相关函数时,如果制定MapNumber为0,则表示不使用IoAccessMap。所以0号map是虚拟出来的,这点在wrk1.2代码中可以确认。

以下三个函数用于访问IoAccessMap:

BOOLEAN Ke386QueryIoAccessMap(ULONG MapNumber, PKIO_ACCESS_MAP IoAccessMap);用于查询IoAccessMap

BOOLEAN Ke386SetIoAccessMap(ULONG MapNumber, PKIO_ACCESS_MAP IoAccessMap);用于设置IoAccessMap

BOOLEAN Ke386IoSetAccessProcess(PKPROCESS Process, ULONG MapNumber);用于设置某个Process使用的IoAccessMap号

下面分别讲一下三个函数的作用。

Ke386QueryIoAccessMap将系统KTSS中的IoMaps复制出来,也就是查询当前的IoAccessMap。MapNumber传入Map号,当为0的时候表示指定IO_ACCESS_MAP_NONE,此时将传入IoAccessMap的所有位置1,当MapNumber为其他值时,复制对应的Map。

Ke386SetIoAccessMap将IoAccessMap中的内容复制到指定MapNumber的内容中,当为0时返回FALSE,当为其他合法值时,Ke386SetIoAccessMap会创建一个DPC,并在DPC中将IoAccessMap的内容复制到进程TSS的IoMaps中。

Ke386IoSetAccessProcess则是设置Process使用的IoAccessMap号。同样,会创建一个DPC,并由DPC修改指定进程的EPROCESS中的IopmOffset。



Ok,回过头来看WinIo的代码就一目了然了

pIOPM = MmAllocateNonCachedMemory(sizeof(IOPM));

          if (pIOPM)

          {

            RtlZeroMemory(pIOPM, sizeof(IOPM));

            Ke386IoSetAccessProcess(PsGetCurrentProcess(), 1);

            Ke386SetIoAccessMap(1, pIOPM);

          }

(来自:码农源库,http://www.vcclass.net/wordpress/?p=344)
  相关解决方案