windows内核研究(系统调用 1)

发布于:2025-07-09 ⋅ 阅读:(18) ⋅ 点赞:(0)

WindowsAPI函数的调用过程


什么是WindowsApi?

Windows API(Application Programming Interface,应用程序编程接口)是微软为Windows操作系统提供的一套系统级编程接口,允许开发者与操作系统内核、硬件、系统服务等进行交互。它是开发Windows应用程序的基础,几乎所有Windows软件(包括系统工具、驱动程序、桌面应用等)都直接或间接依赖于Windows API

WindowsApi主要存放在C:\Windows\system32下的所有.dll文件
几个重要的DLl:

  • Kernel32.dll:最核心的功能模块,比如管理内存,进程和线程相关的函数等
  • User32.dll:是Windows用户界面相关应用程序接口,如创建窗口和发送消息等。
  • GDI32.dll:图形设备接口,包含用于画图和显示
  • NTdll.dll:大多数的Api都会通过这个dll进入内核(0环)

分析ReadProcessMemory函数

使用IDA Pro打开Kernel32.dll,这个DLL中就有ReadProcessMemory
在这里插入图片描述

在windows7系统之后 ,微软把很多内部函数的实现细节放到了KernelBase.dll这个DLL当中,Kernel32.dll在后面的系统为了兼容任然存在,这里我们直接分析KernelBase.dll

x86

在这里插入图片描述
这里就是它32位的ReadProcessMemory的代码

.text:10152910 ; BOOL __stdcall ReadProcessMemory(HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesRead)
.text:10152910                 public _ReadProcessMemory@20
.text:10152910 _ReadProcessMemory@20 proc near         ; CODE XREF: EnumProcessModulesInternal(x,x,x,x,x)+55↑p
.text:10152910                                         ; EnumProcessModulesInternal(x,x,x,x,x)+74↑p ...
.text:10152910
.text:10152910 NumberOfBytesRead= dword ptr -4
.text:10152910 hProcess        = dword ptr  8
.text:10152910 lpBaseAddress   = dword ptr  0Ch
.text:10152910 lpBuffer        = dword ptr  10h
.text:10152910 nSize           = dword ptr  14h
.text:10152910 lpNumberOfBytesRead= dword ptr  18h
.text:10152910
.text:10152910 ; FUNCTION CHUNK AT .text:101E1E90 SIZE 0000000E BYTES
.text:10152910
.text:10152910                 mov     edi, edi        ; 热补丁占用
.text:10152912                 push    ebp             ; ebp入栈
.text:10152913                 mov     ebp, esp        ; 提升堆栈
.text:10152915                 push    ecx             ; 提升栈,相当于sub esp,4
.text:10152916                 lea     eax, [ebp+NumberOfBytesRead] ; 获取ebp-4位置的地址给eax
.text:10152919                 push    eax             ; NumberOfBytesRead 参数5: 实际读取字节数的指针
.text:1015291A                 push    [ebp+nSize]     ; NumberOfBytesToRead 参数4: 要读取的字节数
.text:1015291D                 push    [ebp+lpBuffer]  ; Buffer 参数3: 目标缓冲区
.text:10152920                 push    [ebp+lpBaseAddress] ; BaseAddress 参数2: 源内存地址
.text:10152923                 push    [ebp+hProcess]  ; ProcessHandle 参数1: 进程句柄
.text:10152926                 call    ds:__imp__NtReadVirtualMemory@20 ; 调用内核函数
.text:1015292C                 mov     edx, [ebp+lpNumberOfBytesRead] ; 取lpNumberOfBytesRead指针
.text:1015292F                 test    edx, edx        ; 判断参数lpNumberOfBytesRead是否为空
.text:10152931                 jnz     short loc_10152946 ; 不等于0则跳转
.text:10152933
.text:10152933 loc_10152933:                           ; CODE XREF: ReadProcessMemory(x,x,x,x,x)+3B↓j
.text:10152933                 test    eax, eax        ; 判断是否成功执行函数
.text:10152935                 js      loc_101E1E90    ; 为负数(失败)则跳转
.text:1015293B                 mov     eax, 1          ; 成功返回1
.text:10152940
.text:10152940 loc_10152940:                           ; CODE XREF: ReadProcessMemory(x,x,x,x,x)+8F589↓j
.text:10152940                 mov     esp, ebp        ; 还原栈底
.text:10152942                 pop     ebp             ; 恢复ebp
.text:10152943                 retn    14h             ; 栈内平衡
.text:10152946 ; ---------------------------------------------------------------------------
.text:10152946
.text:10152946 loc_10152946:                           ; CODE XREF: ReadProcessMemory(x,x,x,x,x)+21↑j
.text:10152946                 mov     ecx, [ebp+NumberOfBytesRead] ; 从局部变量加载实际读取的字节数
.text:10152949                 mov     [edx], ecx      ; 写入lpNumberOfBytesRead
.text:1015294B                 jmp     short loc_10152933 ; 返回
.text:1015294B _ReadProcessMemory@20 endp

在这里插入图片描述
x64

在这里插入图片描述
这里就是它64位的ReadProcessMemory的代码

.text:00000001800BBF70 ; 由于x64的调用约定,前4个参数是由rcx,rdx,r8,r9来传递的
.text:00000001800BBF70
.text:00000001800BBF70 ; BOOL __stdcall ReadProcessMemory(HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesRead)
.text:00000001800BBF70                 public ReadProcessMemory
.text:00000001800BBF70 ReadProcessMemory proc near             ; CODE XREF: WerpReadPeb32FromProcess+EA↓p
.text:00000001800BBF70                                         ; tip2::details::recover_vector<tip2::details::TestData *>(void * const,void const *,tip2::vector_nothrow<tip2::details::TestData *> &)+3D↓p ...
.text:00000001800BBF70
.text:00000001800BBF70 NumberOfBytesRead= qword ptr -28h
.text:00000001800BBF70 var_18          = qword ptr -18h
.text:00000001800BBF70 lpNumberOfBytesRead= qword ptr  28h
.text:00000001800BBF70
.text:00000001800BBF70                 sub     rsp, 48h        ; 分配48h(72)字节的栈空间
.text:00000001800BBF74                 lea     rax, [rsp+48h+var_18] ; 获取局部变量var_18的地址
.text:00000001800BBF79                 mov     [rsp+48h+var_18], 0 ; 初始化var_18为0
.text:00000001800BBF82                 mov     [rsp+48h+NumberOfBytesRead], rax ; NumberOfBytesRead
.text:00000001800BBF87                 call    cs:__imp_NtReadVirtualMemory ; 调用内核函数
.text:00000001800BBF8E                 nop     dword ptr [rax+rax+00h] ; 什么都不做(字节对齐)
.text:00000001800BBF93                 mov     rcx, [rsp+48h+lpNumberOfBytesRead] ; 获取lpNumberOfBytesRead地址值给rcx
.text:00000001800BBF98                 test    rcx, rcx        ; 是否为null
.text:00000001800BBF9B                 jz      short loc_1800BBFA5 ; 为null则跳过
.text:00000001800BBF9D                 mov     rdx, [rsp+48h+var_18] ; 获取实际读取的字节数
.text:00000001800BBFA2                 mov     [rcx], rdx      ; 保存到lpNumberOfBytesRead指针
.text:00000001800BBFA5
.text:00000001800BBFA5 loc_1800BBFA5:                          ; CODE XREF: ReadProcessMemory+2B↑j
.text:00000001800BBFA5                 test    eax, eax        ; 校验值
.text:00000001800BBFA7                 js      short loc_1800BBFB4 ; 为负数则跳转
.text:00000001800BBFA9                 mov     eax, 1          ; 设置eax为1
.text:00000001800BBFAE                 add     rsp, 48h        ; 堆栈平衡
.text:00000001800BBFB2                 retn                    ; 返回
.text:00000001800BBFB2 ; ---------------------------------------------------------------------------
.text:00000001800BBFB3                 align 4
.text:00000001800BBFB4
.text:00000001800BBFB4 loc_1800BBFB4:                          ; CODE XREF: ReadProcessMemory+37↑j
.text:00000001800BBFB4                 mov     ecx, eax
.text:00000001800BBFB6                 call    BaseSetLastNTError ; 调用方法
.text:00000001800BBFBB                 xor     eax, eax        ; eax清0
.text:00000001800BBFBD                 add     rsp, 48h        ; 堆栈平衡
.text:00000001800BBFC1                 retn                    ; 返回

在这里插入图片描述
函数真正的实现是在NtReadVirtualMemory


分析NtReadVirtualMemory

查看导出表,可以看到是由ntdll来提供的

在这里插入图片描述
打开ntdll,打到这个方法
在这里插入图片描述

真正的实现是在0环实现的,这里只是提供了一个接口给应用程序


网站公告

今日签到

点亮在社区的每一天
去签到