本帖最后由 小俊 于 2017-12-26 11:36 编辑
首先,先说一下我的环境
Windows10版本,和Windows SDK版本都是目前最新的 版本为:1709(16299)
VisualStudio也是最新的
编写Windows程序,当然需要用到Windows API,目前讲两种方式
动态获取函数地址,在这里我就不过多讲解,有兴趣看我前两篇帖子
正常方式,这就是我接下来要讲的了,导入Lib库,然后声明函数原型,就可以直接调用了32位Lib路径为:C:\Program Files (x86)\Windows Kits\10\Lib\10.0.16299.0\um\x86
最重要的俩个库为:kernel32.Lib User32.Lib吧这俩个库拷贝到我们的源码目录
Source.PNG (2.25 KB, 下载次数: 8)
2017-12-26 08:57 上传
然后在代码中导入
[Asm] 纯文本查看 复制代码;导入Lib库
includelib kernel32.Lib
includelib User32.Lib
声明函数原型,例如:
[Asm] 纯文本查看 复制代码ExitProcess proto,dwExitCode:dword
MessageBoxA proto,hWnd:dword,pText:dword,pTitle:dword,uType:dword
调用函数:例如
[Asm] 纯文本查看 复制代码invoke MessageBoxA,0,0,0,0
invoke ExitProcess,0
整体代码:
[Asm] 纯文本查看 复制代码.386
.model flat,stdcall
option casemap:none
;导入Lib库
includelib kernel32.Lib
includelib User32.Lib
;声明函数原型
ExitProcess proto,dwExitCode:dword
MessageBoxA proto,hWnd:dword,pText:dword,pTitle:dword,uType:dword
;代码段
.code
main:
invoke MessageBoxA,0,0,0,0
invoke ExitProcess,0
end main
这里,我再为小白解释一下代码,老鸟跳过
.386为指令集,微软的解释:https://msdn.microsoft.com/zh-cn/library/ss9fh0d6.aspx
386.PNG (32.44 KB, 下载次数: 2)
2017-12-26 09:12 上传
除了386,Masm还支持以下指令集
CPU.PNG (11.54 KB, 下载次数: 1)
2017-12-26 09:08 上传
.Model我个人理解为指定内存模型,微软的解释:https://msdn.microsoft.com/zh-cn/library/ss9fh0d6.aspx
第一个参数基本为(必选):FLAT
第二个为调用约定:常用的有两种STDCALL,C
FLAT 为平坦模式,学过80386的应该都找到,寻址方式都为段加偏移,而平坦模式段基址都为0(fs,gs除外)所以平坦模式线性地址等于虚拟地址
STDCALL调用约定和C的调用约定 区别就是一个内平衡栈 ,一个外平衡栈 ,入栈顺序都是从右向左依次入栈
option casemap:none为区分大小写,没什么好解释的了
proto声明函数原型
invoke 调用函数
这俩个是Masm的伪指令,并不是汇编
例如:
[Asm] 纯文本查看 复制代码invoke ExitProcess,0
等于:
[Asm] 纯文本查看 复制代码push 0
call ExitProcess
接下来吧代码进行编译,这里用到俩工具:ml.exe link.exe
32位路径为:C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.12.25827\bin\Hostx86\x86
再我电脑上路径为这个,你电脑我就不确定了。但是这个不重要,如果你电脑上装了VS的话,那么你的开始菜单里面应该有 VS 2017的开发人员命令提示符
VS.PNG (146.6 KB, 下载次数: 0)
2017-12-26 09:57 上传
输入ml,出现这些信息,说明环境没问题
ML.PNG (27.32 KB, 下载次数: 1)
2017-12-26 10:10 上传
然后将路径切换到我的源代码路径
cd C:\Users\XiaoJun\Desktop\Source
然后直接编译
ml Source.asm
编译.PNG (47.94 KB, 下载次数: 0)
2017-12-26 10:14 上传
恭喜,没有出现警告或者错误
生成了三个文件
File.png (40.43 KB, 下载次数: 1)
2017-12-26 10:29 上传
运行
Run.png (14.06 KB, 下载次数: 2)
2017-12-26 10:33 上传
没有问题,弹出了个啥也没有的消息框,因为我们给的参数都是0
运行没有问题,我们进一步做一些优化
首先,我为什么用汇编写程序,因为小,而且不依赖C运行时库,不会生成无用代码
但是我一查看文件属性,居然还有2.5k这是我接受不了的,一共这才几条汇编代码
Size.png (39.19 KB, 下载次数: 1)
2017-12-26 11:31 上传
我心算了一下,PE头0x200(512)个字节, .text代码段0x200(512)个字节,导入表在 .data段0x200(512)字节,一共应该是1.5k才对呀
所以我打开010Editor一探究竟
reloc.png (20.01 KB, 下载次数: 2)
2017-12-26 10:47 上传
发现多了个 .reloc 段,并且PE头占用了0x400(1024)个字节,所以才会那么大
因为多了个.reloc 段,PE头也会多个区段表,所以0x200(512)个字节不够,所以PE头才变成了0x400(1024)个字节
问题找到了,是因为编译器默认开启了随机基址为了修复IAT而产生的重定位,我们关闭随机基址试一试,这里重新用link.exe连接一下
link Source.obj /DYNAMICBASE:NO注:(/DYNAMICBASE:NO为关闭随机基址)
link.png (25.03 KB, 下载次数: 0)
2017-12-26 10:59 上传
再来查看一下文件大小
15k.png (38.93 KB, 下载次数: 0)
2017-12-26 11:00 上传
和我预期的一样,变成了1.5k
完善一下代码
[Asm] 纯文本查看 复制代码.386
.model flat,stdcall
option casemap:none
;导入Lib库
includelib kernel32.Lib
includelib User32.Lib
;声明函数原型
ExitProcess proto,dwExitCode:dword
MessageBoxA proto,hWnd:dword,pText:dword,pTitle:dword,uType:dword
;只读数据段
.const
lpStr db "Hello World!",0
lpTitle db "Title",0
;代码段
.code
main:
invoke MessageBoxA,0,offset lpStr,offset lpTitle,0
invoke ExitProcess,0
end main
编译 ml Source.asm /link /DYNAMICBASE:NO /SUBSYSTEM:WINDOWS注:(/SUBSYSTEM:WINDOWS表示生成窗口程序,没有控制台啦)
ok.png (43.93 KB, 下载次数: 1)
2017-12-26 11:22 上传
编译成功,没有警告或者错误
Hello.png (10.32 KB, 下载次数: 1)
2017-12-26 11:23 上传
运行成功,没有问题,黑色的框框也没啦
Source.zip
(81.89 KB, 下载次数: 34)
2017-12-26 11:36 上传
点击文件名下载附件
下载积分: 吾爱币 -1 CB
参考:
http://kipirvine.com/asm/gettingStartedVS2017/index.htm
https://msdn.microsoft.com/zh-cn/library/hb5z4sxd.aspx
https://msdn.microsoft.com/zh-cn/library/y0zzbyt4.aspx