A fast malware scanner made in Rust. It works with PHP using FFI. This scanner reads pattern rules and checks PHP files for bad code. It works like PHP's strpos and preg_match, but it is much faster.
- Fast Pattern Matching: Finds strings and regular patterns, like strpos and preg_match in PHP
- PHP Definitions Parser: Reads files written in PHP's var_export format
- FFI Integration: Works well with PHP using FFI
- Resource-Friendly: Uses half of the CPU cores and controls speed
- Detailed Results: Shows file paths, line numbers, and matched lines
- Comprehensive Detection: Finds many types of bad code patterns
- Memory Safe: Written in Rust for safe and fast memory use
rust-php-scanner/
├── rust/scanner/ # Rust code for scanning
│ ├── src/
│ │ └── lib.rs # Main scanner code with comments
│ ├── Cargo.toml # Rust dependencies
│ └── target/release/ # Built library
├── definitions.txt # Real pattern list (not shared)
├── definitions.sample.txt # Example pattern list
├── scanner.php # PHP wrapper and command-line tool
└── README.md # This file
- Rust 1.92.0 or newer
- PHP 8.0 or newer with FFI turned on
cd rust/scanner
cargo build --releaseThis makes the library at:
- macOS:
target/release/libscanner.dylib - Linux:
target/release/libscanner.so - Windows:
target/release/scanner.dll
You can run scanner.php from the command line:
# Scan a chosen folder
php scanner.php /path/to/wordpress/wp-content/plugins
# Scan default folder
php scanner.phpExample output:
Scanned 1247 files in 0.234s
Found 3 suspicious files
Suspicious Files:
================================================================================
example-plugin/malicious.php
[potential] eval (line 42)
→ eval(base64_decode($_POST['code']));
[obfuscation] base64_decode (line 42)
→ eval(base64_decode($_POST['code']));
<?php
require_once 'scanner.php';
$libPath = match (PHP_OS_FAMILY) {
'Darwin' => __DIR__ . '/rust/scanner/target/release/libscanner.dylib',
'Windows' => __DIR__ . '/rust/scanner/target/release/scanner.dll',
default => __DIR__ . '/rust/scanner/target/release/libscanner.so',
};
$scanner = new RustScanner($libPath);
$results = $scanner->scanDirectory('/path/to/scan');
foreach ($results as $result) {
if ($result['suspicious']) {
echo "Suspicious file: {$result['path']}\n";
foreach ($result['matches'] as $match) {
echo " - {$match['category']}/{$match['name']} (ID: {$match['id']})";
if (isset($match['line'])) {
echo " at line {$match['line']}";
}
if (isset($match['line_content'])) {
echo "\n → {$match['line_content']}";
}
echo "\n";
}
}
}use scanner::{scan_directory, scan_file};
// Scan a folder
let results = scan_directory("/path/to/scan");
for result in results {
if result.suspicious {
println!("Suspicious: {}", result.path);
for m in result.matches {
println!(" {}/{} ({})", m.category, m.name, m.id);
}
}
}
// Scan one file
if let Some(result) = scan_file(Path::new("/path/to/file.php")) {
// Use the result
}-
Copy the example file:
cp definitions.sample.txt definitions.txt
-
Change
definitions.txtto add your patterns
The file should be in this format (PHP var_export array):
array(2) {
["category_name"]=>
array(1) {
["pattern_name"]=>
array(2) {
[0]=>
string(5) "ID123"
[1]=>
string(20) "/regex_pattern/i"
}
}
}Patterns can be:
- Regex patterns: Start with
/or#(like/eval\(/i) - String patterns: Normal text for fast search
The sample file includes these:
- potential: Risky functions (eval, base64_decode)
- dangerous: Very risky functions (exec, assert)
- obfuscation: Hidden code (str_rot13, gzinflate)
- suspicious: Strange PHP code
- backdoor: Known malware code
- cryptominers: Crypto mining code
- exploits: Known exploit patterns
- spam: Spam code
- encoding: Code using encoding tricks
Two ways to match:
-
strpos: Fast string search
-
preg_match: Uses regex with PHP-style options:
i: Ignore cases: Dot matches new linesm: Multi-line
- Scans folders and subfolders
- Looks for
.php,.inc,.module,.theme - Shows matches with file name and line number
- Sends result to PHP as JSON
Exports two functions:
scan_directory_ffi: Scans a folder and gives back JSONfree_result: Frees used memory
Run the tests in Rust:
cd rust/scanner
cargo testRust makes this scanner much faster than PHP-only tools:
- Runs as compiled code: Faster than PHP
- Fast regex: Uses Rust’s good regex engine
- Multi-threaded: Scans many files at once
- Low memory use: Avoids extra memory use
- CPU: Uses only half of CPU power
- Throttling: Small wait between scans avoids overload
- Memory: Handles big files without needing lots of memory
- Safe for servers: Can run on live systems
On normal computers:
- Small projects (100–500 files): 0.1–0.3 seconds
- Medium projects (500–2000 files): 0.3–1.0 seconds
- Large projects (2000+ files): 1.0–3.0 seconds
Times can change based on file size, pattern count, and computer speed.
In rust/scanner/src/lib.rs, line 257:
// Use 25% of CPUs
let num_threads = std::cmp::max(1, num_cpus::get() / 4);
// Use 75% of CPUs
let num_threads = std::cmp::max(1, (num_cpus::get() * 3) / 4);In line 269:
// Faster scan
std::thread::sleep(Duration::from_micros(50));
// Slower scan
std::thread::sleep(Duration::from_micros(500));Then rebuild:
cd rust/scanner && cargo build --releaseEdit your php.ini:
extension=ffi
ffi.enable=trueCheck it:
php -m | grep -i ffiCheck if the library is built:
ls -la rust/scanner/target/release/libscanner.*If not, build it:
cd rust/scanner && cargo build --releaseMake PHP scanner file executable:
chmod +x scanner.phpThis tool is for safe and legal security checks. It looks for:
- Bad eval use
- Hidden code
- Malware code
- Code that runs system commands
- Backdoors and webshells
- Crypto mining code
- And more signs of danger
Important: Only use this tool if you are allowed to. It is for defense, not attack.
You can help by:
- Adding new patterns
- Making it faster
- Improving output
- Connecting it with other tools
This tool is for learning and defense only.
Made with: