Had the same “malware” spread among the many files we had, so had to cobble up the following python code. Contains project specific parts, also can check all .ma files in the current path (and lower) recursively and cleans them (non-destructive, keeps the original file with a timestamp).
Maya Scanner by Autodesk does detect the malware, but is unable to clean it, especially if exists in one of the numerous external references. This one does, since it checks every file individually. Run it from your favorite terminal.
usage: cleaner.py 41
(“41” refers to a non-existing episode number, which tells the script to check current dir and below)
import os
import sys
import re
import glob
import ntpath
import datetime
from datetime import datetime
import time
import argparse
version = "1.81"
print("\n\nRecursive .ma cleaner - Tankut, version " + version + "\n\n")
#signature = r'createNode script -n "vaccine_gene";.*createNode script -n "breed_gene";.*setAttr ".stp" 1;'
signature = r'createNode script -n "vaccine_gene.";.*\]"\);\ncreateNode script -n "breed_gene?";.*setAttr ".stp" 1;'
signature_a = r'createNode script -n "vaccine_gene.{7129}'
signature_b = r'createNode script -n "breed_gene.{405}'
innocent = r'createNode script -n ".*sceneConfigurationScriptNode.*"'
suspicious = r'createNode script -n'
remnant = r'connectAttr "(breed|vaccine)_gene.msg" .*dn"'
number = 0
checked = 0
suspected = 0
red_flag = 0
folderindex = 0
episodeflag = 0
lastcheck = 0
logexists = 0
currentpath = os.getcwd()
def truncate(n, decimals=0):
multiplier = 10 ** decimals
return int(n * multiplier) / multiplier
def quitapp(errorcode):
if errorcode == 1:
print ("\nenter an episode number ( 01 - 40 ) \n")
if errorcode == 2:
print ("\nchecking current dir and below for malware \n")
exit()
return
def noepisode():
print("no episode number, checking current dir : ")
return
episodelist = [".", "e01_oyuncakMuhendisi", "e02_dagDustu", "e03_CokSoguk", "e04_calisirsanOlur", "e05_bulutTamircisi", "e06_bitmeyenKale", "e07_BeniUnutmaNiloya", "e08_aksamOldu", "e09_tospikAraKurtar", "e10_NiloyaHaritasi", "e11_kucukBilimInsanlari", "e12_hayalOyunu", "e13_elimYuzumSobe", "e14_uzaydanSinyal", "e15_yuruyenKutuphane", "e16_temizlikSagliktir", "e17_magaradakiAyi", "e18_goool", "e19_denizciMete", "e20_masaCadiri", "e21_salyangozGibiSakin", "e22_kucukSaglikcilar", "e23_cekirgeOgretmeni", "e24_oyuncakBrosuru", "e25_canimSikiliyor", "e26_koydenHaberler", "e27_sporHerkesIcin", "e28_kurbagaSarkisi", "e29_neseliParkur", "e30_ataTohumlari", "e31_akilliCobanKopegi", "e32_sekerimYok", "e33_haylazSular", "e34_benimGuzelDenizim", "e35_dahaOzel", "e36_disariCikalim", "e37_elifinTeleskobu", "e38_evcilKarinca", "e39_miniklerinParki", "e40_baharTelasi"]
try:
argument = sys.argv[1]
except:
noepisode()
argument =""
try:
force = sys.argv[2]
except:
force = ""
if argument != "":
try:
folderindex = int(argument)
except ValueError:
noepisode()
if folderindex >=0 and folderindex < 41:
episode = episodelist [folderindex]
projectpath = "D:\\Dropbox"
if currentpath.find ("D:\\Dropbox") == -1:
projectpath = "M:\\PROJECTS"
currentpath = projectpath + "\\Niloya_2019\\scenes\\s07\\" + episode
episodeflag = 1
if episode == ".":
episode = "ALL"
print("Checking episode: " + episode + "\n" + currentpath + "\n")
else:
noepisode()
print(currentpath + "\n")
try:
log = open(currentpath + "\\vircheck.ini",'r')
logexists = 1
except FileNotFoundError:
print ("no checkpoint data. skipping..")
if logexists == 1 :
lastcheck = int (log.read())
print ("last checkpoint: " + str(lastcheck))
log.close()
if logexists == 1 and force == "f":
print ("ignoring checkpoint")
lastcheck = 0
## mainloop
filelist = glob.glob(currentpath + '\**\*.ma', recursive=True)
for filename in filelist:
if int(os.path.getmtime(filename)) > lastcheck:
suspectfile = open(filename, "r")
try:
infile = suspectfile.read()
checked = checked + 1
print('\r', str(checked).zfill(6), end = ' ')
except UnicodeDecodeError:
print ("Unicode read error, skipping: "+filename)
infile = ""
except FileNotFoundError:
print ("File not found (moved?) : "+ filename)
infile = ""
except MemoryError:
print ("Mem error (size = "+ str(truncate(os.path.getsize(filename)/1024**2,3)) + " MB) : "+ filename)
infile = ""
suspectfile.close()
red_flag = 0
if re.search (suspicious, infile, flags=re.DOTALL):
red_flag = red_flag + 1
if re.search (innocent, infile, flags=re.DOTALL):
red_flag = red_flag - 1
if red_flag >> 0:
print (str(red_flag) + " unknown scriptnode(s) in " + filename)
if re.search ('vaccine_gene', infile, flags=re.DOTALL):
number = number + 1
currenttime = datetime.now()
datestamp = str(currenttime.year).zfill(4)+"-"+str(currenttime.month).zfill(2)+"-"+str(currenttime.day).zfill(2)+"_"+str(currenttime.hour)+str(currenttime.minute)+str(currenttime.second)
try:
os.rename (filename, filename+"_old_"+datestamp )
except FileExistsError:
os.rename (filename, filename+"_old_"+ datestamp + "_2")
clean = infile
item = 0
while item<4:
clean = re.sub(signature_a, ' ', clean, flags=re.DOTALL)
clean = re.sub(signature_b, ' ', clean, flags=re.DOTALL)
item += 1
oldsize = sys.getsizeof(infile)
newsize = sys.getsizeof(clean)
clean = re.sub(remnant, ' ', clean, flags=re.DOTALL)
print (filename + " " + f'{oldsize:,}' + " " + f'{newsize:,}')
outfile = open(filename, "w+")
outfile.write(clean)
outfile.close()
print ("\nTotal checked: "+ str(checked) + " of " + str(len(filelist)) + " - cleaned : " + str(number) + "\n")
log = open(currentpath + "\\vircheck.ini",'w')
log.write(str(int(time.time())))
log.close()
# requires pip3 install psutil, not standard library
#
#running_from = psutil.Process(os.getpid()).parent().name()
#if running_from == 'explorer.exe':
# input('Press Enter to Exit..')
if episodeflag == 0:
input('Press Enter to Exit..\n')