Skip to content

Latest commit

 

History

13 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Process + Persistence Audit

A one-shot, read-only audit of what is running on a Windows PC and what starts itself automatically.

It is not an antivirus and it does not replace one. It answers a different question: what is on this machine, where did it come from, and what launches it without being asked? Antivirus asks "do I recognise this as bad?" — this asks "can everything here account for itself?"

In short — what it finds, and what it can't

It finds things that hide by looking legitimate:

  • Programs running from odd places — Temp, AppData, Downloads — instead of where software normally installs
  • Files impersonating Windows components: right name, wrong folder, or a lookalike spelling like svch0st.exe
  • Anything unsigned, tampered with, or signed by a company that makes no sense for what it claims to be
  • A malicious DLL loaded into an otherwise genuine, correctly-signed program
  • Everything that starts itself automatically — including the hiding places most tools skip: the \Microsoft\ scheduled-task branch, svchost-hosted services, WMI subscriptions, AppInit_DLLs, IFEO hijacks, per-user COM hijacks, accessibility-key backdoors
  • Programs talking to the internet, or quietly listening for incoming connections
  • Browser extensions (listed for you to recognise — those can't be verified automatically)

It cannot find:

  • Malicious code injected into a running legitimate program. The file on disk is genuine and every check here passes. Catching this needs a kernel driver watching continuously — that is what EDR products are, and no script can substitute.
  • Rootkits. Anything that has taken over the kernel can lie to every check here. If you suspect one, run Microsoft Defender Offline Scan, which boots outside Windows.
  • Bad behaviour inside a signed file. It verifies who signed something, never what it does. Signed software can still be malicious.
  • Anything not present when you ran it. It's a snapshot, not a monitor. Something that ran and exited leaves nothing for it to see.

So use it alongside Defender, not instead of it. They answer different questions, and neither one covers the other's blind spots.

Everything above is explained in detail further down — see What it checks, Reading the output, and Coverage and limits.

Questions?

Discord: discord.gg/mR4Ee5PQ9x — ask in #github-posts. Good for "is this thing on my machine normal?" and for reading a scan report together.

GitHub Issues: open an issue for bugs, false positives, or anything you'd rather keep public and searchable.

False positives are genuinely useful to report — if this tool flags something legitimate on your machine, that's a bug worth fixing, not your problem to work around.

⚠️ Never paste a full scan report publicly. It lists your usernames, file paths, installed software and active network connections. Quote the one or two lines you're asking about.


Download

⬇ Download as ZIP

Or from this page: green Code button → Download ZIP.

Then extract the ZIP somewhere — Desktop or Downloads is fine. This step matters: double-clicking a .bat while you're still browsing inside the zip will not work properly, because Windows opens zip contents from a temporary location.

Prefer the command line? git clone https://github.com/HatefulJb/process-audit.git

Running it

Double-click Run-Scan.bat and approve the UAC prompt. Results appear in a new window (the one you launched from will look like nothing happened — that's expected).

Takes about a minute. A timestamped copy of the output is written to reports\.

Full scan vs quick scan

Double-click Time Checks DLLs?
Full (recommended) Run-Scan.bat ~50s Yes — all ~1,700 loaded modules
Quick Run-Scan-Quick.bat ~15s No

Roughly two thirds of the full runtime is the DLL check, which verifies every module loaded into every running process. Quick mode skips only that; every other check still runs, and the output states plainly that DLLs were not checked, so a quick run can never be mistaken for a full one.

The first run of the day can take two to three minutes. Nothing is wrong. Every file has to be read from disk and hashed, Defender scans each one as it is touched, and Windows may fetch certificate revocation lists over the network for signers it has not seen recently. Run it a second time and it drops to the times above, because all three of those are now cached. If you are impatient, use quick mode — it does not touch anywhere near as many files.

Those timings are measured elevated, which is how Run-Scan.bat runs. Unelevated is faster, but only because it can see less: 1,095 modules instead of 1,685, since it cannot read the modules loaded into service and system processes. Faster for the wrong reason.

What you give up in quick mode: detection of DLL sideloading — a legitimate signed .exe with a malicious DLL dropped beside it. Every other check in this tool passes that scenario, so the DLL check is the only thing that would catch it. Use quick mode for a fast look; use the full scan when it matters.

From a terminal, the same switch works directly:

powershell -NoProfile -ExecutionPolicy Bypass -File .\Scan-Processes.ps1 -Quick

If Windows gets in the way

  • SmartScreen warns about the .bat → More info → Run anyway. It says this about every unsigned batch file from the internet, not just this one.
  • "running scripts is disabled on this system" → that's PowerShell's default Restricted policy. Run-Scan.bat already works around it for this one run only, without changing any setting on your machine.
  • File is "blocked" because it came from the internet → right-click Scan-Processes.ps1 → Properties → tick Unblock → OK. (Windows adds that mark to anything extracted from a downloaded zip.)

Running it without the batch file

Perfectly reasonable if you'd rather not run a .bat you didn't write. Open PowerShell as Administrator in the extracted folder and run:

powershell -NoProfile -ExecutionPolicy Bypass -File .\Scan-Processes.ps1

Drop the as Administrator part if you want — it still works, it just can't see protected processes, and the report tells you exactly how many it missed.

There is deliberately no irm ... | iex one-line installer here. Piping a script straight from the internet into your shell means running code you never read. That's the exact habit this tool exists to help you catch, and it would be absurd to ask you to do it in order to run it. Download it, read it, then run it.

You do have to download it — but nothing installs. There is no setup program, no service, no scheduled task, no background process, no registry changes, and no network calls. It runs when you run it and it's gone when it exits. Afterwards the only things on your disk are the files you downloaded and a text report in reports\. Delete the folder and it's completely gone.


Read this before running it — it does look suspicious, and here's why

If someone sent you this, your instinct to distrust it is correct. This tool does four things that a careful person should refuse on sight. All four are explained below, and all four are verifiable in about a minute. "A friend vouched for it" is not verification.

1. Run-Scan.bat launches an elevated PowerShell with -ExecutionPolicy Bypass. That is genuinely the shape of a malicious dropper. It's used here because the scan needs administrator rights to read protected process paths and service keys, and because most machines block unsigned .ps1 files by default. You do not have to use it — run Scan-Processes.ps1 directly instead and skip the batch file entirely.

2. It compiles C# at runtime (Add-Type) and calls into kernel32.dll. Also a real malware pattern. Here it is one function, ProcPath, that calls OpenProcess + QueryFullProcessImageName to ask Windows "what file is this process running from?" for processes that WMI won't answer for. It requests PROCESS_QUERY_LIMITED_INFORMATION (0x1000) — the most restricted access right that exists for this. It cannot read process memory, write to a process, or inject anything. Read the block; it's about 20 lines.

3. Your antivirus or EDR may flag the script itself. PowerShell that calls Add-Type and OpenProcess trips behavioural heuristics on several products. That is the heuristic doing its job — the pattern is legitimately worth flagging in general. It doesn't mean this script is malicious, and it doesn't mean your AV is broken.

4. It reads a lot about your machine — running processes, autostart entries, services, scheduled tasks, network connections. That's the job. It matters that none of it goes anywhere (see below).

Verify it yourself in one minute

The whole tool is one plain-text PowerShell file. Open it in Notepad. Then, to check the claims rather than trust them, search it for every command that could change or transmit anything:

Select-String -Path .\Scan-Processes.ps1 -Pattern 'Remove-Item|Set-ItemProperty|New-ItemProperty|Remove-ItemProperty|Stop-Process|Stop-Service|Start-Process|sc\.exe|reg\.exe|Invoke-WebRequest|Invoke-RestMethod|WebClient|DownloadString|Net\.Sockets|Invoke-Expression|New-Item|Set-Content|Add-Type'

You should get exactly three results, and nothing else:

What it is Why it's there
Add-Type ... TypeDefinition The ProcPath helper described above.
New-Item -ItemType Directory -Path $ReportDir Creates the reports\ folder.
Set-Content -LiteralPath $reportPath Writes the report text file.

(If you widen the search to include tool names like certutil or rundll32 you'll also hit the $LolBins line. That one is a string — a list of program names the scan looks for in your scheduled tasks. It is pattern data, not a command being run.)

That's the complete list of everything this script does beyond reading. There is no registry write, no file deletion, no process or service manipulation, and no network call of any kind — no Invoke-WebRequest, no WebClient, no sockets, no VirusTotal lookup, nothing. Your data cannot leave your machine because there is no code capable of sending it.

The only thing it writes is a text report, into its own folder.


What it checks

The tool rests on one idea: a process's name means nothing. Anyone can name a program svchost.exe and give it the Windows gear icon. Real identity is path + signature + parent. Every check below gets at one of those three.

# Check Question it answers
1 Path Is this running from a normal install location, or from Temp/AppData/Downloads?
2 Signature Is it cryptographically signed, and by a company that makes sense?
2b Loaded modules Is every DLL loaded into every running process signed? Catches DLL sideloading — where a signed .exe is left alone and a malicious DLL is dropped beside it.
3 Impersonation Is a core Windows process name running from the wrong folder, or a near-miss spelling (svch0st, scvhost, lsas)?
4 Ancestry Did svchost come from services.exe as it must? Did a script host get spawned by Word or a browser?
5a Run keys What launches at login via HKLM/HKCU Run and RunOnce?
5b Services What runs at boot, including svchost-hosted services resolved via their ServiceDll?
5c Scheduled Tasks What runs on a schedule, and with what arguments?
5d Startup folders What's in Startup, and where do those shortcuts actually point?
5e WMI subscriptions Any fileless persistence — event consumers that run commands?
5f The less obvious hooks AppInit_DLLs, Winlogon Shell/Userinit, IFEO debugger hijacks, SilentProcessExit monitors, LSA packages, per-user COM hijacks, Active Setup, print monitors, netsh helpers, accessibility-binary swaps, screensaver.
5g Browser extensions What's installed in Chrome/Edge/Brave — listed for you to recognise.
6 Network Which processes hold connections to the outside world?
7 Defender Real-time protection on? Definitions current?

Section 5f is where the techniques live that most people never check. A few worth understanding:

  • AppInit_DLLs — a DLL listed here is loaded into nearly every GUI process on the machine. It should be empty.
  • IFEO debugger — setting a "debugger" for notepad.exe means launching Notepad silently runs something else instead.
  • Winlogon Shell/Userinit — these run at logon before anything else. Defaults are explorer.exe and C:\Windows\system32\userinit.exe,.
  • Per-user COM hijack — an HKCU CLSID overrides the matching HKLM one, so a component the system loads gets silently replaced. Only flagged when it actually shadows a system entry.
  • Accessibility swaps — replacing sethc.exe or utilman.exe gives a SYSTEM shell from the logon screen without signing in.

These are checked against what a stock Windows install looks like, so the question is "does this differ from default", not "does this look scary".

Browser extensions are listed, not judged. Extensions can't be signature-verified the way a binary can, and adware lives there more than anywhere else. The tool shows you names and IDs; recognising them is your job.


Reading the output

Four levels. Only one of them means "something is wrong."

Level Meaning
OK The check passed, nothing found.
INFO Present and accounted for. Signed, normal location. No action.
REVIEW Not an accusation. Something the tool cannot clear on its own — an unsigned binary, a script it can't read for you, a vendor it doesn't recognise. You decide.
FLAG Reserved for things with no benign explanation: a core Windows name in the wrong folder, a broken signature, a command-running WMI consumer.

A clean machine still produces REVIEW items. Expect a handful. Different PCs will produce completely different lists depending on installed games, vendor utilities, and drivers.

The most important habit

Run it once now, while things are working, and keep that report. Its real value is comparison. "Six review items" on its own means very little. "Six review items last month, nine today, and I don't recognise the three new ones" is a genuine signal.

Things that look alarming but usually aren't

  • powershell.exe -ExecutionPolicy Bypass -WindowStyle Hidden in a scheduled task. Textbook malware shape — and also how plenty of legitimate self-written automation is set up. powershell.exe is signed by Microsoft, so the executable tells you nothing. Judge it by its arguments and by reading the script it points to.
  • A running program whose file is "not on disk." Self-deleting malware does this. So does every auto-updating app — Discord, Spotify, VS Code and others run from version-numbered folders and delete the old one on update while the old process keeps running. Check for a sibling version folder first.
  • Apps running from AppData. Electron apps install per-user by design. Suspicious in combination with unsigned, not on its own.
  • Unsigned .bat / .vbs / .ps1 files. Scripts cannot carry an Authenticode signature at all. "Unsigned" is not a finding for them — read the file instead.
  • Names containing a scary word. A service called WarpJITSvc is Microsoft's Direct3D software renderer, not a VPN leftover. Check the publisher, not the string.

Coverage and limits — read this

Being honest about what it doesn't see matters more than the list of what it does.

It does not check every running process, even elevated. Every report opens with its own coverage line, so you never have to guess:

Processes: 285 total | 104 path from WMI | 12 recovered via Win32 API | 5 kernel (no file) | 164 unresolved

Read that as: 104 processes gave up their image path directly, 12 more were recovered by asking Windows a second way, 5 have no file to check at all, and 164 could not be resolved in this run.

That last number is almost entirely an elevation problem. Measured on the same machine, minutes apart:

Unelevated Elevated
Processes total 285 294
Path from WMI 104 275
Recovered via Win32 API 12 14
Kernel, no file to check 5 5
Unresolved 164 0
Unique executables verified 56 115
Service keys it could not read 2 0

Run it as administrator and every process that has a file on disk gets checked. The unresolved count and the service key(s) could not be read warning disappear because there is genuinely nothing left unchecked. If you see either message, you ran it unelevated.

The only permanent gap is the 5 processes with no file on disk at all — System, Registry, Secure System, System Idle Process and Memory Compression are kernel-space constructs, not programs. There is no .exe to hash and no signature to read.

Protected processes like Defender's MsMpEng.exe are not a gap. You cannot read their memory, but their image path and signature verify normally, because that only needs PROCESS_QUERY_LIMITED_INFORMATION — the most restricted access right there is, which Windows grants for exactly this purpose.

Also note that unique files checked is smaller than process count, correctly: 88 running copies of svchost.exe are 88 processes but one file, and checking that file once is the right thing to do.

Why it takes ~50 seconds

Almost all of it is signature verification, and that cost scales with file size, because Authenticode hashes the entire file. Measured on one desktop:

File Size Signature check
claude.exe 266 MB 1043 ms
Discord.exe 211 MB 801 ms
median file — 17 ms

Three large Electron apps accounted for 70% of the executable-checking total.

The bigger cost is the DLL check — ~1,685 unique modules loaded across ~290 processes, about 34 seconds, or two thirds of the run. That's the price of catching sideloading, and -Quick skips it if you'd rather have a 15-second scan. Measured end to end, elevated:

Mode Modules checked Scan time
Full, elevated 1,683 51.7s
Quick, elevated none ~15s
Full, unelevated 1,095 ~36s

Unelevated is faster only because it sees less — it cannot read the modules inside service and system processes, so 590 of them go unchecked.

Worth knowing why that check produces so little noise: of ~1,685 modules on a stock machine, the vast majority are unsigned on a stock machine, and all 75 fall into two categories that are filtered by name, not by guesswork — Store/MSIX packages (signed at the package level, not per file) and .NET native images under Windows\assembly\NativeImages (compiled locally by ngen from already-signed assemblies, so they never carry a signature). Excluding those two leaves zero. An unsigned DLL that isn't one of those is worth your attention.

Where a check genuinely could not run, the tool says so and counts it — e.g. 2 service key(s) could not be read - NOT checked. A scanner that hides its blind spots is worse than one with fewer checks, because it converts "I couldn't look" into "nothing there."

What it deliberately does not do

  • No network calls, no VirusTotal lookups. Nothing about your machine leaves it. The trade-off: no reputation data, so judgement is yours.

  • No file-content malware detection. It never inspects what a binary actually does. Use Defender or another AV for that — they are complementary.

  • No rootkit detection. Anything that has already subverted the kernel can lie to every API this tool uses. If you suspect that, run Microsoft Defender Offline Scan (Windows Security → Virus & threat protection → Scan options), which boots outside Windows.

  • No process-injection detection — and this is deliberate. Injection means malicious code running inside a legitimate signed process: the file on disk is genuine, the signature is valid, the ancestry is correct, and every check in this tool passes. Catching it means scanning each process's memory for executable regions not backed by any file. Two things make that a bad idea here. Protected processes refuse memory reads outright, so the highest-value targets are exactly the ones you cannot inspect. And every JIT compiler on the machine — .NET, Chrome's JavaScript engine, Java, node — allocates unbacked executable memory constantly and by design, so the check would produce hundreds of hits on a completely clean PC with no path-based rule able to separate a compiler from a payload. That is the same false-positive problem the DLL check had, except unsolvable. Reliable detection needs a kernel driver and continuous monitoring, which is what EDR products are. A 35-second PowerShell script cannot do it, and one that claimed to would just be lying to you.

  • It never changes anything. No fixes, no quarantine, no deletion. It reports; you act.

Do more with dedicated tools

For deeper work, both free from Microsoft (Sysinternals) — you download a zip and run the .exe, there is no setup program:

  • Autoruns — every persistence location and many more, with a VirusTotal detection-ratio column. Enable Options → Hide Microsoft entries and Options → Scan Options → Check VirusTotal.
  • Process Explorer — Task Manager with the answers filled in. Enable Options → Verify Image Signatures and add the VirusTotal column. Shows processes as a tree, so ancestry is visible at a glance.

Requirements

Windows 8 or newer. It relies only on PowerShell 5.1, which is already part of Windows — so once you've downloaded this folder there are no other dependencies to fetch. Runs on Windows 10 and 11 as-is.

Files

File Purpose
Run-Scan.bat Double-click launcher for the full scan, requests elevation
Run-Scan-Quick.bat Same, but skips the DLL check (~15s instead of ~50s)
Scan-Processes.ps1 The scan itself — read it before running
reports\ Timestamped output, created on first run

reports\ contains your machine's process list, file paths and network connections. Don't share those files without reading them first.


Support

This is free, and always will be — every check is in the box, nothing is held back for a paid version.

Most of the work wasn't writing the checks, it was hunting down the false positives so it doesn't cry wolf at your antivirus, your game launchers, or a Windows component that happens to have a scary name. If it found something on your machine, or just told you nothing was wrong and you slept better, and you want to throw a couple of dollars at it, that's genuinely appreciated:

☕ ko-fi.com/hatefuljb

Starring the repo and passing it to someone who needs it helps just as much, and costs nothing. So does reporting a false positive — that one actually makes the tool better for everyone.

About

One-shot, read-only Windows process and persistence audit. Download, run, read the report - no setup program, no service, no network calls.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages