绕过安全限制,通过cmd执行PowerShell脚本

发布时间 2024-01-11 10:41:51作者: fmcdr

我的初衷是写一个自动激活系统的cmd脚本给身边的朋友使用,它需要判断当前运行的系统版本,需要记住大量的与具体的版本对应的key。

开始动手后我发现没法往下写。cmd本质上不支持“结构化编程”,这意味着它没有“函数”这个东西。它只能定义 label,用 label 来模拟函数。过去,当看到 Pascal 对自己开创的“结构化编程”很自豪时我并不是很理解,现在我理解了,原来非“结构化”的编程长这样。

写了一半后我放弃了。

听说 PowerShell 是新的Windows系统脚本语言,要不用 PowerShell 试试?

不懂语法没关系,边查边写,很快就搞定了。但是当我把脚本拷贝到别的机器运行时,duang! 脚本没法运行 - ”在此系统上禁止运行脚本“。运行 Set-ExecutionPolicy修改了安全策略以后再次运行,duang! duang! 还是没法运行,因为没有数字签名。拜托,我只想写一个给朋友用的脚本,我的朋友们不懂得如何运行命令。难道就此放弃?如果换用其它成熟的编程语言去干这个事其实很轻松,比如 Python。但是在发布时必须附带上庞大的运行时环境。我感觉没必要。

灵光一现,可不可以通过cmd去调用powershell呢?于是,下面的方案就出现了:

所有的 PowerShell 脚本代码保存在 ps.txt 中

$pkeys = @{
    'Windows Server 2022 Standard' = 'VDYBN-27WPP-V4HQT-9VMD4-VMK7H';
    'Windows Server 2022 Datacenter' = 'WX4NM-KYWYW-QJJR4-XV3QB-6VM33';

    'Windows Server 2019 Datacenter' = 'WMDGN-G9PQG-XVVXX-R3X43-63DFG';
    'Windows Server 2019 Standard' = 'N69G4-B89J2-4G8F4-WWYCC-J464C';
    'Windows Server 2019 Essentials' = 'WVDHN-86M7X-466P6-VHXV7-YY726';

    'Windows Server 2016 Datacenter' = 'CB7KF-BWN84-R7R2Y-793K2-8XDDG';
    'Windows Server 2016 Standard' = 'WC2BQ-8NRM3-FDDYY-2BFGV-KHKQY';
    'Windows Server 2016 Essentials' = 'JCKRF-N37P4-C2D82-9YXRT-4M63B';

    'Windows 11 Pro' = 'W269N-WFGWX-YVC9B-4J6C9-T83GX';
    'Windows 11 Pro Education' = '6TP4R-GNPTD-KYYHQ-7B7DP-J447Y';
    'Windows 11 Education' = 'NW6C2-QMPVW-D7KKK-3GKT6-VCFB2';
    'Windows 11 Enterprise' = 'NPPR9-FWDCX-D2C8J-H872K-2YT43';

    'Windows 10 Pro' = 'W269N-WFGWX-YVC9B-4J6C9-T83GX';
    'Windows 10 Enterprise' = 'NPPR9-FWDCX-D2C8J-H872K-2YT43';
    'Windows 10 Education' = 'NW6C2-QMPVW-D7KKK-3GKT6-VCFB2';

    'Windows 8.1 Professional' = 'GCRJD-8NW9H-F2CDX-CCM8D-9D6T9';
    'Windows 8.1 Enterprise' = 'MHF9N-XY6XB-WVXMC-BTDCT-MKKG7';

    'Windows 7 Professional' = 'FJ82H-XT6CR-J8D7P-XQJJ2-GPDD4';
    'Windows 7 Enterprise' = '33PXH-7Y6KF-2VJC9-XBBR8-HVTHH';
};

$product = (Get-ItemProperty -Path 'HKLM:\Software\Microsoft\Windows NT\CurrentVersion' -Name ProductName).ProductName;
echo $product;

if($pkeys.ContainsKey($product)){
    $key = $pkeys[$product];
    $slmgr = 'C:\Windows\System32\slmgr.vbs';
    cscript $slmgr //nologo /upk;
    cscript $slmgr //nologo /ipk $key;
    cscript $slmgr //nologo /skms kms.bitsoc.cn;
    cscript $slmgr //nologo /ato;
}

上面的代码和通常的 ps 脚本有什么区别呢?区别就是每一条语句后面都有分号。通过下面的 bat 一行一行地读入,拼接成一行,再调用 powershell -command 去执行。完美绕过限制。

main.bat

@echo off

set src=
setlocal enableDelayedExpansion
for /f "tokens=* delims=" %%a in (%~dp0\ps.txt) do (
    set "line=%%a"
    set "src=!src!!line!"
)

powershell -NoLogo -command "%src%" 

pause
echo on