@@ -21,13 +21,20 @@ public class Indicators {
2121 private final Trie processTrie ;
2222 private final Trie appIdTrie ;
2323 private final Trie propertyTrie ;
24+ private final List <String > processList ;
25+ private final List <String > appIdList ;
26+ private final List <String > propertyList ;
2427
25- private Indicators (Trie domainTrie , Trie urlTrie , Trie processTrie , Trie appIdTrie , Trie propertyTrie ) {
28+ private Indicators (Trie domainTrie , Trie urlTrie , Trie processTrie , Trie appIdTrie , Trie propertyTrie ,
29+ List <String > processList , List <String > appIdList , List <String > propertyList ) {
2630 this .domainTrie = domainTrie ;
2731 this .urlTrie = urlTrie ;
2832 this .processTrie = processTrie ;
2933 this .appIdTrie = appIdTrie ;
3034 this .propertyTrie = propertyTrie ;
35+ this .processList = processList ;
36+ this .appIdList = appIdList ;
37+ this .propertyList = propertyList ;
3138 }
3239
3340 public static Indicators loadFromDirectory (File dir ) throws IOException {
@@ -37,9 +44,12 @@ public static Indicators loadFromDirectory(File dir) throws IOException {
3744 Trie .TrieBuilder processes = Trie .builder ().ignoreCase ();
3845 Trie .TrieBuilder appIds = Trie .builder ().ignoreCase ();
3946 Trie .TrieBuilder properties = Trie .builder ().ignoreCase ();
47+ List <String > procList = new ArrayList <>();
48+ List <String > appIdList = new ArrayList <>();
49+ List <String > propList = new ArrayList <>();
4050
4151 File [] files = dir .listFiles ((d , name ) -> name .endsWith (".json" ) || name .endsWith (".stix2" ));
42- if (files == null ) return new Indicators (domains .build (), urls .build (), processes .build (), appIds .build (), properties .build ());
52+ if (files == null ) return new Indicators (domains .build (), urls .build (), processes .build (), appIds .build (), properties .build (), procList , appIdList , propList );
4353
4454 for (File f : files ) {
4555 if (f .getName ().endsWith (".stix2" )) {
@@ -48,7 +58,8 @@ public static Indicators loadFromDirectory(File dir) throws IOException {
4858 BundleObject bundle = StixParsers .parseBundle (json );
4959 for (BundleableObject obj : bundle .getObjects ()) {
5060 if (obj instanceof IndicatorSdo ind ) {
51- addPattern (domains , urls , processes , appIds , properties , ind .getPattern ());
61+ addPattern (domains , urls , processes , appIds , properties ,
62+ procList , appIdList , propList , ind .getPattern ());
5263 }
5364 }
5465 } catch (Exception ex ) {
@@ -58,7 +69,9 @@ public static Indicators loadFromDirectory(File dir) throws IOException {
5869 if (objects != null && objects .isArray ()) {
5970 for (JsonNode node : objects ) {
6071 if ("indicator" .equals (node .path ("type" ).asText ())) {
61- addPattern (domains , urls , processes , appIds , properties , node .path ("pattern" ).asText ());
72+ addPattern (domains , urls , processes , appIds , properties ,
73+ procList , appIdList , propList ,
74+ node .path ("pattern" ).asText ());
6275 }
6376 }
6477 }
@@ -68,21 +81,24 @@ public static Indicators loadFromDirectory(File dir) throws IOException {
6881 JsonNode arr = root .get ("indicators" );
6982 if (arr == null ) continue ;
7083 for (JsonNode coll : arr ) {
71- addField (domains , coll , "domain-name:value" );
72- addField (domains , coll , "ipv4-addr:value" );
73- addField (urls , coll , "url:value" );
74- addField (processes , coll , "process:name" );
75- addField (appIds , coll , "app:id" );
76- addField (properties , coll , "android-property:name" );
84+ addField (domains , coll , "domain-name:value" , null );
85+ addField (domains , coll , "ipv4-addr:value" , null );
86+ addField (urls , coll , "url:value" , null );
87+ addField (processes , coll , "process:name" , procList );
88+ addField (appIds , coll , "app:id" , appIdList );
89+ addField (properties , coll , "android-property:name" , propList );
7790 }
7891 }
7992 }
80- return new Indicators (domains .build (), urls .build (), processes .build (), appIds .build (), properties .build ());
93+ return new Indicators (domains .build (), urls .build (), processes .build (), appIds .build (), properties .build (),
94+ procList , appIdList , propList );
8195 }
8296
8397 private static void addPattern (Trie .TrieBuilder domains , Trie .TrieBuilder urls ,
8498 Trie .TrieBuilder processes , Trie .TrieBuilder appIds ,
85- Trie .TrieBuilder properties , String pattern ) {
99+ Trie .TrieBuilder properties ,
100+ List <String > procList , List <String > appIdList , List <String > propList ,
101+ String pattern ) {
86102 if (pattern == null ) return ;
87103 String p = pattern .trim ();
88104 if (p .startsWith ("[" ) && p .endsWith ("]" )) {
@@ -98,22 +114,23 @@ private static void addPattern(Trie.TrieBuilder domains, Trie.TrieBuilder urls,
98114 switch (key ) {
99115 case "domain-name:value" , "ipv4-addr:value" -> domains .addKeyword (value .toLowerCase ());
100116 case "url:value" -> urls .addKeyword (value .toLowerCase ());
101- case "process:name" -> processes .addKeyword (value .toLowerCase ());
102- case "app:id" -> appIds .addKeyword (value .toLowerCase ());
103- case "android-property:name" -> properties .addKeyword (value .toLowerCase ());
117+ case "process:name" -> { processes .addKeyword (value .toLowerCase ()); procList . add ( value . toLowerCase ()); }
118+ case "app:id" -> { appIds .addKeyword (value .toLowerCase ()); appIdList . add ( value . toLowerCase ()); }
119+ case "android-property:name" -> { properties .addKeyword (value .toLowerCase ()); propList . add ( value . toLowerCase ()); }
104120 default -> {
105121 }
106122 }
107123 }
108124
109- private static void addField (Trie .TrieBuilder builder , JsonNode coll , String key ) {
125+ private static void addField (Trie .TrieBuilder builder , JsonNode coll , String key , List < String > store ) {
110126 if (coll == null ) return ;
111127 JsonNode node = coll .get (key );
112128 if (node == null || node .isNull ()) return ;
113129 for (JsonNode value : iterable (node )) {
114130 String s = value .asText ();
115131 if (s != null && !s .isBlank ()) {
116132 builder .addKeyword (s .toLowerCase ());
133+ if (store != null ) store .add (s .toLowerCase ());
117134 }
118135 }
119136 }
@@ -125,16 +142,40 @@ private static Iterable<JsonNode> iterable(JsonNode node) {
125142
126143 public List <Detection > matchString (String s , IndicatorType type ) {
127144 if (s == null ) return List .of ();
128- Trie trie = switch (type ) {
129- case DOMAIN -> domainTrie ;
130- case URL -> urlTrie ;
131- case PROCESS -> processTrie ;
132- case APP_ID -> appIdTrie ;
133- case PROPERTY -> propertyTrie ;
134- };
145+ String lower = s .toLowerCase ();
135146 List <Detection > detections = new ArrayList <>();
136- for (Emit e : trie .parseText (s .toLowerCase ())) {
137- detections .add (new Detection (type , e .getKeyword (), s ));
147+ switch (type ) {
148+ case DOMAIN -> {
149+ for (Emit e : domainTrie .parseText (lower )) {
150+ detections .add (new Detection (type , e .getKeyword (), s ));
151+ }
152+ }
153+ case URL -> {
154+ for (Emit e : urlTrie .parseText (lower )) {
155+ detections .add (new Detection (type , e .getKeyword (), s ));
156+ }
157+ }
158+ case PROCESS -> {
159+ for (String kw : processList ) {
160+ if (kw .equals (lower ) || (lower .length () == 16 && kw .startsWith (lower ))) {
161+ detections .add (new Detection (type , kw , s ));
162+ }
163+ }
164+ }
165+ case APP_ID -> {
166+ for (String kw : appIdList ) {
167+ if (kw .equals (lower )) {
168+ detections .add (new Detection (type , kw , s ));
169+ }
170+ }
171+ }
172+ case PROPERTY -> {
173+ for (String kw : propertyList ) {
174+ if (kw .equals (lower )) {
175+ detections .add (new Detection (type , kw , s ));
176+ }
177+ }
178+ }
138179 }
139180 return detections ;
140181 }
0 commit comments