日期:2014-05-16  浏览次数:20897 次

模拟键盘鼠标操作——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,默认只保存了一个。在访问相关函数时,如