- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
此问题与 this one 有关但它并没有填补我的一些空白,所以我决定再问一遍,并提供更多细节,也许会为此提供赏金。
不管怎样,通常如果你在 ntdll 上查找 Nt/Zw 函数,你会看到如下内容:
ZwClose proc near
mov r10, rcx
mov eax, 0Fh
test byte ptr ds:7FFE0308h, 1
jnz short loc_a
syscall
retn
loc_a:
int 2Eh
retn
NtClose endp
现在我知道这是比较 KUSER_SHARED_DATA 的偏移量并决定是否执行 syscall 与 INT 2E。起初我认为如果正在运行的程序是 32 位应用程序,就会执行 INT 2E,但是在阅读了一些关于 WOW64 的信息之后,似乎这些应用程序将使用不执行 int 2e 而是执行的 ntdll 的 32 位版本穿过天堂之门到达内核:
public ZwClose
ZwClose proc near
mov eax, 3000Fh ; NtClose
mov edx, offset j_Wow64Transition
call edx ; j_Wow64Transition
retn 4
ZwClose endp
据我了解,Wow64Transition 最终会跳转到我首先列出的 64 位版本的 ntdll,对吧?如果是这样,那是在执行 INT 2E 而不是系统调用时?我还被告知 INT 2E 的原因之一是 CET兼容性,所以我对 INT 2E 有点困惑。
最佳答案
So as far as I understand Wow64Transition will eventually jump to the 64-bit version of ntdll which I listed first, right?
是的。
If that's so, is that when INT 2E is executed instead of syscall?
没有。
首先,让我们明白一点:您仍然可以在现代 Windows 系统上毫无问题地调用 INT 0x2E,中断向量仍然在这里并指向系统调用调度程序:
0: kd> !idt 0x2e
Dumping IDT: fffff8010a900000
2e: fffff8010ca11ec0 nt!KiSystemServiceShadow
如您所见,执行 ring3/ring0 转换的代码段检查了 KUSER_SHARED_DATA 结构中的位。
在偏移量 0x308 处,我们有一个名为 SystemCall
的字段:
0: kd> dt _kuser_shared_data
nt!_KUSER_SHARED_DATA
...
+0x308 SystemCall : Uint4B
...
KUSER_SHARED_DATA 映射到两个不同的地址:一个在用户区 (0x7FFE0000),另一个在内核区 (0xFFFFF78000000000)。这两个地址都由同一个物理页面支持(用户区显然是只读的)。
请注意,这些地址是恒定的,不受 ASLR 约束。因此,我们可以在内核中搜索0xFFFFF78000000308
地址(即KUSER_SHARED_DATA.SystemCall
,但在内核中)并查看是否匹配。
在名为 KiInitializeKernel
PAGELK:00000001405A36A2 mov r14d, 1
PAGELK:00000001405A36A8 cmp cs:KiSystemCallSelector, r14d
PAGELK:00000001405A36AF jnz loc_1405A3161
;...
PAGELK:00000001405A9236 test cs:HvlEnlightenments, 80000h
PAGELK:00000001405A9240 jz loc_1405A3161
PAGELK:00000001405A9246 mov eax, r14d
PAGELK:00000001405A9249 mov ds:0FFFFF78000000308h, eax
因此,如果 KiSystemCallSelector
为 1 并且 HvlEnlightenments
设置了第 19 位,则设置了 KUSER_SHARED_DATA.SystemCall
。
HvlEnlightenments
是一个位域,当虚拟化操作系统知道它实际上是虚拟化时设置(这些操作系统称为“启蒙操作系统”)。这意味着该功能(调用 INT 0x2E 而不是 SYSCALL)与虚拟化操作系统相关。
我们只剩下 KiSystemCallSelector
;这个变量是在一个名为 KiInitializeBootStructures
的函数中设置的:
PAGELK:00000001405A1E48 mov rsi, rcx ; rsi = rcx (1st function param)
; ...
PAGELK:00000001405A2052 mov rdx, [rsi+0F0h]
PAGELK:00000001405A2059 mov eax, [rdx+74h]
; ...
PAGELK:00000001405A206A loc_1405A206A:
PAGELK:00000001405A206A bt eax, 8
PAGELK:00000001405A206E jnb short loc_1405A2077
PAGELK:00000001405A2070 mov cs:KiSystemCallSelector, r13d ; r13d = 1
我们可以看到这个函数的第一个参数很重要;碰巧它是一个名为 KeLoaderBlock
的全局内核变量:
PAGELK:0000000140597154 mov rcx, cs:KeLoaderBlock_0
PAGELK:000000014059715B call KiInitializeBootStructures
它的类型已知是_LOADER_PARAMETER_BLOCK
,它的定义在内核符号中是公开的,所以前面的代码看起来像这样,带有符号信息:
PAGELK:00000001405A2052 mov rdx, [rsi+_LOADER_PARAMETER_BLOCK.Extension] ; _LOADER_PARAMETER_EXTENSION*
PAGELK:00000001405A2059 mov eax, [rdx+_LOADER_PARAMETER_EXTENSION._bf_74] ; bit field
; ...
PAGELK:00000001405A206A loc_1405A206A:
PAGELK:00000001405A206A bt eax, 8
PAGELK:00000001405A206E jnb short loc_1405A2077
PAGELK:00000001405A2070 mov cs:KiSystemCallSelector, r13d ; r13d = 1
在 _LOADER_PARAMETER_EXTENSION
结构的偏移量 0x74 处,我们有一个位域:
struct // 22 elements, 0x4 bytes (sizeof)
{
/*0x074*/ ULONG32 LastBootSucceeded : 1; // 0 BitPosition
/*0x074*/ ULONG32 LastBootShutdown : 1; // 1 BitPosition
/*0x074*/ ULONG32 IoPortAccessSupported : 1; // 2 BitPosition
/*0x074*/ ULONG32 BootDebuggerActive : 1; // 3 BitPosition
/*0x074*/ ULONG32 StrongCodeGuarantees : 1; // 4 BitPosition
/*0x074*/ ULONG32 HardStrongCodeGuarantees : 1; // 5 BitPosition
/*0x074*/ ULONG32 SidSharingDisabled : 1; // 6 BitPosition
/*0x074*/ ULONG32 TpmInitialized : 1; // 7 BitPosition
/*0x074*/ ULONG32 VsmConfigured : 1; // 8 BitPosition
/*0x074*/ ULONG32 IumEnabled : 1; // 9 BitPosition
/*0x074*/ ULONG32 IsSmbboot : 1; // 10 BitPosition
/*0x074*/ ULONG32 BootLogEnabled : 1; // 11 BitPosition
/*0x074*/ ULONG32 DriverVerifierEnabled : 1; // 12 BitPosition
/*0x074*/ ULONG32 SuppressMonitorX : 1; // 13 BitPosition
/*0x074*/ ULONG32 SuppressSmap : 1; // 14 BitPosition
/*0x074*/ ULONG32 Unused : 6; // 15 BitPosition
/*0x074*/ ULONG32 FeatureSimulations : 6; // 21 BitPosition
/*0x074*/ ULONG32 MicrocodeSelfHosting : 1; // 27 BitPosition
/*0x074*/ ULONG32 XhciLegacyHandoffSkip : 1; // 28 BitPosition
/*0x074*/ ULONG32 DisableInsiderOptInHVCI : 1; // 29 BitPosition
/*0x074*/ ULONG32 MicrocodeMinVerSupported : 1; // 30 BitPosition
/*0x074*/ ULONG32 GpuIommuEnabled : 1; // 31 BitPosition
};
bt eax, 8
指令正在测试第 8 位,因此是 VsmConfigured
位。
因此,如果我们被虚拟化并且 VsmConfigured
为 1,那么我们使用 INT 0x2E。
VSM 代表 Virtual Secure Mode
它引入了用于隔离操作系统本身的部分的 VTL(虚拟信任级别):例如,VTL0 是所谓的“正常世界”,操作系统的“通常”部分驻留(包括内核及其虚拟空间)而 VTL1 包含安全内核和称为“truslets”的非常具体的进程(参见 IUM
以获得更详细的说明)。
那时我只能猜测;我的第一个想法是调用 INT 0x2E 仅适用于特定内核(不是 VTL0 中的“普通”内核,但我仍然不知道是哪个)。
VMM(管理程序)实际上比系统调用更容易捕获 VM 退出以进行中断;当某些事件(例如 INT、RDMSR、WMSR 等特定指令)发生时,会发生 VM 退出,这些事件使代码从其正常执行流回到管理程序,因此管理程序实际上可以查看是什么触发了 VM 退出并采取行动相应地(例如重定向代码流或“撒谎”到操作系统)。
写完这个答案后,我看到有人在一篇解释更详尽的博文中实际上追逐了相同的路径:The Windows 10 TH2 INT 2E mystery .他们不确定内核将在哪种情况下使用 INT2E。我们只能在那个时候猜测。
关于winapi - x86_64 - Windows 上的 64 位应用程序可以执行 INT 2E 而不是系统调用吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70028273/
问题故障解决记录 -- Java RMI Connection refused to host: x.x.x.x .... 在学习JavaRMI时,我遇到了以下情况 问题原因:可
我正在玩 Rank-N-type 并尝试输入 x x .但我发现这两个函数可以以相同的方式输入,这很不直观。 f :: (forall a b. a -> b) -> c f x = x x g ::
这个问题已经有答案了: How do you compare two version Strings in Java? (31 个回答) 已关闭 8 年前。 有谁知道如何在Java中比较两个版本字符串
这个问题已经有答案了: How do the post increment (i++) and pre increment (++i) operators work in Java? (14 个回答)
下面是带有 -n 和 -r 选项的 netstat 命令的输出,其中目标字段显示压缩地址 (127.1/16)。我想知道 netstat 命令是否有任何方法或选项可以显示整个目标 IP (127.1.
我知道要证明 : (¬ ∀ x, p x) → (∃ x, ¬ p x) 证明是: theorem : (¬ ∀ x, p x) → (∃ x, ¬ p x) := begin intro n
x * x 如何通过将其存储在“auto 变量”中来更改?我认为它应该仍然是相同的,并且我的测试表明类型、大小和值显然都是相同的。 但即使 x * x == (xx = x * x) 也是错误的。什么
假设,我们这样表达: someIQueryable.Where(x => x.SomeBoolProperty) someIQueryable.Where(x => !x.SomeBoolProper
我有一个字符串 1234X5678 我使用这个正则表达式来匹配模式 .X|..X|X. 我得到了 34X 问题是为什么我没有得到 4X 或 X5? 为什么正则表达式选择执行第二种模式? 最佳答案 这里
我的一个 friend 在面试时遇到了这个问题 找到使该函数返回真值的 x 值 function f(x) { return (x++ !== x) && (x++ === x); } 面试官
这个问题在这里已经有了答案: 10年前关闭。 Possible Duplicate: Isn't it easier to work with foo when it is represented b
我是 android 的新手,我一直在练习开发一个针对 2.2 版本的应用程序,我需要帮助了解如何将我的应用程序扩展到其他版本,即 1.x、2.3.x、3 .x 和 4.x.x,以及一些针对屏幕分辨率
为什么案例 1 给我们 :error: TypeError: x is undefined on line... //case 1 var x; x.push(x); console.log(x);
代码优先: # CASE 01 def test1(x): x += x print x l = [100] test1(l) print l CASE01 输出: [100, 100
我正在努力温习我的大计算。如果我有将所有项目移至 'i' 2 个空格右侧的函数,我有一个如下所示的公式: (n -1) + (n - 2) + (n - 3) ... (n - n) 第一次迭代我必须
给定 IP 字符串(如 x.x.x.x/x),我如何或将如何计算 IP 的范围最常见的情况可能是 198.162.1.1/24但可以是任何东西,因为法律允许的任何东西。 我要带198.162.1.1/
在我作为初学者努力编写干净的 Javascript 代码时,我最近阅读了 this article当我偶然发现这一段时,关于 JavaScript 中的命名空间: The code at the ve
我正在编写一个脚本,我希望避免污染 DOM 的其余部分,它将是一个用于收集一些基本访问者分析数据的第 3 方脚本。 我通常使用以下内容创建一个伪“命名空间”: var x = x || {}; 我正在
我尝试运行我的test_container_services.py套件,但遇到了以下问题: docker.errors.APIError:500服务器错误:内部服务器错误(“ b'{” message
是否存在这两个 if 语句会产生不同结果的情况? if(x as X != null) { // Do something } if(x is X) { // Do something } 编
我是一名优秀的程序员,十分优秀!