很多刚接触网安的朋友,上手第一课就会撞上一堵墙:Windows系统里那么多进程和服务,密密麻麻的,看着都头疼,更别说从中找出哪个有问题。但不管你是做应急响应、做入侵排查,还是单纯想把自己的电脑收拾利索,进程、服务以及对应的排查手段,都是迟早要啃下的基础功。这篇笔记我就从实际排查的视角出发,把Windows进程与服务的底细捋一遍,再把我平常用得最顺手的排查套路完整走一遍。内容不整虚的,全是能直接照着操作的干货。
1. 先搞清楚Windows里进程与服务到底是什么关系
很多教程上来就甩命令,导致不少人连排查对象都没吃透就开始复制粘贴。我建议动手之前,先把进程和服务这两个概念掰扯清楚,不然遇到"某个进程是不是服务拉起来的""服务停了进程为什么还在"这类问题时,当场就会卡壳。
1.1 进程、线程与服务的实际含义
进程,简单理解就是"正在运行的程序实例"。你双击打开记事本,系统就会创建一个notepad.exe进程;你打开浏览器,可能会看到几十个chrome.exe进程。这里有个容易混淆的点:进程是资源分配的单位,它本身不干活,真正干活的是线程,也就是进程里面的执行单元。一个进程可以只有一个主线程,也可以有几十个线程同时跑,进程池这个概念大家应该听过,本质就是线程复用和并发管理的策略,跟Windows系统里的进程列表是两码事。
服务则是Windows里一种特殊的进程形态。它由服务控制管理器(SCM)统一管理,不依赖用户是否登录,可以在系统启动时就自动运行。很多服务进程的宿主是svchost.exe,这是一个共享进程,一组功能相近的服务会挂到同一个svchost.exe下,这也是新手排查时最懵的地方——打开任务管理器看到一大排svchost.exe,根本不知道哪个是哪个。
进程和服务的关系,我用一个生活化类比来解释:进程就像一家饭店的后厨,可以随时开张随时关门;服务则像饭店委托的物业公司,约定好时间自动上班,即便你人不在店里它也在运行。恶意软件特别喜欢伪装成服务,就是为了实现"用户不在也照常干活"的持久化效果。
1.2 排查工作到底排查的是什么
明确了概念,排查的目标也就清晰了。网安场景下的进程与服务排查,核心就三件事:
第一,发现异常进程。包括CPU和内存占用异常的、路径不在常规目录的、名字伪装成系统进程但签名无效的、网络连接指向可疑地址的。
第二,发现异常服务。重点关注非Microsoft签名的服务、指向临时目录或用户目录的服务、启动类型为"自动"但从未听说过的服务。
第三,理清进程、服务、网络、日志之间的关系。这四者组合起来才能还原一条完整的攻击链,比如某个服务启动了恶意进程,恶意进程对外建立了连接,而安全日志中恰好记录了服务安装事件。
记住排查不是单纯"看进程列表",而是"在系统运行现场找证据"。理解了这层,后面所有操作都是在围绕"找证据"展开。
2. 进程排查手段:从图形界面到命令行
进程排查的手段分两大流派:图形界面流和命令行流。我个人的习惯是图形界面用来快速定位、粗筛,命令行用来深挖细节和批量取证。两者配合,效率和准确性都能拉满。
2.1 任务管理器与资源监视器的正确打开方式
任务管理器谁都会开,但会看的人真不多。按Ctrl+Shift+Esc打开后,第一件事是把"详细信息"标签页调出来,把PID、CPU、内存这些列全部显示。排序方式用CPU占比,这样高消耗进程会立刻冒到顶部。很多恶意进程平时状态不明显,一旦电脑卡顿,CPU就能告诉你谁在搞事。
但任务管理器有硬伤:恶意软件可以借助进程注入或rootkit技术隐藏自身。这时就需要用资源监视器,通过"开始菜单搜索resmon"打开,在"概述"标签页里查看进程的网络活动、磁盘活动。资源监视器的优势是能逐线程展示CPU占用率,一个多线程进程如果某个线程异常活跃,这里能看得很清楚。
我遇到过不少次这样的情况:任务管理器显示某个进程CPU占用为0,但电脑持续卡顿。切到资源监视器才发现,进程句柄数量异常庞大,文件句柄全指向一个可疑的临时文件。所以强烈建议,任务管理器负责初筛,资源监视器负责精查,两者不可互相替代。
2.2 命令行三件套:tasklist、wmic与PowerShell
图形界面看不全的地方,命令行能补位。第一条必背命令是tasklist,配合筛选条件使用。
tasklist /m /fi "STATUS eq RUNNING"/m参数会加载各个进程的模块列表,隐藏DLL注入的线索往往就藏在模块列表里。比如记事本进程突然加载了一个不认识的dll,这几乎可以判定有问题。
第二条好用的工具是wmic,虽然新版Windows里wmic有淘汰趋势,但在老系统中依旧高效。要查进程的可执行文件路径、启动命令行,wmic比tasklist直观得多:
wmic process get processid,executablepath,commandline这条命令能一次性拉出全部进程的PID、程序路径和完整启动参数。之后两行是重点检查对象:
wmic process where processid=xxx get executablepath,commandline wmic process get name,processid,parentprocessidparentprocessid就是父进程PID,不看它你很难判断一个进程是谁拉起来的。恶意软件经常玩"白加黑"——用合法的程序(比如rundll32.exe、powershell.exe)启动恶意代码,只看进程名根本发现不了,但一看父进程关系,立刻露馅。
PowerShell是Windows 10/11时代的进阶工具。推荐一条很少人提的管道组合:
Get-Process | Select-Object Id,ProcessName,Path,StartTime,CPU | Sort-Object CPU -Descending其中StartTime非常关键。如果你发现系统启动时就有某个进程启动,或者某个进程的启动时间恰好在你没开机操作的时间段,那就值得深挖了。
2.3 进程与网络连接对照排查
进程排查必须结合网络连接,因为纯粹高占用CPU的进程好找,真正隐蔽的是那种"偷偷外联"的进程。这时候要用netstat:
netstat -ano | findstr ESTABLISHED-ano会列出所有连接和监听状态,并带上PID。看到ESTABLISHED的连接,就记下右边的PID,再用tasklist反查进程名,一套对照就出来了。更高效的做法是把netstat输出和进程列表做关联,排查思路是同一个PID在两份输出中都出现,且连接的对端IP不是常见公有云或CDN段,那就要高度警惕。
进阶手段是用PowerShell的Get-NetTCPConnection,输出格式更友好,还能直接关联进程对象:
Get-NetTCPConnection -State Established | ForEach-Object { $proc = Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue [PSCustomObject]@{ LocalPort=$_.LocalPort; RemoteIP=$_.RemoteAddress; RemotePort=$_.RemotePort; PID=$_.OwningProcess; ProcName=$proc.ProcessName; ProcPath=$proc.Path } } | Format-Table这段脚本在应急排查时能直接把"连接、进程、路径"三要素一张表输出,省去反复查的麻烦。
2.4 隐藏进程与可疑进程的识别技巧
有些恶意程序会使坏招,直接把自己从常规进程列表中藏起来。这时可以借助系统自带的远程管理工具来"曲线救国"。
第一个技巧是用query process命令。在本地管理员权限的命令行里输入:
query process这个命令走的是系统会话查询机制,与任务管理器走的枚举接口不同,不少rootkit隐藏的进程在query process面前照样现形。
第二个技巧是查看句柄数。用Process Explorer(Sysinternals套件里的王牌工具)打开后,点击"View"菜单里的"Show Lower Pane",选择Handles,就能看到每个进程打开的句柄。正常进程打开的句柄数量相对稳定,如果某个进程几秒钟内句柄数暴涨,多半是循环句柄泄漏或被注入后不断尝试打开文件。
第三个技巧是分析进程路径的"常规程度"。Windows正常程序基本都在这几个目录:
- C:\Windows\System32
- C:\Windows\SysWOW64
- C:\Program Files
- C:\Program Files (x86)
- C:\Windows\Temp(一般不在这里跑程序,但Temp里确实有少量合法场景,需要多留个心眼)
如果进程路径指向C:\Users\用户名\AppData\Roaming\xxx或C:\ProgramData\xxx,基本可以判定为值得复查的可疑进程。恶意软件最爱的持久化藏身处就是这两个目录。
关于隐蔽手段我还要提醒一点,不要只看进程名。攻击者早就学会起一个跟系统进程一模一样的名字。名字一样不等于程序一样,判断依据永远是可执行文件的路径、签名和哈希值。签名可以用PowerShell一行搞定:
Get-AuthenticodeSignature C:\path\to\file.exe输出的Status字段如果是NotSigned或HashMismatch,那就要警惕。
3. 服务排查与安全加固:别被svchost迷了眼
进程排查做完,下一步是服务排查。服务比进程更隐蔽的点在于:普通用户根本不关心系统里注册了哪些服务。但攻击者非常关心,因为服务可以开机自启、可以以高权限运行、可以在用户未登录时工作。Windows服务的安全排查,焦点应该是服务列表审查、异常服务识别、服务权限加固这三块。
3.1 服务列表的审查步骤
服务列表的图形界面在services.msc,但真正高效的审查方式是用命令行导出全部服务的配置明细。我常用的方式:
sc query type= service state= all wmic service get name,displayname,pathname,startmode,statewmic输出的pathname字段是最有价值的信息。服务对应的程序路径全都在这里,一条服务对应一条程序路径,开启手工核对模式。核查的重点是路径是否符合常规目录规则,如果一个服务的路径指向临时目录、下载目录、用户目录,那这个服务大概率有问题。
另一个不能忽略的地方是服务的DLL。很多服务以svchost.exe为宿主,通过注册表项HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\<服务名>\Parameters里的ServiceDll值指向真正的DLL文件。攻击者经常改这个注册表值,让svchost加载恶意DLL。审查时用PowerShell做个批量导出会高效很多:
Get-WmiObject win32_service | Select-Object Name,DisplayName,PathName,StartMode,State | Format-List这一步做的是"全面盘点",前提条件是你得有一份干净的基线清单。新装的干净系统导出一次,留存好,之后做对比,差异项就是排查的优先对象。没有基线也没关系,先排查路径可疑项和非常规启动项,也能筛出大头。
3.2 恶意服务的几类典型特征
见得多了之后,恶意服务其实有很强的共性。核心特征可以归纳为下面几类,在任何环境里适用:
第一,显示名称与服务名不符。比如服务名叫"Windows Update Helper",但显示名称是乱码,或者路径指向一个叫"helper.exe"的奇怪程序。正常的服务名和显示名称会对应,不一致就是故意的。
第二,启动类型是"自动",但服务描述基本空白或只有一句"系统服务"。正规Microsoft服务的描述通常写得比较正式且功能性明确,恶意服务往往懒得写或随便填一句。
第三,服务路径带引号劫持风险。某些服务的路径配置没加引号,比如C:\Program Files\My App\svc.exe,系统会依次尝试解析C:\Program.exe、C:\Program Files\My.exe、C:\Program Files\My App\svc.exe。中间任何一个路径如果放进去攻击者可控的可执行文件,就能在服务启动时被劫持执行。检查时看到未加引号的服务路径,先记下来再处理。
第四,服务依赖关系异常。查看服务属性会发现某些服务依赖了一个根本不存在的服务或依赖一个dll文件,这类异常是手动植入服务的典型特征。打开services.msc的服务属性,切到"依赖关系"标签页,逐个扫一眼就能发现问题。
3.3 服务启动权限的常见加固方案
排查服务还有一个容易被忽略的角度:服务本身的权限配置是否合理。服务运行时会有相应的安全上下文,常见的是LocalSystem、NetworkService、LocalService。普通服务用LocalSystem问题不大,但那些可以被非管理员用户操控重启的服务就要警惕。
手动检查服务权限可以用sc命令:
sc sdshow 服务名输出的SDDL字符串里如果出现(A;;RPWP;;;BU)之类的字样,说明普通用户对该服务拥有启动和写入权限。这种配置一旦被本地低权限用户利用,就能借服务权限提升到高权限。加固方法是把服务权限收紧:
sc sdset 服务名 D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)这条命令会让服务只允许SYSTEM和管理员访问。日常加固中不用背SDDL,理解"普通用户对服务必须有约束"就够用了,真碰到问题时再查命令也不迟。
服务加固的另一个实操点是禁用不用的高危服务。具体禁哪些要根据业务来,但我个人建议至少关注这几个:Remote Registry(远程注册表,攻击者常利用它读写在受害者机器上的注册表)、SSDP Discovery与UPnP Device Host(这几个服务在局域网里容易被利用做反射放大攻击)。同时建议定期检查服务的状态:
sc query type= service state= all | findstr SERVICE_NAME配合计划任务脚本批量导出服务清单,可以做成月度巡检的固定动作。
4. 一次完整排查实操:从发现异常到定位处置
概念和工具都过了一遍,接下来完完整整走一遍实战流程。下面的过程我按真实应急场景还原,你可以把它当成一份排查模板来用,遇到类似情况直接套。
4.1 建立干净基线:排查前的准备工作
排查最怕的是"不知道什么算正常"。所以正式排查开始前,先做基线收集。这一步花不了几分钟,但能让你从"大海捞针"变成"差异核对"。
需要收集的基线信息包括四类:
一是进程基线,用下面这条导出:
Get-Process | Select-Object ProcessName,Id,Path,StartTime | Export-Csv C:\baseline_process.csv二是服务基线:
Get-WmiObject win32_service | Select-Object Name,PathName,StartMode,State | Export-Csv C:\baseline_service.csv三是网络连接基线:
netstat -ano | Out-File C:\baseline_netstat.txt四是启动项基线:
Get-CimInstance Win32_StartupCommand | Format-List Name,Command,Location,User | Out-File C:\baseline_startup.txt有了这些基线文件,后续的排查只看差异项就行。实际应急里大多数情况下我没法拿到那份"干净基线",所以更常用的做法是拿一个正常的同版本系统的基线替代,或者依靠路径常规性和签名有效性做初筛。
4.2 异常现象的定位路径
现在假设你接到一个系统的排查需求:用户反馈电脑最近很卡,且杀软偶发拦截弹窗。这时候按下面流程走。
第一步,先盯任务管理器里的CPU占用。打开详细信息标签页按CPU排序,发现一个名为svchost.exe的进程CPU占用高达30%以上。这里就出现第一个疑点:正常的svchost虽然会合并多个服务,但CPU占用通常不会这么离谱。直接用Process Explorer查看这个svchost加载的服务列表,发现它挂载了一个平时没见过的服务。
第二步,通过wmic定位路径:
wmic process where processid=1234 get executablepath,commandline假设返回的路径是C:\Users\admin\AppData\Roaming\svchost.exe,这一眼就能看出问题所在——真正的svchost不可能跑在用户目录下。继续计算哈希:
certutil -hashfile C:\Users\admin\AppData\Roaming\svchost.exe MD5拿到哈希后丢到Virustotal做扫描确认,命中一堆引擎则基本锁定恶意样本。
第三步,查网络连接。执行netstat -ano找到PID为1234的进程正在连接的远程IP,如果是境外或非标准端口段,那就基本坐实了后门外联行为。
第四步,查持久化机制。因为恶意样本伪装成服务,所以服务列表里一定存在对应的自启动服务。用wmic service命令结合服务名查服务路径,确定启动类型为"自动",删除威胁前先禁用服务,避免进程退出后又被服务拉起来。
4.3 处置动作与证据留存
完成定位后,处置过程的核心原则是:先禁后杀,先留存后清理。也就是先把服务禁用,再结束进程,最后删除文件。这条原则无数人在实战中验证过,直接结束进程而不处理持久化,系统重启后恶意程序自动回归,立刻原地复活。
具体处置顺序如下:
第一步,禁用服务:
sc config 服务名 start= disabled sc stop 服务名注意sc config的参数格式里start=和disabled之间不能有空格,这个小细节非常容易踩坑,命令执行失败时优先检查这里。
第二步,结束进程:
taskkill /pid 1234 /f如果提示拒绝访问,多数是因为进程权限较高,需要以管理员身份运行命令行,或借助Process Explorer的权限提升功能来结束。
第三步,清理文件与启动项。删除可执行文件,同时检查注册表Run键和相关服务注册表项,确保没有残留自启入口。需要重点检查的注册表位置是这几个:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Run HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services第四步,导出安全日志作为证据。用wevtutil导出最近一段时间的日志备用:
wevtutil epl Security C:\evidence_security.evtx安全日志中重点筛选创建进程事件(4688)、服务安装事件(7045)、账户登录事件(4624/4625)。留意这些事件ID,基本就能还原恶意程序的启动链条和执行过程。
5. 常见问题与排查技巧速查
最后分享一些高频踩坑点和排查句集锦,这些都是我平时帮人排查时反复用到的经验,建议直接保存起来当手册用。
5.1 实战中最容易翻车的五个坑
第一个坑:进程名字一样就以为没问题。攻击者把恶意文件改名成explorer.exe放在C:\Windows\Temp下,任务管理器看到同名进程就放松警惕。对策是永远看路径、看签名、看哈希,进程名最多只是个代号。
第二个坑:禁用恶意服务不彻底。只禁用服务而不处理相关计划任务或注册表Run项,重启后恶意程序换个马甲自动启动。排查时要把服务、计划任务、启动项、WMI事件订阅这四条持久化通道全部过一遍,缺一不可。
第三个坑:结束进程导致系统异常或蓝屏。某些恶意程序会与正常系统进程交错。比如通过DLL注入注入到explorer.exe里,结束explorer.exe确实干掉了注入的DLL,但桌面也跟着没了。稳妥做法是先结束注入进程下的恶意句柄,或引导用户在安全模式下排查。
第四个坑:忽略服务重启恢复机制。部分恶意服务会设置sc failure重启选项,服务被杀掉后会自动拉起。处置前先用sc qfailure 服务名查看失败操作配置,提前改成不自动重启。
第五个坑:忘了查计划任务。恶意软件自启动不止服务一条路,计划任务更方便指定时间、指定权限运行。查看计划任务用:
Get-ScheduledTask | Where-Object {$_.State -ne "Disabled"} | Select-Object TaskName,TaskPath,State再配合Get-ScheduledTaskInfo查看最近运行时间,尤其关注名字是随机乱码或路径指向用户目录的计划任务。
5.2 一条命令看全貌的技巧
快速排查时,我会用一条组合命令先拉个全景:
Get-Process | ForEach-Object { $p = $_ $conns = Get-NetTCPConnection -OwningProcess $p.Id -ErrorAction SilentlyContinue if ($conns) { $conns | ForEach-Object { [PSCustomObject]@{ ProcessName = $p.ProcessName PID = $p.Id Path = $p.Path RemoteIP = $_.RemoteAddress RemotePort = $_.RemotePort State = $_.State } } } } | Where-Object {$_.RemoteIP -notin @('127.0.0.1','0.0.0.0')} | Format-Table -AutoSize这条命令会把所有建立了网络连接的进程连同路径一起列出来,是应急响应时效率最高的开图命令。第一次跑会发现很多正常的系统服务也在外联,那都正常;筛掉微软已知IP段和常见云厂商段后,剩下的才是重点怀疑对象。
排查结束前的最后一步,把证据归档。文件名带上日期和主机名,用wevtutil导出的系统安全日志、进程快照、服务快照一起打个包。这个习惯在事态升级或追踪溯源的时候尤其重要,等到需要复盘时才发现当初没留证据,一切排查都等于白做了。
Windows进程与服务排查这件事,门槛不高,但想做到位,需要的是对系统运行机制的理解和足够多的实操积累。我个人的体会是:与其到处求一个"万能查杀工具",不如把tasklist、wmic、netstat、PowerShell这套原生工具链练熟。工具炼精了,配合基线和路径特征分析,多数恶意进程都逃不过你的眼睛。下次遇到电脑卡顿、杀软弹窗、网络异常,别急着重装系统,先按这套流程走一遍,大概率能自己揪出问题所在。