ps-parser

Crates.iops-parser
lib.rsps-parser
version0.1.0
created_at2025-07-16 20:19:24.433885+00
updated_at2025-09-05 13:48:29.416431+00
descriptionThe Powershell Parser
homepage
repository
max_upload_size
id1756552
size379,086
(radkum)

documentation

README

ps-parser

A fast and flexible PowerShell parser written in Rust. Parse, analyze, and manipulate PowerShell scripts with idiomatic Rust types.

Goal

Malicious scripts typically use "safe" operations to obfuscate "unsafe" ones. For example, arithmetic operations are used to obfuscate function arguments.

The goal of this parser is to combat obfuscation in PowerShell by evaluating everything that is "safe" but not anything that is "unsafe."

Features

  • PowerShell script parsing using pest grammar
  • Value types for PowerShell objects (String, Int, HashTable, ScriptBlock, etc.)
  • Arithmetic, logical, and string operations
  • Script block evaluation and variable management
  • HashTable and Array support
  • Extensible for custom PowerShell types

Installation

Add this to your Cargo.toml:

[dependencies]
ps-parser = "0.1.0"

Usage

Parse a PowerShell script

use ps_parser::PowerShellSession;

let mut ps = PowerShellSession::new(); 
let script = r#"
$a = 1 + 2
Write-Output $a
"#;

let result = ps.parse_input(script)?.deobfuscated();
println!("{}", result);

Output:

$a = 3
Write-Output 3

Evaluate arithmetic and variables

use ps_parser::{Val, eval_expression};

let mut ps = PowerShellSession::new(); 
let script = r#"
$x = 5; $y = $x * 8/2; $y%=3;$y
"#;

let result = ps.parse_input(script)?.deobfuscated();
println!("{}", result);
Output: 
```rust
$x = 5
$y = 20
$y = 2

Work with arrays and hashtables

use ps_parser::PowerShellSession;

let mut ps = PowerShellSession::new(); 
let script = r#"
$a = @('a', 'b', 'c');$b=$a[2];$b
"#;

let script_result = ps.parse_input(script)?;
println!("Deobfuscated:\n{}\n", script_result.deobfuscated());
println!("Result:\n{}", script_result.result());

Output:

Deobfuscated:
$a = @('a','b','c')
$b = 'c'

Result:
c

Deal with simple deobfuscation

use ps_parser::PowerShellSession;

let mut ps = PowerShellSession::new(); 
let script = r#"
$ilryNQSTt="System.$([cHAR]([ByTE]0x4d)+[ChAR]([byte]0x61)+[chAr](110)+[cHar]([byTE]0x61)+[cHaR](103)+[cHar](101*64/64)+[chaR]([byTE]0x6d)+[cHAr](101)+[CHAr]([byTE]0x6e)+[Char](116*103/103)).$([Char]([ByTe]0x41)+[Char](117+70-70)+[CHAr]([ByTE]0x74)+[CHar]([bYte]0x6f)+[CHar]([bytE]0x6d)+[ChaR]([ByTe]0x61)+[CHar]([bYte]0x74)+[CHAR]([byte]0x69)+[Char](111*26/26)+[chAr]([BYTe]0x6e)).$(('Ârmí'+'Ùtìl'+'s').NORmalizE([ChAR](44+26)+[chAR](111*9/9)+[cHar](82+32)+[ChaR](109*34/34)+[cHaR](68+24-24)) -replace [ChAr](92)+[CHaR]([BYTe]0x70)+[Char]([BytE]0x7b)+[CHaR]([BYTe]0x4d)+[chAR](110)+[ChAr](15+110))";$ilryNQSTt
"#;

let script_result = ps.parse_input(script)?;
println!("{}", script_result.deobfuscated());

Output:

$ilrynqstt = 'System.Management.Automation.ArmiUtils'

Deal with encoding deobfuscation

use ps_parser::PowerShellSession;

let mut ps = PowerShellSession::new(); 
let script_printed_to_output = r#"
[syStem.texT.EncoDInG]::unIcoDe.geTstRiNg([SYSTem.cOnVERT]::froMbasE64striNg("ZABlAGMAbwBkAGUAZAA="))
"#;

let script_result = ps.parse_input(script_printed_to_output)?;
println!("Output:\n{}\n", script_result.output());

let script_assigned_to_variable = r#"
$encoded = [syStem.texT.EncoDInG]::unIcoDe.geTstRiNg([SYSTem.cOnVERT]::froMbasE64striNg("ZABlAGMAbwBkAGUAZAA="));
"#;

let script_result = ps.parse_input(script_assigned_to_variable)?;
println!("Deobfuscated:\n{}", script_result.deobfuscated());

Output:

Output:
decoded

Deobfuscated:
$encoded = 'decoded'

Work environmental variables

use ps_parser::PowerShellSession;

let mut ps = PowerShellSession::new().with_variables(Variables::env()); 
let input = r#"$env:programfiles"#;
let script_result = ps.parse_input(input)?;
println!("{}", script_result.result());

Output:

C:\Program Files

Check errors

use ps_parser::PowerShellSession;

let mut ps = PowerShellSession::new(); 
let input = r#" 
$var = 1 + "Hello, World!" # Powershell cannot cast string to int
"#;
let script_result = ps.parse_input(input)?;
println!("{:?}", script_result.errors());

Output:

[ValError(InvalidCast("String", "Int"))]

Get tokens

use ps_parser::PowerShellSession;

let mut ps = PowerShellSession::new(); 
let input = r#" 
$a = 5
$b = $a * 2
Write-Output "Addition: $($a + $b)"
"#;
let script_result = ps.parse_input(input)?;
println!("{}", script_result.tokens().expandable_strings()[0]);
println!("{}", script_result.tokens().expression()[0]);

Output:

StringExpandable("\"Addition: $($a + $b)\"", "Addition: 15")
Expression("5", Int(5))

Examples

See the test_scripts/ directory for samples. Input script, deobfuscated script and script output.

Documentation

Contributing

Pull requests, issues, and suggestions are welcome! Please see CONTRIBUTING.md for guidelines.

License

Licensed under MIT or Apache-2.0, at your option. See LICENSE-MIT and LICENSE-APACHE for details.

Commit count: 0

cargo fmt