博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
NSiS“反编译”方法-By蓝色网际
阅读量:4453 次
发布时间:2019-06-07

本文共 6984 字,大约阅读时间需要 23 分钟。

创建 NSIS 脚本的习惯: 创建一个 include 目录,用来保存安装用的 文件, .nsi 文件放在 include 的上级目录,再在 include 目录里创建一个 resource,用来保存一些资源文件比如 图标、 界面位图、自己修改的 UI 等等。
然后分析一下 官方的安装 程序,嗯嗯,先清空临时文件夹,这是为了为了找东西方便,然后启动安装程序,再到临时目录里找一个 nxxx.tmp 这样的目录,里面有一些释放出来的资源 gaydata.ini、modern-header.bmp、classic256.bmp、modern256.bmp、opt2page.ini、opt3page.ini。那几个位图一看就明白,不用解释,gaydata.ini 呢,里面有从 sec0 到 sec47 的 定义,所以我们可以确定一共有 47 个区段,而且区段的名称是根据 gaydata.ini 来确定的,如何知道是根据 gaydata.ini 来确定的 的呢,你在安装程序刚启动的时候(刚显示许可 页面的时候)找到临时的那个目录(也就是 NSIS 里的 $PLUGINSDIR 目录),把一个区段名称改一下,比如把“Winamp (required)”改为 aaa,等进入 组件 选择页面的时候第一个就是 aaa 了,而如果把“Winamp (required)”清空的话,第一个区段就不见了。 opt2page.ini、opt3page.ini 分别是最后两个页面用来选择连接方式和外观的。分析后就可以动手了……
1.建立基本的结构
首先在脚本头部定义一些版本号等值,比如
!define VERSION "5.05"
!define VERSION_NUM "505"
这样版本号变的时候在脚本头部改一下就行了,不用在脚本的每个地方都改
然后定义输出文件名,为了方便 full、pro、lite 三个版本切换方便。
!define FILE_NAME "Winamp${VERSION_NUM}_full"
有关定义的说明可以看这里.PS:链接失效了.
再下来就是安装程序属性的 设置了,必须的设置有
Name "Winamp"OutFile"${FILE_NAME}.exe"
当然
SetCompressor lzma
应该也是必须的,LZMA 不止压缩率大很多,而且不太准确的一个属性是启动快不少,然后再设置一个区段就构成了主体部分,已经能够编译了
Section "主程序"SectionEnd
2. 插入页面
首先要
!include "MUI.nsh"
这样才能使用 NSIS 提供的一些宏来插入页面,要插入的页面是
!insertmacro MUI_PAGE_LICENSE".\resource\License.txt"
!insertmacro MUI_PAGE_COMPONENTS
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_COMPONENTS
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
最后还要插入 语言
!insertmacro MUI_LANGUAGE English
3. 完善安装程序属性设置?当然安装程序的属性还要增加一些设置
BrandingText
"Nullsoft Install System -- built on
${__DATE__}
at
${__TIME__}
"这是设置安装程序个人标志的
InstallDir
"
$PROGRAMFILES
\Winamp"
设置一个默认的安装路径
InstallDirRegKey
HKCU
"Software\Winamp" ""
优先读取 注册表里保存的路径,如果存在就是用 注册表保存的路径
4. 设置页面.图标的定义
!define MUI_ICON
".\resource\inst.ico"
!defineMUI_UNICON
".\resource\uninst.ico"
定义了安装程序图标和 卸载程序图标
!define MUI_HEADERIMAGE
定义在安装程序顶端显示一个位图
!define MUI_HEADERIMAGE_BITMAP
".\resource\modern-header.bmp"
定义要显示的位图,必须是本地机器上的
!define MUI_COMPONENTSPAGE_NODESC
指定组件选择页面不使用描述区域
5. 设置页面文本
!define MUI_LICENSEPAGE_TEXT_TOP
"Please read and agree to the license terms below before installing."
指定许可页面上顶端显示的文本
!define MUI_COMPONENTSPAGE_TEXT_TOP
"This will install Winamp
${VERSION}
. This installer contains the full install."
指定组件选择页面顶端的文本
!define MUI_DIRECTORYPAGE_TEXT_TOP
"Setup has determined the optimal location to install. If you would like to change the folder, do so now."
指定目录选择页面的文本
!define MUI_ABORTWARNING
定义按取消 按钮时,提示是否真的退出
6. 设定安装类型,并把补全所有的区段
InstType
"Full"
InstType
"Standard"
InstType
"Lite"
InstType
"Minimal"
一共四个安装类型,还有一个
Custom 类型 系统会 自动添加,不必干预
然后在创建
46 个区段,一共有
47个,名称可以随便起,因为区段的名称到后面会由 gaydata.ini 来从命名,比如
Section
" "
SectionEnd
7. .onInit 函数
这个函数是在安装程序 GUI 启动完毕的时候开始执行里面的 代码,应该把那些资源文件在这个阶段释放到用户 电脑以供使用
InitPluginsDir
初始化
$PLUGINSDIR 也就是 插件目录?
File
"/oname=
$PLUGINSDIR
\gaydata.ini" ".\resource\gaydata.ini"
File
"/oname=
$PLUGINSDIR
\opt2page.ini" ".\resource\opt2page.ini"
File
"/oname=
$PLUGINSDIR
\opt3page.ini" ".\resource\opt3page.ini"
File
"/oname=
$PLUGINSDIR
\classic256.bmp" ".\resource\classic256.bmp"
File
"/oname=
$PLUGINSDIR
\modern256.bmp" ".\resource\modern256.bmp"
因为在 .onInit 里使用 File 会使程序启动时要搜索很久,所以还应该使用 ReserveFile,ReserveFile 的说明看这里。
!include
"MUI.nsh"上面增加
ReserveFile
".\resource\gaydata.ini"
ReserveFile
".\resource\opt2page.ini"
ReserveFile
".\resource\opt3page.ini"
ReserveFile
".\resource\classic256.bmp"
ReserveFile
".\resource\modern256.bmp"
ReserveFile
"
${NSISDIR}
\Plugins\InstallOptions.dll"
因为 InstallOptions.dll 在自定义界面要使用,所以也要加入
8. 组件的隐藏和显示
细心的朋友都看到了脚本里面有两个
!insertmacro MUI_PAGE_COMPONENTS,那么组件选择页面就会出现两次,察看 gaydata.ini 就知道第一次显示的是 sec0 到 sec36,第二次显示的是 sec37 到 sec47。
关于页面的说明请看这里(链接失效)
每个页面都有三个函数: Pre、Show、Leave,分别是预载入、显示、离开,在 MUI 界面可以用定义的方法来插入函数,比如在
!insertmacro MUI_PAGE_COMPONENTS 前(插入上一个页面之后) 定义一个 MUI_PAGE_CUSTOMFUNCTION_PRE 函数就可以插入一个预载入函数。在本次脚本中在第一个组件选择页面作如下定义?
!define MUI_PAGE_CUSTOMFUNCTION_PRE ComponentPre
!define MUI_PAGE_CUSTOMFUNCTION_SHOW ComponentShow
上面定义了 ComponentPre、ComponentShow 函数,当然定义的函数名可以随便起,但一般来说名字都要表达它的含义,便于阅读。
在开始创建这两个函数之前还要定义一些内容?
!define SECTION_COMPONENT_END
36
!define SECTION_ASSCOIATION_START
37
!define SECTION_TOTAL
47
上面定义了
36 是要安装的组件最后的区段索引好,
37是文件关联等的开始区段索引号,
47 是总共的区段数。ComponentPre 函数的内容如下?
Function ComponentPre
Push
$0
Push
$1
Call SectionTextReset
StrCpy
$1
0
loop:
ReadINIStr
$0
"
$PLUGINSDIR
\gaydata.ini" "secnames" "sec
$1
"
StrCmp
$0
""
0 +
2
SectionSetText
$1
""
StrCmp
$1 ${SECTION_COMPONENT_END}loop_quit
IntOp
$1 $1 +
1
Goto loop
loop_quit:
StrCpy
$1 ${SECTION_ASSCOIATION_START}
SectionSetText
$1
""
StrCmp
$1 ${SECTION_TOTAL}+
3
IntOp
$1 $1+
1
Goto -
3
Pop
$1
Pop
$0
FunctionEnd
这个函数调用了 SectionTextReset 函数,SectionTextReset 函数如下
Function SectionTextReset
Push
$R0
StrCpy
$R0
0
SectionSetText
$R0
" "
StrCmp
$R0 ${SECTION_TOTAL}+
3
IntOp
$R0 $R0+
1
Goto -
3
Pop
$R0
FunctionEnd
SectionTextReset 函数构成一个循环
$R0
0 开始递增,直到等于
${SECTION_TOTAL} 后跳出循环,这个循环把所有区段的名称都重置为空格,在两个 MUI_PAGE_COMPONENTS 页面的预载入函数都调用一次。这是因为
Show 函数会把一些区段隐藏,即把区段名称设为空值,在下一个 MUI_PAGE_COMPONENTS 页面的 Pre 阶段必须给它一个名称,否则它将一直隐藏。
调用了 SectionTextReset 函数之后是一个循环,这个循环读取 "$PLUGINSDIR\gaydata.ini" 的 sec0 到 ${SECTION_COMPONENT_END} ,如果某个 sec 读到的值为空,则把该区段隐藏,也就是把区段名设为空值。你可以试试英文原版,刚启动时把 "$PLUGINSDIR\gaydata.ini" 的 sec0 设为空值,到了组件选择页面 Winamp (required) 区段就被隐藏了。
再下来也是一个循环,把 ${SECTION_ASSCOIATION_START} 到 ${SECTION_TOTAL} 的区段隐藏,因为第一个 MUI_PAGE_COMPONENTS 只需要显示 0 到 ${SECTION_COMPONENT_END} 的区段。ComponentShow 函数如下
Function SectionTextReset
Push $R0
StrCpy $R0 0
SectionSetText $R0" "
StrCmp $R0 ${SECTION_TOTAL}+3
IntOp $R0 $R0+ 1
Goto -3
Pop $R0
FunctionEnd
SectionTextReset 函数构成一个循环$R0 0 开始递增,直到等于 ${SECTION_TOTAL} 后跳出循环,这个循环把所有区段的名称都重置为空格,在两个 MUI_PAGE_COMPONENTS 页面的预载入函数都调用一次。这是因为Show 函数会把一些区段隐藏,即把区段名称设为空值,在下一个 MUI_PAGE_COMPONENTS 页面的 Pre 阶段必须给它一个名称,否则它将一直隐藏。
Function ComponentShow
Push $0
Push $1
StrCpy $1 0
loop:
ReadINIStr $0 "$PLUGINSDIR\gaydata.ini" "secnames" "sec$1"
SectionSetText $1 $0
StrCmp $1 ${SECTION_COMPONENT_END}loop_quit
IntOp $1 $1 + 1
Goto loop
loop_quit:
Pop $1
Pop $0
FunctionEnd
也是一个循环,$1 的值从 0 到 ${SECTION_COMPONENT_END} 递增,则是依次从 sec0 到 sec36 读取 gaydata.ini 相应的值,并根据读取道的值来从命名区段名称。
第二个组件页面对应的 AsscoiationPre、AsscoiationShow 与上面的基本一致,只是要隐藏的区段索引不同而已。
9. 隐藏控件
组件页面第二次显示的时候,有几个控件是隐藏的,用 Resource Hacker 打开 ${NSISDIR}\Contrib\UIs\modern.exe 里面的 104 对话框就是组件显示页面,要隐藏的空间 ID 为 1017 (显示安装类型) 和 1021 (它左边显示的文本) 还有 1023 (磁盘空间显示的控件)。显示和隐藏控件的指令为 ShowWindow ,说明请看这里。
隐藏控件的代码需要加在 AsscoiationShow 函数里。
FindWindow $0"#32770" "" $HWNDPARENT
获取一个窗口句柄保存在 $0
GetDlgItem $1 $0 1017
获取 1017 控件的句柄?
ShowWindow $1 ${SW_HIDE}
隐藏 1017 控件,其他几个控件的隐藏指令依次为
GetDlgItem $1 $0 1021
ShowWindow $1 ${SW_HIDE}
GetDlgItem $1 $01023
ShowWindow $1 ${SW_HIDE}
除了控件隐藏之外,还有两处文本需要更改,由于使用 !define 只能对第一次显示的组件页面更改,所以第二次显示的文本只能自己用 SendMessage 来改了
GetDlgItem $1 $0 1006
SendMessage $1 ${WM_SETTEXT}0 "STR:Select which icons you want installed, and whether you want files and CDs associated with"
GetDlgItem $1 $01022
SendMessage $1 ${WM_SETTEXT}0 "STR:Select icons to install and media associations:"

转载于:https://www.cnblogs.com/ppgs8903/archive/2011/12/16/4343294.html

你可能感兴趣的文章
activeMQ启动失败61616port被占用问题
查看>>
linux下oracle11G DG搭建(三):环绕备库搭建操作
查看>>
rsync配置文件的参数详解
查看>>
简单题
查看>>
MySQL(十)操纵表及全文本搜索
查看>>
begin again
查看>>
VS2008.Net下使用WPF开发Web应用程序小例
查看>>
数据库设计三大范式
查看>>
步步为营——算法初阶 1.算法概述
查看>>
Linux网络基本配置命令
查看>>
docker开启api端口,docker启用加速
查看>>
【bzoj1176】[Balkan2007]Mokia/【bzoj2683】简单题 CDQ分治+树状数组
查看>>
MEAN实践——LAMP的新时代替代方案(下)
查看>>
读《大道至简》第六章有感
查看>>
鸡腿做法
查看>>
Java导出Highcharts生成的图表为图片源码
查看>>
spring整合quartz并持久化
查看>>
商品评分效果JavaScript
查看>>
Python-数据库(编程)
查看>>
Linux操作系统计划任务
查看>>