m1y3ll0w 发表于 2026-3-15 01:54

Xshell、Xftp(7.0 & 8.0)免费版-后续更新

本帖最后由 m1y3ll0w 于 2026-8-14 01:12 编辑


## 🆕📢
之前的帖子 (thread-1714055-1-1.html) 自动关闭了,后续的更新和交流就在这个新帖子哈~

(https://www.xshell.com/zh/free-for-home-school/) **仅用于非商业用途**,如需商用,请购买许可证。




> 通过不断地调试追码和猜测验证“定向爆破”,暂不涉及复杂的授权许可算法分析,作为个人兴趣业余玩家,能解决实际需求问题已经够用了。




## 更新记录
(thread-2096700-1-1.html#54952829_20260814)
(thread-2096700-1-1.html#54952829_20260508)
(thread-2096700-1-1.html#54952829_20260315)




## 版本说明
**以 7.0 最后一个版本为例:**
> 坛友发布的资源帖子中有[官方旧版本](thread-1661646-1-1.html),安装后会提示下载更新到最新版,下载完成后,用 (https://www.voidtools.com/zh-cn/downloads/) 搜“xshell exe”、“xftp exe”,按修改时间降序排列就能找到最后版本的安装包了。
>
> **安装包签名验证**:选中安装包-右键-属性-数字签名-看一下签名者姓名-选中签名-详细信息-此数字签名正常。
>
> **在非官网渠道下载的安装包,一定要检查数字签名是否正常,最好跟官网能下载到的版本对比一下证书信息,查看证书,确认颁发给哪个公司组织、颁发者是否跟官网安装包一致!**

个人版在官网免费授权页面直接下载
https://www.xshell.com/zh/free-for-home-school/

名称: Xshell-7.0.0170p.exe
大小: 49222760 字节 : 46 MiB
SHA1: 852416874cce8462c675711443c06b1249c78c34

名称: Xftp-7.0.0167p.exe
大小: 40753880 字节 : 38 MiB
SHA1: c9d1bda7b2ccbe5270716cc4816d714b08d25c67

- 版本号带p,授权许可为:Personal 个人版,安装过程窗口显示为个人版,安装完成启动程序后,帮助-关于 Xshell,能看到许可状态为个人版
- 联网安装时,可能会限制低版本安装,提示下载安装新版本,可以尝试断网安装
- 启动程序版本过低时,提示需要下载新版本才能运行,版本终止支持时,提示需要下载安装新的大版本
- 版本正常时,需要联网登录账号授权,注册一个临时邮箱即可通过授权验证,后续可能会限制临时邮箱账号
- 半年后可能会要求强制更新版本,更新后可能需要重新登录账号授权验证,使用之前的邮箱账号登录即可通过授权许可验证
- 不想注册账号登录授权,或者在局域网内,可以使用脚本修补去除授权验证和强制更新等各种限制




30天评估试用版需要填写邮箱获取下载链接
https://www.xshell.com/zh/xshell-download/

名称: Xshell-7.0.0170.exe
大小: 49225168 字节 : 46 MiB
SHA1: 1b1ef6efadaa2d0f4366aa6fbe07be7f6163a3e7

名称: Xftp-7.0.0167.exe
大小: 40917640 字节 : 39 MiB
SHA1: 4b5abcef74609a9b8fb0b19ce35134fc97a41c5a

- 版本号不带p,授权许可为:Evaluation 评估版,安装过程窗口显示为评估版,安装完成启动程序后,帮助-关于 Xshell,能看到许可状态为评估版
- 无论网络环境(联网、断网、局域网),都能直接安装,不限制低版本安装,不提示下载新版本
- 启动时不会要求强制更新,没有登录授权弹窗,30天后评估试用到期,不能继续免费试用,修补去除评估到期验证后可继续试用,功能应该是与个人版一致的(没有深度使用验证)

个人版与评估版都是官方签名版本,应用升级只能升级到各自对应的版本
两个版本二进制比对差异比较大,并不是只有一个标志位这么简单
评估版看起来限制更少,但是需要填写邮箱获取下载链接,**修补脚本对个人版和评估版都适用**




## 20260315
> 之前的帖子一直用的是 Personal 个人版进行修补,直到前些天有坛友发消息截图说用不了,验证许久之后才发现还有一个 (https://www.xshell.com/zh/xshell-download/) !!Evaluation 评估版限制相对要少一些,只有一个月的评估试用期,到期后会弹窗提示“评估期已过”,关闭弹窗就退出程序。
>
> 在个人版的基础上,修补去除评估版到期限制。仅验证了修改系统日期到 30+1 天,以及三年后,评估版主程序能正常打开运行,不再弹出“评估期已过”,没有验证局域网SSH是否正常可用,大概率是正常的,如果有问题,可以及时反馈。




Xshell 30天评估试用到期





**验证操作步骤**(新手实战请参照之前的帖子)

1. 安装 Xshell、Xftp 评估版(版本号后面没有p),完成后运行程序,此时没有登录授权弹窗,也没有评估到期弹窗
2. 关闭程序,修改系统日期到 30+1 天,注意先关闭系统自动校时
3. x32dbg 打开安装目录下的主程序 Xshell.exe,命令框输入`bp CreateWindowExW`打上弹窗断点(也可以不用断点,直接一路 F9 运行,直到弹窗提示,再看调用堆栈)
4. 一直按 F9 运行调试,直到出现“评估期已过”的弹窗,可能会遇到调试卡住的情况,到【线程】栏,选中主线程,右键-恢复线程,继续 F9 调试。在【调用堆栈】栏找到用户模块下最近一次调用弹窗函数的入口地址,选择一个通过方法名称能看懂含义的方法,本次找到的是`nslicense.NSLICENSE_CheckLicense+4C0`
5. 双击入口地址跳转到代码位置,上方的 call 则是处理弹窗的方法,在 call 这一行 F2 打个断点
6. 重新开始调试,F9 运行到 call 断点(出现卡住就恢复主线程运行),F8 单步调试,call 执行后,立马出现弹窗
7. 猜测并尝试修改,在流程图分支处,修改不走评估到期分支,然后 F9 放行,运气不错,已经绕过了离线许可验证




Xshell 评估期已过-调试追码





Xshell 评估期已过-修补





## 20260508
> 特征码改用更为“通杀”的修补方式
> 添加 7.0 低版本【限制标签】和【退出弹窗】修补




## 20260814
> 新增`??`通配符修补,修复 8.0.0107p 新版本特征码变化导致去除登录授权验证弹窗失效问题
> 脚本修复不能正常识别自定义安装路径问题




## 最新脚本
> 理论上支持全版本 7.0.x、8.0.x 家庭/学校免费版和30天评估版
> 7.0 低版本有标签限制、退出弹窗,将脚本中 $rmTabLimit、$rmExitDialog 设置 true 即可修补去除

cmd 执行 notepad,打开记事本空白文档,复制脚本内容粘贴进去
Ctrl + S 保存,设置文件后缀名为.ps1,编码格式指定为ANSI
在脚本文件上右键-使用 PowerShell 运行,允许本次执行

```
# 默认情况下,Windows PowerShell 的执行策略为 Restricted,不允许运行任何脚本。
# 按住 Shift,右键-在此处打开 PowerShell 窗口
# 查看当前执行策略:Get-ExecutionPolicy
# 修改执行策略(当前用户有效):Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
# 确认执行策略为 RemoteSigned,选中这个脚本文件,右键-使用 PowerShell 运行

# PowerShell 5.1 版本对 UTF-8 中文支持不友好,中文解析报错,导致脚本不能正常执行,所以脚本编码使用的是 ANSI
# 查看版本:Get-Host | Select-Object Version

# 脚本自动修补只对【家庭/学校免费版】、【30天评估版】有效,其他专业收费版无效
# https://www.xshell.com/zh/free-for-home-school/

# 教程出处:https://www.52pojie.cn/thread-2096700-1-1.html


function Repair-BinaryFile {
    param(
      $FilePath,
      $SearchHex,
      $ReplaceHex,
      $ReplaceAll,
      $IsMask
    )
   
    # 验证文件存在
    if (-not (Test-Path $FilePath)) {
      #Write-Error "文件不存在: $FilePath"
      Write-Host "文件不存在: $FilePath" -ForegroundColor Cyan
      return
    }
    Write-Host "`n正在修补文件: $FilePath" -ForegroundColor Green
   
    # 创建备份
    $backupPath = Create-Backup -FilePath $FilePath
   
    # 转换十六进制为字节数组
    $SearchHex = $SearchHex -replace '\?', '0'
    $SearchHex = $SearchHex -replace '\s', ''
    $ReplaceHex = $ReplaceHex -replace '\s', ''
   
    if ($SearchHex.Length -ne $ReplaceHex.Length) {
      #throw "搜索和替换的十六进制字符串长度必须相同"
    }
    if ($SearchHex.Length % 2 -ne 0) {
      throw "十六进制字符串长度必须是偶数"
    }
   
    $searchBytes = for ($i = 0; $i -lt $SearchHex.Length; $i += 2) {
      ::ToByte($SearchHex.Substring($i, 2), 16)
    }
   
    $replaceBytes = for ($i = 0; $i -lt $ReplaceHex.Length; $i += 2) {
      ::ToByte($ReplaceHex.Substring($i, 2), 16)
    }
   
    Write-Host "开始搜索特征码..." -ForegroundColor Yellow
    Write-Host "搜索: $SearchHex" -ForegroundColor Cyan
    Write-Host "替换: $ReplaceHex" -ForegroundColor Cyan
    Write-Host "模式: $(if ($ReplaceAll) { '替换所有匹配项' } else { '替换第一个匹配项' })" -ForegroundColor Cyan
   
    # 执行直接替换
    $matchesFound = SearchAndReplaceBinary -FilePath $FilePath -SearchBytes $searchBytes -ReplaceBytes $replaceBytes -ReplaceAll:$ReplaceAll -IsMask:$IsMask
   
    if ($matchesFound -gt 0) {
      Write-Host "修补完成! 共替换了 $matchesFound 个匹配项" -ForegroundColor Green
      #Write-Host "原文件备份: $backupPath" -ForegroundColor Cyan
    } else {
      Write-Host "未找到匹配的特征码" -ForegroundColor Yellow
      <#
      if (Test-Path $backupPath) {
            Remove-Item $backupPath -Force
            Write-Host "原文件备份已删除: $backupPath" -ForegroundColor Cyan
      }
      #>
    }
}

function SearchAndReplaceBinary {
    param(
      $FilePath,
      ]$SearchBytes,
      ]$ReplaceBytes,
      $ReplaceAll,
      $IsMask
    )
   
    $searchLength = $SearchBytes.Length
    $matchesFound = 0
   
    # 以读写方式打开文件
    $stream = ::Open($FilePath, ::Open, ::ReadWrite)
   
    try {
      $buffer = New-Object byte[] (64KB)
      $fileLength = $stream.Length
      $position = 0
      $maskByte = ::ToByte("00", 16)
      
      while ($position -lt $fileLength) {
            # 计算要读取的字节数
            $bytesToRead = ::Min($buffer.Length, $fileLength - $position)
            
            # 读取数据到缓冲区
            $bytesRead = $stream.Read($buffer, 0, $bytesToRead)
            
            if ($bytesRead -eq 0) { break }
            
            # 在缓冲区中搜索
            for ($i = 0; $i -le $bytesRead - $searchLength; $i++) {
                $isMatch = $true
                for ($j = 0; $j -lt $searchLength; $j++) {
                  if ($IsMask -and ($maskByte -eq $SearchBytes[$j])) {
                        continue
                  }
                  if ($buffer[$i + $j] -ne $SearchBytes[$j]) {
                        $isMatch = $false
                        break
                  }
                }
               
                if ($isMatch) {
                  # 计算文件中的绝对位置
                  $matchPosition = $position + $i
                  
                  # 定位并写入替换数据
                  $stream.Seek($matchPosition, ::Begin) | Out-Null
                  $stream.Write($ReplaceBytes, 0, $ReplaceBytes.Length)
                  
                  Write-Host "在位置 0x$($matchPosition.ToString('X8')) 找到匹配并替换" -ForegroundColor Green
                  $matchesFound++
                  
                  if (-not $ReplaceAll) {
                        return $matchesFound
                  }
                }
            }
            
            # 定位到新的读取位置
            $position += $bytesRead
            #$stream.Seek($position, ::Begin) | Out-Null
            
            # 显示进度
            $percentComplete = ::Round(($position / $fileLength) * 100, 2)
            Write-Progress -Activity "处理文件" -Status "已扫描 $position/$fileLength 字节" -PercentComplete $percentComplete
      }
      
      Write-Progress -Activity "处理文件" -Completed
    }
    finally {
      $stream.Close()
    }
   
    return $matchesFound
}

function Create-Backup() {
    param(
      $FilePath
    )
   
        #$backupPath = "$FilePath.backup_$(Get-Date -Format 'yyyyMMdd_HHmmss')"
    $backupPath = Get-Backup-Path -FilePath $FilePath
    if (Test-Path $backupPath) {
      Write-Host "原文件备份已存在: $backupPath" -ForegroundColor Cyan
      return $backupPath
    }

    Write-Host "正在创建备份..." -ForegroundColor Yellow
    Copy-Item $FilePath $backupPath -Force
    Write-Host "备份已创建: $backupPath" -ForegroundColor Green
   
    return $backupPath
}

function Get-Backup-Path() {
    param(
      $FilePath
    )
   
    return $FilePath + "0000";
}

function Get-Install-Path-Parent() {
    #$xshellExe = Get-Command -Name "Xshell" | Select-Object -ExpandProperty Source
    $xshellExe = (Get-Command -Name "Xshell" 2>$null).Source # D:\Program Files (x86)\NetSarang\Xshell 8\Xshell.exe
    #$xshellExe = ""
    if ($xshellExe) {
      $installDir = Split-Path -Path $xshellExe -Parent # D:\Program Files (x86)\NetSarang\Xshell 8
      $parentDir = Split-Path -Path $installDir -Parent # D:\Program Files (x86)\NetSarang
    } else {
      #Write-Host "脚本所在路径:$pwd" -ForegroundColor Gray
      $xshellExe = $pwd.Path
      $xshellVer = Get-FileVersion -FilePath ($xshellExe + "\Xshell.exe")
      #Write-Host "主程序文件版本:$xshellVer" -ForegroundColor Gray
      if ($xshellVer) {
            $installDir = Split-Path -Path $xshellExe # D:\Program Files (x86)\NetSarang
            #Write-Host "installDir:$installDir" -ForegroundColor Gray
            $parentDir = $installDir
      } else {
            throw "请确认使用官方安装包正常完成安装,或者将脚本文件放在 Xshell.exe 主程序所在的安装目录下,再重新执行脚本"
      }
    }
   
    # 最终返回程序安装父级目录 -> D:\Program Files (x86)\NetSarang\
    return $parentDir + "\"
}

function Get-FileVersion {
    param(
      $FilePath
    )
   
    if (Test-Path $FilePath) {
      # 获取安装目录下主程序文件版本(8,0,0,21),用于判断处理逻辑
      return (Get-Item $FilePath).VersionInfo.FileVersion
    }
    return ""
}

function Rename-File {
    param(
      $FilePath
    )
   
    if ((Test-Path $FilePath) -and !(Test-Path ($FilePath + "0000"))) {
      $fName = (Get-Item $FilePath).Name
      #$bName = (Get-Item $FilePath).BaseName
      #$ext = Get-ChildItem $FilePath | Select-Object Extension
      $rName = $fName + "0000"
      Rename-Item -Path $FilePath -NewName $rName
      Write-Host "$FilePath 文件已重命名为: $rName" -ForegroundColor Green
    }
    #return $FilePath
}

function Show-ExitMessage {
    Write-Host "脚本执行完成,按任意键退出..." -ForegroundColor Gray
    $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
}


# 设置错误处理,报错后不再往下执行
#$ErrorActionPreference = "Stop"

# 修补程序
$xshell7 = $true
$xftp7 = $true
$xshell8 = $true
$xftp8 = $true
# 去除4个标签限制,家庭/学校免费版安装包版本在 build [7.0.x, 7.0.0099),限制一个窗口最多只能打开4个标签
$rmTabLimit = $false
# 去除退出程序时弹窗,家庭/学校免费版安装包版本在 build [7.0.0099, 7.0.0134),退出程序时会弹窗提示当前是家庭/学校免费版
$rmExitDialog = $false


# 主程序入口【需要放在函数定义之后】
try {
   
    Write-Host "`n【使用安装包升级版本后,需要手动将安装目录下的备份文件删除(后缀0000结尾的文件),再执行修补脚本】`n" -ForegroundColor Yellow
   
    $installPath = Get-Install-Path-Parent
    Write-Host "程序安装父级目录:$installPath" -ForegroundColor Gray
   
    # Xshell 7.0.x
    if ($xshell7) {
      $fPath = $installPath + "Xshell 7\"
      $fName = "nsssh3.dll"
      # 去除授权登录弹窗-校验输入内容 NSSSH_CheckSubmitTokenIsValid
      Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "53 56 E8 A9 F9 FF FF 83 C4 08 8D 4D D8" -ReplaceHex "B8 01 00 00 00 59 5F 5E 5B 8B E5 5D C3"
      $fName = "nslicense.dll"
      # 绕过应用版本及授权许可检查/去除强制更新弹窗 NSLICENSE_CheckLicense
      Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "55 8B EC 81 EC CC 0D 00 00" -ReplaceHex "B8 05 00 00 00 C3 90 90 90"
      # 去除首次启动时提示免费版;去除[7.0, 7.0.0090p)最多4个标签限制;去除[7.0.0099p, 7.0.0134p)在程序退出时弹出一个免费许可弹窗 NSLICENSE_GetLicenseState
      if ($rmTabLimit -or $rmExitDialog) { # TODO 需要手动将标识变量赋值为$true
            #Write-Host "7.0 旧版本修补:rmTabLimit=$rmTabLimit, rmExitDialog=$rmExitDialog" -ForegroundColor Gray
            Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "55 8B EC 81 EC 38 04 00 00" -ReplaceHex "B8 05 00 00 00 C3 90 90 90"
      }
      $fName = "nsutil2.dll"
      # 去除授权登录弹窗-校验返回内容 NsIsLastCheckInReturnPassed
      Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "57 56 E8 3E FE FF FF 83 C4 08" -ReplaceHex "33 C0 59 5F 5E 5B 8B E5 5D C3"
      # 重命名 LiveUpdate.exe,让检查更新功能失效
      $fName = "LiveUpdate.exe"
      Rename-File -FilePath ($fPath + $fName)
    }
    # Xftp 7.0.x
    if ($xftp7) {
      $fPath = $installPath + "Xftp 7\"
      $fName = "nsssh3.dll"
      # 去除授权登录弹窗-校验输入内容 NSSSH_CheckSubmitTokenIsValid
      Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "53 56 E8 A9 F9 FF FF 83 C4 08 8D 4D D8" -ReplaceHex "B8 01 00 00 00 59 5F 5E 5B 8B E5 5D C3"
      $fName = "nslicense.dll"
      # 绕过应用版本及授权许可检查/去除强制更新弹窗 NSLICENSE_CheckLicense
      Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "55 8B EC 81 EC CC 0D 00 00" -ReplaceHex "B8 05 00 00 00 C3 90 90 90"
      # 去除首次启动时提示免费版;去除[7.0, 7.0.0090p)最多4个标签限制;去除[7.0.0099p, 7.0.0134p)在程序退出时弹出一个免费许可弹窗 NSLICENSE_GetLicenseState
      if ($rmTabLimit -or $rmExitDialog) { # TODO 需要手动将标识变量赋值为$true
            Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "55 8B EC 81 EC 38 04 00 00" -ReplaceHex "B8 05 00 00 00 C3 90 90 90"
      }
      $fName = "nsutil2.dll"
      # 去除授权登录弹窗-校验返回内容 NsIsLastCheckInReturnPassed
      Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "57 56 E8 3E FE FF FF 83 C4 08" -ReplaceHex "33 C0 59 5F 5E 5B 8B E5 5D C3"
      # 重命名 LiveUpdate.exe,让检查更新功能失效
      $fName = "LiveUpdate.exe"
      Rename-File -FilePath ($fPath + $fName)
    }
   
    # Xshell 8.0.x
    if ($xshell8) {
      $fPath = $installPath + "Xshell 8\"
      $fName = "nsssh3.dll"
      # 去除授权登录弹窗-校验输入内容 NSSSH_CheckSubmitTokenIsValid
      Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "53 56 E8 ?? ?? ?? ?? 83 C4 08 8D 4D D8" -ReplaceHex "B8 01 00 00 00 59 5F 5E 5B 8B E5 5D C3" -IsMask $true
      $fName = "nslicense.dll"
      # 绕过应用版本及授权许可检查/去除强制更新弹窗 NSLICENSE_CheckLicense
      Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "55 8B EC 81 EC CC 0D 00 00" -ReplaceHex "B8 05 00 00 00 C3 90 90 90"
      $fName = "nsutil2.dll"
      # 去除授权登录弹窗-校验返回内容 NsIsLastCheckInReturnPassed
      Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "57 56 E8 3E FE FF FF 83 C4 08" -ReplaceHex "33 C0 59 5F 5E 5B 8B E5 5D C3"
      # 去除启动时检查更新及系统通知 NsIsUpdateIntervalPassed
      Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "55 8B EC FF 75 10 8B 55 0C" -ReplaceHex "B8 00 00 00 00 C3 90 90 90"
      # 重命名 LiveUpdate.exe,让检查更新功能失效
      $fName = "LiveUpdate.exe"
      Rename-File -FilePath ($fPath + $fName)
    }
   
    # Xftp 8.0.x
    if ($xftp8) {
      $fPath = $installPath + "Xftp 8\"
      $fName = "nsssh3.dll"
      # 去除授权登录弹窗-校验输入内容 NSSSH_CheckSubmitTokenIsValid
      Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "53 56 E8 ?? ?? ?? ?? 83 C4 08 8D 4D D8" -ReplaceHex "B8 01 00 00 00 59 5F 5E 5B 8B E5 5D C3" -IsMask $true
      $fName = "nslicense.dll"
      # 绕过应用版本及授权许可检查/去除强制更新弹窗 NSLICENSE_CheckLicense
      Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "55 8B EC 81 EC CC 0D 00 00" -ReplaceHex "B8 05 00 00 00 C3 90 90 90"
      $fName = "nsutil2.dll"
      # 去除授权登录弹窗-校验返回内容 NsIsLastCheckInReturnPassed
      Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "57 56 E8 3E FE FF FF 83 C4 08" -ReplaceHex "33 C0 59 5F 5E 5B 8B E5 5D C3"
      # 去除启动时检查更新及系统通知 NsIsUpdateIntervalPassed
      Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "55 8B EC FF 75 10 8B 55 0C" -ReplaceHex "B8 00 00 00 00 C3 90 90 90"
      # 重命名 LiveUpdate.exe,让检查更新功能失效
      $fName = "LiveUpdate.exe"
      Rename-File -FilePath ($fPath + $fName)
    }

} catch {
    Write-Host "错误: $($_.Exception.Message)" -ForegroundColor Red
    Write-Host "堆栈跟踪: $($_.Exception.StackTrace)" -ForegroundColor Red
} finally {
    Show-ExitMessage
}
```




## 附录
- (https://www.xshell.com/zh/noncompliance/)
- (https://mp.weixin.qq.com/s?__biz=MzkwMzI1ODUwNA==&mid=2247487164&idx=1&sn=d98600cb28d75af03ce2cc0adaf05bee)

m1y3ll0w 发表于 2026-3-16 19:15

脚本支持 7.0.0134+,8.0+,7.0.0134 之前的授权弹窗是在退出程序时弹出,可以参照之前的帖子手动修补。

b98 发表于 2026-3-16 19:24

非常不错!!

991547436 发表于 2026-6-25 09:47

Xmanager 8和Xlpd 8逻辑一样的 XmanagerPowerSuite-8.0.0018.exe可用
比如xshell8已经处理过了 想处理xmanager8的 就把代码中xshell8改成false再执行 否则二次执行报错
$xshell7 = $true
$xftp7 = $true
$xshell8 = $true
$xftp8 = $true
$xmanager8 = $true
$xlpd8 = $true




# 默认情况下,Windows PowerShell 的执行策略为 Restricted,不允许运行任何脚本。
# 按住 Shift,右键-在此处打开 PowerShell 窗口
# 查看当前执行策略:Get-ExecutionPolicy
# 修改执行策略(当前用户有效):Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
# 确认执行策略为 RemoteSigned,选中这个脚本文件,右键-使用 PowerShell 运行

# PowerShell 5.1 版本对 UTF-8 中文支持不友好,中文解析报错,导致脚本不能正常执行,所以脚本编码使用的是 ANSI
# 查看版本:Get-Host | Select-Object Version

# 脚本自动修补只对【家庭/学校免费版】、【30天评估版】有效,其他专业收费版无效
# https://www.xshell.com/zh/free-for-home-school/

# 教程出处:https://www.52pojie.cn/thread-2096700-1-1.html

function Repair-BinaryFile {
    param(
      $FilePath,
      $SearchHex,
      $ReplaceHex,
      $ReplaceAll
    )

    # 验证文件存在
    if (-not (Test-Path $FilePath)) {
      #Write-Error "文件不存在: $FilePath"
      Write-Host "文件不存在: $FilePath" -ForegroundColor Cyan
      return
    }
    Write-Host "`n正在修补文件: $FilePath" -ForegroundColor Green

    # 创建备份
    $backupPath = Create-Backup -FilePath $FilePath

    # 转换十六进制为字节数组
    $SearchHex = $SearchHex -replace '\s',''
    $ReplaceHex = $ReplaceHex -replace '\s',''

    if ($SearchHex.Length -ne $ReplaceHex.Length) {
      throw "搜索和替换的十六进制字符串长度必须相同"
    }
    if ($SearchHex.Length % 2 -ne 0) {
      throw "十六进制字符串长度必须是偶数"
    }

    $searchBytes = for ($i = 0; $i -lt $SearchHex.Length; $i += 2) {
      ::ToByte($SearchHex.Substring($i, 2), 16)
    }

    $replaceBytes = for ($i = 0; $i -lt $ReplaceHex.Length; $i += 2) {
      ::ToByte($ReplaceHex.Substring($i, 2), 16)
    }

    Write-Host "开始搜索特征码..." -ForegroundColor Yellow
    Write-Host "搜索: $SearchHex" -ForegroundColor Cyan
    Write-Host "替换: $ReplaceHex" -ForegroundColor Cyan
    Write-Host "模式: $(if ($ReplaceAll) { '替换所有匹配项' } else { '替换第一个匹配项' })" -ForegroundColor Cyan

    # 执行直接替换
    $matchesFound = SearchAndReplaceBinary -FilePath $FilePath -SearchBytes $searchBytes -ReplaceBytes $replaceBytes -ReplaceAll:$ReplaceAll

    if ($matchesFound -gt 0) {
      Write-Host "修补完成! 共替换了 $matchesFound 个匹配项" -ForegroundColor Green
      #Write-Host "原文件备份: $backupPath" -ForegroundColor Cyan
    } else {
      Write-Host "未找到匹配的特征码" -ForegroundColor Yellow
      <#
      if (Test-Path $backupPath) {
            Remove-Item $backupPath -Force
            Write-Host "原文件备份已删除: $backupPath" -ForegroundColor Cyan
      }
      #>
    }
}

function SearchAndReplaceBinary {
    param(
      $FilePath,
      ]$SearchBytes,
      ]$ReplaceBytes,
      $ReplaceAll
    )

    $searchLength = $SearchBytes.Length
    $matchesFound = 0

    # 以读写方式打开文件
    $stream = ::Open($FilePath, ::Open, ::ReadWrite)

    try {
      $buffer = New-Object byte[] (64KB)
      $fileLength = $stream.Length
      $position = 0

      while ($position -lt $fileLength) {
            # 计算要读取的字节数
            $bytesToRead = ::Min($buffer.Length, $fileLength - $position)

            # 读取数据到缓冲区
            $bytesRead = $stream.Read($buffer, 0, $bytesToRead)

            if ($bytesRead -eq 0) { break }

            # 在缓冲区中搜索
            for ($i = 0; $i -le $bytesRead - $searchLength; $i++) {
                $isMatch = $true
                for ($j = 0; $j -lt $searchLength; $j++) {
                  if ($buffer[$i + $j] -ne $SearchBytes[$j]) {
                        $isMatch = $false
                        break
                  }
                }

                if ($isMatch) {
                  # 计算文件中的绝对位置
                  $matchPosition = $position + $i

                  # 定位并写入替换数据
                  $stream.Seek($matchPosition, ::Begin) | Out-Null
                  $stream.Write($ReplaceBytes, 0, $ReplaceBytes.Length)

                  Write-Host "在位置 0x$($matchPosition.ToString('X8')) 找到匹配并替换" -ForegroundColor Green
                  $matchesFound++

                  # 恢复读取位置
                  $stream.Seek($position + $bytesRead, ::Begin) | Out-Null

                  if (-not $ReplaceAll) {
                        return $matchesFound
                  }
                }
            }

            $position += $bytesRead

            # 显示进度
            $percentComplete = ::Round(($position / $fileLength) * 100, 2)
            Write-Progress -Activity "处理文件" -Status "已扫描 $position/$fileLength 字节" -PercentComplete $percentComplete
      }

      Write-Progress -Activity "处理文件" -Completed
    }
    finally {
      $stream.Close()
    }

    return $matchesFound
}

function Create-Backup() {
    param(
      $FilePath
    )

      #$backupPath = "$FilePath.backup_$(Get-Date -Format 'yyyyMMdd_HHmmss')"
    $backupPath = Get-Backup-Path -FilePath $FilePath
    if (Test-Path $backupPath) {
      Write-Host "原文件备份已存在: $backupPath" -ForegroundColor Cyan
      return $backupPath
    }

    Write-Host "正在创建备份..." -ForegroundColor Yellow
    Copy-Item $FilePath $backupPath -Force
    Write-Host "备份已创建: $backupPath" -ForegroundColor Green

    return $backupPath
}

function Get-Backup-Path() {
    param(
      $FilePath
    )

    return $FilePath + "0000";
}

function Get-Install-Path-Parent() {
    #$xshellExe = Get-Command -Name "Xshell" | Select-Object -ExpandProperty Source
    $xshellExe = (Get-Command -Name "Xshell").Source # D:\Program Files (x86)\NetSarang\Xshell 8\Xshell.exe
    if ($xshellExe) {
      $installDir = Split-Path -Path $xshellExe -Parent # D:\Program Files (x86)\NetSarang\Xshell 8
      $parentDir = Split-Path -Path $installDir -Parent # D:\Program Files (x86)\NetSarang
    } else {
      $xshellExe = $pwd
      #Write-Host "脚本所在路径:$pwd" -ForegroundColor Gray
      if ($xshellExe) {
            $installDir = Split-Path -Path $xshellExe # D:\Program Files (x86)\NetSarang
            #Write-Host "installDir:$installDir" -ForegroundColor Gray
            $parentDir = $installDir
      }
    }

    if (-not ($parentDir -match "NetSarang")) {
      throw "请确认系统环境变量 Path 中存在程序安装路径,或者将脚本文件放在 Xshell 的安装目录下,并确保安装目录上级为 NetSarang"
    }

    # 最终返回程序安装父级目录:D:\Program Files (x86)\NetSarang\
    return $parentDir + "\"
}

function Get-FileVersion {
    param(
      $FilePath
    )

    if (Test-Path $FilePath) {
      # 获取安装目录下主程序文件版本(8,0,0,21),用于判断处理逻辑
      return (Get-Command $FilePath).FileVersionInfo.FileVersion
    }
    return ""
}

function Rename-File {
    param(
      $FilePath
    )

    if ((Test-Path $FilePath) -and !(Test-Path ($FilePath + "0000"))) {
      $fName = (Get-Item $FilePath).Name
      #$bName = (Get-Item $FilePath).BaseName
      #$ext = Get-ChildItem $FilePath | Select-Object Extension
      $rName = $fName + "0000"
      Rename-Item -Path $FilePath -NewName $rName
      Write-Host "$FilePath 文件已重命名为: $rName" -ForegroundColor Green
    }
    #return $FilePath
}

function Show-ExitMessage {
    Write-Host "脚本执行完成,按任意键退出..." -ForegroundColor Gray
    $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
}

# 设置错误处理,报错后不再往下执行
#$ErrorActionPreference = "Stop"

# 修补程序
$xshell7 = $true
$xftp7 = $true
$xshell8 = $true
$xftp8 = $true
$xmanager8 = $true
$xlpd8 = $true
# 去除4个标签限制,家庭/学校免费版安装包版本在 build [7.0.x, 7.0.0099),限制一个窗口最多只能打开4个标签
$rmTabLimit = $false
# 去除退出程序时弹窗,家庭/学校免费版安装包版本在 build [7.0.0099, 7.0.0134),退出程序时会弹窗提示当前是家庭/学校免费版
$rmExitDialog = $false

# 主程序入口【需要放在函数定义之后】
try {

    Write-Host "`n【使用安装包升级版本后,需要手动将安装目录下的备份文件删除(后缀0000结尾的文件),再执行修补脚本】`n" -ForegroundColor Yellow

    $installPath = Get-Install-Path-Parent
    Write-Host "程序安装父级目录:$installPath" -ForegroundColor Gray

    # Xshell 7.0.x
    if ($xshell7) {
      $fPath = $installPath + "Xshell 7\"
      $fName = "nsssh3.dll"
      # 去除授权登录弹窗-校验输入内容 NSSSH_CheckSubmitTokenIsValid
      Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "53 56 E8 A9 F9 FF FF 83 C4 08 8D 4D D8" -ReplaceHex "B8 01 00 00 00 59 5F 5E 5B 8B E5 5D C3"
      $fName = "nslicense.dll"
      # 绕过应用版本及授权许可检查/去除强制更新弹窗 NSLICENSE_CheckLicense
      Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "55 8B EC 81 EC CC 0D 00 00" -ReplaceHex "B8 05 00 00 00 C3 90 90 90"
      # 去除首次启动时提示免费版;去除[7.0, 7.0.0090p)最多4个标签限制;去除[7.0.0099p, 7.0.0134p)在程序退出时弹出一个免费许可弹窗
      if ($rmTabLimit -or $rmExitDialog) { # TODO 需要手动将标识变量赋值为$true
            #Write-Host "7.0 旧版本修补:rmTabLimit=$rmTabLimit, rmExitDialog=$rmExitDialog" -ForegroundColor Gray
            Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "55 8B EC 81 EC 38 04 00 00" -ReplaceHex "B8 05 00 00 00 C3 90 90 90"
      }
      $fName = "nsutil2.dll"
      # 去除授权登录弹窗-校验返回内容 NsIsLastCheckInReturnPassed
      Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "57 56 E8 3E FE FF FF 83 C4 08" -ReplaceHex "33 C0 59 5F 5E 5B 8B E5 5D C3"
      # 重命名 LiveUpdate.exe,让检查更新功能失效
      $fName = "LiveUpdate.exe"
      Rename-File -FilePath ($fPath + $fName)
    }
    # Xftp 7.0.x
    if ($xftp7) {
      $fPath = $installPath + "Xftp 7\"
      $fName = "nsssh3.dll"
      # 去除授权登录弹窗-校验输入内容 NSSSH_CheckSubmitTokenIsValid
      Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "53 56 E8 A9 F9 FF FF 83 C4 08 8D 4D D8" -ReplaceHex "B8 01 00 00 00 59 5F 5E 5B 8B E5 5D C3"
      $fName = "nslicense.dll"
      # 绕过应用版本及授权许可检查/去除强制更新弹窗 NSLICENSE_CheckLicense
      Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "55 8B EC 81 EC CC 0D 00 00" -ReplaceHex "B8 05 00 00 00 C3 90 90 90"
      # 去除首次启动时提示免费版;去除[7.0, 7.0.0090p)最多4个标签限制;去除[7.0.0099p, 7.0.0134p)在程序退出时弹出一个免费许可弹窗
      if ($rmTabLimit -or $rmExitDialog) { # TODO 需要手动将标识变量赋值为$true
            Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "55 8B EC 81 EC 38 04 00 00" -ReplaceHex "B8 05 00 00 00 C3 90 90 90"
      }
      $fName = "nsutil2.dll"
      # 去除授权登录弹窗-校验返回内容 NsIsLastCheckInReturnPassed
      Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "57 56 E8 3E FE FF FF 83 C4 08" -ReplaceHex "33 C0 59 5F 5E 5B 8B E5 5D C3"
      # 重命名 LiveUpdate.exe,让检查更新功能失效
      $fName = "LiveUpdate.exe"
      Rename-File -FilePath ($fPath + $fName)
    }

    # Xshell 8.0.x
    if ($xshell8) {
      $fPath = $installPath + "Xshell 8\"
      $fName = "nsssh3.dll"
      # 去除授权登录弹窗-校验输入内容 NSSSH_CheckSubmitTokenIsValid
      Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "53 56 E8 A9 F9 FF FF 83 C4 08 8D 4D D8" -ReplaceHex "B8 01 00 00 00 59 5F 5E 5B 8B E5 5D C3"
      $fName = "nslicense.dll"
      # 绕过应用版本及授权许可检查/去除强制更新弹窗 NSLICENSE_CheckLicense
      Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "55 8B EC 81 EC CC 0D 00 00" -ReplaceHex "B8 05 00 00 00 C3 90 90 90"
      $fName = "nsutil2.dll"
      # 去除授权登录弹窗-校验返回内容 NsIsLastCheckInReturnPassed
      Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "57 56 E8 3E FE FF FF 83 C4 08" -ReplaceHex "33 C0 59 5F 5E 5B 8B E5 5D C3"
      # 去除启动时检查更新及系统通知 NsIsUpdateIntervalPassed
      Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "55 8B EC FF 75 10 8B 55 0C" -ReplaceHex "B8 00 00 00 00 C3 90 90 90"
      # 重命名 LiveUpdate.exe,让检查更新功能失效
      $fName = "LiveUpdate.exe"
      Rename-File -FilePath ($fPath + $fName)
    }

    # Xftp 8.0.x
    if ($xftp8) {
      $fPath = $installPath + "Xftp 8\"
      $fName = "nsssh3.dll"
      # 去除授权登录弹窗-校验输入内容 NSSSH_CheckSubmitTokenIsValid
      Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "53 56 E8 A9 F9 FF FF 83 C4 08 8D 4D D8" -ReplaceHex "B8 01 00 00 00 59 5F 5E 5B 8B E5 5D C3"
      $fName = "nslicense.dll"
      # 绕过应用版本及授权许可检查/去除强制更新弹窗 NSLICENSE_CheckLicense
      Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "55 8B EC 81 EC CC 0D 00 00" -ReplaceHex "B8 05 00 00 00 C3 90 90 90"
      $fName = "nsutil2.dll"
      # 去除授权登录弹窗-校验返回内容 NsIsLastCheckInReturnPassed
      Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "57 56 E8 3E FE FF FF 83 C4 08" -ReplaceHex "33 C0 59 5F 5E 5B 8B E5 5D C3"
      # 去除启动时检查更新及系统通知 NsIsUpdateIntervalPassed
      Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "55 8B EC FF 75 10 8B 55 0C" -ReplaceHex "B8 00 00 00 00 C3 90 90 90"
      # 重命名 LiveUpdate.exe,让检查更新功能失效
      $fName = "LiveUpdate.exe"
      Rename-File -FilePath ($fPath + $fName)
    }

    # Xmanager 8.0.x
    if ($xmanager8) {
      $fPath = $installPath + "Xmanager 8\"
      $fName = "nsssh3.dll"
      # 去除授权登录弹窗-校验输入内容 NSSSH_CheckSubmitTokenIsValid
      Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "53 56 E8 A9 F9 FF FF 83 C4 08 8D 4D D8" -ReplaceHex "B8 01 00 00 00 59 5F 5E 5B 8B E5 5D C3"
      $fName = "nslicense.dll"
      # 绕过应用版本及授权许可检查/去除强制更新弹窗 NSLICENSE_CheckLicense
      Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "55 8B EC 81 EC CC 0D 00 00" -ReplaceHex "B8 05 00 00 00 C3 90 90 90"
      $fName = "nsutil2.dll"
      # 去除授权登录弹窗-校验返回内容 NsIsLastCheckInReturnPassed
      Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "57 56 E8 3E FE FF FF 83 C4 08" -ReplaceHex "33 C0 59 5F 5E 5B 8B E5 5D C3"
      # 去除启动时检查更新及系统通知 NsIsUpdateIntervalPassed
      Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "55 8B EC FF 75 10 8B 55 0C" -ReplaceHex "B8 00 00 00 00 C3 90 90 90"
      # 重命名 LiveUpdate.exe,让检查更新功能失效
      $fName = "LiveUpdate.exe"
      Rename-File -FilePath ($fPath + $fName)
    }
       
    # Xlpd 8.0.x
    if ($xlpd8) {
      $fPath = $installPath + "Xlpd 8\"
      $fName = "nsssh3.dll"
      # 去除授权登录弹窗-校验输入内容 NSSSH_CheckSubmitTokenIsValid
      Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "53 56 E8 A9 F9 FF FF 83 C4 08 8D 4D D8" -ReplaceHex "B8 01 00 00 00 59 5F 5E 5B 8B E5 5D C3"
      $fName = "nslicense.dll"
      # 绕过应用版本及授权许可检查/去除强制更新弹窗 NSLICENSE_CheckLicense
      Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "55 8B EC 81 EC CC 0D 00 00" -ReplaceHex "B8 05 00 00 00 C3 90 90 90"
      $fName = "nsutil2.dll"
      # 去除授权登录弹窗-校验返回内容 NsIsLastCheckInReturnPassed
      Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "57 56 E8 3E FE FF FF 83 C4 08" -ReplaceHex "33 C0 59 5F 5E 5B 8B E5 5D C3"
      # 去除启动时检查更新及系统通知 NsIsUpdateIntervalPassed
      Repair-BinaryFile -FilePath ($fPath + $fName) -SearchHex "55 8B EC FF 75 10 8B 55 0C" -ReplaceHex "B8 00 00 00 00 C3 90 90 90"
      # 重命名 LiveUpdate.exe,让检查更新功能失效
      $fName = "LiveUpdate.exe"
      Rename-File -FilePath ($fPath + $fName)
    }

} catch {
    Write-Host "错误: $($_.Exception.Message)" -ForegroundColor Red
    Write-Host "堆栈跟踪: $($_.Exception.StackTrace)" -ForegroundColor Red
} finally {
    Show-ExitMessage
}

小枭 发表于 2026-3-16 17:03

认真学习

m1y3ll0w 发表于 2026-3-16 17:29

小枭 发表于 2026-3-16 17:03
认真学习

感谢评分哈!

ibrucekong 发表于 2026-3-16 18:04

感谢提供的思路,学习了

cadd 发表于 2026-3-16 18:23

学习了,Xshell非要联网 {:1_926:}头疼

m1y3ll0w 发表于 2026-3-16 18:39

cadd 发表于 2026-3-16 18:23
学习了,Xshell非要联网 头疼

联网许可、半年强制更新、版本终止支持、离线许可到期,局域网内使用是有点头疼的!现在这个修改版本应该是可以局域网内使用的了,有问题可以来这里反馈

m1y3ll0w 发表于 2026-3-16 19:27

InBetween 发表于 2026-3-16 18:50
学习了,不过现在主力已经换成mobaxterm了

去 mobaxterm 官网看了以下使用许可,应该是可以个人自行官网下载在公司使用!纯商业使用也是得购买许可。许可方面,比 Xshell 宽松一些。

在公司确实得按规定的来,家里或学校里的电脑这个免费版是有许可的,但长期不更新使用还是得修补一下。。

blawhickte 发表于 2026-3-16 19:51

以前喜欢用xshell, 现在喜欢用terminal/termius
页: [1] 2 3 4 5 6 7 8
查看完整版本: Xshell、Xftp(7.0 & 8.0)免费版-后续更新