Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature Request]: replace invisible.vbs with run-hidden #465

Open
andreasbrett opened this issue Nov 2, 2023 · 43 comments
Open

[Feature Request]: replace invisible.vbs with run-hidden #465

andreasbrett opened this issue Nov 2, 2023 · 43 comments
Labels
enhancement New feature or request

Comments

@andreasbrett
Copy link
Contributor

The request

Microsoft officially announced last month that VBS will be deprecated in the future. No deadlines or time frames were mentioned. Nevertheless since invisible.vbs is merely used for spawning a powershell.exe process in a hidden fashion, it should be easy to migrate to another workaround before Microsoft decides to kill off VBS.

PowerShell/PowerShell#3028 mentions a C++ implementation. You can find it here: https://github.com/stax76/run-hidden. It would be a great drop-in replacement. License allows deploying WAU with the run-hidden binary. Of course using an external binary might trigger some AV/EDR tools and is worse than using embedded OS tools. VirusTotal result is 1/72.

Background info on VBS deprecation:
https://isvbscriptdead.com/
https://learn.microsoft.com/en-us/windows/whats-new/deprecated-features

Is your feature request related to a problem?

No response

Additional information

No response

@andreasbrett andreasbrett added the enhancement New feature or request label Nov 2, 2023
@Romanitho
Copy link
Owner

Thanks for spotting that point. Indeed, we need to think about the replacement of this vbs.

@KnifMelti
Copy link
Contributor

In my work I belong to an organization that has an exe replacement, but that I can't share - VirusTotal result is 0/72 (not at work now 😉)

@AndrewDemski-ad-gmail-com
Copy link
Contributor

We could write our own exe in C# that would be mind-dumbing class.

using System.Diagnostics;

namespace InvisiLauncher
{
  internal static class Program
  {
    [STAThread]
    static void Main(string[] args)
    {
      NotifyIcon icon = new NotifyIcon();
      icon.Icon = SystemIcons.Question;
      icon.Click += delegate { MessageBox.Show("Bye!","how about that?", MessageBoxButtons.OK, MessageBoxIcon.Question); icon.Visible = true; Application.Exit(); };
      icon.Visible = true;
      if (args.Length == 1)
      {
        var scriptArguments = "-ExecutionPolicy Bypass -File \"" + args[0] + "\"";
        var processStartInfo = new ProcessStartInfo("powershell.exe", scriptArguments);
        processStartInfo.RedirectStandardOutput = true;
        processStartInfo.RedirectStandardError = true;
        using var process = new Process();
        process.StartInfo = processStartInfo;
        process.Start();
        string output = process.StandardOutput.ReadToEnd();
        string error = process.StandardError.ReadToEnd();
      }
      Application.Run();
    }
  }
}

or..
we could tell PowerShell to hide own window.. but I would need some time digging up the old scripts repo.

@AndrewDemski-ad-gmail-com
Copy link
Contributor

This PowerShell script hides own window

enum WindowStates {
              FORCEMINIMIZE = 11
              HIDE = 0
              MAXIMIZE = 3
              MINIMIZE = 6
              RESTORE = 9
              SHOW = 5
              SHOWDEFAULT = 10
              SHOWMAXIMIZED = 3
              SHOWMINIMIZED = 2
              SHOWMINNOACTIVE = 7
              SHOWNA = 8
              SHOWNOACTIVATE = 4
              SHOWNORMAL = 1
          }
$Win32ShowWindowAsync = Add-Type -MemberDefinition @'
[DllImport("user32.dll")]
public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool SetForegroundWindow(IntPtr hWnd);
'@ -Name 'Win32ShowWindowAsync' -Namespace Win32Functions -PassThru

$process = [System.Diagnostics.Process]::GetCurrentProcess()
$id = $process.Id
$myHandle = $process.MainWindowHandle

$Win32ShowWindowAsync::ShowWindowAsync($myHandle, [WindowStates]::MINIMIZE) | Out-Null

@Romanitho
Copy link
Owner

Our own EXE would not be signed?
If a full PS solution can be implement, I'd go for that. But I don't know 😅

@AndrewDemski-ad-gmail-com
Copy link
Contributor

@Romanitho
Copy link
Owner

It seems to be the top priority topic to work on...

@AndrewDemski-ad-gmail-com
Copy link
Contributor

It seems to be the top priority topic to work on...

Very well. I'll check the latest release

@AndrewDemski-ad-gmail-com
Copy link
Contributor

digging..

Already something useful came from that excavation operation.

Piece of code which could make User experience a bit less stressful.

UserNotificationState (MSDN) which will allow User-side deployments to wait for actual user if interaction of manual postpones will be necessary.

findings

Current version of PDT launcher (v.1.1.1.1) is basically a C# equivalent of current invisible.vbs script :)
image

All paths are semi-hardcoded, if we allow CPU arch detection to let it be called a dynamic setting.
Later is the same process invocation as in my previous example.
image

The verdict

We do not need 3rd party binaries, we can write our own.

@AndrewDemski-ad-gmail-com
Copy link
Contributor

There is a 3rd option, AutoHotkey.
There are examples how to do that.. F.ex. AHK to run PowerShell command

In our case we would need to define powershell.exe with full path rather than letting the $env:path variable and binary search order picking something malicious with matching exe name from any path higher on the list.

@AndrewDemski-ad-gmail-com
Copy link
Contributor

4th option would be calling PowerShell directly from C# using System.Management.Automation Namespace, no exe file paths would be required, all parameters could be fed from C# app command line.

docs
examples

@Romanitho
Copy link
Owner

Your invest is really appreciated 🙂
To be honest, I think we need something as simple as possible.
I don't know what could be the best option.

@KnifMelti
Copy link
Contributor

KnifMelti commented Dec 7, 2023

All of this because the flawed behavior of Powershell -WindowsStyle Hidden 😁with a brief flashing of a window...
...https://stackoverflow.com/questions/1802127/how-to-run-a-powershell-script-without-displaying-a-window
image

[EDIT] Still flashes...

@AndrewDemski-ad-gmail-com
Copy link
Contributor

All of this because the flawed behavior of Powershell -WindowsStyle Hidden 😁with a brief flashing of a window...
[EDIT] Still flashes...

I'd love to see MS adding powershellw.exe similar to java.exe/javaw.exe
But before that happens, I'd pick option #1(C# launcher via filepath) or #4(C# launcher via API) and use it for now.

How bad could it be if even Snyk says its OK?
image

@Romanitho
Copy link
Owner

If you know what to do, let's try then... 😅

@KnifMelti
Copy link
Contributor

The only thing left know is a coding certificate...

@KnifMelti
Copy link
Contributor

The only thing left know is a coding certificate...

Ah, run-hidden!

@Romanitho
Copy link
Owner

run-hidden.exe seems to be a good option too

@AndrewDemski-ad-gmail-com
Copy link
Contributor

Good evening.
It's been a while and after some brain grinding I think that whoever cares about signing the exe/assembly/code probably has access to Active Directory Certificate Services in their company and could sign anything using their internal code signing certs. Same with AppLocker, all they would ever need is a checksum.
Buying code signing cert is a waste of resource.
Keeping even part of that info in a public github repo - pure nightmare.
using self-signed code proves only that file was not modified in the transfer.
I even considered option of sending "launcher.cs" file and using CSC.exe on the target machine to compile it :)
image

TL;DR: The only issues related to "Custom PowerShell Startup in Window Mode" will only affect companies that are more than qualified to deal with this illusory problem.

This project is public, everyone can read what is inside, calling it unsafe only because someone did not configure AppLocker/WDAG or did not sign the code during on-boarding is both a rude jab at the supplier and an indirect confirmation that either the company's IT OPS processes are lame or their employees are not proactive.

@AndrewDemski-ad-gmail-com
Copy link
Contributor

Word of caution, any C# based application which gets into contact with System.Management.Automation bypasses execution policies.
IMHO If we create and decide to ship something like that with WAU, we should have a disclaimer added to the readme file.

@AndrewDemski-ad-gmail-com
Copy link
Contributor

I'd pick option No.1(C# launcher via filepath)

@Romanitho, Guys, how to share that minute C# project with you?
I set it to private and shared gave view perm to you, @Romanitho.
here

@Romanitho
Copy link
Owner

it can be public, no ?

@AndrewDemski-ad-gmail-com
Copy link
Contributor

it can be public, no ?

it could be, but i still feel like it is not "production ready".
There is no compilation workflow in place etc.. I'll need some help with that.

@Romanitho
Copy link
Owner

That's why GitHub is made for, I guess 😜

@AndrewDemski-ad-gmail-com
Copy link
Contributor

Stop teasing me :) I'd like to see that code at least once in the daylight. before I share it with the rest of this planet.
I'll clean that up this week after the PI plannings are done.. and then change the repository visibility to public,

@KnifMelti
Copy link
Contributor

@AndrewDemski-ad-gmail-com
We have another function using WScript.Shell
Sources/WAU/Winget-AutoUpdate/functions/Add-Shortcut.ps1

If that falls under the same category, could you consider building a simular function into your release too?

@AndrewDemski-ad-gmail-com
Copy link
Contributor

@AndrewDemski-ad-gmail-com We have another function using WScript.Shell Sources/WAU/Winget-AutoUpdate/functions/Add-Shortcut.ps1

If that falls under the same category, could you consider building a simular function into your release too?

I am not sure it hat shortcut would ever re-emerge as a problem. If we could just use the built-in cmdlet new-item which has been expanded in PS5.0 with option to create symlinks.

windowless launcher is capable of launching processes with custom args. That means the only difference between LNK and symlink functionalities are eliminated (from our POV/needs)

All it needs is some polishing over this weekend.

@KnifMelti
Copy link
Contributor

KnifMelti commented Dec 15, 2023

That Function in WAU is used to create shortcuts for:

        #Create Shortcuts
        if ($StartMenuShortcut) {
            if (!(Test-Path "${env:ProgramData}\Microsoft\Windows\Start Menu\Programs\Winget-AutoUpdate (WAU)")) {
                New-Item -ItemType Directory -Force -Path "${env:ProgramData}\Microsoft\Windows\Start Menu\Programs\Winget-AutoUpdate (WAU)" | Out-Null
            }
            Add-Shortcut "wscript.exe" "${env:ProgramData}\Microsoft\Windows\Start Menu\Programs\Winget-AutoUpdate (WAU)\WAU - Check for updated Apps.lnk" "`"$($WAUinstallPath)\Invisible.vbs`" `"powershell.exe -NoProfile -ExecutionPolicy Bypass -File `"`"`"$($WAUinstallPath)\user-run.ps1`"`"" "${env:SystemRoot}\System32\shell32.dll,-16739" "Manual start of Winget-AutoUpdate (WAU)..."
            Add-Shortcut "wscript.exe" "${env:ProgramData}\Microsoft\Windows\Start Menu\Programs\Winget-AutoUpdate (WAU)\WAU - Open logs.lnk" "`"$($WAUinstallPath)\Invisible.vbs`" `"powershell.exe -NoProfile -ExecutionPolicy Bypass -File `"`"`"$($WAUinstallPath)\user-run.ps1`" -Logs`"" "${env:SystemRoot}\System32\shell32.dll,-16763" "Open existing WAU logs..."
            Add-Shortcut "wscript.exe" "${env:ProgramData}\Microsoft\Windows\Start Menu\Programs\Winget-AutoUpdate (WAU)\WAU - Web Help.lnk" "`"$($WAUinstallPath)\Invisible.vbs`" `"powershell.exe -NoProfile -ExecutionPolicy Bypass -File `"`"`"$($WAUinstallPath)\user-run.ps1`" -Help`"" "${env:SystemRoot}\System32\shell32.dll,-24" "Help for WAU..."
        }

        if ($DesktopShortcut) {
            Add-Shortcut "wscript.exe" "${env:Public}\Desktop\WAU - Check for updated Apps.lnk" "`"$($WAUinstallPath)\Invisible.vbs`" `"powershell.exe -NoProfile -ExecutionPolicy Bypass -File `"`"`"$($WAUinstallPath)\user-run.ps1`"`"" "${env:SystemRoot}\System32\shell32.dll,-16739" "Manual start of Winget-AutoUpdate (WAU)..."
        }

And the created shortcuts are in fact calling wscript.exe

A New-Item with -ItemType SymbolicLink can't handle (what I know of) all of the $Target, $Shortcut, $Arguments, $Icon, $Description

So, if you could also add the possibility to pass $Icon, $Description to your solution (and save it as a shortcut) we would be all good

[EDIT]
But, if $WScriptShell = New-Object -ComObject WScript.Shell from PowerShell isn't removed we could just use your solution to replace wscript.exe in the shortcuts!

@KnifMelti
Copy link
Contributor

All it needs is some polishing over this weekend.

Hello (tried to answer in your invitation but your mail account seems to be flooded)!
As I interpret the code it isn't restricted to just running PS silent. .
By editing the config file it can call and run anything silent!
Great 👍

@AndrewDemski-ad-gmail-com
Copy link
Contributor

By editing the config file it can call and run anything silent!

That was precisely my point, with all configuration pushed outside of LNK, functional differences between SymLink and ms-shllink will be negligible.

I made that repository public.
I will finish the code after Xmass

@AndrewDemski-ad-gmail-com
Copy link
Contributor

#not-stale-yet.
Functionality is there, but part where github does the compilation for PR is still missing.

@AndrewDemski-ad-gmail-com
Copy link
Contributor

image

With great please I'd like to announce that launcher is ready :)

Releases are automated, more details there and there:

Copy link
Contributor

This issue is stale because it has been open for 30 days with no activity.

@github-actions github-actions bot added the stale label Feb 17, 2024
@Romanitho
Copy link
Owner

up

@github-actions github-actions bot removed the stale label Feb 20, 2024
Copy link
Contributor

This issue is stale because it has been open for 30 days with no activity.

@github-actions github-actions bot added the stale label Mar 21, 2024
@andreasbrett
Copy link
Contributor Author

How do we proceed from here? We'd need a way to configure an alternative to invisible.vbs

@KnifMelti
Copy link
Contributor

#465 (comment)

@andreasbrett
Copy link
Contributor Author

#465 (comment)

Invisible.vbs usage is still fixed in WAU. I can not simply replace Invisible.vbs with the binary provided by @AndrewDemski-ad-gmail-com. That's why I ask if WAU will get the necessary changes to use alternatives to Invisible.vbs

@KnifMelti
Copy link
Contributor

I meant that that must be imolemented in WAU @Romanitho

@github-actions github-actions bot removed the stale label Mar 26, 2024
@AndrewDemski-ad-gmail-com
Copy link
Contributor

Sorry for being absent from this discussion for so long (I was moving to a new place).

It would be possible to use either job action with wget to pull the zip with latest binary which is being compiled by github.
The last remaining step would be saving the XML config file to save the whole command line currently invoked by VBScript.

@Romanitho
Copy link
Owner

yes. We need to work on that part. But I'm a bit like @andreasbrett 😅

@colourofsound
Copy link

colourofsound commented Apr 23, 2024

Just another a bump on this - I have Applocker in place in my environment and it really doesn't like VBS scripts running from ProgramData (even if I whitelist that path)

@AndrewDemski-ad-gmail-com
Copy link
Contributor

@colourofsound,
Please do not whitelist paths, use file hashes. that way AppLocker will block any modified scripts.
Someone may replace content of your whitelisted script with something more sinister and there will be..

..trouble!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

5 participants