top | item 37491862

Any sufficiently advanced uninstaller is indistinguishable from malware

887 points| mycall | 2 years ago |devblogs.microsoft.com | reply

510 comments

order
[+] 8organicbits|2 years ago|reply
Here's the codeproject link the code came from.

https://www.codeproject.com/Articles/17052/Self-Deleting-Exe...

> Whether they follow the licensing terms for that code I do not know.

I'm guessing they didn't ship the binary with a link pointing back to this page?

These's also another codeproject example that uses a bat file, which is fairly similar to the recommendation in the post. I guess that's the better example.

https://www.codeproject.com/Articles/4027/Writing-a-self-des...

[+] xg15|2 years ago|reply
At least the author seems to agree with Raymond Chan on the similarities between his approach and malware...

> shellcode is the technical term (in security circles) for binary machine code that is typically used in exploits as the payload. Here's a quick and dirty way of generating the shellcode from the obj file generated when you compile your source files. In our case, we are interested in whipping the shellcode up for the remote_thread routine. Here's what you've got to do:

The whole article has the vibes of some questionable DIY blog along the lines of "Your house is infested by vermin? Here is an easy way to get rid of them using a small, homebuilt neutron bomb!"

[+] taway1237|2 years ago|reply
Funnily enough, real malware does this correctly. Usually by just ShellExecing "ping -n 3 127.0.0.1 >nul" followed by "del" - no temporary file needed.
[+] sim7c00|2 years ago|reply
The author says the binary looks like malware because it self-deletes, sleeps and touches this uninstaller thing. But the script he proposes, which would be triggered by this same thing, does the same. I am ignoring the injection thing since he guesses at it (likely correct) and also because, lots of things inject into processes without being malware. (monitoring stuff like AV etc.) Additionally, binaries which terminate with a run some script via a scripthost... this could just as well be some malware? (stage1 malware downloads script, runs it via scripthost?)

my question(s): How is the proposed solution better than the original thing? Isn't this a case of using bad heuristics to determine maliciousness?

In the end, he goes a bit further, and sees its non-malicious. So, with a more elaborate rule or heuristic, wouldn't it be clear its not malicious?

[+] blackpill0w|2 years ago|reply
Why do Windows programs need special installers/uninstallers? Why isn't this handled by Windows itself?
[+] EvanAnderson|2 years ago|reply
Windows has had an installer as an OS component since the late 90s (called Windows Installer). As a sysadmin I'd prefer apps use it. Many application developers do not. It's maddening. (Doubly so when Microsoft themselves don't use it-- newer versions of Office, Teams, etc. Microsoft suffers from too much NIH.)

I get unattended installs and uninstalls "for free" when well-behaved applications use Windows Installer. Patching is included, too. Customizing installations is fairly straightforward.

On the developer side it has historically used a very quirky proprietary file format (MSI) with a fairly steep learning curve and a ton of "tribal knowledge" required to make it work for all but the most trivial cases. (Though, to be fair, most installs are the trivial case-- copy some files, throw some stuff into the registry, make some shortcuts.)

Worse, it allows for arbitrary code execution ("Custom Actions"), at which point all bets are off re: unattended installs, removal, etc. Some Windows Installer packages are just "wrapped" EXEs (Google Chrome, for example).

I've packaged a ton of 3rd party software as Windows Installer packages. It's an ugly system with lots of warts and legacy crap, but if you need to load an application on a large number of Windows PCs reliably unattended it's decently fit for purpose.

There is reasonable free and libre tooling to generate MSI packages from plain text source (the WiX toolkit) and it can be used in a CI pipeline.

[+] highwaylights|2 years ago|reply
I don't think any major desktop OS handles this well.

I suspect the final form for software installation is probably where iOS and Android are going in the EU, where there's a single means of installing software to the device so that everything can be sandboxed properly, but the acquisition/update process can be pointed to a URL/Store that the user has pre-approved.

macOS comes pretty close to what I'd ideally want in an OS with regards to installation - independent packages that are certified/notarised, but I'd like to see the OS allow for user-specified authorities beyond just Apple. That being said, I'm not sure I'd ever use them as it's part of what I'm paying Apple for, I'm really thinking more of Linux there.

A kind of flatpak/snap approach, but that has signing of the package and centralised management of the permissions for the sandbox at an OS level would be ideal in my view. That way it's still free-as-in-speech as the user can specify which notarisation authority to use (or none at all).

I really don't understand why seperate programs are handling removing their mother program in 2023, that's registry spaghetti messy.

[+] BoppreH|2 years ago|reply
How could Windows handle it by itself?

If it provides a framework for installers/uninstallers, it'll be fighting the inertia of decades of legacy software, programmer habits, and old tutorials.

If it tracks file ownership by program, it might accidentally delete user files. How would it differentiate between a VSCode extension that should be uninstalled, and a binary compiled with VSCode for a user project? A false positive could be catastrophic.

If it restricts what programs can do to accurately track file ownership, you end up with Android. Which is fantastic for security, but is a royal pain in the ass for all parties:

- The app developers have to jump through hoops for the simplest actions, and rewrite most of their code in the new style.

- The operating system has to implement a ton of scaffolding, like permissions-restricted file pickers and ways to hand off "intents" between applications.

- The user is faced with confusing dialogs, and software with seemingly arbitrary limitations.

In the age of shared runtimes, auto-updaters, extension marketplaces, and JIT compilers, managing installed applications is harder than ever.

Edit: the answer above applies only to Windows, because of its baggage. Linux'es are in a much better position, for example, though their solution is still not perfect.

[+] daemin|2 years ago|reply
It allows you to install applications from any source, not only the official store.

It allows for a variety of installers to exist with different features for different use cases.

It allows you to install the application in any location you choose.

It allows for portable installations and to run software just copied from other sources.

[+] mike_hearn|2 years ago|reply
It is, these days. Windows 10 onwards has a native package format called MSIX that somewhat resembles packages on Linux. They're special zips containing an XML file that declares how the software should be integrated into the OS (start menu, commands on the PATH, file associations etc). Windows takes care of installation, update and uninstallation.

The system is great, in theory. In practice adoption has been held back by the fact that it was originally only for UWP apps which almost nobody writes, and also only for the MS Store. These days you can use it for Win32 apps outside the store but then you will hit bugs in Windows. And packages must be signed.

Still, the feature set is pretty great if you can make it work. For example you can get Chrome-style updates where Windows will keep the app fresh in the background even if it's not running. And it will share files on disk between apps if they're the same, avoid downloading them, do delta updates and more. It also tracks all the files your app writes to disk outside of the user's home directory so they can be cleanly uninstalled, without needing any custom uninstaller logic.

One interesting aspect of the format is that because it's a "special" (read: weird) kind of zip, you can make them on non-Windows platforms. Not using any normal zip tool of course, oh no, that would be too easy. You can only extract them using normal zip tools. But if you write your own zip library you can create them.

A couple of years ago I sat down to write a tool that would let anyone ship apps to Win/Mac/Linux in one command from whatever OS they liked, no harder than copying a website to a server. I learned about MSIX and decided to make this package format. It took us a while to work around all the weird bugs in Windows that only show up on some machines and not others for no explicable reason, but it's stable now and it works pretty well. For example you can take some HTML and JS files, write a 5 line config file pointing at those files, run one command and now you have a download page pointing to fully signed (or self signed) self-updating Windows, Mac and Linux Electron app. Or a JVM app. Or a Flutter app. Or any kind of app, really! Also IT departments love it because, well, it's a real package format and not an installer.

Writing more about this tech has been on my todo list for a while, but I have now published something about the delta update scheme it uses which is based on block maps, it's somewhat unusual (a bit Flatpak like):

https://hydraulic.dev/blog/20-deltas-diffed.html

The tool is free to download, and free for open source projects if anyone is wanting to ship stuff to Windows without installers:

https://conveyor.hydraulic.dev/

[+] GuB-42|2 years ago|reply
Besides the "special uninstaller" thing. One of the things I hate the most with Windows filesystem management compared to Unix-like OSes.

On Windows, opening a file locks it. So you can't delete a program that is running, you will get an error. It means of course that an executable can't delete itself without resorting to ugly tricks like the one mentioned in the article. That's also why you get all these annoying "in use" popups.

On Unix, files (more precisely: directory entries) are just reference-counted pointers to the actual data (inode on Linux), removing a file is never a problem: remove the pointer, decrement the reference counter. If the file wasn't in use or referenced from elsewhere, the counter will go to zero and the actual data will be deleted. If the file is in use, for example because it is an executable that is running, the file will disappear from the directory, but the data will only be deleted when it stops being in use, in this case, when the executable process terminates. So you can write your uninstaller in the most straightforward way possible and it will do as expected.

[+] tetris11|2 years ago|reply
One thing I like about Linux package managers is that you can query any file to see which package owns it. How does Windows not track this?
[+] gwbas1c|2 years ago|reply
> Why do Windows programs need special installers/uninstallers?

This is supposed to happen using MSI-based installers. It's a windows component.

> Why isn't this handled by Windows itself?

Now, here's where things get tricky.

In the article, the issue is an explorer plugin. MSI is notoriously buggy with installing and uninstalling explorer plugins. If you don't jump through hoops, your installer will have a bug where it prompts the user to close Explorer.exe.

I know because I shipped a product with an explorer plugin. The installer was always a thorn in our side; and the workarounds, ect, that we had to do to install / uninstall / delete our plugin were more complicated than the plugin itself.

[+] NotYourLawyer|2 years ago|reply
When the subject is Windows, and the question includes a “why,” the answer is always “for historical reasons.”
[+] tsukikage|2 years ago|reply
It's hardly specific to Windows. All the major Linux distros have excellent package management systems, and yet many, many packages and applications choose to ignore these in favour of party solutions, scripts, or even curl https://not-malware.trustme.lol | sudo bash style hodgepodge.
[+] turndown|2 years ago|reply
I had never heard of detours before, but I guess it isn’t any different that a good old fashioned LD_PRELOAD
[+] kevingadd|2 years ago|reply
it's a little more general, I think, since one common use case for it is to use it on your own process in order to intercept calls to stdlib/OS code from libraries you don't control.

For example, in the bad old days I used detours to virtualize the windows registry so that I could do "fake installs" of COM components inside of a VB6 app, allowing it to run without an install and without administrator permissions. This worked by detouring all the Win32 registry APIs, which was sufficient to intercept registry accesses performed by the COM infrastructure.

[+] sim-|2 years ago|reply
Imagine if Windows just allowed DeleteFile() even if the file was open, like unlink() on almost any other OS...
[+] tgtweak|2 years ago|reply
Dropping wscripts is a good way to get malware profiled too, and no way to code sign it or verify it's integrity before executing.
[+] readyplayernull|2 years ago|reply
Reminds me of a simple app I made for Windows 95/98 to add every directory including System32 to the uninstallers' lists. No AV, neither Norton or McAfee, saw that timebomb comming. Good times.
[+] fennecfoxy|2 years ago|reply
Well maybe if Windows applications were packaged similar to MacOS (one of the few things I like) with the application data and user data for the application in 2 folders then it wouldn't be such an issue.

Most Windows apps sit under program files, some sit directly on drive root. But all spray configuration/user data files for themselves all over the damn place, requiring unique uninstallers.

MS, build app install/uninstall into Windows directly...

[+] wolfendin|2 years ago|reply
This tracks, I’ve flagged the nvidia uninstall for hours work because it code injected and flagged behavioral consistent with malware
[+] bdamm|2 years ago|reply
And today I learned that Windows supports running Javascript as shell script. huh
[+] technion|2 years ago|reply
Malware delivered as an email with a link to a zip file containing a .js file is one of the most common methods of delivery, right behind word macros. The "map the .js extension to notepad.exe" is a common security trick with a measurable, immediate drop in malware in large orgs. You can deploy it via GPO or InTune.

Personal promotion, I built this as a better alternative:

https://github.com/technion/open_safety

Note the built in .js parser hasn't basically ever updated, if you're writing for this you're writing like you're targetting IE5.

[+] Roark66|2 years ago|reply
It is very common for malware to contain java script payloads that try to obfuscate themselves like like this:

Seemingly_random_code(seemingly_random_string)

The seemingly_random_code decompresses/decodes whatever is in the seemingly_random_string and hands over control to it. Interestingly the decoded code is another version of the same with different code and string. This goes on for ~100 layers deep then at the end it just downloads and executes some file from the net.

[+] mark_and_sweep|2 years ago|reply
Been using this for years. Mostly really useful. Sometimes tricky to get right since the available APIs are semi-well documented and it's JScript, which is some sort of old Internet Explorer-ish version of JavaScript.

By the way, there are also HTAs, which are Microsoft HTML Applications. You can create a simple double-clickable GUI with these using only HTML and JScript.

[+] dolmen|2 years ago|reply
This feature has existed for more than 25 years.

My concern is more than Raymond Chen suggest that using it is still the recommended way. So much malware came through WScript.

[+] jraph|2 years ago|reply
Yes, the same way one could write VBS (Visual Basic Script).

I think Windows 98 already had this ability. Possibly Windows 95 as well. It's a variant of the language called JScript, which is what was used in old versions of IE too.

[+] parasti|2 years ago|reply
It's technically JScript.
[+] drbig|2 years ago|reply
I still long for the approach many software used on the AmigaOS - the app is a folder, the folder has the main exec and any assets it needs (libraries, images, etc.) and documentation and... That's it.

Install? Copy the directory to where you like. Uninstall? Delete the directory.

And if you wish you could keep any files used/generated with such an app in the same folder, making it 100% self-contained.

I remember being rather grossed out when I learnt Windows has "a registry" (that was a long time ago). "Why would you have a global registry? Whatever preferences a piece of software has they should live where the exe is".

(and yes, I am aware AmigaOS had an installer and dir structure not that unlike of Unix, with `sys:`, `devs:` and so on)

[+] ryandrake|2 years ago|reply
To be fair, Windows applications can be designed to be installable this way: a single executable, with everything it needs sitting next to it in the folder. Even better, a single executable with no other dependent files at all! Lots of little utilities used to be distributed this way. But many developers deliberately choose to structure their monster such that it needs to spread its tentacles all over the filesystem for it to work.

And for legacy/backward compatibility reasons, once MS allowed this behavior to go unchecked, there was no way to put the genie back in the bottle and stop it, without giving up backward compatibility. It didn't help that Microsoft software tended to be the "tentacle" kind as well.

[+] robinsonb5|2 years ago|reply
I still love most aspects of the Amiga user experience, but a lot of Amiga applications would need libraries installed to Libs: and deleting the application's "drawer" would leave those libraries behind. (Having said that, by default libs: is assigned to sys:libs but you could assign extra targets, so that libraries would be sought from application-specific directories.)

Also, it suffers from the same problem as Windows here, in that you can't delete a file or directory which is currently open. The executable itself wouldn't be open after launch is complete (with the possible exception of overlay executables, but they were pretty rare) but the directory would be locked for as long as it was the program's current directory. If a subdirectory with app-specific libraries was assigned to Libs: that would also prevent deletion.

[+] realslimjd|2 years ago|reply
This is how a lot of apps on MacOS still work.
[+] unnouinceput|2 years ago|reply
Does that means the corollary: "Any sufficiently advanced malware is indistinguishable from an uninstaller" would be true as well?

I mean can you write a simulation of an uninstaller to create havoc on target's system and still remain "the good guy, the OS is at fault" type of situation when you write a malware?

[+] darklycan51|2 years ago|reply
I had an old hacky community program basically ruin my Windows install so I agree, it was a BLP viewer it automatically added previews on windows explorer, but if yo u removed a file while previewing a blp it'd crash your explorer and all your open tabs would close, really annoying.
[+] WeylandYutani|2 years ago|reply
I've seen Malwarebytes flag uninstallers a few times.
[+] el_benhameen|2 years ago|reply
Any time I see a Microsoft link with a cheeky title, I assume it’s a great Raymond Chen deep dive. Haven’t been wrong yet!
[+] dataflow|2 years ago|reply
You can't rely on JScript being present unfortunately. It can be disabled.
[+] doloputer|2 years ago|reply
It probably should be disabled on most machines. The last time I heard about it was @swiftonsecurity complaining about it being an easily overlooked malware vector.

I'd be surprised if this capability is only available from jscript though. (and sad, I don't think jscript has been updated in years)

[+] OtomotO|2 years ago|reply
Can't spell unfortunately without fortunately.
[+] senectus1|2 years ago|reply
funny because any application without a sufficiently advanced uninstaller should also be considered malware.
[+] terabytest|2 years ago|reply
I’m probably missing something but why is an uninstaller allowed to inject code into explorer.exe? That seems like a massive security flaw?