Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Extract the contents of the executed script from the PowerShell memory dump

2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

Extract the content of the executed script from the PowerShell memory dump, in order to solve this problem, this article introduces the corresponding analysis and solution in detail, hoping to help more partners who want to solve this problem to find a more simple and feasible method.

After the last release of extracting activity history from PowerShell process dumps, I came up with an interesting question: "can I extract the contents of executed scripts (from disk), even if these files are not captured?" The answer I got was "yes", but it was also complicated. This will require a lot of WinDbg automation, so the first step is to install the WinDbg module.

Let's create a simple script first.

Open a PowerShell session, run the script, and then create a dump file.

Now, use the WinDbg module to connect to the dump file:

Connect-DbgSession-ArgumentList'- z "C:\ Users\ lee\ AppData\ Local\ Temp\ powershell.DMP"'

Start

We want to extract the object, if any, that represents the script running in the session. But how do we find these?

First, let's use SOS's dump object command to dump everything it knows about each object in the process. Therefore, we will start from! The DumpHeap command starts looking for all object instances (that is, we don't even use the-Type filter). But there are other ways to do this, but this step and the next will take a long time.

$allReferences = dbg! dumpheap-short

Once we have all the object references, let's use them! Do (dump object command) asks SOS to visualize them all. The output of the dump object does not include the address of the object being dumped, so we will also use Add-Member to track it.

$allObjects = $allReferences | Foreach-Object {$object = dbg "! do $"; Add-Member-InputObject $object Address $- PassThru-Force}

SOS knows that there are about a million objects in this process example. But will any of their GUID be visualized by SOS?

Looks like we're lucky! Of these millions of objects, we managed to narrow them down to seven System.String objects in PowerShell memory that somehow refer to GUID. If we think the information may be in System.String all the time, we can use "$allReferences = dbg! dumpheap-type System.String-short" to make our initial "$allObjects" query faster. But how do we figure out what these GUID are?

To find out, we will use SOS's! The gcroot command. This is usually used to diagnose managed memory leaks! The gcroot command tells you the object that references it and the object that references it-all the way to the root of the object. Let's explore these root causes.

Item 5 is rooted in the object array (System.Object []), where one element is ConcurrentDictionary, which contains a ScriptBlock, which in turn contains CompiledScriptBlockData, which contains nodes in PowerShell AST, which hit bottom in the command AST that references this GUID.

This is the fourth item in my example:

This is interesting! This starts with the same array of root objects (0000026e101e9a40), the same ConcurrentDictionary (0000026e003bc440), but this time it ends with a tuple containing our string and another string (a simple pairing of two items). Let's take a closer look at that tuple and the string it contains.

So this tuple has two elements. The first element appears to be the path to the execution of the script, and the second element appears to be the content of the script. Let's look at PowerShell Source's response to these data structures. I will search ConcurrentDictionary to see what I can find. On page 3, we can see what we are looking at:

There is a class called CompiledScriptBlock. It contains a static (process-wide) cache called "s_cachedScripts". This is a dictionary that maps a pair of strings to an ScriptBlock instance. If you read the source code, you can see exactly the contents of the Tuple-the mapping of the script path to the content contained in the ScriptBlock cache:

This data structure is what we finally discuss. For performance reasons, PowerShell maintains an internal script block cache so that you don't need to recompile the script block every time you see a script. This cache is key to the path and the content of the script. What is stored in the cache is an instance of the ScriptBlock class that contains (among other things) the AST of the compiled script.

So now that we know that this thing exists, we can be smarter in automation and extract these things! Now we need a real script, and that's what we're going to do:

1. Use! Dumpheap finds an instance of this Tuple class. The dumpheap command performs a substring search, so we'll do some post-processing using regular expressions.

two。 This gives us the MT of the tuple class we actually want to study.

3. Run it again using the MT as a filter! Dumpheap

Now we can explore one of the nodes. It has a m_key that we can study in depth.

Almost! Let's extract two projects from those result keys and generate a beautiful PowerShell object:

This is a script that packages all of this into functions.

Function Get-ScriptBlockCache

{

$nodeType = dbg! dumpheap-type ConcurrentDictionary |

Select-String 'ConcurrentDictionary.Node.Tuple.String.String.] $'

$nodeMT = $nodeType | ConvertFrom-String | Foreach-Object P1

$nodeAddresses = dbg! dumpheap-mt $nodeMT-short

$keys = $nodeAddresses |% {dbg! do $_} | Select-String m_key

$keyAddresses = $keys | ConvertFrom-String | Foreach-Object P7

Foreach ($keyAddress in $keyAddresses) {

$keyObject = dbg! do $keyAddress

$item1 = $keyObject | Select-String m_Item1 | ConvertFrom-String |% P7

$string1 = dbg! do $item1 | Select-String 'String:\ s + (.)' |% {$_ .Matches.groups [1] .value}

$item2 = $keyObject | Select-String mItem2 | ConvertFrom-String |% P7

$string2 = dbg! do $item2 | Select-String 'String:\ s + (. *)' |% {$.Matches.groups [1] .value}

[PSCustomObject] @ {Path = $string1; Content = $string2}

}

} this is the answer to the question about extracting the content of the script executed from the PowerShell memory dump. I hope the above content can be of some help to you. If you still have a lot of doubts to be solved, you can follow the industry information channel for more related knowledge.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report