【问题标题】:Signing NSIS Uninstaller from Linux or Mac从 Linux 或 Mac 签署 NSIS 卸载程序
【发布时间】:2015-10-24 22:42:22
【问题描述】:

我正在将我们的 NSI 安装程序移植到 Linux 和 Mac 而不是 Windows,以更好地与我们的 Maven 构建系统集成。

我们需要签署我们的安装程序和卸载程序。这是按照http://nsis.sourceforge.net/Signing_an_Uninstaller 的建议完成的,但我刚刚意识到它会尝试运行 tempinstaller 以强制它生成可以签名的卸载程序.exe。

显然,这个技巧在 *Nix 系统上效果不佳,并使这部分过程不可移植。

谁有更好的解决方案。我不是 NSIS 的专家,想知道是否有一种聪明的方法可以获取 uninstall.exe 以便对其进行签名?

【问题讨论】:

    标签: nsis


    【解决方案1】:

    我认为没有真正的解决方案。

    安装程序和卸载程序使用相同的 exe 代码,并且仅在启动时检查一个标志(firstheader 中的FH_FLAGS_UNINSTALL)以查看它是否是卸载程序。仅仅翻转这一位是不够的,程序将无法通过 CRC 检查,即使您绕过卸载程序数据被压缩,因此您必须将其解压缩到文件中的正确位置。要真正做到这一点,您必须编写一个自定义工具。如果您搜索EW_WRITEUNINSTALLER,您可以在 exec.c 中的 NSIS 源中看到此操作。

    【讨论】:

    • 编写卸载程序和仅仅将卸载程序行为(但进入“安装”部分)复制到全新的安装程序并与之捆绑有什么区别?
    • 回答我自己的问题.... 最棘手的部分似乎是卸载程序的自删除行为(复制到 TEMP,然后在重新启动时自行删除)。 SelfDel 插件有一个处理这个问题的技巧,但底部有一个警告,指出卡巴斯基已将该技术标记为威胁,因为它使用了内存注入/资源管理器挂起技术。作为替代方案,已经发布了 NSIS !ifdef INNER 自我执行技术,尽管重新发明了众所周知的轮子,但这些技术可能是可行的。
    【解决方案2】:

    我们需要签署我们的安装程序和卸载程序。这是按照http://nsis.sourceforge.net/Signing_an_Uninstaller 的建议完成的,但我刚刚意识到它试图运行 tempinstaller 以强制它生成可以签名的卸载程序.exe。 [...] 这个技巧在 *Nix 系统上效果不佳,并且使这部分过程不可移植。

    如果您利用存根安装程序进行卸载操作(无负载),这似乎是可能的。

    它将从$TEMP 文件夹中生成一个uninstall.exe 进程,然后可以删除$INSTDIR

    此脚本将创建一个存根(卸载)安装程序,然后可以对其进行身份验证签名。它将在 Windows、MacOS 和 Linux 上编译。

    注意事项:

    • 您必须手动将其捆绑到安装程序中(简单)
    • 您必须管理自己的卸载注册表项(琐碎)
    • 外观可能与 NSIS 的默认卸载程序不匹配
    • 您会看到安装程序打开了两次(第一次来自$INSTDIR,第二次来自$TEMP)。这是一个允许uninstall.exe 删除自身的子进程,类似于NSIS does it in the Section "Uninstall"
    • 您将需要一个专用于卸载操作的辅助.nsi 脚本,如果您在安装/卸载部分之间有很多共享逻辑,这会很麻烦。
      • 更糟糕的是,您必须避免使用 "Uninstall" 部分标题,因为在生成该字节码时,您将遇到与 OP 相同的问题。
    • $TEMP 显式运行时,某些相关文件逻辑将不正确。该示例分别将这些作为$DELETE_DIR$DELETE_EXE 传回。

    代码:

    !include MUI2.nsh
    !include x64.nsh
    !include LogicLib.nsh
    !include FileFunc.nsh
    !include WinMessages.nsh
    
    !define MUI_PRODUCT "My App"
    !define MUI_VERSION "1.0.0"
    
    ; Masquerade the title
    !define MUI_PAGE_HEADER_TEXT "Uninstall My App"
    !define MUI_PAGE_HEADER_SUBTEXT "Remove My App from your computer"
    !define MUI_INSTFILESPAGE_FINISHHEADER_TEXT "Uninstallation Complete"
    !define MUI_INSTFILESPAGE_FINISHHEADER_SUBTEXT "Uninstall was completed successfully."
    
    !insertmacro MUI_PAGE_INSTFILES
    !insertmacro MUI_LANGUAGE "English"
    !insertmacro GetParameters
    
    RequestExecutionLevel admin
    CRCCheck On
    
    OutFile "uninstall.exe"
    Name "Uninstall"
    
    Var /GLOBAL RESPAWN
    Var /GLOBAL DELETE_DIR
    Var /GLOBAL DELETE_EXE
    
    Section
      ; Masquerade as uninstall
      SendMessage $HWNDPARENT ${WM_SETTEXT} 0 "STR:Uninstall"
    
      ${GetParameters} $0
      ${GetOptions} "$0" "/RESPAWN=" $RESPAWN
      ${GetOptions} "$0" "/DELETE_DIR=" $DELETE_DIR
      ${GetOptions} "$0" "/DELETE_EXE=" $DELETE_EXE
    
      ${If} $RESPAWN != ""
        ; We're running from $TEMP; Perform the uninstall
        !define yay "We're running from $EXEPATH, yay, we can remove the install directory!$\n$\n"
        !define myvars "$\tRESPAWN$\t$RESPAWN$\n$\tDELETE_EXE$\t$DELETE_EXE$\n$\tDELETE_DIR$\t$DELETE_DIR"
        MessageBox MB_OK "${yay}${myvars}"
        ; Your uninstall code goes here
        ; RMDir /r $DELETE_DIR\*.*
        ; Delete "$DESKTOP\${MUI_PRODUCT}.lnk"
        ; Delete "$SMPROGRAMS\${MUI_PRODUCT}\*.*"
        ; RmDir  "$SMPROGRAMS\${MUI_PRODUCT}"
        ; Delete Uninstaller And Unistall Registry Entries
        ; DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\${MUI_PRODUCT}"
        ; DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${MUI_PRODUCT}"  
    
        ; Remove the old version of ourself
        ClearErrors
        Delete $DELETE_EXE
        IfErrors 0 +3
        MessageBox MB_OK "File could NOT be deleted: $DELETE_EXE"
        Goto +2
        MessageBox MB_OK "File was successfully deleted: $DELETE_EXE"
    
        ; Remove ourself from $TEMP after reboot
        Delete /REBOOTOK $EXEPATH
    
        ; ${If} ${RunningX64}
        ;   ${EnableX64FSRedirection}
        ; ${EndIf}
        SetDetailsPrint textonly
        DetailPrint "Completed"
      ${Else}
        ; We're NOT running from $TEMP, copy to temp and respawn ourself
        GetTempFileName $0
        CopyFiles "$EXEPATH" "$0"
        Exec '"$0" /RESPAWN=1 /DELETE_DIR="$EXEDIR" /DELETE_EXE="$EXEPATH"'
        Quit
      ${EndIf}
    SectionEnd
    
    Function .onInit
      ; ${If} ${RunningX64}
      ;   SetRegView 64
      ;   ${DisableX64FSRedirection}
      ; ${EndIf}
    FunctionEnd
    

    【讨论】:

      猜你喜欢
      • 2012-01-26
      • 2012-02-12
      • 1970-01-01
      • 2011-02-18
      • 2017-11-15
      • 2011-07-25
      • 2016-06-30
      • 2014-09-13
      • 2014-09-27
      相关资源
      最近更新 更多