Getting Off the Windows Defender "No-Fly" list
When an app is falsely accused of being a virus, it will stop at nothing to clear its besmirched name
Recently, it was brought to my attention that Windows Defender was mistaking some jDeploy apps for a virus. If you tried to download an app on Windows, using Chrome, it would fail with the message “Download failed: Virus Detected”, or something along those lines. In fact, even when I tried to use the command-line install option, which uses cURL to download the installer, it would refuse to launch, saying that I did not have permission to perform that function.
I was embarrassed, frustrated, and angry (at Defender) that it was accusing my app, which is most certainly NOT a virus, of being a virus.
Initially, I thought that the answer was to start signing the installer bundle using a code signing certificate, so I ordered a certificate and started to develop the infrastructure to perform the signing. Unfortunately, the process of verifying my company’s address was proving to be difficult. Long story short, the code-signing authority relies on the Brad & Dunstreet directory as their official source of company records, and they have an old address on file - and it is frustratingly difficult to prove a company address has changed.
Investigating the Cause of the False Accusation
So, in the mean time, I decided to investigate the the alternative hypothesis: That there was something about the executable that Windows Defender didn’t like, and if I could identify it, I could fix it.
I used this site to analyze my exe file and try to detect a virus.
Interestingly, it claimed to have found a virus, but unlike Windows Defender and Chrome, it provided some details to justify its accusation.
It’s complaint was that the exe had base64-encoded content appended to the end of it, a feature shared by many viruses. Apparently viruses often add some sort of payload to their end of an exe, that they deliver. I don’t know. If you ask me, that’s a pretty weak justification for such a damning accusation.
It’s not what it looks like! Really it’s not!
A little bit of background on the jDeploy launcher. My goal, in building the launcher, was to create a small native binary that would launch a Java app, and it was important that it could be precompiled and reused in any Java app without having to recompile. This was a key feature to allow me to deploy on any platform from any other platform, since you didn’t have to compile any native code.
Of course, for this to work, the launcher would need to be able to load details about the current app (e.g. what Java class it should run as the main method) from a data file. So I created a minimal XML file format to store the details that the launcher needs to launch the app at hand. On Mac, since applications are directories, I simply placed this XML file inside the app bundle in a well-known location.
On Windows and Linux, however, applications are just single binary files, so it was more difficult. Yes, I could have just placed the XML file in the same directory as the exe file, but this felt clunky. What if, for example, the user copied the exe to a different location, but failed to also copy the XML file. Then the app wouldn’t work. The only acceptable solution, then, would be to embed the XML into the app binary. Since the launcher exe is pre-compiled, I would either need to embed it at the beginning or end of the launcher, and placing it at the beginning would yield a malformed exe, so I was left with only one option: Appending the XML file to the end of the exe.
When the launcher loads, it splices the XML content out of itself, and parses it. When I first got this working, I was mighty pleased with my cleverness. Unfortunately, this clever little trick had resulted in my apps being flagged by a few virus detection algorithms.
In light of this, I soberly considered my options. The way I saw it, I had three options:
Hope that code-signing would cause the virus scanners to ignore this breach of protocol.
Pull the XML out of the exe, and find another way to feed this metadata to the launcher.
Encode the XML to placate the algorithm.
I chose door number three.
The virus scanners were complaining about base64 content, so I figured, why not just encode the XML into binary? It might just work.
The Fix
The only thing I needed to decide was what type of encoding to use. I considered using a symmetric encryption algorithm using some encryption key, as that would result in binary gibberish that couldn’t possible be confused with base64. But this would have been overkill, and might be a bit tricky to get right, since the encoding would be done in both Java (since the bundle builder is written in Java) and Go (since the launcher is written in Go).
I preferred something simple, and the solution I chose was to “invert” each byte of the XML (i.e. b’ := 255 - b
). This was cheap and easy to both encode and decode, and the result, importantly, would not be base64.
Verifying the Fix
After making this change, I ran the new exe file through the virustotal service again, and this time it produced green checkmarks across the board. This was in contrast to the checkered mix of green and red that it produced for the previous, unobfuscated exe.
My initial tests on Windows 10 were promising. Chrome no longer complained about it being a virus, and I was able to run in with only the usual Windows Defender warning about it being from an unknown developer. This will be remedied when I get the code signing plugged in.
I have four windows machines that I routinely test on, and this solution seemed to fix the issue on all but one of them. Most of them required me to restart Chrome before it would allow me to download my installer (after a previous failed download from the old version), but that is all.
Caveat
On one of my Windows machines, however, Windows Defender seems to be holding a grudge against my app. It is still adamant that my app is a virus. I’m fairly certain that it is just “remembering” the old version of the exe and painting my new version with the same poopy brush, but this is difficult to prove.
If you have a Windows machine, I’d appreciate you trying to install the test app (a deployment of the JavaFX Ensemble app), and let me know if it lets you install and run it. It’s not a virus, I swear!
"Windows protected your PC"
Any app that uses jDeploy prompt this while trying to run the installer. Surely enough, that's the greatest issue with jDeploy. No one would continue the installation of an app after being notified this app is potentialy a virus.