飘云阁

 找回密码
 加入我们

QQ登录

只需一步,快速开始

查看: 3934|回复: 8

[x64] X64 初接触续

[复制链接]

该用户从未签到

发表于 2015-1-1 12:11:09 | 显示全部楼层 |阅读模式
正好这三天看一下这方面的资料,希望可以有所收获。

看X64的汇编,得先去弄明白这几个事情:
一方面是看官方文档,找点资料,另一方面自行事件,非亲眼所见的东西都不靠谱。

http://msdn.microsoft.com/zh-cn/library/h2k70f3s.aspx


先来个下马威,EXE的载入的默认基地址是大于 0xFFFF-FFFF的,当然用户也可以指定基地址。

01.jpg

一、传参,先看非浮点的。

参数小于4,参数大于4。谁去平衡堆栈,调用系统 stdcall 和 cdecl 的堆栈平衡。X64使用 __vectorcall 调用约定 ...



  1. // DEBUG 编译

  2. 000000013F6B197D | B9 01 00 00 00           | mov ecx,1                               | ;crtexe.c:527
  3. 000000013F6B1982 | FF 15 10 9B 00 00        | call qword ptr ds:[<__imp__CrtSetCheckC |
  4. 000000013F6B1988 | 4C 8B 1D 11 9B 00 00     | mov r11,qword ptr ds:[<__imp___winitenv | ;crtexe.c:582
  5. 000000013F6B198F | 48 8B 05 DA 77 00 00     | mov rax,qword ptr ds:[<envp>]           |
  6. 000000013F6B1996 | 49 89 03                 | mov qword ptr ds:[r11],rax              | ;r11:__winitenv
  7. 000000013F6B1999 | 4C 8B 05 D0 77 00 00     | mov r8,qword ptr ds:[<envp>]            | ;crtexe.c:583
  8. 000000013F6B19A0 | 48 8B 15 D1 77 00 00     | mov rdx,qword ptr ds:[<argv>]           |
  9. 000000013F6B19A7 | 8B 0D BB 77 00 00        | mov ecx,dword ptr ds:[<argc>]           |
  10. 000000013F6B19AD | E8 6C F6 FF FF           | call <testasm64.@ILT+25(wmain)>         |


  11. // 为什么没有看到调用函数前先把堆栈空间申请出来,函数内就直接用 RSP+XX 往里塞数据了,看下文解释 ....

  12. int _tmain(int argc, _TCHAR* argv[])

  13. 000000013F6B1140 | 48 89 54 24 10           | mov qword ptr ss:[rsp+10],rdx           | ;testasm64.cpp:29
  14. 000000013F6B1145 | 89 4C 24 08              | mov dword ptr ss:[rsp+8],ecx            |
  15. 000000013F6B1149 | 57                       | push rdi                                |
  16. 000000013F6B114A | 48 81 EC 90 00 00 00     | sub rsp,90                              |
  17. 000000013F6B1151 | 48 8B FC                 | mov rdi,rsp                             |
  18. 000000013F6B1154 | 48 B9 24 00 00 00 00 00  | mov rcx,24                              |
  19. 000000013F6B115E | B8 CC CC CC CC           | mov eax,CCCCCCCC                        |
  20. 000000013F6B1163 | F3 AB                    | rep stos dword ptr es:[rdi]             |


  21. ....

  22. 000000013F6B1247 | 48 81 C4 90 00 00 00     | add rsp,90                              |
  23. 000000013F6B124E | 5F                       | pop rdi                                 |
  24. 000000013F6B124F | C3                       | ret                                     |

复制代码



01.  函数内基本看不到再用 EBP 去寻址,全部变成用 ESP 来寻址参数及其函数内局部变量了。

函数内部无需保存的寄存器:
RAX, RCX, RDX, R8, R9, R10, R11  (一下子可以多用4个寄存器,爽歪歪)
函数内部无需保存的寄存器:
RBX, RSP, RBP, RSI, RDI, R12~R15 (前五个寄存器和X86是一样的,后边四个算是福利了)

所以编译器,在函数内部能不使用后边的寄存器就不使用,所以基本看不到 PUSHAD POPAD 这样的全部压栈指令了。

02. 我们来看下,为啥函数调用方不去申请 RSP 空间,而函数内部就可以直接给 RSP+XX 赋值:



  1. __declspec(noinline)
  2. int
  3. __tmainCRTStartup(
  4.         void
  5.         )
  6. {
  7.         __try
  8.         {

  9.             void *lock_free=0;
  10.             void *fiberid=((PNT_TIB)NtCurrentTeb())->StackBase;
  11.             int nested=FALSE;
  12.             while((lock_free=InterlockedCompareExchangePointer((volatile PVOID *)&__native_startup_lock, fiberid, 0))!=0)
  13.             {
  14.                  ....
  15.             }

  16.             if (__native_startup_state == __initializing)
  17.             {
  18.                 _amsg_exit( _RT_CRT_INIT_CONFLICT);
  19.             }
  20.             else if (__native_startup_state == __uninitialized)
  21.             {
  22.                 __native_startup_state = __initializing;

  23.                 if (_initterm_e( __xi_a, __xi_z ) != 0)    // here ...
  24.                 {
  25.                     return 255;
  26.                 }

  27.             }
  28.             else
  29.             {
  30.                 has_cctor = 1;
  31.             }

  32. 000000013F6F1820 | 48 83 EC 68              | sub rsp,68                                    | ;crtexe.c:410
  33. 000000013F6F1824 | 48 C7 44 24 40 00 00 00  | mov qword ptr ss:[rsp+40],0                   | ;+40 // void *lock_free
  34. 000000013F6F182D | E8 EE 01 00 00           | call <testasm64.NtCurrentTeb>                 | ;crtexe.c:458
  35. 000000013F6F1832 | 48 8B 40 08              | mov rax,qword ptr ds:[rax+8]                  |
  36. 000000013F6F1836 | 48 89 44 24 38           | mov qword ptr ss:[rsp+38],rax                 | ;+38 // void *fiberid
  37. 000000013F6F183B | C7 44 24 30 00 00 00 00  | mov dword ptr ss:[rsp+30],0                   | ;+30 // int nested
  38. 000000013F6F1843 | 48 8B 54 24 38           | mov rdx,qword ptr ss:[rsp+38]                 | ;crtexe.c:460
  39. 000000013F6F1848 | 48 8D 0D 01 7F 00 00     | lea rcx,qword ptr ds:[<__native_startup_lock> | ;rcx:__xi_a
  40. 000000013F6F184F | 33 C0                    | xor eax,eax                                   | ;0
  41. 000000013F6F1851 | F0 48 0F B1 11           | lock cmpxchg qword ptr ds:[rcx],rdx           | ;rcx:__xi_a, rdx:__xi_z
  42. 000000013F6F1856 | 48 89 44 24 40           | mov qword ptr ss:[rsp+40],rax                 |
  43. 000000013F6F185B | 48 83 7C 24 40 00        | cmp qword ptr ss:[rsp+40],0                   | ;跟0比较
  44. 000000013F6F1861 | 74 23                    | je testasm64.13F6F1886                        |
  45. 000000013F6F1863 | 48 8B 44 24 38           | mov rax,qword ptr ss:[rsp+38]                 | ;crtexe.c:462
  46. 000000013F6F1868 | 48 39 44 24 40           | cmp qword ptr ss:[rsp+40],rax                 |
  47. 000000013F6F186D | 75 0A                    | jnz testasm64.13F6F1879                       |
  48. 000000013F6F186F | C7 44 24 30 01 00 00 00  | mov dword ptr ss:[rsp+30],1                   | ;crtexe.c:464
  49. 000000013F6F1877 | EB 0D                    | jmp testasm64.13F6F1886                       | ;crtexe.c:465
  50. 000000013F6F1879 | B9 E8 03 00 00           | mov ecx,3E8                                   | ;crtexe.c:472
  51. 000000013F6F187E | FF 15 6C 9A 00 00        | call qword ptr ds:[<__imp_Sleep>]             |
  52. 000000013F6F1884 | EB BD                    | jmp testasm64.13F6F1843                       | ;crtexe.c:473
  53. 000000013F6F1886 | 8B 05 B4 7E 00 00        | mov eax,dword ptr ds:[<__native_startup_state | ;crtexe.c:475
  54. 000000013F6F188C | 83 F8 01                 | cmp eax,1                                     |
  55. 000000013F6F188F | 75 0C                    | jnz testasm64.13F6F189D                       |
  56. 000000013F6F1891 | B9 1F 00 00 00           | mov ecx,1F                                    | ;crtexe.c:477
  57. 000000013F6F1896 | E8 95 0D 00 00           | call <testasm64._amsg_exit>                   |
  58. 000000013F6F189B | EB 41                    | jmp testasm64.13F6F18DE                       |
  59. 000000013F6F189D | 8B 05 9D 7E 00 00        | mov eax,dword ptr ds:[<__native_startup_state | ;crtexe.c:479
  60. 000000013F6F18A3 | 85 C0                    | test eax,eax                                  |
  61. 000000013F6F18A5 | 75 2D                    | jnz testasm64.13F6F18D4                       |
  62. 000000013F6F18A7 | C7 05 8F 7E 00 00 01 00  | mov dword ptr ds:[<__native_startup_state>],1 | ;crtexe.c:481
  63. 000000013F6F18B1 | 48 8D 15 A8 4D 00 00     | lea rdx,qword ptr ds:[<__xi_z>]               | ;crtexe.c:483
  64. 000000013F6F18B8 | 48 8D 0D 71 4A 00 00     | lea rcx,qword ptr ds:[<__xi_a>]               | ;rcx:__xi_a
  65. 000000013F6F18BF | E8 74 10 00 00           | call <testasm64._initterm_e>                  | ;这个时候 RSP 就没有变过 ...
  66. 000000013F6F18C4 | 85 C0                    | test eax,eax                                  |



  67. // call <testasm64._initterm_e>
  68. 000000005B992A60 | 48 89 54 24 10           | mov qword ptr ss:[rsp+10],rdx                 | ;rdx:__xi_z
  69. 000000005B992A65 | 48 89 4C 24 08           | mov qword ptr ss:[rsp+8],rcx                  | ;rcx:__xi_a
  70. 000000005B992A6A | 48 83 EC 38              | sub rsp,38                                    |

复制代码


02.jpg


000-002BFCC0 : -68 // sub rsp,68  

XXXX  // 函数参数 START 这里预留给本函数内,调用其他函数(B)时函数B的预留参数位置。猜测预留参数个数是本函数内调用函数的参数最大值。
XXXX
XXXX
XXXX
XXXX  // 超过四个参数时 第五个之后直接从这里开始赋值
XXXX  // 函数参数 End 最大参数个数
CCCC // 局部变量 START 这里是函数内部的变量 预留空间,DEBUG是有多少分配多少,Release应该会有所优化。
CCCC
CCCC
CCCC // 局部变量 END

000-002BFD28 : 进到函数时的 ESP

所以,函数内调用函数B时,ESP总在 000-002BFCC0(-68) 这里,为什么这么NB,因为X64空间无限大,有内存就可以这样任性 。。。

3. Release 编译:


  1. // scanf( "%d %c",&a,&c);

  2. 0000000070A62E30 | 48 8B C4                 | mov rax,rsp                                   |
  3. 0000000070A62E33 | 48 89 48 08              | mov qword ptr ds:[rax+8],rcx                  |
  4. 0000000070A62E37 | 48 89 50 10              | mov qword ptr ds:[rax+10],rdx                 |
  5. 0000000070A62E3B | 4C 89 40 18              | mov qword ptr ds:[rax+18],r8                  |
  6. 0000000070A62E3F | 4C 89 48 20              | mov qword ptr ds:[rax+20],r9                  |
  7. 0000000070A62E43 | 48 83 EC 28              | sub rsp,28                                    |
  8. 0000000070A62E47 | 48 8B D1                 | mov rdx,rcx                                   |
  9. 0000000070A62E4A | 4C 8D 48 10              | lea r9,qword ptr ds:[rax+10]                  |
  10. 0000000070A62E4E | 48 8D 0D 13 16 02 00     | lea rcx,qword ptr ds:[70A84468]               |
  11. 0000000070A62E55 | 45 33 C0                 | xor r8d,r8d                                   |
  12. 0000000070A62E58 | E8 A7 48 00 00           | call msvcr90.70A67704                         |
  13. 0000000070A62E5D | 48 83 C4 28              | add rsp,28                                    |
  14. 0000000070A62E61 | C3                       | ret                                           |
复制代码


用 RAX 来寻址参数

在X64下,全部由函数内部来维护堆栈平衡,自己获取参数,自己申请空间处理变量, sub rsp, xx,  最后恢复堆栈 ret .

4. 参数全部为浮点数,或参数为浮点+非浮点。
以后再看 ...

二、类机制传参分析。




  1. NsTestX64::NsTestX64(void)
  2. {
  3.     double bb = 12.36;
  4.     m_a = 0;
  5.     m_b = TRUE;
  6. }

  7. 000000013FB71360 | 48 89 4C 24 08           | mov qword ptr ss:[rsp+8],rcx                  | ;this 指针仍然放于 rcx
  8. 000000013FB71365 | 57                       | push rdi                                      |
  9. 000000013FB71366 | 48 83 EC 10              | sub rsp,10                                    |
  10. 000000013FB7136A | 48 8B FC                 | mov rdi,rsp                                   |
  11. 000000013FB7136D | 48 B9 04 00 00 00 00 00  | mov rcx,4                                     |
  12. 000000013FB71377 | B8 CC CC CC CC           | mov eax,CCCCCCCC                              |
  13. 000000013FB7137C | F3 AB                    | rep stos dword ptr es:[rdi]                   |
  14. 000000013FB7137E | 48 8B 4C 24 20           | mov rcx,qword ptr ss:[rsp+20]                 |
  15. 000000013FB71383 | F2 0F 10 05 6D 55 00 00  | movsd xmm0,qword ptr ds:[13FB768F8]           |
  16. 000000013FB7138B | F2 0F 11 04 24           | movsd qword ptr ss:[rsp],xmm0                 |
  17. 000000013FB71390 | 48 8B 44 24 20           | mov rax,qword ptr ss:[rsp+20]                 | ;this 给 rax 去寻址
  18. 000000013FB71395 | 48 C7 00 00 00 00 00     | mov qword ptr ds:[rax],0                      |
  19. 000000013FB7139C | 48 8B 44 24 20           | mov rax,qword ptr ss:[rsp+20]                 |
  20. 000000013FB713A1 | C7 40 08 01 00 00 00     | mov dword ptr ds:[rax+8],1                    |
  21. 000000013FB713A8 | 48 8B 44 24 20           | mov rax,qword ptr ss:[rsp+20]                 |
  22. 000000013FB713AD | 48 83 C4 10              | add rsp,10                                    |
  23. 000000013FB713B1 | 5F                       | pop rdi                                       |
  24. 000000013FB713B2 | C3                       | ret                                           |
复制代码



  1. obj.NsSetThreeParam( TRUE, &a, ii );
  2. // this 指针仍处于 RCX 中

  3. 000000013FB71213 | 4C 8B 8C 24 80 00 00 00  | mov r9,qword ptr ss:[rsp+80]                  | ;__int64
  4. 000000013FB7121B | 4C 8D 44 24 44           | lea r8,qword ptr ss:[rsp+44]                  | ;PVOID
  5. 000000013FB71220 | BA 01 00 00 00           | mov edx,1                                     | ;TURE
  6. 000000013FB71225 | 48 8D 8C 24 98 00 00 00  | lea rcx,qword ptr ss:[rsp+98]                 | ;this
  7. 000000013FB7122D | E8 D3 FD FF FF           | call testasm64_.13FB71005                     |

复制代码


类机制的话和X86传参一样 this指针放 rcx 中,可认为是普通函数多了第一个参数。


三、异常机制分析。(不使用SEH链了 )
以后再看 ...

评分

参与人数 1威望 +8 飘云币 +8 收起 理由
GeekCat + 8 + 8 赞一个!

查看全部评分

PYG19周年生日快乐!
  • TA的每日心情
    开心
    2018-10-30 22:05
  • 签到天数: 6 天

    [LV.2]偶尔看看I

    发表于 2015-1-1 12:36:29 | 显示全部楼层
    先站楼{:soso_e113:}
    PYG19周年生日快乐!
  • TA的每日心情
    开心
    2024-3-8 19:52
  • 签到天数: 461 天

    [LV.9]以坛为家II

    发表于 2015-1-1 12:55:21 | 显示全部楼层
    学习了
    现在好多程序都只有64位了
    希望OD早日支持64位程序

    点评

    用这款神器 [attachimg]59135[/attachimg]  详情 回复 发表于 2015-1-1 13:08
    PYG19周年生日快乐!

    该用户从未签到

     楼主| 发表于 2015-1-1 13:08:22 | 显示全部楼层
    wangwei628 发表于 2015-1-1 12:55
    学习了
    现在好多程序都只有64位了
    希望OD早日支持64位程序




    用这款神器

    00.jpg

    点评

    谢谢大牛,但还是觉得OD习惯  详情 回复 发表于 2015-1-2 10:05
    PYG19周年生日快乐!
  • TA的每日心情
    开心
    2024-3-8 19:52
  • 签到天数: 461 天

    [LV.9]以坛为家II

    发表于 2015-1-2 10:05:01 | 显示全部楼层

    谢谢大牛,但还是觉得OD习惯

    点评

    x64-dbg也用过,感觉有些程序调试不了  详情 回复 发表于 2015-1-2 10:05
    PYG19周年生日快乐!
  • TA的每日心情
    开心
    2024-3-8 19:52
  • 签到天数: 461 天

    [LV.9]以坛为家II

    发表于 2015-1-2 10:05:44 | 显示全部楼层
    wangwei628 发表于 2015-1-2 10:05
    谢谢大牛,但还是觉得OD习惯

    x64-dbg也用过,感觉有些程序调试不了
    PYG19周年生日快乐!
  • TA的每日心情
    无聊
    2022-8-22 16:57
  • 签到天数: 89 天

    [LV.6]常住居民II

    发表于 2015-1-2 20:41:06 | 显示全部楼层
    什么东东,用多了,就好了。
    PYG19周年生日快乐!
  • TA的每日心情
    开心
    2022-11-29 10:06
  • 签到天数: 71 天

    [LV.6]常住居民II

    发表于 2017-2-12 23:49:44 | 显示全部楼层
    挺详细的,感谢分享!
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 登录 | 加入我们

    本版积分规则

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