内核调用用户

正常的系统调用过程为Ring3->Ring0->Ring3,而KeUserModeCallback提供了一种Ring0->Ring3->Ring0的方式,即从内核去用户层执行代码。

KeUserModeCallback (
IN ULONG ApiNumber, //对应函数在KernelCallback表中的索引
IN PVOID InputBuffer, //ApiNumber不同(即调用的函数不同),此参数对应不同的结构
IN ULONG InputLength,
OUT PVOID *OutputBuffer, //执行后输出的结果
IN PULONG OutputLength
)

KeUserModeCallback是ntoskrnl.exe导出的,系统中很多回调机制都是通过KeUserModeCallback实现的。

其参数ApiNumber是需要执行的回调函数在KernelCallback回调函数表中的索引,这张回调函数表的地址存放在PEB->KernelCallback中的每一个函数都有不同的用处,在windbg中好看如下。

其对应的回调函数表为:

第二个参数InputBuffer会根据ApiNumber索引回调函数的不同而指向不同的结构体,第四个参数OutputBuffer指向的缓冲区中是执行完回调函数后返回的信息。

KeUserModeCallback的执行流程

一般是含有GDI系统服务的win32k.sys调用KeUserModeCallback,所以一般要HOOKKeUserModeCallback时都会通过IAThook win32k.sys的导入表中对KeUserModeCallback的调用。接着会调用nt!KiCallUserMode--->KiServiceExit--->sysexit进入应用层中,然后在应用层执行的第一个函数就是ntdll!KiUserCallbackDispatcher。



为什么调用堆栈中没有显示调用了nt!KiServiceExit呢,因为其是通过nt!KiCallUserMode执行jmp执行调用的。

应用层执行的第一个函数就是ntdll!KiUserCallbackDispatcher,此函数会根据从内核中传入的ApiNumber也就是回调函数在KernelCallback回调函数表中的索引调用对应的回调函数,执行完对应的回调函数调用User32!XyCallbackReturn,此函数会在内部执行int 0x2e,通过中断门返回内核。

接着回到内核中后执行的第一个函数就是nt!KiCallbackReturn,然后会继续返回到nt!KeUserModeCallback中。

总结一般其调用过程就是这样

win32k.sys --->nt!KeUserModeCallback --->nt!KiCallUserMode--->KiServiceExit--->sysexit     //Ring0--->Ring3

ntdll!KiUserCallbackDispatcher--->对应KernelCallback表中的回调函数                           //Ring3

对应KernelCallback表中的回调函数--->User32!XyCallbackReturn--->int 0x2e                     //Ring3--->Ring0

nt!KiCallbackReturn--->nt!KeUserModeCallback                                               //Ring0

KeUserModeCallback的应用

全局钩子

我们通常利用SetWindwosHook设置全局消息钩子来实现dll注入,其实其就是利用nt!KeUserModeCallback函数来完成函数的调用的。

当我们在一个应用 程序中调用SetWindowsHook安装全局消息钩子并设置hook回调函数后,如果我们这时候打开另一个程序,如果此程序是一个GUI程序,其在加载过程中会产生一些消息,这样系统就会尝试调用我们刚刚注册的全局消息回调函数,如果发现此回调函数对应的dll还没有加载其就会尝试加载此dll,从而实现dll的注入。

这其实就是内核通过调用nt!KeUserModeCallback 函数,然后进入到用户层后调用KernelCallback回调函数表中的位于USER32.dll模块中的USER32!_ClientLoadLibrary函数,此函数会进一步调用kernel32!LoadLibraryEx加载需要加载的dll文件。

对应的nt!KeUserModeCallback 的InputBuffer参数结构为,

typedef struct DLLHOOK
{
DWORD dwBufferSize; //结构长度
DWORD dwAdditionalData;
DWORD dwFixupsCount;
LPVOID pbFree
DWORD offCbkPtrs;
DWORD bFixed;
UNICODE_STRING lpDLLPath; //加载的Dll名字
union
{
DWORD lpfnNotify // 调用函数相对于模块的RVA
UNICODE_STRING lpInitFunctionName; // 调用函数名
}
DWORD offCbk[2];
};

所以只有GDI程序,即加载user32.dll的程序才能使用全局消息钩子注入dll了。我们可以通过IAThook win32k.sys的KeUserModeCallback函数并判断dll的名字来达到防止全局消息钩子注入。

WH_JOURNALRECORD消息记录钩子

我们可以调用SetWindowsHook来设置WH_JOURNALRECORD消息记录钩子,这要求我们提供一个回调函数,且此回调函数和设置WN_JOURNALRECORD消息钩子的进程是在同一进程地址空间中,那么当其他进程产生鼠标或者键盘消息的时候是如何发送到此回调函数中处理的呢。实际上其也是利用KeUserModeCallback函数。



产生消息的进程通过调用USER32.dll中的PeekMessage()将消息发送到内核中,然后在内核中会调用KeUserModeCallback函数并将消息传递给他,之后会调用PEB->KernelCallback回调函数表中的USER32!_fnHkOPTINLPEVENTMSG()。这个函数会调用我们设置的那个用户层的消息回调函数。

如果我们想对消息记录钩子进行拦截就可以IAThook win32k.sys中导入的KeUserModeCallback函数。

WM_COPYDATA进程间通讯

我们可以利用WM_COPYDATA进行进程间通讯,通过SendMessage发送WM_COPYDATA消息给目标进程的窗口过程并传递COPYDATASTRUCT结构传递信息,然后目标进程的窗口过程会处理接收到的WM_COPYDATA消息并接收到COPYDATASTRUCT结构。其原理是通过将COPYDATASTRUCT结构复制到内核中,然后调用KeUserModeCallback函数并接着调用USER32!_fnCOPYDATA函数并将COPYDATASTRUCT结构从内核层复制到接收进程的用户层,然后调用其对应的窗口过程。

输入法注入DLL

利用加载输入法来注入dll,输入法实际就是一个导出特定接口的DLL文件,windows规定其后缀为ime并放在c:\windows\system32中。我们可以通过在此ime文件的dll入口处通过调用LoadLibrary来加载我们需要注入的DLL。

当系统切换输入法时会通过imm32.dll调用KeUserModeCallback然后调用User32.dll的回调函数USER32!_ClientImmLoadLayout。接着此函数会调用kernel32!LoadLibraryEx加载对应输入法的ime文件。

KeUserModeCallback函数的更多相关文章

  1. 驱动里执行应用层代码之KeUserModeCallBack(WOW64是由三个动态库wow64.dll wow64win.dll wow64cpu.dll来实现)

    在驱动层(ring0)里执行应用层(ring3)代码,这是个老生常谈的技术,而且方法也挺多. 这种技术的本质:其实就是想方设法在驱动层里把应用层代码弄到应用层去执行. 比如在APC异步调用中,KeIn ...

  2. CVE-2015-0057 POC构造 & 利用分析(2015.7)

    CVE-2015-0057 POC构造 & 利用分析 主要内容: 构造POC 利用思路 0x00 初探 从这篇文章可以获知: 1.问题出在 win32k!xxxEnableWndSBArrow ...

  3. 【旧文章搬运】KeUserModeCallback用法详解

    原文发表于百度空间及看雪论坛,2010-01-10 看雪论坛地址:https://bbs.pediy.com/thread-104918.htm  代码及附件可到这里下载=============== ...

  4. Python 小而美的函数

    python提供了一些有趣且实用的函数,如any all zip,这些函数能够大幅简化我们得代码,可以更优雅的处理可迭代的对象,同时使用的时候也得注意一些情况   any any(iterable) ...

  5. 探究javascript对象和数组的异同,及函数变量缓存技巧

    javascript中最经典也最受非议的一句话就是:javascript中一切皆是对象.这篇重点要提到的,就是任何jser都不陌生的Object和Array. 有段时间曾经很诧异,到底两种数据类型用来 ...

  6. JavaScript权威指南 - 函数

    函数本身就是一段JavaScript代码,定义一次但可能被调用任意次.如果函数挂载在一个对象上,作为对象的一个属性,通常这种函数被称作对象的方法.用于初始化一个新创建的对象的函数被称作构造函数. 相对 ...

  7. C++对C的函数拓展

    一,内联函数 1.内联函数的概念 C++中的const常量可以用来代替宏常数的定义,例如:用const int a = 10来替换# define a 10.那么C++中是否有什么解决方案来替代宏代码 ...

  8. 菜鸟Python学习笔记第一天:关于一些函数库的使用

    2017年1月3日 星期二 大一学习一门新的计算机语言真的很难,有时候连函数拼写出错查错都能查半天,没办法,谁让我英语太渣. 关于计算机语言的学习我想还是从C语言学习开始为好,Python有很多语言的 ...

  9. javascript中的this与函数讲解

    前言 javascript中没有块级作用域(es6以前),javascript中作用域分为函数作用域和全局作用域.并且,大家可以认为全局作用域其实就是Window函数的函数作用域,我们编写的js代码, ...

随机推荐

  1. logging日志的使用和设置过期自动删除

    一.logging的基础使用 1.logging的级别 import logging logging.debug('debug message') # 计算或者工作的细节 logging.info(' ...

  2. Hive源码分析(1)——HiveServer2启动过程

    1.想了解HiveServer2的启动过程,则需要找到启动HiveServer2的入口,hive服务的启动命令为hive --service HiveServer2,通过分析$HIVE_HOME/bi ...

  3. 攻防世界 reverse 流浪者

    流浪者 int __thiscall sub_401890(CWnd *this) { struct CString *v1; // ST08_4 CWnd *v2; // eax int v3; / ...

  4. [Design Pattern With Go]设计模式-单例模式

    定义 一个类只允许创建一个对象(或者实例),那这个类就是一个单例类,这种设计模式就叫作单例模式.当某些数据只需要在系统中保留一份的时候,可以选择使用单例模式. 饿汉式 饿汉式的实现方式比较简单.在类加 ...

  5. 使用 Android Studio 的日志工具 Log

    •Log简介 Android中的日志工具类是Log,这个类中提供了5个方法来供我们打印日志: 1. $Log.v()$ 用于打印那些最为琐碎的,意义最小的日志信息 对应级别 verbose,是 And ...

  6. 学习笔记-vue 打包去#和页面空白问题

    文件资源路径是对的,但是页面空白.百度了很久找了一篇文章解决了. 1.vue项目中config文件下index.js中打包配置 build: { // Template for index.html ...

  7. 201871030122-牛建疆 实验三 结对项目——《D{0-1}KP 实例数据集算法实验平台》项目报告

    项目 内容 课程班级博客链接 班级博客链接 作业要求链接 作业要求链接 我的课程学习目标 (1)体验软件项目开发中的两人合作,练习结对编程(Pair programming).(2)掌握Github协 ...

  8. 前端面试回顾(1)---javascript的面向对象

    前言 前一阵面试,过程中发现问到一些很基础的问题时候,自己并不能很流畅的回答出来.或者遇到一些基础知识的应用,由于对这些点理解的不是很深入,拿着笔居然什么都写不出来,于是有了回顾一下这些基础知识的想法 ...

  9. MySQL学习之路(一)锁机制

    1 锁的分类 1.1 操作类型 读锁(共享锁):针对同一份数据,多个操作可以同时进行而不会互相影响 写锁(排它锁):当写操作没有完成前,它会阻塞其他读锁或者写锁 1.2 操作粒度 表锁:锁住整张表 行 ...

  10. xss-labs全关教程

    0x01 Level 1 查看源码,可以看到接收了name参数,并直接嵌入到HTML页面中了 没有任何过滤,而且直接会当作代码执行. 0x02 Level 2 先传入<script>ale ...