欢迎来到天天文库
浏览记录
ID:31238444
大小:841.00 KB
页数:19页
时间:2019-01-07
《NSIS插件工作原理》由会员上传分享,免费在线阅读,更多相关内容在学术论文-天天文库。
1、NSIS插件工作原理了解NSIS的童鞋都知道,在NSIS中调用插件有两种方式,一种是通过Push将参数压入栈中,然后使用CallInstDLL来调用插件中的函数;另一种方式是使用插件命令,如plugin::function_nameparam1param2param3...,本文的目的就是深入理解NSIS的插件命令是如何工作的,NSIS脚本是如何和插件dll进行交流的接下来我会以一个例子nsDialogs::Create1018为例,具体讲述NSIS究竟是怎样解析这条语句,又是怎样调用nsDialogs.dll中的Create函数的
2、NSIS脚本代码是写在一个.nsi的文件中的,这种文件其实是一个文本文件,并不具备可执行代码的功能,它需要NSIS中的makensis.exe来编译这种文件,编译后会产生一个.exe文件,就是生成的安装包程序了,这个文件打开后就是一些安装页面,引导用户进行下一步操作,从而安装文件到用户的电脑上,也就是说NSIS中最厉害的其实是makensis.exe这个NSIS脚本编译器了,NSIS是开源的,那么我们就来看看它的源码是如何解析插件命令的调用的到目前为止,NSIS的最新版本是2.46,它的源码文件如下图所示,NSIS是用C/C++写的
3、其中有几个文件在解析插件命令时比较重要,build.cpp、Plugins.cpp、script.cpp、tokens.cpp、exeheadexec.c、exeheadplugin.cNSIS中支持的命令、属性、预处理指令等都在tokens.cpp中有定义,如下图所示,只有少数几个没有具体的命令关键字,如插件命令可以看到这里把NSIS支持的关键字和TOK_XXX关联起来了,但是插件命令比较特殊,这里虽然没有定义,但是在tokens.h中TOK__LAST的后面有一句TOK__PLUGINCOMMAND,也就是说这个其实就是解析
4、插件命令时的token,makensis.exe源码中的主函数是定义在makenssi.cpp中的,而解析这其中最关键是一个CEXEBuild类,NSIS大部分的解析工作都由此类和它的成员来完成的,在makenssi.cpp中的main函数中构造了CEXEBuild的实例build,经过一些初始化和预处理后,开始解析nsi脚本,在使用时是用命令行的方式传递nsi脚本的文件名给makensis.exe,在makenssi.cpp的main函数中的470行开始读取脚本文件的内容:然后接下来的代码开始解析脚本文件,主要是调用了CEXEBu
5、ild类的process_script函数来解析脚本代码解析完成后,是生成一个exe文件,就是生成的安装程序,根据前面解析的信息,最后调用CEXEBuild类的write_output函数生成exe程序本文要讲的是插件的工作原理,因此我们重点来看看NSIS是怎样解析nsi脚本的,具体又是怎样解析插件命令,调用插件的,来看CEXEBuild类的process_script函数是怎样处理的,process_script函数是定义在script.cpp中的,如下图所示:函数的一开始将filepointer文件指针传递给了CEXEBuild
6、的成员变量fp,以便后续的文件读取,然后解析的工作交给了222行的parseScript函数,代码如下:可以看到这里有一个for循环,通过fgets函数读取nsi脚本中的一行,然后调用doParse函数来解析这行脚本代码,解析完一行for循环继续进行,继续读取一行,解析脚本,直到解析完最后一行脚本代码为止!!那么就来看看doParse是怎样解析一行脚本代码的doParse函数中又使用了LineParser类来解析具体的一行脚本代码,这里调用的是LineParser类的parse函数,parse又调用了doline函数来解析一行代码:
7、这里用了while(*line)来遍历这一行字符串,解析是否有NSIS指定的命令、属性等关键字,具体的代码在它的后面,如下图所示:m_tokens是一个char**二级指针,它保存了所有扫描到的token关键字,至此,解析完了这一行代码了,就是把扫描到的关键字保存起来以便后续使用,当然这些处理之后会回到CEXEBuild::doParse函数中,就是thisline.parse((char*)str)返回,然后继续执行后面的代码,这里的代码首先使用get_commandtoken函数获取这一行解析到的关键字对应的TOK_XXX,如关
8、键字Abort对应的token是TOK_ABORT然后来到365行调用m_plugins.IsPluginCommand来判断关键字是不是插件命令,如果是,则设置tkid为TOK__PLUGINCOMMAND然后是处理一些tkid为T
此文档下载收益归作者所有