13.Windows驱动-深入理解系统调用过程

免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动!

本次游戏没法给

内容参考于:微尘网络安全

上一个内容:12.Windows驱动-R3到R0的系统调用

上一个内容里通过ReadProcessMemory和OpenProcess两个函数查看了它们进入内核的过程,还有一个东西就只我们通过GetLastError可以得到一个错误号,如下图框框它有两个ret,函数运行成功是通过下图红框的ret进行返回的,如果函数运行失败会执行下图蓝框的代码然后ret返回

下图红框的代码是用来执行注册GetLastError的错误码的

如下图红框,它执行了两个函数RtlNtStatusToDosError和RtlRestoreLastWin32Error

说明:

RtlNtStatusToDosError用于把内核的错误翻译成用户态的 Win32 错误码
RtlRestoreLastWin32Error用来保存错误码,方便后续我们调用GetLastError函数得到错误码进行排错

然后分析下图红框的代码,我们调用的 OpenProcess(123, TRUE, 555);

代码分析:如果下方的代码说明看不明白,那就复制给ai,让ai一行一行的更细致的解释

; ======================================
; kernelbase!OpenProcess 函数入口
; 入参寄存器分布(x64调用约定):
;   RCX = 第一个参数 123(dwDesiredAccess)
;   RDX = 第二个参数 TRUE(1,bInheritHandle)
;   R8  = 第三个参数 555(dwProcessId)
; ======================================
00007FF881FAF310 <kernelbase.OpenProcess>   | 4C 8B DC      | mov r11,rsp                                       ; 【栈基准】保存原始栈顶到r11,后续用r11定位栈上的参数存储位置(避免rsp变动影响寻址)
00007FF881FAF313                            | 48 83 EC 68   | sub rsp,68                                        ; 【栈空间】分配0x68字节栈空间,用于存放123/TRUE/555的转换后数据、临时值
00007FF881FAF317                            | 45 33 C9      | xor r9d,r9d                                       ; 【临时值初始化】r9d清零(后续用于给栈上的临时位置赋0,辅助参数转换)
00007FF881FAF31A                            | 49 63 C0      | movsxd rax,r8d                                    ; 【处理555】把r8d中的555(32位)扩展为64位存入rax(555从32位转64位,适配x64系统)
00007FF881FAF31D                            | 45 89 4B E4   | mov dword ptr ds:[r11-1C],r9d                     ; 【辅助初始化】把0写入r11-0x1C(栈位置),为后续TRUE的转换预留干净的内存
00007FF881FAF321                            | 4D 8D 43 C8   | lea r8,qword ptr ds:[r11-38]                      ; 【处理TRUE】计算r11-0x38的栈地址存入r8(后续将TRUE转换后的标志位存入该地址,作为NtOpenProcess的参数地址)
00007FF881FAF325                            | 4D 89 4B D0   | mov qword ptr ds:[r11-30],r9                      ; 【辅助初始化】把0写入r11-0x30(栈位置),为555的存储预留干净的内存
00007FF881FAF329                            | F7 DA         | neg edx                                           ; 【处理TRUE】对edx中的TRUE(1)取反,得到edx=-1(0xFFFFFFFF),这是转换TRUE为内核标志位的第一步
00007FF881FAF32B                            | 49 89 43 B8   | mov qword ptr ds:[r11-48],rax                     ; 【存储555】把rax中64位的555写入r11-0x48(栈位置),保存555的转换后数据
00007FF881FAF32F                            | 0F 57 C0      | xorps xmm0,xmm0                                   ; 【辅助初始化】xmm0寄存器清零(后续用于清空栈上的连续内存,保证参数数据干净)
00007FF881FAF332                            | 49 C7 43 C8 3 | mov qword ptr ds:[r11-38],30                      ; 【处理TRUE】把0x30写入r11-38(栈位置,即上面r8指向的地址),完成TRUE转换前的内存初始化
00007FF881FAF33A                            | 1B C0         | sbb eax,eax                                       ; 【处理TRUE】利用借位标志计算,将eax置为-1(0xFFFFFFFF),这是转换TRUE为内核标志位的第二步
00007FF881FAF33C                            | 83 E0 02      | and eax,2                                         ; 【处理TRUE】eax(-1)与2做与运算,得到eax=2(TRUE最终转换为标志位0x2,这是NtOpenProcess需要的格式)
00007FF881FAF33F                            | 4D 89 4B 20   | mov qword ptr ds:[r11+20],r9                      ; 【辅助初始化】把0写入r11+0x20(栈位置),为123的传递预留干净的内存
00007FF881FAF343                            | 89 44 24 48   | mov dword ptr ss:[rsp+48],eax                     ; 【存储TRUE转换结果】把eax中的标志位2写入rsp+0x48(栈位置),保存TRUE的最终转换值
00007FF881FAF347                            | 8B D1         | mov edx,ecx                                       ; 【处理123】把ecx中的123存入edx(123从RCX转移到RDX,作为NtOpenProcess的参数值)
00007FF881FAF349                            | 4D 89 4B D8   | mov qword ptr ds:[r11-28],r9                      ; 【辅助初始化】把0写入r11-0x28(栈位置),辅助123的参数传递
00007FF881FAF34D                            | 49 8D 4B 20   | lea rcx,qword ptr ds:[r11+20]                     ; 【辅助参数】计算r11+0x20的栈地址存入rcx(作为NtOpenProcess的第一个参数地址,接收内核返回的句柄)
00007FF881FAF351                            | 4D 89 4B C0   | mov qword ptr ds:[r11-40],r9                      ; 【辅助初始化】把0写入r11-0x40(栈位置),辅助555的参数传递
00007FF881FAF355                            | 4D 8D 4B B8   | lea r9,qword ptr ds:[r11-48]                      ; 【处理555】计算r11-0x48的栈地址(即存储555的位置)存入r9(555从数值变为地址,作为NtOpenProcess的第四个参数地址)
00007FF881FAF359                            | F3 0F 7F 44 2 | movdqu xmmword ptr ss:[rsp+50],xmm0               ; 【辅助初始化】把xmm0(0)写入rsp+0x50(栈位置,16字节),清空内存避免脏数据影响参数
00007FF881FAF35F                            | 48 FF 15 72 1 | call qword ptr ds:[<&NtOpenProcess>]              ; 【参数传递完成】调用NtOpenProcess,此时:
                                                                 ; RCX = r11+20(句柄地址)、RDX=123(权限值)、R8=r11-38(TRUE转换后的标志位地址)、R9=r11-48(555的地址)
                                                                 ; 123、TRUE、555已全部转换为NtOpenProcess需要的格式(数值/地址)
00007FF881FAF366                            | 0F 1F 44 00 0 | nop dword ptr ds:[rax+rax]                        ; 【指令对齐】空指令,不影响参数,仅为CPU执行效率
00007FF881FAF36B                            | 85 C0         | test eax,eax                                      ; 【结果判断】检查NtOpenProcess的返回值(eax),判断参数转换后的调用是否成功
00007FF881FAF36D                            | 78 0E         | js kernelbase.7FF881FAF37D                        ; 【分支跳转】若调用失败(eax为负数),跳转到错误处理
00007FF881FAF36F                            | 48 8B 84 24 8 | mov rax,qword ptr ss:[rsp+88]                     ; 【成功处理】取出内核返回的进程句柄,作为OpenProcess的返回值(参数转换后的最终结果)
00007FF881FAF377                            | 48 83 C4 68   | add rsp,68                                        ; 【栈恢复】释放之前分配的0x68字节栈空间(参数转换用的临时空间)
00007FF881FAF37B                            | C3            | ret                                               ; 【函数返回】回到调用处,返回句柄(参数转换完成后的结果)
00007FF881FAF37C                            | CC            | int3                                              ; 【调试标记】断点指令,无参数处理逻辑
; ======================================
; 错误处理分支(参数转换后的调用失败时执行)
; ======================================
00007FF881FAF37D                            | 8B C8         | mov ecx,eax                                       ; 【错误处理】把失败的返回值存入ecx,准备传递给错误处理函数
00007FF881FAF37F                            | E8 DC F2 FF F | call kernelbase.7FF881FAE660                      ; 【错误处理】调用错误函数(处理参数转换后调用失败的情况)
00007FF881FAF384                            | 33 C0         | xor eax,eax                                       ; 【返回设置】eax清零,OpenProcess返回NULL(参数转换后的调用失败)
00007FF881FAF386                            | EB EF         | jmp kernelbase.7FF881FAF377                       ; 【栈恢复】跳转到释放栈空间的指令,结束错误处理

上方前部分的代码是把 OpenProcess(123, TRUE, 555); 的三个参数转换成NtOpenProcess的4个参数,NtOpenProcess函数的第一个参数是一个内存地址,用来存放返回值句柄、第二个参数是权限也就是123,第三个参数是要不要继承句柄这里是TRUE,第四个参数是要打卡的进程id,这里是555,然后这些操作是在Kernelbase.dll里做的,做这个的原因是为了兼容,在早期的Windows系统(比如Windows xp、Windows 7)是没有Kernelbase.dll的它是直接kernel32.dll到ntdll.dll然后进入内核,所以为了兼容老版本的系统,在新版本的操作系统(比如Windows10、Windows11)做了一个Kernelbase.dll进行扩展


img

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值