Skip to content

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.

Notifications You must be signed in to change notification settings

devkabir/rust-php-scanner

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Rust PHP Malware Scanner

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.

Features

  • 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

Project Structure

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

Building

Needs

  • Rust 1.92.0 or newer
  • PHP 8.0 or newer with FFI turned on

Build the Rust library

cd rust/scanner
cargo build --release

This makes the library at:

  • macOS: target/release/libscanner.dylib
  • Linux: target/release/libscanner.so
  • Windows: target/release/scanner.dll

Usage

Quick Start (Command Line)

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.php

Example 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']));

From PHP (In 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";
        }
    }
}

From Rust

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
}

Pattern Definitions

Setup

  1. Copy the example file:

    cp definitions.sample.txt definitions.txt
  2. Change definitions.txt to 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"
    }
  }
}

Pattern Types

Patterns can be:

  • Regex patterns: Start with / or # (like /eval\(/i)
  • String patterns: Normal text for fast search

Example Categories

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

How It Works

Pattern Matching

Two ways to match:

  1. strpos: Fast string search

  2. preg_match: Uses regex with PHP-style options:

    • i: Ignore case
    • s: Dot matches new lines
    • m: Multi-line

File Scanning

  • Scans folders and subfolders
  • Looks for .php, .inc, .module, .theme
  • Shows matches with file name and line number
  • Sends result to PHP as JSON

FFI Interface

Exports two functions:

  • scan_directory_ffi: Scans a folder and gives back JSON
  • free_result: Frees used memory

Testing

Run the tests in Rust:

cd rust/scanner
cargo test

Performance

Rust makes this scanner much faster than PHP-only tools:

Speed

  • 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

Resource 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

Benchmarks

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.

Advanced Usage

Change CPU Use

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);

Change Delay Between Scans

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 --release

Troubleshooting

FFI Not Enabled in PHP

Edit your php.ini:

extension=ffi
ffi.enable=true

Check it:

php -m | grep -i ffi

Shared Library Missing

Check if the library is built:

ls -la rust/scanner/target/release/libscanner.*

If not, build it:

cd rust/scanner && cargo build --release

No Permission

Make PHP scanner file executable:

chmod +x scanner.php

Security Note

This 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.

Contributing

You can help by:

  • Adding new patterns
  • Making it faster
  • Improving output
  • Connecting it with other tools

License

This tool is for learning and defense only.

Credits

Made with:

About

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.

Topics

Resources

Stars

Watchers

Forks