1+ # =============================================================================
2+ # Helper function to prevent code duplication for generic scoring.
3+ # =============================================================================
4+ def _calculate_generic_score (matched : list ) -> float :
5+ """Calculates a generic score based on a list of matched signatures."""
6+ score = 0.0
7+ for match in matched :
8+ # We apply the 'maximum' attribute if present in the signature.
9+ # Check for key existence and that the value is not None to handle the case where maximum could be 0.
10+ if "maximum" in match and match ["maximum" ] is not None :
11+ score = max (score , match ["maximum" ])
12+ continue # Skip to next signature
13+
14+ if match ["severity" ] == 1 :
15+ score += match ["weight" ] * 0.5 * (match ["confidence" ] / 100.0 )
16+ else :
17+ score += match ["weight" ] * (match ["severity" ] - 1 ) * (match ["confidence" ] / 100.0 )
18+
19+ # Clamp the score between 0.0 and 10.0 using a common Python idiom.
20+ score = max (0.0 , min (score , 10.0 ))
21+
22+ return score
23+
24+
25+ # =============================================================================
26+ # Main scoring function.
27+ # =============================================================================
128def calc_scoring (results : dict , matched : list ):
229 """
330 Calculate the final malware score and status based on the analysis results and matched signatures.
@@ -25,35 +52,34 @@ def calc_scoring(results: dict, matched: list):
2552 """
2653 finalMalscore = 0.0
2754 status = None
55+ # Identify the analysis category (file or url).
56+ category = results .get ("target" , {}).get ("category" )
2857 fileType = results .get ("target" , {}).get ("file" , {}).get ("type" )
2958
59+ # IF THE ANALYSIS IS OF URL TYPE, we use the generic scoring logic
60+ if category == "url" :
61+ # Calculate score using the helper function
62+ finalMalscore = _calculate_generic_score (matched )
63+
64+ # We assign a status based on the score
65+ if finalMalscore >= 7.0 :
66+ status = "Malicious"
67+ elif finalMalscore >= 4.0 :
68+ status = "Suspicious"
69+ elif finalMalscore > 0.0 :
70+ status = "Clean"
71+ else :
72+ status = "Undetected"
73+
74+ return finalMalscore , status
75+
3076 if not fileType :
3177 return finalMalscore , status
3278
3379 if "executable" in fileType :
3480 # We have 5 methodologies
3581 # 1. The file is Malicious-Known (The sample is detected by YARA)
36- ## score 10/10 (Malicious)
37- # =======================================================================================================#
38- # 2. If the file is Malicious-Unknown
39- ## triggered some signatures that has specific malicious categories such as:
40- ## ["malware", "ransomware", "infostealer", "rat", "trojan", "rootkit", "bootkit", "wiper", "banker",
41- ## "bypass", "anti-sandbox", "keylogger"]
42- ## score [7-9]/10 (Malicious)
43- # =======================================================================================================#
44- # 3. If the file is Suspicious-Unknown
45- ## triggered some signatures that has specific suspicious categories such as:
46- ## ["network", "encryption", "anti-vm", "anti-analysis", "anti-av", "anti-debug", "anti-emulation",
47- ## "persistence", "stealth", "discovery", "injection", "generic", "account", "bot", "browser",
48- # "allocation", "command"]
49- ## score[4-6]/10 (Suspicious)
50- # =======================================================================================================#
51- # 4. If the file is benign
52- ## Likely all trusted files are digitally signed.
53- ## score [0-3]/10 (benign)
54- # =======================================================================================================#
55- # 5. If the file doesn't trigger any signatures
56- ## The file is undetected/failed
82+ # ... (and so on, this logic is specific to executables)
5783 tempScore1 = 0.0
5884 tempScore2 = 0.0
5985 is_maliciousCategoryHit = False
@@ -66,39 +92,14 @@ def calc_scoring(results: dict, matched: list):
6692 )
6793
6894 maliciousCategories = [
69- "malware" ,
70- "ransomware" ,
71- "infostealer" ,
72- "rat" ,
73- "trojan" ,
74- "rootkit" ,
75- "bootkit" ,
76- "wiper" ,
77- "banker" ,
78- "bypass" ,
79- "anti-sandbox" ,
80- "keylogger" ,
95+ "malware" , "ransomware" , "infostealer" , "rat" , "trojan" , "rootkit" , "bootkit" , "wiper" , "banker" ,
96+ "bypass" , "anti-sandbox" , "keylogger" ,
8197 ]
8298
8399 suspiciousCategories = [
84- "network" ,
85- "encryption" ,
86- "anti-vm" ,
87- "anti-analysis" ,
88- "anti-av" ,
89- "anti-debug" ,
90- "anti-emulation" ,
91- "persistence" ,
92- "stealth" ,
93- "discovery" ,
94- "injection" ,
95- "generic" ,
96- "account" ,
97- "bot" ,
98- "browser" ,
99- "allocation" ,
100- "command" ,
101- "execution" ,
100+ "network" , "encryption" , "anti-vm" , "anti-analysis" , "anti-av" , "anti-debug" , "anti-emulation" ,
101+ "persistence" , "stealth" , "discovery" , "injection" , "generic" , "account" , "bot" , "browser" ,
102+ "allocation" , "command" , "execution" ,
102103 ]
103104
104105 for detection in results .get ("detections" , []):
@@ -122,74 +123,46 @@ def calc_scoring(results: dict, matched: list):
122123 else :
123124 tempScore2 += matchedSig ["weight" ] * (matchedSig ["severity" ] - 1 ) * (matchedSig ["confidence" ] / 100.0 )
124125
125- # 1. The file is Malicious-Known (The sample is detected by YARA)
126- ## score 10/10 (Malicious)
126+ # 1. Malicious-Known
127127 if is_detected :
128128 status = "Malicious"
129129 finalMalscore = 10.0
130130
131- # 2. If the file is Malicious-Unknown
132- ## triggered some signatures that has specific malicious categories such as:
133- ## ["malware", "ransomware", "infostealer", "rat", "trojan", "rootkit", "bootkit", "wiper", "banker",
134- ## "bypass", "anti-sandbox", "keylogger"]
135- ## score [7-9]/10 (Malicious)
131+ # 2. Malicious-Unknown
136132 elif is_maliciousCategoryHit :
137133 finalMalscore = tempScore1
138134 status = "Malicious"
139- ## Include numbers between that range
140135 if 7.0 < finalMalscore < 9.0 :
141136 pass
142137 elif finalMalscore >= 9.0 :
143138 finalMalscore = 9.0
144139 elif finalMalscore < 7.0 :
145140 finalMalscore = 7.0
146141
147- # 3. If the file is Suspicious-Unknown
148- ## triggered some signatures that has specific suspicious categories such as:
149- ## ["network", "encryption", "anti-vm", "anti-analysis", "anti-av", "anti-debug", "anti-emulation",
150- ## "persistence", "stealth", "discovery", "injection", "generic", "account", "bot", "browser",
151- # "allocation", "command"]
152- ## score[4-6]/10 (Suspicious)
142+ # 3. Suspicious-Unknown
153143 elif is_suspiciousCategoryHit :
154144 finalMalscore = tempScore2
155-
156- # 4. If the file is benign
157- ## Likely all trusted files are digitally signed.
158- ## score [0-3]/10 (benign)
159145 if is_digital_signauture_verified :
160146 finalMalscore = 0.0
161147 status = "Clean"
162-
163148 elif finalMalscore < 4.0 :
164149 status = "Clean"
165-
166- ## Include numbers between that range
167- elif 4.0 < finalMalscore < 6.0 :
168- status = "Suspicious"
169- elif finalMalscore == 4 :
170- finalMalscore = 4
171- status = "Suspicious"
172150 elif finalMalscore >= 6.0 :
173151 finalMalscore = 6.0
174152 status = "Suspicious"
153+ elif 4.0 <= finalMalscore < 6.0 :
154+ status = "Suspicious"
175155
176- # 5. If the file doesn't trigger any signatures
177- ## The file is undetected/failed
156+ # 5. Undetected/Failed
178157 else :
179158 finalMalscore = 0
180159 if results .get ("behavior" , {}).get ("processtree" , []):
181160 status = "Undetected"
182161 else :
183162 status = "Failed"
184163 else :
185- for match in matched :
186- if match ["severity" ] == 1 :
187- finalMalscore += match ["weight" ] * 0.5 * (match ["confidence" ] / 100.0 )
188- else :
189- finalMalscore += match ["weight" ] * (match ["severity" ] - 1 ) * (match ["confidence" ] / 100.0 )
190- if finalMalscore > 10.0 :
191- finalMalscore = 10.0
192- if finalMalscore < 0.0 :
193- finalMalscore = 0.0
164+ # For all other non-executable file types, use the generic scoring logic
165+ finalMalscore = _calculate_generic_score (matched )
166+ # Note: The original logic did not assign a status here, so we keep that behavior.
194167
195168 return finalMalscore , status
0 commit comments