---
title: Potential PowerShell Obfuscation via Character Array Reconstruction
description: Detects PowerShell scripts that reconstructs strings from char[] arrays, index lookups, or repeated ([char]NN)+ concatenation/join logic. Attackers use...
url: https://www.elastic.co/docs/reference/security/prebuilt-rules/rules/windows/defense_evasion_posh_obfuscation_char_arrays
products:
  - Elastic Security
---

# Potential PowerShell Obfuscation via Character Array Reconstruction
Detects PowerShell scripts that reconstructs strings from char[] arrays, index lookups, or repeated ([char]NN)+
concatenation/join logic. Attackers use character-array reconstruction to hide commands, URLs, or payloads and evade
static analysis and AMSI.
**Rule type**: esql
**Rule indices**:
**Rule Severity**: high
**Risk Score**: 73
**Runs every**: 
**Searches indices from**: `now-9m`
**Maximum alerts per execution**: 100
**References**:
**Tags**:
- Domain: Endpoint
- OS: Windows
- Use Case: Threat Detection
- Tactic: Defense Evasion
- Data Source: PowerShell Logs
- Resources: Investigation Guide

**Version**: 9
**Rule authors**:
- Elastic

**Rule license**: Elastic License v2

## Setup

PowerShell Script Block Logging must be enabled to generate the events used by this rule (e.g., 4104).
Setup instructions: [https://ela.st/powershell-logging-setup](https://ela.st/powershell-logging-setup)

## Investigation guide


## Triage and analysis> **Disclaimer**:
This guide was created by humans with the assistance of generative AI. While its contents have been manually curated to include the most valuable information, always validate assumptions and adjust procedures to match your internal runbooks and incident triage and response policies.

### Investigating Potential PowerShell Obfuscation via Character Array Reconstruction

This rule identifies PowerShell Script Block Logging content that reconstructs strings at runtime from character codes or character arrays. This technique is commonly used to conceal intent (for example, commands, URLs, or file paths) and can indicate attempts to evade static inspection.
Focus triage on what strings are being rebuilt, who ran the script, where it ran, and whether the decoded content leads to follow-on activity.

#### Key alert fields to review

- `user.name`, `user.domain`, `user.id`: Account execution context for correlation, prioritization, and scoping.
- `host.name`, `host.id`: Host execution context for correlation, prioritization, and scoping.
- `file.path`, `file.directory`, `file.name`: File-origin context when the script block is sourced from an on-disk file.
- `powershell.file.script_block_text`: Script block content that matched the detection logic.
- `powershell.file.script_block_id`, `powershell.sequence`, `powershell.total`: Script block metadata to pivot to other fragments or reconstruct full script content when split across multiple events.
- `Esql.script_block_tmp`: Transformed script block where detection patterns replace original content with a marker to support scoring/counting and quickly spot match locations.
- `Esql.script_block_pattern_count`: Count of matches for the detection pattern(s) observed in the script block content.
- `powershell.file.script_block_entropy_bits`: Shannon entropy of the script block. Higher values may indicate obfuscation.
- `powershell.file.script_block_surprisal_stdev`: Standard deviation of surprisal across the script block. Low values indicate uniform randomness. High values indicate mixed patterns and variability.
- `powershell.file.script_block_unique_symbols`: Count of distinct characters present in the script block.
- `powershell.file.script_block_length`: Script block length (size) context.


#### Possible investigation steps

- Review `powershell.file.script_block_text` and use `Esql.script_block_tmp` to quickly spot the segments that triggered the match. Identify the reconstruction method (for example, `[char[]](...)`, repeated `([char]NN)+` concatenation, joins, or index-based lookups).
- If the script block is split, reconstruct the full content using `powershell.file.script_block_id` together with `powershell.sequence` and `powershell.total`. Verify that all expected sequences are present and in order before drawing conclusions.
- If `powershell.total` indicates multiple fragments but one or more `powershell.sequence` values are missing, treat the script as incomplete context. Attempt to retrieve the missing fragments and consider the possibility of log gaps or ingestion delays.
- Deobfuscate the reconstructed strings by translating numeric character codes and arrays into their resulting text. Capture any decoded values that look like commands, script content, URLs, file paths, registry paths, or encoded blobs.
- After decoding, re-review the full script block content for additional obfuscation layers or execution logic that is not covered by the character reconstruction pattern (for example, secondary decoding steps or dynamically-invoked script).
- Use `Esql.script_block_pattern_count` as a quick measure of how heavily the script relies on this obfuscation pattern. Higher counts typically indicate more deliberate concealment and can help prioritize review.
- Use the script statistics to support prioritization and comparison against expected baselines: `powershell.file.script_block_entropy_bits`, `powershell.file.script_block_surprisal_stdev`, `powershell.file.script_block_unique_symbols`, and `powershell.file.script_block_length`. Look for unusually long, high-entropy, or highly variable content relative to known-good PowerShell activity in your environment.
- Review the execution context: `user.name`, `user.domain`, and `user.id` to understand who executed the script and whether the account matches expected administrative or automation usage for the `host.name` and `host.id` involved.
- Review file origin indicators when present: `file.path`, `file.directory`, and `file.name`. Assess whether the script appears to originate from an expected location for your environment versus a user-writable, temporary, or unusual directory.
- Pivot to the source event using `_id` and `_index` to review the full event payload and confirm whether additional relevant `powershell.file.*` context is available for analysis.
- Scope for related activity by searching for additional script blocks that share the same `powershell.file.script_block_id`, similar `powershell.file.script_block_text` content, the same `file.path`, the same `user.id`, or the same `host.id` around the alert time window.
- Correlate the alert timestamp with adjacent telemetry from the same host and user (process activity, network connections, file writes, registry modifications, and authentication events) to identify how PowerShell was launched (including the initiating/parent process) and what occurred immediately before and after the obfuscated content executed.
- If decoded content indicates external communication or secondary payload retrieval, identify potential indicators (domains, IPs, URLs, file names) and check for additional occurrences across other hosts and users.
- If decoded content indicates credential access, lateral movement, or persistence, expand the investigation to related accounts and hosts within the same timeframe and document the full execution chain.


### False positive analysis

- Some benign scripts reconstruct strings from character codes for formatting, localization, or to safely represent special characters. These cases are often limited in scope and decode to human-readable, expected values.
- Software deployment, management, or monitoring tooling may generate PowerShell dynamically and use string reconstruction as an implementation detail. Validate whether the script source (`file.path`) and execution context (`user.id`, `host.id`) align with known tooling behavior.
- Internal scripts may use light obfuscation to reduce casual tampering or to embed configuration values. Treat unknown sources, unexpected accounts, or unusually high `Esql.script_block_pattern_count` / `powershell.file.script_block_entropy_bits` as higher risk until validated.
- If determined benign, document the script source and expected execution context (account and host) and retain the decoded strings for faster triage of future alerts.


### Response and remediation

- If malicious or suspicious activity is confirmed, contain the affected host to prevent additional execution and lateral movement. Consider restricting the involved account based on investigation results.
- Preserve evidence: retain the full `powershell.file.script_block_text` and any reconstructed/decoded strings, along with related events for the same `powershell.file.script_block_id` (all `powershell.sequence` values).
- If the script originates from disk (`file.path` present), collect and quarantine the referenced file and review for additional related artifacts created or modified around the alert time window.
- Identify and remediate follow-on actions indicated by the decoded content (for example, downloaded payloads, persistence mechanisms, or changes to system configuration).
- Hunt for spread: search for the same decoded indicators, similar reconstruction patterns, and elevated `Esql.script_block_pattern_count` across other hosts and users.
- If account misuse is suspected, perform appropriate credential hygiene and review recent authentication activity for the affected `user.id` and related accounts.
- Review and strengthen PowerShell controls and monitoring based on findings (for example, ensure Script Block Logging is consistently enabled and that anti-malware scanning integration is functioning as expected).


## Rule Query

```esql
from logs-windows.powershell_operational* metadata _id, _version, _index
| where event.code == "4104"

// Filter for scripts that contain the "char" keyword using MATCH, boosts the query performance
| where powershell.file.script_block_text : "char"

// replace the patterns we are looking for with the 🔥 emoji to enable counting them
// The emoji is used because it's unlikely to appear in scripts and has a consistent character length of 1
| eval Esql.script_block_tmp = replace(
    powershell.file.script_block_text,
    """(char\[\]\]\(\d+,\d+[^)]+|(\s?\(\[char\]\d+\s?\)\+){2,})""",
    "🔥"
)

// count how many patterns were detected by calculating the number of 🔥 characters inserted
| eval Esql.script_block_pattern_count = length(Esql.script_block_tmp) - length(replace(Esql.script_block_tmp, "🔥", ""))

// keep the fields relevant to the query, although this is not needed as the alert is populated using _id
| keep
    Esql.script_block_pattern_count,
    Esql.script_block_tmp,
    powershell.file.*,
    file.path,
    powershell.sequence,
    powershell.total,
    _id,
    _version,
    _index,
    host.name,
    host.id,
    agent.id,
    user.id

// Filter for scripts that match the pattern at least once
| where Esql.script_block_pattern_count >= 1
```

**Framework:** MITRE ATT&CK
- Tactic:
  - Name: Defense Evasion
- Id: TA0005
- Reference URL: [[https://attack.mitre.org/tactics/TA0005/](https://attack.mitre.org/tactics/TA0005/)](https://attack.mitre.org/tactics/TA0005/)
- Technique:
  - Name: Obfuscated Files or Information
- Id: T1027
- Reference URL: [[https://attack.mitre.org/techniques/T1027/](https://attack.mitre.org/techniques/T1027/)](https://attack.mitre.org/techniques/T1027/)
- Sub Technique:
  - Name: Command Obfuscation
- Id: T1027.010
- Reference URL: [[https://attack.mitre.org/techniques/T1027/010/](https://attack.mitre.org/techniques/T1027/010/)](https://attack.mitre.org/techniques/T1027/010/)
- Technique:
  - Name: Deobfuscate/Decode Files or Information
- Id: T1140
- Reference URL: [[https://attack.mitre.org/techniques/T1140/](https://attack.mitre.org/techniques/T1140/)](https://attack.mitre.org/techniques/T1140/)

**Framework:** MITRE ATT&CK
- Tactic:
  - Name: Execution
- Id: TA0002
- Reference URL: [[https://attack.mitre.org/tactics/TA0002/](https://attack.mitre.org/tactics/TA0002/)](https://attack.mitre.org/tactics/TA0002/)
- Technique:
  - Name: Command and Scripting Interpreter
- Id: T1059
- Reference URL: [[https://attack.mitre.org/techniques/T1059/](https://attack.mitre.org/techniques/T1059/)](https://attack.mitre.org/techniques/T1059/)
- Sub Technique:
  - Name: PowerShell
- Id: T1059.001
- Reference URL: [[https://attack.mitre.org/techniques/T1059/001/](https://attack.mitre.org/techniques/T1059/001/)](https://attack.mitre.org/techniques/T1059/001/)