简介:这份《VBS整人代码大全》以Word文档形式汇编Windows环境下常见的VBS恶作剧脚本示例,面向希望了解脚本基础语法、运行机制与安全风险的入门读者。内容围绕消息框反复弹窗、调用系统命令诱导关机或重启、无限循环、输入框条件判断、键盘按键模拟以及媒体播放等典型手法展开,配有代码片段和风险提醒,可用于认识脚本如何制造系统警告、反复打扰或触发非预期操作,并理解其实现思路与潜在危害。压缩包内仅含1个docx文档,大小约192KB,篇幅轻量,适合对照阅读与安全演示;其中部分示例可能干扰电脑正常使用,建议在虚拟机环境中查看。已有11805人浏览学习,读者可借此建立对VBS能力边界、恶作剧脚本套路及日常防范要点的相关基本认知。
1. VBS 整人代码大全值不值得拆:一行 Run 能关机,也能让人背锅
搜「VBS 整人代码」的人,多半想要两样东西:能立刻跑起来的效果,和不至于把事闹大的边界。这一包脚本能满足前一半——纯文本、双击就执行、不编译不装运行库;后一半得靠自己把笼子先扎好。整包里真正有技术含量的只有三四类:MsgBox的话术层、WScript.Shell的命令层、SendKeys的输入层,以及媒体对象那点可逆的小动作。剩下的是把这几样用Do...Loop串起来,靠“对方没有撤销手段”制造效果。原文里还有一段用ntsd结束winlogon.exe制造蓝屏、以及自复制到移动盘配autorun.inf的写法,那已经不是恶作剧而是破坏和传播,我不复现,只在排查那一章讲怎么认、怎么清。适合谁:想把 VBScript 语法和 Windows 脚本宿主摸一遍、并且手上有一台隔离虚拟机的人。不适合谁:想发给同事、同学看笑话的人。
2. 把实验场关进笼子:虚拟机快照、三层隔离和一份开机自检表
2.1 为什么 .vbs 双击就等于交出当前用户权限
VBScript 本身没有运行时沙箱这个概念,它靠 Windows Script Host 解释执行,宿主是wscript.exe(图形宿主,弹窗走 GUI)或cscript.exe(控制台宿主,输出走 stdout)。这两个进程以当前登录用户的身份运行,脚本里CreateObject("WScript.Shell").Run起的子进程继承同一身份。换句话说,脚本能做的事,和你手动在“运行”里敲命令能做的事完全一样——不多不少。这是它门槛低到离谱的原因,也是它危险的原因:不需要管理员权限,不需要编译,一个 200 字节的文本文件就能调shutdown。
先确认宿主关联没被改过。下面三行是只读查询,不会改动任何配置:
:: 查看 .vbs 的宿主关联,只读,不修改注册表 assoc .vbs ftype VBSFile :: 用控制台宿主跑脚本,能看到真实报错,并加 10 秒超时兜底 cscript //nologo //T:10 demo.vbsassoc .vbs正常应返回.vbs=VBSFile,ftype VBSFile应返回类似wscript.exe "%1" %*的关联。如果关联被改成用记事本打开,双击就只会打开源码而不执行;如果被安全策略拦掉,脚本会静默失败。cscript //nologo去掉版权头,//T:10是脚本超时参数,单位秒,到点宿主强制终止进程——对付死循环脚本这一招比任务管理器快得多。同一份脚本在wscript下WScript.Echo会弹对话框,在cscript下才打到控制台,排错一律走cscript。
2.2 快照与回滚:把“重装一次”压到 20 秒
整人脚本的测试成本看着低,其实不低:一次关机、一次自启动项写入、一次文件关联被改,就够你花半小时收拾。所以流程应该是“先有回滚点,再放脚本”。
| 环境项 | 建议配置 | 这样配的理由 |
|---|---|---|
| 虚拟机 | 单独建一台,只放测试用脚本 | 关机、改关联、写启动项都只污染这台 |
| 干净基线快照 | 装完系统与补丁后立刻拍 | 之后每次测试前回滚,20 秒回到原点 |
| 共享文件夹 | 关闭或设为只读 | 防止脚本往宿主机目录写文件 |
| 剪贴板/拖放 | 双向都关 | VBS 虽不能直接读剪贴板,但能起程序间接操作 |
| 虚拟网卡 | 断开或仅主机模式 | 防止脚本调外部命令、防止误触发在线行为 |
| 账号 | 普通用户,不用管理员 | 让需要提权的写法直接失败,暴露问题 |
这个顺序有讲究:先拍基线快照,再关共享和网卡,然后再放脚本。很多人反过来,先跑脚本发现问题,再去补快照,结果快照里已经带了污染。回滚之后还要做一件事——把快照名写清楚,比如clean-base-2024,别拍一堆快照1快照2,一周后自己都分不清哪个是干净的。
2.3 三层隔离与测后清理
隔离分三层,缺一层都会漏。第一层是虚拟化层,脚本跑在客户机里,宿主机只作为显示终端;第二层是文件层,客户机看不到宿主机磁盘,剪贴板和拖放都关掉;第三层是时间层,测完立刻回滚,不做“先放着回头再说”。
清理不是回滚就完事,回滚前先确认脚本到底动了什么。下面这组命令用来查常被整人脚本盯上的三个位置,全都是读取操作:
:: 1. 查当前用户和本机的开机启动项 reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Run" reg query "HKLM\Software\Microsoft\Windows\CurrentVersion\Run" :: 2. 查启动文件夹里有没有陌生文件 dir /a "%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup" :: 3. 查文件关联是否被改回记事本 ftype VBSFilereg query只读不写,输出里如果出现wscript.exe加一个你从没见过的.vbs路径,基本就是被写了自启动。启动文件夹那条dir /a里的/a是把隐藏属性文件也列出来,整人脚本常给自己加隐藏和系统属性,不加/a会看不到。第三行复查关联,如果ftype VBSFile已经不是wscript.exe "%1" %*,说明有脚本改过它——改回来用assoc .vbs=VBSFile和ftype VBSFile=wscript.exe "%1" %*,这两条会写注册表,只在虚拟机里做。
3. MsgBox 与 InputBox 撑起的话术层:按钮常量、返回值与可控循环
3.1 MsgBox 的五个参数,真正决定观感的是第二个
MsgBox的完整签名是MsgBox(prompt, buttons, title, helpfile, context)。第一个参数是正文,第三个是标题栏,后两个是帮助文件和上下文编号,整人脚本基本不用。真正决定“像不像系统提示”的是第二个参数buttons——它是按钮类型、图标类型、默认按钮、模态级别四个值的按位相加结果。
| 常量 | 值 | 作用 |
|---|---|---|
vbOKOnly | 0 | 只有一个确定按钮 |
vbOKCancel | 1 | 确定 + 取消 |
vbYesNoCancel | 3 | 是 + 否 + 取消 |
vbYesNo | 4 | 是 + 否 |
vbRetryCancel | 5 | 重试 + 取消 |
vbCritical | 16 | 红色叉号图标 |
vbQuestion | 32 | 问号图标 |
vbExclamation | 48 | 黄色感叹号 |
vbInformation | 64 | 蓝色信息图标 |
vbDefaultButton2 | 256 | 默认焦点落在第二个按钮 |
返回值同样是整数:vbOK=1、vbCancel=2、vbAbort=3、vbRetry=4、vbIgnore=5、vbYes=6、vbNo=7。理解了这张表就明白整人脚本的“话术”怎么来的:把图标设成vbCritical,标题写成带感叹号的样子,正文模仿系统措辞,观感立刻变成“系统警告”。原文里那句“您灌水太多需要重新启动计算机”就是这个套路——技术上只是vbOKCancel + vbInformation,没有任何系统级东西。
3.2 InputBox 返回的是字符串,取消返回空串
InputBox(prompt, title, default, xpos, ypos, helpfile, context)前五个参数最常用。第四个第五个是坐标,单位是 twips(1 英寸 = 1440 twips),原文里写8000, 7000换算下来大约在屏幕中间偏右下,属于“能显示但不居中”的不讲究写法,正经做法是留空让系统自己居中。
关键行为是:用户点取消或直接关窗口,返回空字符串"",不是Null也不是False。所以千万不能写If InputBox("...") Then——空串在布尔判断里是 False,看着能用,但用户输入0的时候同样返回 False,逻辑就歪了。
' demo_input.vbs —— 输入校验 + 取消分支 + 次数上限 Option Explicit Dim ans, tries tries = 0 Do ans = InputBox("请输入 abc 后点确定:", "输入校验", "", , ) If ans = "" Then ' 取消或关闭窗口,返回空串 MsgBox "已取消,脚本退出。", vbInformation, "提示" Exit Do End If tries = tries + 1 If LCase(Trim(ans)) = "abc" Then MsgBox "输入正确,结束。", vbInformation, "结果" Exit Do End If MsgBox "不对,已试 " & tries & " 次。", vbExclamation, "提示" If tries >= 3 Then ' 必须给上限,否则就是死循环 MsgBox "次数到上限,退出。", vbCritical, "结果" Exit Do End If LoopOption Explicit强制声明变量,能挡住拼写错误——整包里大量WSHshellWSHshellA这种随手命名的变量,不声明的话写错一个字母就是静默的Empty。LCase(Trim(ans))做大小写无关和首尾空格容错,否则用户输ABC就判失败。xpos和ypos这里留空,用连续逗号占位,让窗口居中。整个循环有三条出口:取消、答对、次数到顶,这就是“可控”和“整人”的分界线。
3.3 把 Do...Loop 从死循环改成有出口的循环
整包脚本里出现频率最高的一句是do msgbox "hi" loop。这行的技术含量为零,破坏力却集中:MsgBox是模态对话框,会阻塞脚本线程直到用户点击,所以每关掉一个才有下一个;脚本宿主进程一直活着,用户要关掉几十个窗口才能碰到任务管理器。原文里还有一个do createobject("wscript.shell").run chr(34) & wscript.scriptname & chr(34) loop,让脚本反复启动自己,几秒钟就能堆出几十个wscript.exe——这一条已经开始接近资源耗尽型攻击了,我在自己机器上测的时候只跑了两秒就滚出一屏进程。
' demo_loop.vbs —— 带计数与退出条件的弹窗演示 Option Explicit Dim i, total, ret total = 3 ' 次数写死在这里,改这一行就能改行为 For i = 1 To total ret = MsgBox("第 " & i & " / " & total & " 次,点取消立刻退出。", _ vbOKCancel + vbInformation + vbDefaultButton1, _ "计数弹窗演示") If ret = vbCancel Then Exit For Next MsgBox "循环已结束,脚本正常返回。", vbInformation, "结束"_是 VBScript 的续行符,前面必须有一个空格。vbDefaultButton1值 0,把默认焦点放在确定上,这样用户狂按回车也不会误触取消。For...Next天然带计数器,比Do...Loop加手写i = i + 1少一个出错点。真要用Do While,条件里必须有会变化的变量,并且循环体内要有Exit Do兜底——两条保险都上,才不会把自己锁在虚拟机里。
4. WScript.Shell 的权限面:Run 三个参数、shutdown 的后悔药与 SendKeys 抢焦点
4.1 Run 的三个参数:命令行、窗口样式、要不要等
CreateObject("WScript.Shell")返回的是脚本与 Windows Shell 之间的桥,Run(strCommand, intWindowStyle, bWaitOnReturn)是它最常用的方法。
strCommand是完整命令行字符串,带空格的路径要自己用Chr(34)或""转义包起来,否则会被拆成多个参数。intWindowStyle常用值是 0(隐藏窗口)、1(正常显示)、2(最小化)、3(最大化),隐藏窗口就是整人脚本里,0或vbhide的来源——脚本在后台跑,用户只看到结果看不到过程。bWaitOnReturn为True时脚本会阻塞到子进程退出,为False时立刻返回下一行。整人脚本普遍用False,因为要让弹窗和命令“同时发生”。
vbhide这个常量在 VBScript 里其实没有内置定义,它来自 VBA 常量库,原文里直接写vbhide在某些环境下会报“变量未定义”。稳妥写法是直接写数字 0。
4.2 shutdown 的 -t 是唯一缓冲,-a 是唯一后悔药
shutdown是系统自带命令,参数不多但每个都关键:/s关机、/r重启、/a中止、/t 秒设置倒计时、/f强制关闭未响应程序、/c "注释"在关机界面显示说明文字(最长 512 字符)。/t的合法范围是 0 到 315360000 秒(10 年),默认 30 秒。
整人脚本的典型写法是把/t设成 5 到 10 秒,让人来不及反应。但同一套参数反过来用,就是最好的“后悔药”练习:
' demo_shutdown.vbs —— 只在你自己控制的虚拟机里跑 Option Explicit Dim sh, leftSec leftSec = 60 ' 倒计时秒数,练习时别低于 60 Set sh = CreateObject("WScript.Shell") If MsgBox("将在 " & leftSec & " 秒后关机。" & vbCrLf & _ "点取消不执行。", vbOKCancel + vbExclamation, "倒计时") = vbCancel Then WScript.Quit End If sh.Run "shutdown /s /t " & leftSec & " /c ""演示用倒计时,可用 shutdown /a 取消""", 0, False WScript.Sleep 3000 MsgBox "倒计时已开始,现在执行 shutdown /a 可以取消。", vbInformation, "提示"VBScript 里没有反斜杠转义,双引号用""表示,所以/c ""演示用…""这一段在命令行里会变成一个带引号的注释。vbCrLf是换行常量。WScript.Sleep 3000让脚本停 3 秒再弹第二个提示,给人留出反应时间。Run的第二个参数 0 表示隐藏命令行窗口,第三个False表示不等待。
取消用一行就够,在任何命令行窗口里执行:
:: 中止正在进行的关机/重启倒计时 shutdown /a/a只能中止“已预告但未执行”的关机,一旦倒计时归零、系统进入关闭流程就无效了。加了/f的关机更狠,会直接强制结束所有程序,没保存的文档不会给你确认机会——这也是为什么练习时不要模仿/t 5 /f这种组合。
4.3 SendKeys 只认当前活动窗口,这是所有翻车的起点
WScript.Shell的SendKeys方法把按键消息投递给当前活动窗口。注意“当前”两个字:脚本自己弹窗、自己抢焦点,按键就发给了自己的对话框;用户中途切到别的程序,按键就发给了那个程序。原文里do ws.sendkeys "{f5}" loop想刷浏览器,实际效果取决于脚本运行时焦点在哪,属于玄学——我这边的实测是脚本启动的瞬间焦点还在资源管理器,前几十次按键全刷到了文件夹窗口。
按键语法要点:字母数字直接写,功能键用花括号包起来({F5}、{ENTER}、{TAB}、{ESC}),修饰键前缀加号是 Shift、脱字符是 Ctrl、百分号是 Alt,~表示回车。
' demo_sendkeys.vbs —— 有次数上限的按键模拟 Option Explicit Dim sh, i Set sh = CreateObject("WScript.Shell") WScript.Sleep 2000 ' 留 2 秒切到目标窗口 For i = 1 To 5 sh.SendKeys "{F5}" WScript.Sleep 500 NextWScript.Sleep 2000是给用户留的手动切窗口时间,这是唯一可靠的焦点控制方式。真要指定窗口,用sh.AppActivate "窗口标题",但它按标题匹配,标题变了就失效,返回值True/False一定要判一下。For i = 1 To 5的 5 是硬上限,别改成Do...Loop——无限按键会把前台程序刷到未响应,而且你很难把焦点抢回来关掉脚本。
4.4 媒体对象:WMPlayer.OCX 与 SAPI 的可逆玩法
WMPlayer.OCX是 Windows Media Player 的 COM 组件,除了播放还能控制光驱:CreateObject("WMPlayer.OCX").cdromCollection.Item(0).Eject会把第一个光驱的托盘弹出来。索引从 0 开始,cdromCollection.Count是光驱数量。这一招在整包里出现多次,因为效果直观、成本低。
' demo_cdrom.vbs —— 有光驱才有效,没光驱会报错 On Error Resume Next Dim wmp, cds, i Set wmp = CreateObject("WMPlayer.OCX") Set cds = wmp.cdromCollection If Err.Number <> 0 Or cds.Count = 0 Then WScript.Echo "没有可用的光驱,退出。" WScript.Quit End If For i = 1 To 2 cds.Item(0).Eject WScript.Sleep 1500 Next现在的笔记本大多没有光驱,cdromCollection.Count直接是 0,Item(0)会抛错,所以前面必须判数量。On Error Resume Next只在这一段生效,并且紧接着用Err.Number检查——这是它能用的正确姿势;原文里通篇第一行就写on error resume next,所有错误都被吞掉,脚本行为变得不可预测,这是后面排查章要专门讲的一条。
另一个常被忽略的组件是SAPI.SpVoice:CreateObject("SAPI.SpVoice").Speak "文本"用系统 TTS 朗读,效果是“电脑自己说话”。它的好处是完全可逆——不会弹窗、不会关机、不写文件,打断就停。想把“整人”做成不伤人的演示,这类只产生声音和视觉、不改变系统状态的操作才是安全区。
5. 避坑与排查:五条把玩笑变成事故的现场记录
5.1 双击没反应,打开的却是记事本
现象:把代码贴进记事本,另存为demo.vbs,双击后记事本又弹出来一次,里面就是源码;或者窗口一闪而过什么都看不到。
原因:资源管理器默认隐藏已知文件类型的扩展名,你在文件名框里敲demo.vbs,实际保存成了demo.vbs.txt,双击自然还是文本文件。另一种情况是安全软件按行为规则拦了wscript.exe,进程被终止,所以“一闪而过”。
解决:在资源管理器“查看”里把“文件扩展名”打开,先确认真实后缀;另存为时把文件名用英文引号包起来写"demo.vbs",保存类型选“所有文件”,编码选 ANSI。存完在地址栏看一眼扩展名对不对。如果确认是.vbs还闪退,改用cscript //nologo demo.vbs在命令行跑,报错会打出来。
5.2 中文变问号或方块
现象:弹窗标题正常,正文里的中文全变成????或者一堆方块。
原因:Windows Script Host 默认按系统 ANSI 代码页(简体中文环境是 GBK/936)解析脚本文件。记事本从某个版本起默认另存为 UTF-8,还不带 BOM,宿主按 GBK 去读 UTF-8 字节,中文必然乱码。这是整包里最普遍的“跑起来不对”的原因之一。
解决:另存为的时候把编码改成 ANSI 重存一次,最简单。如果必须用 UTF-8,就存成“UTF-8 带 BOM”,或者更稳的做法是源码里只用 ASCII,中文用ChrW()拼——ChrW(&H4F60)是“你”。验证方法是先只弹一个MsgBox "中文测试",中文正常了再往里填内容。
5.3 弹窗铺满桌面、任务管理器结束不掉
现象:脚本跑起来后弹窗一个接一个,关掉一个立刻又出来,桌面被铺满,鼠标点不到任务栏。
原因:Do...Loop里套MsgBox,没有退出条件,也没有计数器。MsgBox是模态的,脚本线程阻塞在对话框上,所以宿主进程一直活着;结束单个弹窗不会终止脚本,只是让循环进入下一轮。
解决:Ctrl+Shift+Esc打开任务管理器,切到“详细信息”页,找到所有wscript.exe(用cscript跑的是cscript.exe),全选结束任务。如果桌面已经被铺满,先按住Esc或Enter连点几个,等出现空隙再叫任务管理器。事后一定回头改脚本:把Do...Loop换成For i = 1 To N,或者保留Do但加If 计数 >= 上限 Then Exit Do,两条保险一起上。
5.4 倒计时已经开始,人先慌了
现象:脚本调了shutdown,屏幕右下角弹出关机提示,操作的人第一反应是拔电源或者长按电源键。
原因:/t设得太短(整包里常见 5 秒、6 秒),加上/f强制关闭程序,来不及走正常流程。长按电源键属于硬断电,比正常关机更容易伤文件系统。
解决:第一反应永远是打开命令行敲shutdown /a,只要还没进入关闭流程就能中止。平时练习就把/t设成 60 秒以上、不加/f,先自己跑一遍确认能取消,再考虑给别人演示——而且演示对象只能是你自己的虚拟机。养成习惯:任何带shutdown的脚本,写的时候就把shutdown /a那行注释贴在它下面。
5.5 发给别人之后收不回来
现象:脚本发出去,对方机器上出现异常弹窗、开机自动运行、插上移动盘又自动执行。
原因:整包后半段有一段自复制逻辑,手法是三步:把自己复制到目标盘根目录、写一个autorun.inf指向wscript.exe执行脚本、再给自己加隐藏和系统属性(属性值 7 = 隐藏+系统+只读)。这套组合是移动介质传播的经典结构,和“整人”已经没关系了。VBS 脚本本身没有沙箱,对方双击就等于用对方账号跑你的代码,你无法控制它在对方机器上碰到什么。
解决:不要发。要展示就录屏,或者在自己虚拟机里演示。如果怀疑某台机器中过这类脚本,按顺序查三处——移动盘根目录有没有autorun.inf和陌生的.vbs(用dir X:\ /a看隐藏文件)、HKCU\...\CurrentVersion\Run有没有陌生启动项、shell:startup文件夹有没有陌生快捷方式。删除前先把文件属性去掉:attrib -h -s -r X:\autorun.inf,否则普通删除会失败。清完再回滚一次虚拟机快照,比逐个清理更省事。
6. 从整人脚本退一步:加参数、加日志、加超时,再用三张表验收
整包里唯一值得留下来的写法,是“效果可控”那部分。把MsgBox的返回值、Run的等待标志、循环的计数器三样拼起来,就能把一个只会骚扰人的脚本改成能交付的小工具:带命令行参数、带日志、带超时。
' remind.vbs —— 带参数、日志、超时的可退出小工具 Option Explicit Dim sh, fso, logPath, f, sec Set sh = CreateObject("WScript.Shell") Set fso = CreateObject("Scripting.FileSystemObject") sec = 30 If WScript.Arguments.Count > 0 Then If IsNumeric(WScript.Arguments(0)) Then sec = CInt(WScript.Arguments(0)) End If logPath = sh.ExpandEnvironmentStrings("%TEMP%") & "\remind.log" Set f = fso.OpenTextFile(logPath, 8, True) ' 8 = 追加写,True = 不存在就建 f.WriteLine Now & " start, timeout=" & sec & "s" f.Close If MsgBox("将在 " & sec & " 秒后提示一次,点取消不执行。", _ vbOKCancel + vbQuestion, "提醒") = vbCancel Then WScript.Quit WScript.Sleep sec * 1000 MsgBox "到点了。日志在 " & logPath, vbInformation, "提醒"WScript.Arguments是命令行参数集合,IsNumeric先判再转,避免CInt("abc")抛错。OpenTextFile的第二个参数 8 是ForAppending,第三个True表示文件不存在时创建——日志一定要追加,覆盖写会把上一次的记录冲掉。ExpandEnvironmentStrings把%TEMP%展开成真实路径,别硬编码C:\Users\...。这段代码里没有一处会改系统状态,出问题最多是多一个日志文件,这才是能交给别人跑的东西。
验收看三张表就够了。第一张查启动项,命令在 2.3 节;第二张查文件关联,ftype VBSFile应始终指向wscript.exe "%1" %*;第三张查移动盘根目录,dir X:\ /a里出现autorun.inf就是异常。三张表跑一遍不超过一分钟,但能挡住绝大多数“跑完才发现不对劲”的情况。
血泪经验是:我以前觉得脚本这么小的东西,跑完删掉就行,直到有一次测完忘记回滚快照,第二天打开虚拟机发现启动文件夹里多了一个自己不认识的.vbs,愣了几秒才反应过来是前一天的回声。从那以后我每次放脚本进虚拟机之前,都强制走一遍“拍快照—断网卡—关共享”三步,少一步就不动手。希望帮到你。
本文还有配套的精品资源,点击获取