吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1709|回复: 1
收起左侧

[其他转载] x64调用约定理论及实战

[复制链接]
b917893200 发表于 2020-9-26 12:25
fastcall资料网上很多了,我再总结一下,调用方为被调用方开辟堆栈(维护堆栈),填充函数,准备调用环境。
image.png
样本程序。a函数入口打断点.
断下之后

void a()
{
00007FF6B11117C0 40 55                push        rbp  
00007FF6B11117C2 57                   push        rdi  
00007FF6B11117C3 48 81 EC F8 00 00 00 sub         rsp,0F8h  
00007FF6B11117CA 48 8D 6C 24 30       lea         rbp,[rsp+30h]  
00007FF6B11117CF 48 8B FC             mov         rdi,rsp  
00007FF6B11117D2 B9 3E 00 00 00       mov         ecx,3Eh  
00007FF6B11117D7 B8 CC CC CC CC       mov         eax,0CCCCCCCCh  
00007FF6B11117DC F3 AB                rep stos    dword ptr [rdi]  
00007FF6B11117DE 48 8D 0D 60 F8 00 00 lea         rcx,[__0A9402C3_main@cpp (07FF6B1121045h)]  
00007FF6B11117E5 E8 9D F8 FF FF       call        __CheckForDebuggerJustMyCode (07FF6B1111087h)   //上面是Debug模式下的初始化代码 rep stos类似循环,循环次数在rcx中,一般都是for(;;;){memcpy();}这种代码
    f(1,2,3,4,5);
00007FF6B11117EA C7 44 24 20 05 00 00 00 mov         dword ptr [rsp+20h],5 //超过四个参数,存放在栈中。这里为什么是20h,因为rsp->rsp+16h是暂存前4个参数,寄存器有易失性,你要多次用参数就得保存
00007FF6B11117F2 41 B9 04 00 00 00    mov         r9d,4  //第四个参数r9中
00007FF6B11117F8 41 B8 03 00 00 00    mov         r8d,3  //第三个参数r8中
00007FF6B11117FE BA 02 00 00 00       mov         edx,2  //第二个参数rdx中
00007FF6B1111803 B9 01 00 00 00       mov         ecx,1  //第一个参数rcx中
00007FF6B1111808 E8 8D F9 FF FF       call        f (07FF6B111119Ah)     
}
00007FF6B111180D 48 8D A5 C8 00 00 00 lea         rsp,[rbp+0C8h]  
00007FF6B1111814 5F                   pop         rdi  
00007FF6B1111815 5D                   pop         rbp  
00007FF6B1111816 C3                   ret  


bool f(int a,int b, int c,int d ,int f)
{
//x86可以根据ret n 来看函数参数,ia-64的话可以根据入口堆栈赋值和入口前堆栈赋值的情况判断参数个数
00007FF6B1111830 44 89 4C 24 20       mov         dword ptr [rsp+20h],r9d  //进入函数的第一件事,保存前4个参数,因为返回地址压入占8个字节,所以是rsp+8到rsp+20
00007FF6B1111835 44 89 44 24 18       mov         dword ptr [rsp+18h],r8d  
00007FF6B111183A 89 54 24 10          mov         dword ptr [rsp+10h],edx  
00007FF6B111183E 89 4C 24 08          mov         dword ptr [rsp+8],ecx  
00007FF6B1111842 55                   push        rbp  
00007FF6B1111843 57                   push        rdi  
00007FF6B1111844 48 81 EC 68 01 00 00 sub         rsp,168h  
00007FF6B111184B 48 8D 6C 24 20       lea         rbp,[rsp+20h]  
00007FF6B1111850 48 8B FC             mov         rdi,rsp  
00007FF6B1111853 B9 5A 00 00 00       mov         ecx,5Ah  
00007FF6B1111858 B8 CC CC CC CC       mov         eax,0CCCCCCCCh  
00007FF6B111185D F3 AB                rep stos    dword ptr [rdi]  
00007FF6B111185F 8B 8C 24 88 01 00 00 mov         ecx,dword ptr [rsp+188h]  
00007FF6B1111866 48 8D 0D D8 F7 00 00 lea         rcx,[__0A9402C3_main@cpp (07FF6B1121045h)]  
00007FF6B111186D E8 15 F8 FF FF       call        __CheckForDebuggerJustMyCode (07FF6B1111087h)  
    b = c = d = f = 1;
00007FF6B1111872 C7 85 80 01 00 00 01 00 00 00 mov         dword ptr [rbp+0000000000000180h],1  //用rbp索引,更常见的其实是rsp索引
00007FF6B111187C 8B 85 80 01 00 00    mov         eax,dword ptr [rbp+0000000000000180h]  
00007FF6B1111882 89 85 78 01 00 00    mov         dword ptr [rbp+0000000000000178h],eax  
00007FF6B1111888 8B 85 78 01 00 00    mov         eax,dword ptr [rbp+0000000000000178h]  
00007FF6B111188E 89 85 70 01 00 00    mov         dword ptr [rbp+0000000000000170h],eax  
00007FF6B1111894 8B 85 70 01 00 00    mov         eax,dword ptr [rbp+0000000000000170h]  
00007FF6B111189A 89 85 68 01 00 00    mov         dword ptr [rbp+0000000000000168h],eax  
    int k1, k12k2, k2, k;
    if (a == 1)
00007FF6B11118A0 83 BD 60 01 00 00 01 cmp         dword ptr [a],1  
00007FF6B11118A7 75 02                jne         f+7Bh (07FF6B11118ABh)  
        return true;
00007FF6B11118A9 B0 01                mov         al,1  
}
00007FF6B11118AB 48 8D A5 48 01 00 00 lea         rsp,[rbp+148h]  
00007FF6B11118B2 5F                   pop         rdi  
00007FF6B11118B3 5D                   pop         rbp  
00007FF6B11118B4 C3                   ret  

//接下来实战分析一个内核api  PsLookupProcessByProcessId
PAGE:00000001403530A6 loc_1403530A6:                          ; CODE XREF: PsOpenProcess+230↓j
PAGE:00000001403530A6                 cmp     qword ptr [rsp+218h+var_1C8+8], 0
PAGE:00000001403530AC                 jnz     loc_140353147
PAGE:00000001403530B2                 lea     rdx, [rsp+218h+Object]
PAGE:00000001403530B7                 mov     rcx, qword ptr [rsp+218h+var_1C8]
PAGE:00000001403530BC                 call    PsLookupProcessByProcessId  //我们可以看到这个函数有2个参数


PsLookupProcessByProcessId proc near    ; CODE XREF: ViCreateProcessCallback+AA058↑p
PAGE:00000001403531FC                                         ; PsOpenProcess+15C↑p ...
PAGE:00000001403531FC
PAGE:00000001403531FC var_38          = dword ptr -38h
PAGE:00000001403531FC arg_0           = qword ptr  8
PAGE:00000001403531FC arg_8           = qword ptr  10h
PAGE:00000001403531FC arg_10          = qword ptr  18h
PAGE:00000001403531FC
PAGE:00000001403531FC ; FUNCTION CHUNK AT PAGE:00000001403B8030 SIZE 00000082 BYTES
PAGE:00000001403531FC
PAGE:00000001403531FC                 mov     [rsp+arg_0], rbx    //我们看到这里并不是将参数保存,而是保存其他的寄存器,说明这个函数的流程一定不长,并且参数只用一次(这点可以在wrk或者reactos中验证)
PAGE:0000000140353201                 mov     [rsp+arg_8], rbp
PAGE:0000000140353206                 mov     [rsp+arg_10], rsi
PAGE:000000014035320B                 push    rdi
PAGE:000000014035320C                 push    r12
PAGE:000000014035320E                 push    r13
PAGE:0000000140353210                 sub     rsp, 20h
PAGE:0000000140353214                 mov     rdi, gs:_KPCR.Prcb.CurrentThread
PAGE:000000014035321D                 xor     r12d, r12d
PAGE:0000000140353220                 mov     rbp, rdx
PAGE:0000000140353223                 dec     word ptr [rdi+1C4h]
PAGE:000000014035322A                 mov     rbx, r12
PAGE:000000014035322D                 mov     rdx, rcx     //rcx(arg0 ) ProcessId 这里调用完之后此参数就不用了,所以不用保存这个参数,因此前面保存的是寄存器环境
PAGE:0000000140353230                 mov     rcx, cs:PspCidTable
PAGE:0000000140353237                 call    ExMapHandleToPointer
………………………………………………
函数末尾
PAGE:00000001403532C4                 mov     rbx, [rsp+38h+arg_0]   //将原先保存的寄存器恢复
PAGE:00000001403532C9                 mov     rbp, [rsp+38h+arg_8]
PAGE:00000001403532CE                 mov     rsi, [rsp+38h+arg_10]
PAGE:00000001403532D3                 add     rsp, 20h
PAGE:00000001403532D7                 pop     r13
PAGE:00000001403532D9                 pop     r12
PAGE:00000001403532DB                 pop     rdi
PAGE:00000001403532DC                 retn



发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

tark 发表于 2020-9-26 12:57
收藏起来,慢慢学习
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-26 01:34

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表