Windows中的系统调用和本地API?

30 人关注

最近我在*NIX操作系统中使用了大量的汇编语言。我想知道Windows领域的情况。

Linux中的调用惯例。

mov $SYS_Call_NUM, %eax
mov $param1 , %ebx
mov $param2 , %ecx
int $0x80

就这样了。这就是我们在Linux中应该如何进行系统调用。

Linux中所有系统调用的参考。

Regarding which $SYS_Call_NUM & which parameters we can use this reference : http://docs.cs.up.ac.za/programming/asm/derick_tut/syscalls.html

官方参考 :http://kernel.org/doc/man-pages/online/dir_section_2.html

Windows中的调用惯例。

Windows中所有系统调用的参考。

非官方的:http://www.metasploit.com/users/opcode/syscalls.html,但我如何在汇编中使用这些,除非我知道调用惯例。

  • If you say, they didn't documented it. Then how is one going to write libc for windows without knowing system calls? How is one gonna do Windows Assembly programming? Atleast in the driver programming one needs to know these. right?
  • Now, whats up with the so called Native API? Is Native API & System calls for windows both are different terms referring to same thing? In order to confirm I compared these from two UNOFFICIAL Sources

    系统调用。http://www.metasploit.com/users/opcode/syscalls.html

    本地API。http://undocumented.ntinternals.net/aindex.html

    我的观察。

  • All system calls are beginning with letters Nt where as Native API is consisting of lot of functions which are not beginning with letters Nt.
  • System Call of windows are subset of Native API. System calls are just part of Native API.
  • 有谁能证实这一点并加以解释。

    EDIT:

    还有一个答案。那是第二个答案。我很喜欢它,但我不知道为什么回答者删除了它。我请求他重新发布他的答案。

    4 个评论
    你的metasploit链接被破坏了...
    "how is one going to write libc for windows" - By using the 文件化的API .Linux没有API,系统调用是最接近的东西,所以这就是你在Linux上需要使用的东西。这并不是因为这是与操作系统交互的一种非常好的方式,而是因为它是 only 有的方式。
    how is one going to write libc for windows - 通过调用WinAPI函数。 你如何自己实现这些呢? 通过在微软工作,查阅他们的内部文档和带有调用号码的代码。 对于其他任何人来说,如果你真的想编写代码,当他们改变DLLs和内核之间的私有接口时,在未来的Windows版本上会被破坏,那么就逆向工程MS的现有库。
    windows
    linux
    assembly
    kernel
    nt-native-api
    claws
    claws
    发布于 2010-03-22
    5 个回答
    RaptorFactor
    RaptorFactor
    发布于 2010-03-24
    已采纳
    0 人赞同

    如果你在Windows下做汇编编程,你不会做手动系统调用。你使用NTDLL和本地API为你做这些。

    Native API只是一个围绕内核模式的包装。它所做的就是为正确的API执行系统调用。

    你应该永远不需要手动调用系统,所以你的整个问题是多余的。

    Linux的系统调用代码不会改变,而Windows则会,这就是为什么你需要通过一个额外的抽象层(又称NTDLL)来工作。

    EDIT:

    另外,即使你在汇编级工作,你仍然可以完全访问Win32的API,没有理由一开始就使用NT的API!进口、出口等在汇编程序中都能正常工作。

    EDIT2:

    如果你真的想进行手动系统调用,你将需要为每个相关的Windows版本反转NTDLL,添加版本检测(通过PEB),并为每个调用执行系统调用查询。

    然而,这将是愚蠢的。NTDLL的存在是有原因的。

    人们已经完成了反向工程的部分:见 https://j00ru.vexillium.org/syscalls/nt/64/ 为每个Windows内核的系统调用号码的表格。 (注意,即使在Windows 10的不同版本之间,后面的行也会发生变化。) 同样,除了在你自己的机器上进行个人使用的实验以了解更多关于asm和/或Windows内部的信息之外,这是一个坏主意。 不要将系统调用内联到你发布给其他人的代码中。

    A short & concise article that is a great supplement to this answer: codeproject.com/KB/system/Win32.aspx
    那篇文章不是你要找的东西。 它显示了如何执行手动系统调用,你不应该这样做,因为这些数字在不同的Windows版本和服务包中是变化的。 正如我已经说过的,你应该使用Windows API来为你执行调度。 NTDLL会自动映射到所有进程中。因此,即使由于某种原因你不能使用导入(我想不出有什么合理的时候会出现这种情况),你仍然可以获得NTDLL的句柄,并手动枚举EAT以获得必要的函数指针(尽管你不应该有这种需要)。
    @claws 该文章是一个 very 有趣的阅读,非常感谢
    jrh
    这并不是专门针对这个答案的作者,但我不明白为什么这些 "不要这样做 "的答案在SO上如此盛行,这不是一个 "为专业和业余程序员 "的网站吗?为什么一方面,这个网站 鼓励极端的研究工作 但当你问到这些低层次的好奇心问题时,我看到的是源源不断的 "你不需要知道这些!!"。这个网站的真正目标受众是谁呢?是那些需要握住他们的手的人,还是那些真正愿意深入挖掘的人?
    riQQ
    这里是爪子在10年3月22日5:09最初链接的文章的新位置。 codeproject.com/Articles/33870/...
    Stewart
    Stewart
    发布于 2010-03-24
    0 人赞同

    关于windows系统调用惯例,你需要知道的另一件事是,据我所知,系统调用表是作为构建过程的一部分生成的。这意味着它们可以简单地改变--没有人跟踪它们。如果有人在列表的顶部添加了一个新的,这并不重要。NTDLL仍然工作,所以其他调用NTDLL的人也仍然工作。

    甚至用于执行系统调用的机制(即int,或sysenter)也不是固定不变的,在过去也曾发生过变化,我认为从前同一版本的windows使用不同的DLL,根据机器中的CPU使用不同的进入机制。

    +1 因为我发现这非常有趣。你有什么资源(互联网或书籍)可以让人更多地了解那种Win32 API/syscall的内部情况吗?
    这本书有点过时了,但《Windows 2000内部》我认为涵盖了这一点。 nynaeve.net/?p=48 有一个很好的讨论,也证明了在x86和x64的windows系统上至少有三个系统调用约定在使用。IA64可能又做了一些完全不同的事情,然后当然还有Alpha、PowerPC、MIPS和可能其他的。 当然,通常的告诫是适用的--所有这些都是没有记录的,而且可能会改变。
    Elliot
    Elliot
    发布于 2010-03-24
    0 人赞同

    我对在汇编中做一个没有导入的windows API调用很感兴趣(作为一个教育练习),所以我写了下面这个FASM汇编来做NtDll!NtCreateFile的工作。这是在我的64位版本的Windows(Win10 1803版本10.0.17134)上的粗略演示,它在调用后崩溃了,但syscall的返回值是0,所以它是成功的。一切都是按照Windows x64的调用惯例设置的,然后将系统调用号加载到RAX中,然后就是syscall汇编指令来运行调用。我的例子创建了文件c:\HelloWorldFile_FASM,所以必须以 "管理员 "身份运行。

    format PE64 GUI 4.0
    entry start
    section '.text' code readable executable
     start: 
     ;puting the first four parameters into the right registers
                                mov rcx, _Handle
                                mov rdx, [_access_mask]
                                mov r8, objectAttributes
                                mov r9, ioStatusBlock
     ;I think we need 1 stack word of padding:
                                push 0x0DF0AD8B
     ;pushing the other params in reverse order:
                                push [_eaLength]
                                push [_eaBuffer]
                                push [_createOptions]
                                push [_createDisposition]
                                push [_shareAcceses]
                                push [_fileAttributes]
                                push [_pLargeInterger]
     ;adding the shadow space (4x8)
     ;                               push 0x0
     ;                               push 0x0
     ;                               push 0x0
     ;                               push 0x0
     ;pushing the 4 register params into the shadow space for ease of debugging
                                push r9
                                push r8
                                push rdx
                                push rcx
     ;now pushing the return address to the stack:
                                push endOfProgram
                                mov r10, rcx ;copied from ntdll!NtCreateFile, not sure of the reason for this
                                mov eax, 0x55
                                syscall
     endOfProgram:
     section '.data' data readable writeable
     ;parameters------------------------------------------------------------------------------------------------
     _Handle                         dq      0x0
     _access_mask                    dq      0x00000000c0100080
     _pObjectAttributes              dq      objectAttributes        ; at 00402058
     _pIoStatusBlock                 dq           ioStatusBlock
     _pLargeInterger                 dq      0x0
     _fileAttributes                 dq      0x0000000000000080
     _shareAcceses                   dq      0x0000000000000002
     _createDisposition              dq      0x0000000000000005
     _createOptions                  dq      0x0000000000000060
     _eaBuffer                       dq      0x0000000000000000       ; "optional" param
     _eaLength                       dq      0x0000000000000000
     ;----------------------------------------------------------------------------------------------------------
                                align   16
     objectAttributes:
     _oalength                       dq      0x30
     _rootDirectory                  dq      0x0
     _objectName                     dq           unicodeString
     _attributes                     dq      0x40
     _pSecurityDescriptor            dq      0x0
     _pSecurityQualityOfService      dq      securityQualityOfService
     unicodeString:
     _unicodeStringLength            dw      0x34
     _unicodeStringMaxumiumLength    dw      0x34, 0x0, 0x0
     _pUnicodeStringBuffer           dq      _unicodeStringBuffer
     _unicodeStringBuffer            du      '\??\c:\HelloWorldFile_FASM'       ; may need to "run as adinistrator" for the file create to work.
     ioStatusBlock:
     _status_pointer                 dq      0x0
     _information                    dq      0x0
     securityQualityOfService:
     _sqlength                       dd      0xC
     _impersonationLevel             dd      0x2
     _contextTrackingMode            db      0x1
     _effectiveOnly                  db      0x1, 0x0, 0x0
    

    我使用了Ntdll!NtCreateFile的文档,我还使用了内核调试器来查看和复制很多参数。

    __kernel_entry NTSTATUS NtCreateFile(
      OUT PHANDLE                      FileHandle,
      IN ACCESS_MASK                   DesiredAccess,
      IN POBJECT_ATTRIBUTES            ObjectAttributes,
      OUT PIO_STATUS_BLOCK             IoStatusBlock,
      IN PLARGE_INTEGER AllocationSize OPTIONAL,
      IN ULONG                         FileAttributes,
      IN ULONG                         ShareAccess,
      IN ULONG                         CreateDisposition,
      IN ULONG                         CreateOptions,
      IN PVOID EaBuffer                OPTIONAL,
      IN ULONG                         EaLength
        
    谢谢你提供的关于mov r10, rcx行的信息;我还没有研究过这个。我的Windows版本是10.0.17134 Build 17134。
    @PeterCordes 我并不是说我推荐直接使用系统调用号码(因为它们确实在变化),但系统调用号码是 非官方记录的 .Windows版本10.0.17134是Windows(1803),NtCreateFile的syscall是0x55。到目前为止,Win10的5个发布版本都使用0x55。(Win10之前的版本使用了0x55以外的系统调用号码)
    替换代码0】是因为syscall接口通过r10而不是RCX传递第一个参数。一个普通的64位函数调用使用RCX、RDX、R8和R9。Syscall使用R10、RDX、R8和R9。原因是 syscall 指令指令覆盖了RCX(它也覆盖了R11)。微软选择使用R10来代替系统调用的第一个参数,因此你会看到 mov r10, rcx
    额外的填充(即 push 0x0DF0AD8B )的原因是为了保持堆栈对齐,以达到性能的目的。如果在系统调用之前有相等于偶数的推送,你应该添加8个字节(一个四字)的填充(否则你不需要填充)。这是因为在执行 start 的时候,由于返回地址在堆栈上,所以堆栈错位了8。
    至于为什么你的代码会失败,那是因为你在 syscall 之后没有清理堆栈。你推送了相当于13个四字节的数据来设置系统调用,你需要在系统调用后调整堆栈,在做 ret 前将堆栈指针恢复到之前的状态。13*8=104字节在syscall之前放在栈上。在系统调用之后,你可以简单地做 add rsp, 104 来清理堆栈。
    Will
    Will
    发布于 2010-03-24
    0 人赞同

    Windows系统调用是通过调用到系统DLLs,如 kernel32.dll gdi32.dll 来进行的,这是用普通的子程序调用完成的。 捕获到操作系统特权层的机制是没有记录的,但这没关系,因为像 kernel32.dll 这样的DLL为你做这些。

    而我所说的系统调用,指的是记录在案的Windows API入口点,如 CreateProcess() GetWindowText() 。 设备驱动程序一般会使用与Windows DDK不同的API。

    1.我将如何在汇编语言编程中使用这些东西?2.Windows API和系统调用不是一回事。WINDOWS API use 系统调用。在linux领域的类似比喻是POSIX API(WINDOWS API)使用linux内核(windows内核)提供的系统调用。所以,我的担心是关于 true 系统调用。
    Will
    我明白,API调用和进入操作系统特权层的陷阱(你所说的 "真正的 "系统调用)之间是有区别的。 这些 "真正的 "系统调用是Windows系统DLLs的一个实现细节。 你也许可以通过拆解DLLs和查看汇编来弄清楚它们是如何工作的。 或者你可以直接写你的汇编代码,适当地调用DLLs......这是有可能的。
    claws
    claws
    发布于 2010-03-24
    0 人赞同