首页
社区
课程
招聘
[原创]Windows X64汇编入门(1)
2007-5-5 23:31 66536

[原创]Windows X64汇编入门(1)

2007-5-5 23:31
66536
Windows X64汇编入门(1)
tankaiha

    最近断断续续接触了些64位汇编的知识,这里小结一下,一是阶段学习的回顾,二是希望对64位汇编新手有所帮助。我也是刚接触这方面知识,文中肯定有错误之处,大家多指正。
文章的标题包含了本文的四方面主要内容:
(1)Windows:本文是在windows环境下的汇编程序设计,调试环境为Windows Vista 64位版,调用的均为windows API。
(2)X64:本文讨论的是x64汇编,这里的x64表示AMD64和Intel的EM64T,而不包括IA64。至于三者间的区别,可自行搜索。
(3)汇编:顾名思义,本文讨论的编程语言是汇编,其它高级语言的64位编程均不属于讨论范畴。
(4)入门:既是入门,便不会很全。其一,文中有很多知识仅仅点到为止,更深入的学习留待日后努力。其二,便于类似我这样刚接触x64汇编的新手入门。
        本文所有代码的调试环境:Windows Vista x64,Intel Core 2 Duo。

1.        建立开发环境
1.1        编译器的选择
    对应于不同的x64汇编工具,开发环境也有所不同。最普遍的要算微软的MASM,在x64环境中,相应的编译器已经更名为ml64.exe,随Visual Studio 2005一起发布。因此,如果你是微软的忠实fans,直接安装VS2005既可。运行时,只需打开相应的64位命令行窗口(图1),便可以用ml64进行编译了。


    第二个推荐的编译器是GoASM,共包含三个文件:GoASM编译器、GoLINK链接器和GoRC资源编译器,且自带了Include目录。它的最大好外是小,不用为了学习64位汇编安装几个G 的VS。因此,本文的代码就在GoASM下编译。

    第三个Yasm,因为不熟,所以不再赘述,感兴趣的朋友自行测试吧。
不同的编译器,语法会有一定差别,这在下面再说。

1.2        IDE的选择
    搜遍了Internet也没有找到支持asm64的IDE,甚至连个Editor都没有。因此,最简单的方法是自行修改EditPlus的masm语法文件,这也是我采用的方法,至少可以得到语法高亮。当然,如果你懒得动手,那就用notepad吧。
    没有IDE,每次编译时都要手动输入不少参数和选项,做个批处理就行了。

1.3        硬件与操作系统
    硬件要求就是64位的CPU。操作系统也必须是64位的,如果在64位的CPU上安装了32位的操作系统,就算编译成功也无法运行程序。

2.        寄存器的改变
    汇编是直接与寄存器打交道的语言,因此硬件对语言影响很大。先来看看x64与x32相比在硬件上多了什么,变了什么(图2)。


    X64多了8个通用寄存器:R8、R9、R10、R11、R12、R13、R14、R15,当然,它们都是64位的。另外还增加了8个128位XMM寄存器,不过通常用不着。
    X32中原有的寄存器在X64中均为扩展为64位,且名称的第一个字母从E改为R。不过我们还是可以在64位程序中调用32位的寄存器,如RAX(64位)、EAX(低32)、AX(低16位)、AL(低8位)、AH(8到15位),相应的有R8、R8D、R8W和R8B。不过不要在程序中使用如AH之类的寄存器,因为在AMD的CPU上这种用法会与某些指令产生冲突。

3.        第一个x64汇编程序
    本节,我们开始编写自己的第一个x64汇编程序。在这之前,先讲一下calling convention的改变。
3.1        API调用方式
    把Calling convention放在第一个讲,代表它的重要性。在32位汇编中,我们调用一个API时,采用的是stdcall,它有两个特点:一是所有参数入栈,通过椎栈传递;二是被调用的API负责栈指针(ESP)的恢复,我们在调用MessageBox后不用add esp,14h,因为MessageBox已经恢复过了。
而在x64汇编中,两方面都发生了变化。一是前四个参数分析通过四个寄存器传递:RCX、RDX、R8、R9,如果还有更多的参数,才通过椎栈传递。二是调用者负责椎栈空间的分配与回收。
    下面给出一段代码,功能是显示一个简单的MessageBox,注意对RSP的操作:
;示例代码1.asm
;语法:GoASM
DATA SECTION
text     db 'Hello x64!', 0
caption  db 'My First x64 Application', 0

CODE SECTION
START:
sub rsp,28h
xor r9d,r9d
lea r8, caption
lea rdx, text
xor rcx,rcx
call MessageBoxA
add rsp,28h
ret


    这段代码是在GoASM中编译,指令部分GoASM与ML64差不多,关键是一些宏的定义有差别。比如masm中的.code,在这里就成了CODE SECTION。下面再说区别,先编译。GoASM中编译分两步:
(1)        编译:goasm /x64 1.asm
(2)        链接:golink 1.obj user32.dll
    如果一些正常,命令行中应显示图3的内容。


    运行一下,我们的第一个64位windows程序就运行了。


    GoASM还有一个特点是支持宏:ARG和INVOKE,使用这两个宏可以免除程序员自己对椎栈进行操作。不过初学吗,还是从基础掌握比较好。下面的一段代码相同的功能的MASM代码,注意看看区别。ML64至今仍不支持宏,所以每一步工作都要自己做。

;示例代码2.asm
;语法:ML64
extrn MessageBoxA: proc

.data
text     db 'Hello x64!', 0
caption  db 'My First x64 Application', 0

.code
Main proc
sub rsp,28h
xor r9d,r9d
lea r8, caption
lea rdx, text
xor rcx,rcx
call MessageBoxA
add rsp,28h
ret

Main ENDP
end


    编译这段代码的命令行是:ml64 2.asm /link /subsystem:windows /entry:Main user32.lib。如果正常,应该如图5显示那样。


    很有意思吧,在64位系统下,我们仍然调用user32的API。可能是名称用习惯了,微软自己都懒得改了吧。

3.2        64位的椎栈
    代码中还有一处值得注意,那就是sub rsp,28h和add rsp,28h。28h这个数值是怎么来的呢?
首先,x64中椎栈被扩展为64位;其次,我们在调用MessageBoxA时,要给四个参数外加一个返回地址留空间,因此8(位)*5=40=28h。
    另外一些小问题要注意,AMD64不支持push 32bit寄存器的指令,最好的方法就是push和pop都用64位寄存器。EM64T如何?看了下Intel的开发手册,各个指令都分三种情况:纯32位、纯64位和32与64位混合。下面是手册的片段:

Opcode*      Instruction        64-Bit Mode       Compat/Leg Mode      Description
FF /6         PUSH r/m16         Valid                 Valid            Push r/m16.
FF /6         PUSH r/m32         N.E.                  Valid            Push r/m32.
FF /6         PUSH r/m64         Valid                  N.E.           Push r/m64.
Default operand size 64-bits.

    没别的好方法,使用中多注意,尽量在64位程序中保用64位寄存器。

4.        一些参考资料
    写完了第一个hello world,本文就此打住。本还想写一些内容,但掌握不深,留待下回吧。感觉有些资料不得不在第一篇文章中放出来,因为它们是现有学习x64汇编的最好教材了,文中很多代码和知识点也来自于这些资料。
(1)《Moving to Windows x64》,出自:http://www.ntcore.com/Files/vista_x64.htm
(2)GoASM的帮助文档,目前最好的64位汇编教程。出自:www.jorgon.freeserve.co.uk
(3)《开始进行 64 位 Windows 系统编程之前需要了解的所有信息》,出自:http://www.microsoft.com/china/MSDN/library/Windev/64bit/issuesx64.mspx
(4)来自CodeGurus的两篇文章
《Assembler & Win64》,
http://www.codegurus.be/codegurus/Programming/assembler&win64_en.htm
《bout RIP relative addressing》
http://www.codegurus.be/codegurus/Programming/riprelativeaddressing_en.htm
(5)AMD开发手册
(6)Intel开发手册,注意是新的《ntel® 64 and IA-32 Architectures software Developer’s Manual》

[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

上传的附件:
  • 1.jpg (55.41kb,2344次下载)
  • 2.jpg (63.77kb,2472次下载)
  • 3.jpg (29.36kb,2271次下载)
  • 4.jpg (6.28kb,2246次下载)
  • 5.jpg (37.78kb,2288次下载)
收藏
点赞7
打赏
分享
最新回复 (41)
雪    币: 229
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
paradise 2007-5-5 23:41
2
0
沙发,好帖。32位的还才刚看。。。。收藏以后看
雪    币: 625
活跃值: (1037)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
xzchina 1 2007-5-6 10:32
3
0
好文
tankaiha 的本本太强悍. 汗一下
在问tankaiha一个问题,是不是一些句柄必须放在RCX中?
loc_10000B2FA:          ; lParam
xor     r9d, r9d
xor     r8d, r8d        ; wParam
mov     edx, 0C5h       ; Msg
mov     rcx, rbp        ; hWnd
mov     cs:qword_100012760, rdi
call    cs:PostMessageW
mov     rcx, cs:qword_100011148 ; hWnd
mov     ebx, 5
mov     edx, ebx        ; nCmdShow
call    cs:ShowWindow
mov     rcx, cs:hWnd    ; hWnd
movsxd  r8, r13d        ; wParam
xor     r9d, r9d        ; lParam
mov     edx, 0B9h       ; Msg
call    cs:SendMessageW
mov     rcx, cs:hWnd    ; hWnd
call    cs:SetFocus
mov     rcx, rsi        ; hCursor
call    cs:SetCursor
雪    币: 5276
活跃值: (406)
能力值: (RANK:1170 )
在线值:
发帖
回帖
粉丝
tankaiha 29 2007-5-6 11:44
4
0
rcx只是第一个参数,在许多API如MessageBox,PostMessage和SendMessage中确实是句柄,不过别的API应该不一定。

呵呵,偶也是刚学啊,多讨论。
雪    币: 150
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
chinatme 2007-5-7 07:18
5
0
一不小心就让我看到了,win64刚接触学习学习~
雪    币: 107
活跃值: (246)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
stonenb 2007-5-7 09:05
6
0
天啦,都出64位了,32位还没过关。汗。。。
雪    币: 214
活跃值: (11)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
wuchuanren 2 2007-5-7 10:57
7
0
太有才了……
不知道能流畅运行Vista的计算机什么时候才会降到普通学生能接受的价格
雪    币: 207
活跃值: (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
ekin 1 2007-5-7 15:34
8
0
现在学64位有用么?
雪    币: 29412
活跃值: (18675)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
kanxue 8 2007-5-7 15:41
9
0
好像听到64位脚步声了,tankaiha每次都能与大家分享这些新的技术,谢谢
雪    币: 625
活跃值: (1037)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
xzchina 1 2007-5-7 17:01
10
0
64位PE文件的结构,64位执行文件需要PEID的支持,支持64位EXE,DLL的OllyDBG,等等等等.
雪    币: 314
活跃值: (15)
能力值: ( LV12,RANK:410 )
在线值:
发帖
回帖
粉丝
王仁军 10 2007-5-7 17:30
11
0
学习学习再学习
雪    币: 156
活跃值: (48)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
aaa2520 1 2007-5-8 08:34
12
0
od 2.0 是不是 在等 64位的普及啊?
雪    币: 235
活跃值: (50)
能力值: ( LV9,RANK:210 )
在线值:
发帖
回帖
粉丝
8713007 5 2007-5-8 15:07
13
0
学习!学习!再学习!
雪    币: 117
活跃值: (20)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
无奈无赖 2007-5-9 15:37
14
0
sub rsp,28h

这个每个还要去自己计算,感觉麻烦些了.
雪    币: 5276
活跃值: (406)
能力值: (RANK:1170 )
在线值:
发帖
回帖
粉丝
tankaiha 29 2007-5-9 20:24
15
0
呵呵,可以用GoASM的Invoke宏,不过masm还没支持。

如果连续几个API调用的话,在第一个之前sub一个比较大的值就OK了,不用一个个sub再add,也不是非常麻烦。
雪    币: 716
活跃值: (162)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
elance 6 2007-5-9 22:53
16
0
好文章啊,怎么现在才看到,
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
工人一号 2007-5-10 18:36
17
0
怎一个强字了得!
顺便请教下,初学者应该先从32位开始还是直接从64开始好?
雪    币: 5276
活跃值: (406)
能力值: (RANK:1170 )
在线值:
发帖
回帖
粉丝
tankaiha 29 2007-5-10 19:15
18
0
偶觉得32位目前还是根本
雪    币: 201
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
xiong779 2007-5-10 22:41
19
0
之前有愈到過64bit 下的問題,藉此可以學一下
雪    币: 223
能力值: (RANK:130 )
在线值:
发帖
回帖
粉丝
hefei2 3 2007-5-10 23:59
20
0
好文章啊,一直想学64位汇编呢
雪    币: 202
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
harold 2007-5-11 12:47
21
0
好是好,看来我得先搞台机子了
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
renetspy 2007-9-5 15:45
22
0
代码中还有一处值得注意,那就是sub rsp,28h和add rsp,28h。28h这个数值是怎么来的呢?

四个参数不是通过寄存器传递的吗?
雪    币: 5276
活跃值: (406)
能力值: (RANK:1170 )
在线值:
发帖
回帖
粉丝
tankaiha 29 2007-9-5 20:27
23
0
caller负责构造stack frame
平时win32中,由callee构造并释放了,所以我们一般不太注意
雪    币: 153
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
verybigbug 2007-9-6 06:33
24
0
注意:sample中就4个参数,刚好利用了rcx, rdx, r8, r9,如果有5个甚至更多的话这么办?
就是mov [rsp+20h], param5
   mov [rsp+28h], param6
这样的啦。
雪    币: 442
活跃值: (107)
能力值: ( LV9,RANK:350 )
在线值:
发帖
回帖
粉丝
hopy 8 2007-9-8 11:14
25
0
羡慕...你的本本...^0^
游客
登录 | 注册 方可回帖
返回