经过两天的折腾,终于模拟成功了。在此感谢坛友cvcvxk, 在我提出问题的时候给与我的回答和帮助,嘿嘿。。还有就是偶是小菜,可能你知道这种方法,切莫拍砖。。

  最近玩一个梦幻诛仙的游戏,有幸的google了下它的驱动保护。。网上有人发帖说它利用 int 0x21和int 0x22进行数据交互。。看后很心动,想模拟一下。。于是,操刀实验。。
  思路是:1,利用寄存器在ring3和ring0传递大量数据。想法可行,可操作太难,我想到的是难点是同步问题。中断进入内核貌似只会将错误码,eflags,cs,eip压栈,其他的很多寄存器,我们都可以使用,最起码的8个基本寄存器。用户层可以把它们pushad压栈,在中断结束操作完中断返回的数据再popad。
  思路2:利用共享物理内存和寄存器传递数据。这种方法我测试成功了,嘿嘿。在这种方法中,寄存器只是负责传递少量数据,在这我传递的是物理内存在用户空间的映射基址。
   首先,添加中断。。我添加的是0x24号中断
     IDTINFO m_idt = {0};   //IDTINFO是定义的一个保存中断寄存器的结构体
  __asm sidt m_idt;
  ULONG ulBase = m_idt.LowIDTbase;
  ulBase += (ULONG)(m_idt.HiIDTbase<<16);

  KdPrint(("idt的基地址x%x\n",ulBase));
    InterruptGate_t *idtentry = (InterruptGate_t *)ulBase; //InterruptGate_t保存的是中断项指针
     
__asm
  {
    cli
      push eax
      mov eax,cr0
      and eax,not 0x10000
      mov cr0,eax
      pop eax
  }
    idtentry[0x24].Dpl = 3;
    idtentry[0x24].OffsetHigh = (USHORT)((ULONG)bingle>>16);
    idtentry[0x24].OffsetLow = (USHORT)bingle;
    idtentry[0x24].Present = 1;
    idtentry[0x24].Reserved = 0;
    idtentry[0x24].SegmentType = 0xe;
         idtentry[0x24].Selector = 0x8;
         idtentry[0x24].SystemSegmentFlag = 0;
    __asm
    {
       push eax
         mov eax,cr0
         or eax,0x10000
         mov cr0,eax
         pop eax
         sti
    }  
      然后,中断历程函数比较纠结,我还没有摸透它为什么调用kdprint的时候有时会出错(ring3不能正常收数据)。可能还有很多限制,有研究过的可以告诉我。呵呵。。下边是Cvcvxk的框架,我只是修改了一个寄存器eax。这里有我纠结的问题,本来8个普通寄存器使用应该没问题的。可是有时候会出错。我没法摸透为什么。。
      ULONG ulBuf ;  //缓存的一个堆栈空间,没有初始化为0是因为在裸函数中
   __asm
   {
        pushad
      pushfd
      push ds
      push es
      push fs
      push eax
      mov eax, 0x23
      mov ds, ax
      mov es, ax
      mov eax, 0x30
      mov fs, ax
      pop eax
      
         call MapUserSpace  //MapUserSpace是用来映射的函数。。
      mov ulBuf,eax
      pop fs
      pop es
      pop ds
      popfd
      popad
      mov eax,ulBuf
      Iretd  //貌似中断返回就是iretd 不是sysexit呀  呵呵
   }
 接下来就是想法作映射了。我在ring0空间开辟了一页大小的空间。利用它来缓存交互的数据。

#pragma code_seg("PAGE")
__declspec(naked) VOID MapUserSpace()
{
  PVOID pBuf;
  pBuf = ExAllocatePool(NonPagedPool,0x1000);
  PMDL pMdl;
  pMdl = IoAllocateMdl(pBuf,0x1000,FALSE,FALSE,NULL);
  memset(pBuf,0xAA,100); //我把分配的空间数据初始化为0xAA,为了完成测试,ring3下可读出
  if(!pMdl) ExFreePool(pBuf);

  MmBuildMdlForNonPagedPool(pMdl);

  ULONG ulUserBase;
  ulUserBase =    (ULONG)MmMapLockedPagesSpecifyCache(pMdl,UserMode,MmCached,NULL,FALSE,NormalPagePriority);

  
  //KdPrint(("用户空间的基地址:x%x\n",ulUserBase));
    有这个打印函数会出错,不知道为什么。非得把这个打印函数单独放在一个自定义函数中调用,然后才ok。。。至此还是困惑
  __asm mov eax,ulUserBase
   __asm ret 
 }
接下来就是收尾工作,清理ExallocatePool分配的空间。。

在我测试中,ring3只负责接受映射后的基地址,然后从基地址读取数据。。
     LoadLibrary("user32.dll");//控制台程序
  DWORD dwBingle = 0;
  __asm int 0x24;
  
  __asm mov dwBingle,eax
  printf("Ox%x",dwBingle);
  printf("0x%x\n",*(BYTE *)dwBingle);//把0xaa读取出来了。

欠缺:我还没有进行ring3写入,ring0读取的测试。还没有搞明白为什么使用了打印函数会出错的问题。还没有透彻的理解假如直接在中断历程中使用8个寄存器会不会出错的问题。。。。。晚上回来继续研究,女友等我一块看书呢,嘿嘿!


最后再次感谢Cvcvxk,不知道我有没有拼错。。

  • 标 题:答复
  • 作 者:cvcvxk
  • 时 间:2011-09-18 12:05:16

还是的我来改改你的代码吧~~你这真复杂~

第一关于函数XX的修改~弄个stdcall直接return就好,naked反而容易挂花~,里面代码可以随意print~

代码:
DWORD __stdcall MapUserSpace(DWORD Arg1)
{
  PVOID pBuf;
  pBuf = ExAllocatePool(NonPagedPool,0x1000);
  PMDL pMdl;
  pMdl = IoAllocateMdl(pBuf,0x1000,FALSE,FALSE,NULL);
  memset(pBuf,0xAA,100); 
  if(!pMdl) ExFreePool(pBuf);

  MmBuildMdlForNonPagedPool(pMdl);

  ULONG ulUserBase;
  ulUserBase =    (ULONG)MmMapLockedPagesSpecifyCache(pMdl,UserMode,MmCached,NULL,FALSE,NormalPagePriority);

 return ulUserBase;
 }
第二对 中断的修改,既然是naked,那么就彻底naked!
__asm
   {
      push ebp
      mov ebp,esp
      sub esp,8h//8h差不多够了放2个值了,其实这里只保存一个局部变量
      pushad
      pushfd
      push ds
      push es
      push fs
      push eax
      mov eax, 0x23
      mov ds, ax
      mov es, ax
      mov eax, 0x30
      mov fs, ax
      pop eax
      push eax
      call MapUserSpace  //MapUserSpace是用来映射的函数。。
      mov [ebp-4],eax
      pop fs
      pop es
      pop ds
      popfd
      popad
      mov eax,[ebp-4]
      mov esp,ebp
      pop ebp
      Iretd 
   }