自从开始上次Win32汇编系列结束已经有些年头了,期间也在接触其他新东西,所以把Win32汇编系列暂时放在了后面,后面会更新Linux下汇编,介绍NASM,本章来学习下汇编环境下的网络请求,也就是读取远程服务器中的数据,据我知道的有两种办法,一是创建Socket,但是同时还要构建HTTP请求信息,然后在发送给服务器,接收的时候还要解析HTTP响应信息,把响应体分割出来,显然有些麻烦,更何况是使用汇编,所以为了简单,使用第二种方法,直接调用Windows提供的WinInet API,WinInet的全称是Windows Internet,里面的API可能帮助我们完成三个常见的Internet协议,也就是万维网的超文本传输协议(HTTP)、文件传输协议(FTP)和另一个称为Gopher的文件传输协议。
关于以前文章,可以从这里跳转
Win32汇编开篇、Hello World
Win32汇编系列二、数据传送指令
Win汇编系列三、整数算数运算符
Win32汇编系列四、逻辑运算指令
Win32汇编系列五、分支结构程序设计
Win32汇编系列六、循环结构程序设
Win32汇编系列七、窗口程序原理及实现
Win32汇编系列八,多线程
Win32汇编系列九,GDI画个寂寞
好了,我们先看代码。
.386
.model flat, stdcall
option casemap:none
include C:\masm32\include\windows.inc
include C:\masm32\include\kernel32.inc
includelib C:\masm32\lib\kernel32.lib
include C:\masm32\include\wininet.inc
includelib C:\masm32\lib\wininet.lib
.data
szAgent db "OK", 0
szUrl db "https://houxinlin.com/", 0
szError db "ERROR.", 13, 10, 0
szData db 5000 DUP(0)
.data?
hConsoleOutput dd ?
hInternet dd ?
hFile dd ?
bytesWritten dd ?
dwContext dw ?
bytesRead dd ?
.code
failInternet proc
invoke WriteConsole, hConsoleOutput, offset szError, sizeof szError, offset bytesWritten, 0
jmp complete
failInternet endp
complete proc
invoke CloseHandle, hConsoleOutput
invoke ExitProcess, 0
ret
complete endp
start:
invoke GetStdHandle, -11
mov [hConsoleOutput], eax
invoke InternetOpen, addr szAgent, INTERNET_OPEN_TYPE_DIRECT, 0, 0, 0
mov [hInternet], eax
cmp hInternet, 0
je failInternet
invoke InternetOpenUrl, hInternet, offset szUrl, 0, 0, INTERNET_FLAG_RELOAD, 0
mov [hFile], eax
cmp hFile, 0
je failInternet
invoke InternetReadFile, hFile, offset szData, 5000, offset bytesRead
cmp eax, 0
je failInternet
invoke WriteConsole, hConsoleOutput, offset szData, bytesRead, offset bytesWritten, 0
invoke InternetCloseHandle, hInternet
jmp complete
end start
还记得以前我们是怎么输出字符到控制台的嘛?
是通过print,但是这回我们换一种方式,通过WriteConsole,这是一个API函数,使用方法也比较简单,但是前提我们要拿到控制台的标准输出句柄,也就是通过GetStdHandle,参数-11代表标准输出,-12代表标准错误句柄,-10是标准输入句柄。
接下来就是通过InternetOpen初始化应用程序对WinInet函数的使用,他的第二个参数INTERNET_OPEN_TYPE_DIRECT代表在本地解析主机名。并将返回值保存在hInternet变量中,以前在说过,eax寄存器也是函数调用后返回值保存的地方,下面我们还要判断是否成功,这里没有使用.IF伪指令,而是使用cmp和je指令,cmp会将目的操作数减去原操作数,并更具差设置标志位(ZF和CF),后面je指令会判断ZF标志位是否等于1,如果为1的话则跳转,也就在是cmp指令的两个操作数相等的情况下会进行跳转,一旦相等,那么就是说函数的返回值是0,0代表函数调用失败,进而提示用户,(cmp在只有两个操作数相等的情况下ZF标志位是1,其他情况都是0).
然后在通过InternetOpenUrl打开HTTP URL指定的资源,并将句柄保存在hFile。这里拿我的博客作为示例,同样要判断是否调用成功。
最后就是通过InternetReadFile从打开的句柄中读取数据 ,这里我们写死读取的字节数,严谨的话十需要循环读取的。最后就是关闭打开的资源。
来运行一下。