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程序员必然会想要知道这个过程到底是怎么样的,内核源码会告诉你 ...
随机推荐
- 取余运算 C和python的区别
今天看书发现python与C的负数取余运算结果不同,查资料理解. 取余运算的算法是相同的 r = a- n*(a/n) n!=0 r是余数,a是被除数,n是除数.n不能为0,否则都会报错. 负数 ...
- hive sql基础了解
会有些不一样 1 例如使用SQL 之前,要了解用了那个库,use jz_daojia 2 使用GET_JSON_OBJECT 函数等,以及参数 匹配 $.childBrithDay 挺有意思的.新玩意 ...
- GET and POST
有待补充:
- T1387:搭配购买(buy)
[题目描述] Joe觉得云朵很美,决定去山上的商店买一些云朵.商店里有n朵云,云朵被编号为1,2,…...,n,并且每朵云都有一个价值.但是商店老板跟他说,一些云朵要搭配来买才好,所以买一朵云则与这朵 ...
- static关键字_1
static关键字 1.在类中,用static声明的成员变量为静态成员变量,它为该类的公用变量,在第一次使用时被初始化,对于该类的所以对象来说,static成员变量只有一份. 2.用static声 ...
- Deepin环境下安装科学研究版Python和Pytorch--防网卡
Deepin环境下安装科学研究版Python和Pytorch--防网卡 由于本教程所引起的一切损失作者概不负责,本教程不使用pip和conda命令,因此下载好包后配合U盘可以给某个机器进行离线安装 · ...
- Python 2 将死,你准备好了吗?
Python 软件基金会宣布,到 2020 年元旦,将不再为编程语言 Python 2.x 分支提供任何支持.这一天将标志着一出延续多年的戏剧的高潮:Python 从较旧的.功能较弱的.广泛使用的版本 ...
- 一些关于SEO优化的笔记
高级搜索指令: 双引号:“xxx” 代表完全匹配的搜索 减号:-(减号前面必须是空格,后面必须没有空格)代表搜索不包含减号后面的词的页面 filetype:用于搜索特定文件格式(百度支持的文件类型:P ...
- jmeter beanshell 写入文件
1.首先F:\test.txt文件为空
- 3年Java,鏖战腾讯
作者:codegoose https://segmentfault.com/a/1190000017864721 经过半年的沉淀,加上对MySQL,redis和分布式这块的补齐,终于重拾面试信心,再次 ...