wowocock
VIP专家组
VIP专家组
  • 注册日期2002-04-08
  • 最后登录2016-01-09
  • 粉丝16
  • 关注2
  • 积分601分
  • 威望1651点
  • 贡献值1点
  • 好评度1227点
  • 原创分1分
  • 专家分0分
阅读:4008回复:13

Ring0 Call Ring3

楼主#
更多 发布于:2005-03-12 14:55
       pjf(jfpan20000@sina.com)
    很久没写什么东西,一来文笔太烂,二来我不是一般的懒。这个
东西一看题目也就知道又是一篇无聊的帖子,凑凑数先。
    因为最近决定把读本科时的古董机上的东西收拾一下,看到一些
最初学习时的老代码,回忆往日的时光,还颇有一些感慨呢...以后有
空就选一些贴贴,也不怕人笑了。今天第一帖,代码原是大二时为NT4
系统写的,是原先实践x86体系写的,作用是在Driver中“调用”用
户态的MessageBoxA做出显示。朋友都说:“你无聊不无聊,好多人写
过这个题目了”,呵呵,我只是把以前的东西贴贴,尽量少提及别人
说过的,可能初学者们会有收获呢。现在作了一点点修改,只在2000
上测了测,还可以跑跑。
    这就是一个Ring0 Call Ring3的问题。对于这个问题,在原先试
验之前网上就有一些讨论了,有了一些替代方案,比如说User APC。
记得见过最早的是应该是Anatoly Vorobey在某新闻组的发言,查了
查,他发帖是97年的时候,很古老了。最近www.rootkit.com贴出了
一篇关于ring0创建进程 的文章用的就是这个方法,不过仅是其一
个简单应用。
    UserAPC的代码网上很多。就不贴了,使用很方便很简单,只是注
意用时对Thread->ApcState.UserApcPending的处理。
    如果我们把处理控制的直接转移作为“调用”的基本要求,那么
依赖于系统间接转移的APC机制就算不上“调用”。那么Ring3代码如
何“调用”Ring0代码呢?方法是显然的,我们模拟这样一个场景:系
统通过某种机制(比如中断或是改变特权的调用)由ring3进入了
ring0时候的现场(主要是栈现场)。于是我们模拟好后,直接通过返
回指令达到直接控制转移的目的。当然,我们应当保存原始现场,以
便用户台代码执行完毕后能顺利回到“调用”指令后的第一条指令执
行(如同真正的call)。
    实质上windows自己也在用这个方法来进行一些有必要的核心态向
用户态的直接控制转移,即KeUserModeCallback。典型的例子就是
wind32k中的使用,“防止消息钩子注入”里也简单提到。
    当时2000还没出来,研究的比较多的是linux和9x的核,对于NT使用
此回调的具体过程就不甚清楚,现在源码都漏了颇久了,初学者们看起
来方便多了。下面我们自己不利用NT的代码,自己做一个类似的东西。
 下面仅仅讨论直接“调用”的基本方法。ring0转向ring3之前
首先要确保用户空间的合法性以及ring3代码与用户栈的合法性,这
一点根据需求会有许多做法,为了简单起见,调用的时机选在ring3
使用DeviceIoControl进入驱动例程时回调,回调的地址与用户栈均
由应用程序传入,这样使预处理最小化。
    驱动程序分派例程里只需写:

    switch(IoControlCode)
    {
    case IOCTL_CALL_RING3:
        {
            addr = *PULONG(InputBuffer); //ring3函数地址
            stack = *(PULONG(InputBuffer)+1);//ring3栈地址
            cfunc();
            return 0;
        }
    }

    其中cfunc函数即完成了向ring3的调用,其代码如下(很老的代码,
很凌乱,加了点注释):

void __declspec(naked) cfunc()
{
    _asm pushad
    _asm sidt buffer
    IdtEntry = (PIdtEntry_t)Idtr->Base;
    OldEntry = IdtEntry[HOOKINT];  //#define HOOKINT 0xF0
    _asm lea eax,interrupt
    _asm mov NewHandler,eax
    /*接管中断0xF0,目的是让应用程序能通过使用int 0f0h
    指令返回到核心态。
    int 0f0h起的作用正是等同于ret
    F0陷阱的处理函数恢复内核栈等至“调用”前的状态*/
    _asm cli
    IdtEntry[HOOKINT].Dpl        = 3;
    IdtEntry[HOOKINT].Type       = 0xF;
    IdtEntry[HOOKINT].Present    = 1;
    IdtEntry[HOOKINT].OffsetLow  = (unsigned short)NewHandler;
    IdtEntry[HOOKINT].OffsetHigh = \\
               (unsigned short)((unsigned int)NewHandler>>16);
    _asm sti
    _asm {
        str word ptr[tr]
        push eax
        sgdt [esp-2]
        pop eax
        movzx ebx,word ptr[tr]
        and ebx,0fffffff8h
        add eax,ebx
        mov ebx,[eax]
        and ebx,0ffff0000h
        shr ebx,16
        mov ecx,[eax+4]
        and ecx,0ffh
        shl ecx,16
        or ebx,ecx
        mov ecx,[eax+4]
        and ecx,0ff000000h
        or ebx,ecx
        mov tss,ebx
        mov cur,esp
    }
    count=tss->esp0-cur;
    /*上面代码获取当前内核栈的地址与需保存大小
    下面代码保存栈内容*/
    _asm{
        mov ecx,count
        mov edi,TMP
        mov esi,cur
        rep movsb
    }
    /*模拟返回环境,不用多解释了
    iretd我们把它类比于call*/
    _asm{
        mov eax,3bh
        mov fs,ax
        mov eax,23h
        push eax
        mov eax,stack
        push eax
        pushfd
        mov eax,1bh
        push eax
        mov eax,addr
        push eax
        iretd
    }
    /*int 0f0h后返回这里开始执行*/
interrupt:
    _asm{
        mov eax,30h
        mov fs,ax
        mov ecx,count
        mov esi,TMP
        mov edi,cur
        rep movsb
        mov esp,cur
    }
    IdtEntry=(PIdtEntry_t)Idtr->Base;
    _asm cli
    IdtEntry[HOOKINT] = OldEntry;
    _asm sti
    _asm popad
    _asm ret
}

    基本方法十分简单,具体使用需要的预处理就比较繁琐了。
它可能并不实用,不过可以为一些朋友提供练手机会。
    被调用的用户代码就很简单了:

void __declspec(naked) FuncAddr()
{
    MessageBox(NULL, \"OK\",\"OK\",MB_OK);
    _asm int 0xF0  //ret
}

...
{
    ...
    BOOL result;
    ULONG param[2];
    DWORD BytesReturned;
    char *stack = (char*)malloc(0x10000);
    param[0] = (DWORD)FuncAddr;
    param[1] = (DWORD)(stack+0x10000);
    result = DeviceIoControl(
                    hDevice,
                    IOCTL_CALL_RING3,
                    param,
                    8,
                    0,
                    0,
                    &BytesReturned,
                    0
                    ;
    free(stack);
    ...
}

    ring0的驱动程序就这样“调用”了ring3的FuncAddr并显示出了
对话框。
    理解这些之后,有兴趣可以看看windows是如何利用这个手段的,
它又复杂在哪点。
    最后说一句的是,因为我们的处理过于简单,如果你在ring3的函
数里发生了异常,或是结束进程,那么效果是这个进程会成为清不掉的
“僵尸”进程,可能一看“清不掉”,有的朋友又想到了可不可以利用
来实现“进程不死术”,呵呵,会失望的。僵尸不同于不死,自己看看
吧。
上面是PJF老大的帖子,下面是我根据他的做的例子,我发现通过MALLOC来分配的RING3堆栈在你FREE的时候会异常,可能堆栈的数据信息被破坏了,所以只能用静态数据区来代替下,大家也测试看看
注意的是在输入缓冲区大小的时候应该>=8,因为我们把RING3的地址和堆栈都传入到RING0去执行了.
附件名称/大小 下载次数 最后更新
2005-03-12_CallMsgRing0.rar (1178KB)  373

最新喜欢:

sunseasunsea
花开了,然后又会凋零,星星是璀璨的,可那光芒也会消失。在这样 一瞬间,人降生了,笑者,哭着,战斗,伤害,喜悦,悲伤憎恶,爱。一切都只是刹那间的邂逅,而最后都要归入死亡的永眠
violin
驱动牛犊
驱动牛犊
  • 注册日期2003-10-02
  • 最后登录2009-08-22
  • 粉丝0
  • 关注0
  • 积分4分
  • 威望83点
  • 贡献值0点
  • 好评度41点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2005-03-12 19:05
顶 :)
jution
驱动牛犊
驱动牛犊
  • 注册日期2004-09-17
  • 最后登录2008-08-12
  • 粉丝0
  • 关注0
  • 积分7分
  • 威望4点
  • 贡献值0点
  • 好评度2点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2005-03-12 23:47
老大的东西看到一定要顶!

                                 XFreeBoy
jution
idaxsy
驱动大牛
驱动大牛
  • 注册日期2004-12-09
  • 最后登录2006-03-17
  • 粉丝0
  • 关注0
  • 积分386分
  • 威望54点
  • 贡献值0点
  • 好评度8点
  • 原创分0分
  • 专家分0分
地板#
发布于:2005-03-15 12:50
 
代码原是大二时为NT4系统写的


羡慕。学习。
[b]万水千山总是情,回个帖子行不行?[/b]
dalaoban
驱动牛犊
驱动牛犊
  • 注册日期2004-02-02
  • 最后登录2009-12-07
  • 粉丝0
  • 关注0
  • 积分8分
  • 威望2点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地下室#
发布于:2005-05-11 00:39
怎么下不了了
bmyyyud
驱动老牛
驱动老牛
  • 注册日期2002-02-22
  • 最后登录2010-01-21
  • 粉丝0
  • 关注0
  • 积分1000分
  • 威望130点
  • 贡献值0点
  • 好评度106点
  • 原创分0分
  • 专家分0分
5楼#
发布于:2005-05-11 09:43
Ring 0 call Ring 3的方法,OS在处理用户例外时要回调用户的处理例程就采用这种方法
滚滚长江东逝水 浪花淘尽英雄 是非成败转头空 青山依旧在 几度夕阳红 白发渔樵江渚上 惯看秋月春风 一壶浊酒喜相逢 古今多少事 尽付笑谈中
wywwwl
驱动大牛
驱动大牛
  • 注册日期2002-08-16
  • 最后登录2018-04-07
  • 粉丝1
  • 关注0
  • 积分-10分
  • 威望135点
  • 贡献值6点
  • 好评度76点
  • 原创分0分
  • 专家分0分
  • 社区居民
6楼#
发布于:2005-05-12 09:18

    最后说一句的是,因为我们的处理过于简单,如果你在ring3的函
数里发生了异常,或是结束进程,那么效果是这个进程会成为清不掉的
“僵尸”进程,可能一看“清不掉”,有的朋友又想到了可不可以利用
来实现“进程不死术”,呵呵,会失望的。僵尸不同于不死,自己看看
吧。


这个我遇见过,还有一种情况就是:windows任务管理器和softice在R3和R0都看不见某个进程的信息,但这个进程的主界面却显示着,还能运行呢,有意思吧
琢磨悟真知
bmyyyud
驱动老牛
驱动老牛
  • 注册日期2002-02-22
  • 最后登录2010-01-21
  • 粉丝0
  • 关注0
  • 积分1000分
  • 威望130点
  • 贡献值0点
  • 好评度106点
  • 原创分0分
  • 专家分0分
7楼#
发布于:2005-05-12 09:44
[quote]
    最后说一句的是,因为我们的处理过于简单,如果你在ring3的函
数里发生了异常,或是结束进程,那么效果是这个进程会成为清不掉的
“僵尸”进程,可能一看“清不掉”,有的朋友又想到了可不可以利用
来实现“进程不死术”,呵呵,会失望的。僵尸不同于不死,自己看看
吧。


这个我遇见过,还有一种情况就是:windows任务管理器和softice在R3和R0都看不见某个进程的信息,但这个进程的主界面却显示着,还能运行呢,有意思吧 [/quote]
还能运行呢??????
这就不叫僵尸了 :D
僵尸进程,核心已不再调度它,如何运行??? :mad:
僵尸不同于不死,自己看看吧。
滚滚长江东逝水 浪花淘尽英雄 是非成败转头空 青山依旧在 几度夕阳红 白发渔樵江渚上 惯看秋月春风 一壶浊酒喜相逢 古今多少事 尽付笑谈中
kernel_kernel
驱动小牛
驱动小牛
  • 注册日期2002-12-08
  • 最后登录2009-02-06
  • 粉丝0
  • 关注0
  • 积分435分
  • 威望51点
  • 贡献值0点
  • 好评度41点
  • 原创分0分
  • 专家分0分
8楼#
发布于:2005-05-12 11:45
此文作者已经n年没上这里发贴了,怀念几年前啊,
一帮活跃的高人
dalaoban
驱动牛犊
驱动牛犊
  • 注册日期2004-02-02
  • 最后登录2009-12-07
  • 粉丝0
  • 关注0
  • 积分8分
  • 威望2点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
9楼#
发布于:2005-05-12 16:52
     各位老大,wowocock提供的代码我下不了,不知道怎么回事。

小弟想在核心态创建一个用户态的进程,需要一些参考。近日看了rootkit上的文章“WORKING* CreateProcess in KernelMode! ”,调试了一下,发现程序卡在
// apc is fired, wait event to signal completion
    KeWaitForSingleObject (pEvent,Executive,KernelMode,FALSE,NULL);

     现在不知道是什么地方出了问题,有哪位老大实现了这一功能,能否给小弟发一份,我的邮箱 panqz_1980@163.com。如果谁能下载wowocock提供的代码,请帮忙给我发一份,xx。

[编辑 -  5/12/05 by  dalaoban]
bmyyyud
驱动老牛
驱动老牛
  • 注册日期2002-02-22
  • 最后登录2010-01-21
  • 粉丝0
  • 关注0
  • 积分1000分
  • 威望130点
  • 贡献值0点
  • 好评度106点
  • 原创分0分
  • 专家分0分
10楼#
发布于:2005-05-14 10:38
我估计wowocock用的是vs2003,我用vs2003编译,只有_asm leave出错
c:\\CallMsgRing0\\driver\\CallMsgRing0.c(126): error C2400: inline assembler syntax error in \'opcode\'; found \'newline\'
leave是186下就有的指令,vc6嵌入汇编宣称都支持到486的汇编了,为什么在vs 2003下会出这样的问题?但我试了一下Enter却是支持的,难道是vs 2003 bug,我查了一下,C2400是有其它的Bug,但没有_asm leave,只好改为最土的两句,试验一下,功能正常,显示Dialog没问题,而且能正常退出
代码也贴上来
附件名称/大小 下载次数 最后更新
2005-05-14_CallMsgRing0.rar (1135KB)  159
滚滚长江东逝水 浪花淘尽英雄 是非成败转头空 青山依旧在 几度夕阳红 白发渔樵江渚上 惯看秋月春风 一壶浊酒喜相逢 古今多少事 尽付笑谈中
kf200512
驱动牛犊
驱动牛犊
  • 注册日期2007-01-24
  • 最后登录2008-03-10
  • 粉丝0
  • 关注0
  • 积分260分
  • 威望27点
  • 贡献值0点
  • 好评度26点
  • 原创分0分
  • 专家分0分
11楼#
发布于:2007-03-02 08:47
终于找到了,羡慕啊,谢谢老大
驱网无线,快乐无限
WQXNETQIQI
驱动大牛
驱动大牛
  • 注册日期2006-06-12
  • 最后登录2010-10-26
  • 粉丝0
  • 关注0
  • 积分13分
  • 威望1076点
  • 贡献值0点
  • 好评度895点
  • 原创分1分
  • 专家分0分
12楼#
发布于:2007-03-02 10:12
又一个顶老贴的。。。
驱动开发者 呵呵
beiujm
驱动小牛
驱动小牛
  • 注册日期2005-11-03
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分983分
  • 威望129点
  • 贡献值0点
  • 好评度98点
  • 原创分0分
  • 专家分0分
13楼#
发布于:2007-04-16 20:14
引用第10楼bmyyyud2005-05-14 10:38发表的“”:
我估计wowocock用的是vs2003,我用vs2003编译,只有_asm leave出错
c:\CallMsgRing0\driver\CallMsgRing0.c(126): error C2400: inline assembler syntax error in 'opcode'; found 'newline'
leave是186下就有的指令,vc6嵌入汇编宣称都支持到486的汇编了,为什么在vs 2003下会出这样的问题?但我试了一下Enter却是支持的,难道是vs 2003 bug,我查了一下,C2400是有其它的Bug,但没有_asm leave,只好改为最土的两句,试验一下,功能正常,显示Dialog没问题,而且能正常退出
代码也贴上来



同样的问题,不知道为什么。
http://beiyu.bokee.com
游客

返回顶部