Under Review

Live Discover Query - Software version check

  REVIEWED by Sophos 

One thing I have found helpful with osquery is the flexibility it provides for what sometimes seems an obvious task such as the version of a piece of software.

Take for example the client software of Zoom given it's pretty popular right now.  How hard can it be to get the version, well quite easy but how accurate do you want to be?

If you look at the release notes for Zoom client on Windows - https://support.zoom.us/hc/en-us/articles/201361953 you see at the time of writing:

  • Current version: April 12, 2020 Version 4.6.11 (20559.0413)
  • Previous version: April 7, 2020 version 4.6.10 (20033.0407)
  • earlier than that: April 2, 2020 Version 4.6.9 (19253.0401)

Clearly, the full version to 2 decimal points is helpful so where might one get that data from?  Traditionally with software, you have a few options for gathering such information, such as:

  1. Management platform, if one exists.
  2. Client UI.
  3. OS "Uninstall" registry key.
  4. The software has its own custom file/registry values or APIs.
  5. File version information from binaries.

For the most part these are proprietary and no guarantees they will always work or report what you think they might represent. Even then, I suspect for most software the above are probably a mixture of versions down to the build number, component versions, product marketing versions, suite versions etc.

The most reliable interface I believe and least likely to change is probably the classic "Uninstall" key, unless you have a particularly stealthy or portable application.  These are of course:

  • 32-bit software on 64-bit:
    • HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\xxx
  • Native software: 
    • HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\xxx

No Zoom here, ahh, there it is under HKCU, it was installed per user:

  • HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\ZoomUMX

...and the version number stored in "DisplayVersion" is.... 4.6.  Well, that's not very accurate if I'm looking for 4.6.11.

Of course, I knew this would be the case as it's the same source as displayed in Programs and Features (appwiz.cpl).  There is also no broken down separate major, minor, build values for this product which you sometimes get.  Likewise, the "Programs" table of osquery is only going to give us the same simple version string. I.e.:

select name, version, install_location, publisher from Programs where Name = 'Zoom';
| name | version | install_location                        | publisher                       |
| Zoom | 4.6     | C:\Users\jak\AppData\Roaming\Zoom\bin   | Zoom Video Communications, Inc. |

So where to next, the Zoom client UI, tells me I have: "Version: 4.6.11 (20559.0413)" but where can I get that from for our Central report?

The main exe file version maybe?  Typically the main executables are re-built for each software update (again an assumption here) but where is it on disk?  How many locations on disk might it be in?

As you've probably seen we have the "install_location" from the "Programs" table so we could use that to join on, for example:

select f.path, f.product_version from file as f where f.path = (select install_location || "\Zoom.exe" as path from programs where name ='Zoom');

| path                                             | product_version |
| C:\Users\jak\AppData\Roaming\Zoom\bin\Zoom.exe   | 4.6.20559.413   |

One other option we have would be to use the "processes" table to get the path to Zoom.exe.  

select f.path, f.product_version from file as f where f.path = (select path from processes where name like '%Zoom.exe');

| path                                             | product_version |
| C:\Users\jak\AppData\Roaming\Zoom\bin\Zoom.exe   | 4.6.20559.413   |

So this will do, but then this only works if the software is running as we're getting the path to the exe from the "processes" table before then using the "file" table to get the version info.  I could perhaps go straight to the "file" table but I might be guessing where it is or using lots of IN or OR statements so this is one option. 

Then there is the additional concerns regarding modules actually in use?  Just because an application has updated and probably updated the 'uninstall' key values with the latest version number; although it perhaps doesn't help here as we have seen, is the new software running or has it been deferred to reboot or the requires the process to restart?

The Zoom Outlook plugin, for example, loads at least 6 modules in Outlook.exe on my computer as of now.  If I need to be sure that Outlook is running with the latest version of say ZoomOutlookPlugin.DLL, how might I be able to do that?  Maybe the following could answer that:

select path, product_version from file where path = (select path from process_memory_map where path like '%ZoomOutlookPlugin.dll' and pid = (select pid from processes where name = 'OUTLOOK.EXE') limit 1);
| path                                                                  | product_version |
| C:\Program Files (x86)\Zoom\Zoom Outlook Plugin\ZoomOutlookPlugin.dll | 4.8.20547.412   |

Does the file version on disk always prove it's loaded?  Probably a question for another day.

Then there is always the "hash" table of osquery we could lean on to check if you have a reference sha-256 for the expected file!

Maybe this sort of brain dump is helpful for someone, it probably raises more questions than answers but it shows how even a simple question about the version of software can get very nuanced and having a tool that's flexible may help.  Maybe in the future Zoom will update the DisplayVersion registry key to better reflect the installed version.


  • I took this query and decided to tweak it for those that may want a simple OK/Critical flag over certain applications.  So using your query, adding a simple CASE logic and combining the Variable features we get the below.  A query that can be quickly and repeatably run by simply defining all or a partial application name and EXPECTED version. Tested on Windows. === SELECT name, version, CASE WHEN version > '$$Expected Version$$' THEN 'OK' WHEN version < '$$Expected Version$$' THEN 'CRITICAL' end Patch_Level FROM programs WHERE name like '%$$App in Question$$%' ORDER BY version ASC; ===