NtCallbackReturn是否导致了用户态栈的不平衡
0:000> u ntdll!KiFastSystemCall
ntdll!KiFastSystemCall:
7c92eb8b 8bd4 mov edx,esp
7c92eb8d 0f34 sysenter
ntdll!KiFastSystemCallRet:
7c92eb8f 90 nop
7c92eb90 90 nop
7c92eb91 90 nop
7c92eb92 90 nop
7c92eb93 90 nop
ntdll!KiFastSystemCallRet:
7c92eb94 c3 ret
而我们通过dump disasm得到的结果
0x77d1a146 : FF 15 24 14 D1 77 call dword ptr [0x77d11424]
【ntdll.dll.[.text].NtCallbackReturn】
0x7c92d51d : B8 14 00 00 00 mov eax, 0x14
0x7c92d522 : BA 00 03 FE 7F mov edx, 0x7ffe0300
0x7c92d527 : FF 12 call dword ptr [edx]
【ntdll.dll.[.text].KiFastSystemCall】
0x7c92eb8b : 8B D4 mov edx, esp
0x7c92eb8d : 0F 34 sysenter
0x7c92eb94 : C3 ret
0x77ef67d4 : C3 ret
根据上面的结果显示,KiFastSystemCall在执行结束本来应该返回到0x7c92d527的下一条指令即0x7c92d529处执行,但是为什么会返回到0x77ef67d4处呢?
通过查看调用栈
call [0x0012f43c] : 0x7c92d527 --> 0x7c92eb8b
return [0x0012f458] : 0x77ef67d4 <-- 0x7c92eb94
Thread 38:
[# 0] [0x0012fb20]:[0x7c941739 - 0x7c94173e] ==> [0x7c93c9e4] ntdll.dll.[.text].LdrFindResourceDirectory_U_0x000000af
[# 1] [0x0012fa18]:[0x7c93cba6 - 0x7c93cbab] ==> [0x7c921193] ntdll.dll.[.text].LdrInitializeThunk_0x00000015
[# 2] [0x0012f9f8]:[0x7c9211a4 - 0x7c9211a7] ==> [0x77d1f518] USER32.dll.[.text].UserClientDllInitialize
[# 3] [0x0012f46c]:[0x77d1f76f - 0x77d1f774] ==> [0x77d1f791] USER32.dll.[.text].UserClientDllInitialize_0x00000279
[# 4] [0x0012f460]:[0x77ef655e - 0x77ef6563] ==> [0x77ef67c8] GDI32.dll.[.text].GdiProcessSetup_0x000001ac
[# 5] [0x0012f45c]:[0x77ef67d2 - 0x77ef67d4] ==> [0x7c92eb8b] ntdll.dll.[.text].KiFastSystemCall
[# 6] [0x0012f450]:[0x7c92eae0 - 0x7c92eae3] ==> [0x77d1a12e] USER32.dll.[.text].ClientThreadSetup_0x00000134
[# 7] [0x0012f440]:[0x77d1a146 - 0x77d1a14c] ==> [0x7c92d51d] ntdll.dll.[.text].NtCallbackReturn
--> [# 8] [0x0012f43c]:[0x7c92d527 - 0x7c92d529] ==> [0x7c92eb8b] ntdll.dll.[.text].KiFastSystemCall
可见,0x77ef67d4是在第一次调用KiFastSystemCall的时候,保存在栈上的返回地址,当时的栈的位置是0x0012f45c(还没有将返回地址压到栈上时);
而在返回时,栈的位置是0x0012f458,因此正好是返回到了第一次调用KiFastSystemCall的位置。
如果是这样,那么我们的影子调用栈出现了什么问题呢?
我们知道,当用户态程序进入内核态执行后(通过sysenter),内核可能会调度到用户态的APC等等回调函数执行,这些回调函数的执行发起者是内核态代码,因此它们需要将执行流程返回给内核代码;
Windows提供了一种机制,当用户态的回调函数没有提供显式的返回到内核的代码时,Windows会自动执行默认的返回到内核态的代码,而这一段代码恰好也是通过KiFastSystemCall机制完成的(因为KiFastSystemCall是用户态通向内核态的唯一入口),这一机制被称为NtCallbackReturn。
因此,我们怀疑,NtCallbackReturn机制会使用户态的代码孤立起来看,是不符合栈平衡的,原因就是NtCallbackReturn的内核服务程序中会对用户态的栈做调整,以掩盖异步回调函数被执行过的痕迹。
因此,我们相信,NtCallbackReturn的存在,使得我们单纯地依据用户态的call/ret指令建立起来的影子调用栈出现了不平衡的现象。
解决方法,就是在调用过NtCallbackReturn之后,添加三次等效ret的效果,可以解决影子栈的不平衡问题。
事情到了这里,还没有结束,因为还不知道有哪些系统调用会破坏用户态栈的平衡。
比如NtContinue就很可疑(根据实现结果),那么用户态的影子调用栈要通过什么方式来保证其正确性呢?
更普遍的做法,可以根据KiFastSystemCallRet来判断,它可以与KiFastSystemCall配对,从而消除中间的多余项目。
NtCallbackReturn是否导致了用户态栈的不平衡的更多相关文章
- Linux中的栈:用户态栈/内核栈/中断栈
http://blog.chinaunix.net/uid-14528823-id-4136760.html Linux中有多种栈,很容易弄晕,简单说明一下: 1.用户态栈:在进程用户态地址空间底部, ...
- v79.01 鸿蒙内核源码分析(用户态锁篇) | 如何使用快锁Futex(上) | 百篇博客分析OpenHarmony源码
百篇博客分析|本篇为:(用户态锁篇) | 如何使用快锁Futex(上) 进程通讯相关篇为: v26.08 鸿蒙内核源码分析(自旋锁) | 当立贞节牌坊的好同志 v27.05 鸿蒙内核源码分析(互斥锁) ...
- 总在用户态调试 C# 程序,终还是搭了一个内核态环境
一:背景 一直在用 WinDbg 调试用户态程序,并没有用它调试过 内核态,毕竟不是做驱动开发,也没有在分析 dump 中需要接触用内核态的需求,但未知的事情总觉得很酷,加上最近在看 <深入解析 ...
- 130行C语言实现个用户态线程库——ezthread
准确的说是除掉头文件,测试代码和非关键的纯算法代码(只有双向环形链表的ADT),核心代码只有130行左右,已经是蝇量级的用户态线程库了.把这个库取名为ezthread,意思是,这太easy了,人人都可 ...
- NFV、DPDK以及部分用户态协议研究
本文为作者原创,转载请注明出处(http://www.cnblogs.com/mar-q/)by 负赑屃 对我而言,这是一个新的领域,很有意思. 一.解释名词: NFV(Network Functio ...
- 用户态使用 glibc/backtrace 追踪函数调用堆栈定位段错误【转】
转自:https://blog.csdn.net/gatieme/article/details/84189280 版权声明:本文为博主原创文章 && 转载请著名出处 @ http:/ ...
- [中英对照]Device Drivers in User Space: A Case for Network Device Driver | 用户态设备驱动: 以网卡驱动为例
前文初步介绍了Linux用户态设备驱动,本文将介绍一个典型的案例.Again, 如对Linux用户态设备驱动程序开发感兴趣,请阅读本文,否则请飘过. Device Drivers in User Sp ...
- linux 用户态和内核态以及进程上下文、中断上下文 内核空间用户空间理解
1.特权级 Intel x86架构的cpu一共有0-4四个特权级,0级最高,3级最低,ARM架构也有不同的特权级,硬件上在执行每条指令时都会对指令所具有的特权级做相应的检查.硬件已经提 ...
- Linux内核笔记--内存管理之用户态进程内存分配
内核版本:linux-2.6.11 Linux在加载一个可执行程序的时候做了种种复杂的工作,内存分配是其中非常重要的一环,作为一个linux程序员必然会想要知道这个过程到底是怎么样的,内核源码会告诉你 ...
随机推荐
- 使用Excel表格的记录单功能轻松处理工作表中数据的方法
使用Excel表格的记录单功能轻松处理工作表中数据的方法 记录单是将一条记录分别存储在同一行的几个单元格中,在同一列中分别存储所有记录的相似信息段.使用记录单功能可以轻松地对工作表中的数据进行查看.查 ...
- javascript: 禁用右键、文本选择功能、复制按键
<script type="text/javascript"> //禁用右键.文本选择功能.复制按键 //http://www.jinyuanbao.cn $(docu ...
- T1219:马走日
[题目描述] 马在中国象棋以日字形规则移动. 请编写一段程序,给定n×m大小的棋盘,以及马的初始位置(x,y),要求不能重复经过棋盘上的同一个点,计算马可以有多少途径遍历棋盘上的所有点. [输入] 第 ...
- SSD如何设置预留空间OP(Over-Provision)
Over-Provision操作指南 SSD OP全称是(Over-Provision), 中文名预留空间, 指用户不可操作的容量,大小为SSD实际容量减去用户可用容量.简单来说over-provis ...
- Excel文件加密后忘记密码破解方法
最好使用VBA 工程密码破解方法 新建一个excel文档,然后打开,同时按Alt和F11,进入VBA界面 点击菜单上的插入,模块 在新的窗口粘贴以下代码: Sub crack() Dim i As L ...
- 初识Flink-从WorldCount开始
Apache Flink是一个用于分布式流和批处理数据处理的开源平台.Flink的核心是流数据流引擎,为数据流上的分布式计算提供数据分发,通信和容错.Flink在流引擎之上构建批处理,覆盖本机迭代支持 ...
- ftrace 使用方法
1. 追蹤Kernel function (以schedule()示範) 先至 /sys/kernel/debug/tracing# cat available_tracers 確定有無 函式追蹤器( ...
- foobar2000 频谱给我的win10 任务栏添加一点会动背景
在任务栏右键,"任务栏设置",颜色 -> 透明效果, 然后 foobar2000 的 view -> layout -> Quick Setup,选择带有Visu ...
- java web项目获取项目路径
注意:有时获取到的项目路径后再+“自定义路径后” 路径不可用,这时要看下项目里自定义路径是不是空文件夹,如果是空文件夹则调试和运行时文件夹不会编译到部署文件里. 1.方法一 调试时只能获取eclips ...
- C++ 浅析移位运算
按位左移(<<): 按二进制形式把所有的数字向左移动对应的位数,高位移出(舍弃),低位的空位补零 按位右移(>>): 按二进制形式把所有的数字向右移动对应位移位数,低位移出(舍 ...