我在二月份发表了拙文《在64位 VC程序里内嵌汇编》后,没想到被一些朋友提了一大
堆意见,主要都是说我没有说清楚怎么编译Win64 汇编代码。我之前以为人人都会用VS2010
的命令行,没想到竟然有不少人不会用,所以我在此文里认真介绍下编译Win64 汇编代码的
工具,以及使用方法。上次的文章还有两个重大不足,一是内嵌的汇编程序不能有参数和返
回值,这使内嵌汇编的价值大打折扣;二是只能说了在VC里内嵌汇编的方法,没有说在VB
程序里内嵌汇编的方法,这就愧对了不少喜爱VB的读者。
Win64汇编代码我是使用MASM64来编译的。请注意:这个MASM64不是微软出的,第一
个M不是Microsoft的意思,也不是macro的意思,而是压根没有意思。只是叫惯了MASM的叫
法,Win32汇编开发工具包叫MASM32,所以Win64汇编开发工具包就叫MASM64了。MASM64
汇编开发工具包最早是由64 位汇编语言论坛(www.x64asm.com/asmbbs)的旖旎网友制作,
我下载后修改了一些我认为不好的地方,现在把修改后的压缩包挂在了老马的紫水晶编程技
术论坛上下载。下载地址是:http://www.m5home.com/bbs/thread-5170-1-1.html(建议编
辑去下载一下放在PDF里,我就不发邮件了,因为那个东西有10MB大,不好发,Tudor在那
里有帐号,下载很方便)。下载完文件后请按照帖子的说明操作,把压缩包解压到C盘根目录,
既C盘下面有个名为MASM64的文件夹(必须!)。
编译Win64汇编代码需要使用到一个CMD文件,它的内容大致如下:
@Set ProgName=64位程序
@Color 0E
@Title %ProgName%
@call C:\Masm64\Env.Cmd
::此处修改为您的应用程序所在目录
@set Directory="F:\x64asm"
::此处修改为您的应用程序源文件名称(无需扩展名)
@Set SrcName=AsmSrc
@cd %Directory%
@echo 正在删除 %ProgName% 早期版本文件与临时文件...
@del "%Directory%\%SrcName%.obj"
@del "%Directory%\%SrcName%.exe"
@Echo 正在编译 %ProgName% 代码...
@C:\Masm64\BIN\x64\ml64 /c "%Directory%\%SrcName%.asm"
@Echo 正在链接 %ProgName% 代码...
@C:\Masm64\BIN\x64\Link /RELEASE /subsystem:windows /Entry:Entry
"%Directory%\%SrcName%.obj" /Out:"%Directory%\%SrcName%.exe"
@Color 0E
@Echo 构建完成请按任意键运行 %ProgName% 应用程序,按 CTRL+C键退出...
@pause
@"%Directory%\%SrcName%.Exe"
每次编译 Win64汇编代码时,仅仅需要修改染成蓝色部分的文字。修改完毕后,双击这
个 CMD文件即可。
为了方便大家获得机器码,我还特地写了个获取Win64汇编机器码的程序。使用方法很
简单,在上面的文本框输入汇编代码(用10个NOP分割两条汇编指令),然后点击【Get BIN】
按钮即可,生成的机器码样式支持VB 和C++样式。不过,这个程序必须在安装了MASM64之
后才能使用,而且计算机上必须安装了.NET 4.0运行库:
上次我仅仅说了在VC 里内嵌汇编的方法,但是却没有说明如何让内嵌的汇编子程序有
返回值和给汇编子程序传入参数。现在我把这个方法给大家说说。首先是使用typedef定义
一下你的汇编子程序的原型,然后获得机器码所在CHAR 数组的地址(指针p),最后把指针
p 强制转换为你用typedef定义的原型。最后把那个存放了机器码的CHAR数组当作函数调
用。当然,要把CHAR的内存属性改为PAGE_EXECUTE_READWRITE。为了方便传递参数,汇编
子程序使用__fastcall约定比较好。代码示例如下(输入四个数字相加,返回它们相加的
值):
#include <stdio.h>
#include <Windows.h>
typedef UINT64 (__fastcall *SCFN)(UINT64,UINT64,UINT64,UINT64);
void test_function_params_return()
{
SCFN scfn;
DWORD xxx;
UINT64 ret;
UCHAR
strShellCode[14]="\x48\x03\xCA\x49\x03\xC8\x49\x03\xC9\x48\x8B\xC1\xC3";
/*
add rcx,rdx
add rcx,r8
add rcx,r9
mov rax,rcx
ret
*/
PVOID p=strShellCode; |