zoukankan      html  css  js  c++  java
  • vc在x64体系的一般传参数方式

    前篇分析过在objc中函数调用传参的一般方式,本篇分析vc在x64体系中的一般传参方式。手头上因为没有64位的vc编译器,只好用windbg看ms自身的函数是怎么样调用的。

    首先看两个再熟悉不过的api,memset和CreateHeap。函数原型和使用像呼吸一样了,也不用多解释一看就明白。

    调用memset(rcx, rdx, r8):

    00000000`76df5f63 488b842480000000 mov     rax,qword ptr [rsp+80h]
    00000000`76df5f6b 4889842498000000 mov     qword ptr [rsp+98h],rax
    00000000`76df5f73 458bc5          mov     r8d,r13d
    00000000`76df5f76 33d2            xor     edx,edx
    00000000`76df5f78 488bc8          mov     rcx,rax
    00000000`76df5f7b e810cfffff      call    ntdll!memset (00000000`76df2e90)
    
    

    调用RtlCreateHeap(rcx, rdx, r8, r9, [rsp+20h], [rsp+28h]):

    00000000`76de47a6 4c8b842498000000 mov     r8,qword ptr [rsp+98h]
    00000000`76de47ae 488d05ab200000  lea     rax,[ntdll!RtlReleaseMemoryStream (00000000`76de6860)]
    00000000`76de47b5 448d4e01        lea     r9d,[rsi+1]
    00000000`76de47b9 488bd7          mov     rdx,rdi
    00000000`76de47bc 4889842488010000 mov     qword ptr [rsp+188h],rax
    00000000`76de47c4 488d842440010000 lea     rax,[rsp+140h]
    00000000`76de47cc b900800000      mov     ecx,8000h
    00000000`76de47d1 4889442428      mov     qword ptr [rsp+28h],rax
    00000000`76de47d6 c784244001000060000000 mov dword ptr [rsp+140h],60h
    00000000`76de47e1 48c784247801000000100000 mov qword ptr [rsp+178h],1000h
    00000000`76de47ed 4889742420      mov     qword ptr [rsp+20h],rsi
    00000000`76de47f2 4c89842480010000 mov     qword ptr [rsp+180h],r8
    00000000`76de47fa e8a18cffff      call    ntdll!RtlCreateHeap (00000000`76ddd4a0)

    再来分析一下有多个参数的api函数。

    00000000`74a4b6f9 4c8d5c2450      lea     r11,[rsp+50h]
    00000000`74a4b6fe 488d442470      lea     rax,[rsp+70h]
    00000000`74a4b703 4c895c2448      mov     qword ptr [rsp+48h],r11
    00000000`74a4b708 4889442440      mov     qword ptr [rsp+40h],rax
    00000000`74a4b70d 488d842480000000 lea     rax,[rsp+80h]
    00000000`74a4b715 4889442438      mov     qword ptr [rsp+38h],rax
    00000000`74a4b71a 488d842490000000 lea     rax,[rsp+90h]
    00000000`74a4b722 4c8d8c24b0000000 lea     r9,[rsp+0B0h]
    00000000`74a4b72a 4889442430      mov     qword ptr [rsp+30h],rax
    00000000`74a4b72f 488d8424a0000000 lea     rax,[rsp+0A0h]
    00000000`74a4b737 4c8d8424c0000000 lea     r8,[rsp+0C0h]
    00000000`74a4b73f 488d542460      lea     rdx,[rsp+60h]
    00000000`74a4b744 488d8c2400010000 lea     rcx,[rsp+100h]
    00000000`74a4b74c 4c89742428      mov     qword ptr [rsp+28h],r14
    00000000`74a4b751 4889442420      mov     qword ptr [rsp+20h],rax
    00000000`74a4b756 ff153c5affff    call    qword ptr [wow64+0x1198 (00000000`74a41198)]

    wow64经一些处理后跳转到ntdll!RtlCreateProcessParameters

    ntdll!RtlCreateProcessParameters:
    00000000`76dede20 4883ec68        sub     rsp,68h
    00000000`76dede24 488b8424b8000000 mov     rax,qword ptr [rsp+0B8h]
    00000000`76dede2c c744245000000000 mov     dword ptr [rsp+50h],0
    00000000`76dede34 4889442448      mov     qword ptr [rsp+48h],rax
    00000000`76dede39 488b8424b0000000 mov     rax,qword ptr [rsp+0B0h]
    00000000`76dede41 4889442440      mov     qword ptr [rsp+40h],rax
    00000000`76dede46 488b8424a8000000 mov     rax,qword ptr [rsp+0A8h]
    00000000`76dede4e 4889442438      mov     qword ptr [rsp+38h],rax
    00000000`76dede53 488b8424a0000000 mov     rax,qword ptr [rsp+0A0h]
    00000000`76dede5b 4889442430      mov     qword ptr [rsp+30h],rax
    00000000`76dede60 488b842498000000 mov     rax,qword ptr [rsp+98h]
    00000000`76dede68 4889442428      mov     qword ptr [rsp+28h],rax
    00000000`76dede6d 488b842490000000 mov     rax,qword ptr [rsp+90h]
    00000000`76dede75 4889442420      mov     qword ptr [rsp+20h],rax
    00000000`76dede7a e851b4feff      call    ntdll!RtlCreateProcessParametersEx (00000000`76dd92d0)

    RtlCreateProcessParameters函数将上一层传入的参数原封不动,并在后面增加一个参数0,然后调RtlCreateProcessParametersEx。

    RtlCreateProcessParameters函数一共有10个参数,RtlCreateProcessParametersEx函数一共有11个参数。
    前4个参数使用的寄存器rcx,rdx,r8和r9, 后6个参数用了入栈方式,虽然前4个参数作用了寄存器,但仍然在堆栈中空出了4个qword的位置。第五个参数起是由rsp+20h处开始放入(mov)堆栈(,入栈push是由最后一个开始)。
    线程在调用RtlCreateProcessParameters前,准备调用栈过程中并没有往rsp~rsp+18h处写东西,而从寄存器的调配可以看出用了寄存器rcx,rdx,r8,r9。
    线程在调用RtlCreateProcessParametersEx前,将上一层调用栈后面6个参数搬运了过来,并增加了一个参数放到rsp+50h处。

    通过windbg浏览几处api函数调用,可以看出vc的__stdcall调用的传参方式。前4个参数使用rcx,rdx,r8,r9,之后的参数使用堆栈并且在调用栈中空出4个qword位置,第5个参数不是rsp-8而是rsp-28h在函数入口处时。如果参数数量不超过4个,不使用堆栈。反汇编代码也说明vc在传参数时没有使用到rdi,rsi。

    下一篇分析gcc在x64的传参方式。

    上一篇分析objc在x64的传参方式。

  • 相关阅读:
    万亿养老市场如何抢占商机?云巢智慧康养物联网加速器,三招化解ISV痛点!
    13个VSCode使用技巧,开启高效的开发模式
    添零占位 —— 快速生成N个0的六种办法
    使用 dumi 打包 React 组件库并生成文档站点
    Transformer架构记录(四)
    Transformer架构记录(三)
    Transformer架构记录(二)
    Transformer架构记录(一)
    NLP预训练发展小结二(Bert之后)
    p3c 插件,是怎么检查出你那屎山的代码?
  • 原文地址:https://www.cnblogs.com/bbqzsl/p/5082929.html
Copyright © 2011-2022 走看看