Nomalua -- GMod/Lua malware scanner (v1.1)

Nomalua v1.10 (released 2015-04-20)

Nomalua is a malware scanner for GMod Lua files. It scans Lua files on the server (including those mounted through Steam Workshop GMA files) and reports on any suspicious code or code patterns that may warrant further invesitgation.

IT IS IMPORTANT to understand that detection by Nomalua does NOT necessarily mean you have a problem – simply that a code construct or pattern exists that meets Nomalua’s critera for reporting. The vast majority of alerts will be false positives. However, when you run an addon you are trusting that author to be a good citizen. Addons can harbor backdoors and other nefarious code. It’s better to trust but verify rather than simply trust blindly. Nomalua allows server administrators to have better insight into what’s running without having to analyze every addon line-by-line. This is especially true as more server administrators use addons through the Steam Workshop, which makes it harder for admins to review code and track updates.

---------- SUPPORT ----------

Visit for downloads, support and release info.

---------- REQUIREMENTS ----------

Nomalua has no requirements.

---------- INSTALLATION ----------

To install Nomalua, simply extract the files from the archive to your garrysmod/addons folder.
When you’ve done this, you should have a file structure like this–

Please note that installation is the same on dedicated servers. Installation requires a server restart.

---------- USAGE ----------

Once installed and the server restarted, you can run the scanner by opening console and issuing the “nomalua_scan” command. If running directly on the server, you should immediately begin to see output (sample below). If running through a client, you must have superadmin priviledges. When running through a client console there may be a delay before output is rendered. Nomalua is rather resource-intensive, so it’s not recommended that you run it when the server is particularly busy.

Nomalua reports back the following (sample):

AUTHENT		gamemodes/jailbreak/gamemode/core/cl_menu_help_options.lua:218          : Excl (STEAM_0:0:19441588) - Lead developer in charge of Jail Break since version 1
NETWORK		addons/hatschat2/lua/hatschat/cl_init.lua:196           		http.Fetch( FUrl, function( body, len, header, code)
BANMGMT		addons/customcommands_onecategory/lua/ulx/modules/sh/cc_util.lua:283	local banip = ulx.command( "Custom", "ulx banip", ulx.banip )
DYNCODE		lua/autorun/luapad.lua:152						RunString(file.Read("luapad/_server_globals.txt", "DATA"));
FILESYS		addons/customcommands_onecategory/lua/ulx/modules/sh/cc_util.lua:909	file.Delete( "watchlist/" .. id .. ".txt" )

The first column is the detection group. Currently, Nomalua detects dynamic code (code that executes dynamically, using compilestring, etc), authentication checks (references to Steam IDs), network activity (calls to http.Post and Fetch), ban related items (changes in ban status) and file system calls (file deletions).

The second column points to the file and line number of the detection. Note that if this addon is contained within in a GMA, you will need to manually decompress the .gma file in order to view the file directly.

The third column shows the line itself, with the detection phrase highlighted in yellow.

---------- CONFIGURATION ----------

Whitelisting (beta): Whitelisting is currently managed in the sv_nomalua_whitelist.lua file, specifically via calls to NOMALUA.AddWhiteListElement, which takes 3 parameters. The first parameter in the call is a Lua pattern (see for a tutorial in Lua patterns). The second parameter is the line number (0 to match all), and the third is the detection group ("*" to match all). Whitelisting is currently Beta and will be moved to a proper data file in a future release.

Whitelist samples:

	NOMALUA.AddWhiteListElement("addons/nomalua/lua/sv_nomalua.lua", 0, "*")   			-- prevents Nomalua from reporting on its own pattern checks
	NOMALUA.AddWhiteListElement("addons/cac%-release%-.*.lua", 0, "*")					-- ignores Cake Anti-cheat
	NOMALUA.AddWhiteListElement("addons/ulib/lua/ulib/server/player.lua", 0, "BANMGMT")	-- Ignores ban related items in ULib's player.lua

---------- CHANGELOG ----------

v1.10 - (2015-04-20)
* Adjusted directory recursion logic to prepend root search directory
* Added whitelisting and some default whitelist items
* Restructured lua file search so that matching files in addons/<addonname>/lua/… and lua/… purposely collide in storage table (de-dupe)
* Refactored scan to queue output, eliminating need to pass ply var around.

v1.00 - (2015-04-19)
* Initial version

---------- LICENSE ----------

This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License.
To view a copy of this license, visit or send a letter to
Creative Commons
543 Howard Street
5th Floor
San Francisco, California 94105

(what the <censor> does “nomalua” mean? No-Mal-Lua. Get it? Don’t worry - the code is better than the name. :slight_smile: )



–[] RunString(file.Read(“rip.txt”))

Thanks. RunString (in verbose form) would get caught. I’m catching hex notation in 0xAA format, but not in escaped ascii values – I’ll add that as well.

I’ve shied away from catching file.Read (for now) simply because of the bazillions of false positives it would generate. I didn’t want people to get overwhelmed before I had a chance to build out the default whitelist entries as well as build a “risk factor” piece. But I’ll definitely be adding it. Thanks.

Why not search for _G

Why don’t you just detour all of the relevant functions? Where is the download link even?


I’m struggling to find a download link too.

Edit: You must log in to the ulyssesmod board to see/download attachments.


[editline]20th April 2015[/editline]

This should be on github.

Also I think this should be a stand-alone program.

local G = getfenv()
local G = {}; package.seeall( G )
local G = baseclass
local G = cookie
local G = weapons
local G = team
local G = properties
local G = constraint



G[ "R" .. "unString" ]( ... )

Good luck with that.


Make getfenv() detectable too.

I guess the search code could ignore … ’ " [] patterns, but then you’d not be able to detect stuff like.
local part1 = “Run”
local part2 = “String”
Gpart1 … part2

Lua just too damn flexible.

I’ll get there. This is all of < 24 hours old, from idea to first light. I figured the Ulysses link might be a hassle for some, but I also didn’t want to maintain two downloads at the moment. Will set up a Github repo shortly.

[editline]21st April 2015[/editline]

This is currently an out-of-band, on-demand scanner, not something that’s running real-time. Detouring the functions would change the paradigm. But that might be part of the evolution…

I’m not sure but I think lua preprocesses stuff like that (if they are constants), so it might be possible to do a search of the bytecode of a chunk.


I just went through the source and it seems this doesn’t detect obfuscated code at all other than bytecode.

I know, and that’s part of the problem. I’m not saying this is useless, but if you want to cover the broadest spectrum, you need to load the scripts and detour the functions. As said before, Lua is too flexible to simply do pattern matching.

Here’s an idea. Compile all the scripts you want to scan and run them in a sandbox environment that and see if they run any malicious functions. Very similar to an antivirus sandbox.

That puts a lot of responsibility on the server owner, which I wouldn’t necessarily want to do or expect to be able to do. Running things in-line with the server (whether it’s an on-demand scanner or something more akin to a real-time scanner/firewall via detours) would be easier for folks to implement.

That being said, I’m beginning to feel like I stepped out into traffic a bit, given the immense flexibility of Lua and my rather sophomoric approach to detection through pattern matching. A two-pronged approach with active checking through detours would, as man w/ hat said, would cover the biggest spectrum.

I’ll keep going w/ what I’ve got (moving to Github shortly), but the goal here will ultimately be a two pronged approach… before-the-fact pattern detection through scanning, and function detours/alerts in real-time).

Thanks folks.

Nice that we have these. Prevents harm before it can be done. Cheers mate.

My partially implemented and overambitious solution is to just detour all the potentially malicous functions and report usage of them to a central server for review. That or scan the bytecode for fuckery, but that would probably be even more work.

FYI - out on GitHub now.