node-yara-rs

git clone git://archive.git.mtrnord.blog/MTRNord/node-yara-rs.git
Log | Files | Refs | README | LICENSE

commit 3bbf253741a20a6cc2878a8856c1058c6db95144
parent 4677e0a1a67badcf0904f1b20231679917b70f8d
Author: MTRNord <mtrnord1@gmail.com>
Date:   Fri, 13 Oct 2023 18:10:16 +0200

Extend function of the yara json module

Diffstat:
MCargo.toml | 8+++++++-
M__test__/index.spec.mjs | 18++++++++++++++++++
M__test__/json_test.yara | 51+++++++++++++++++++++++++++++++++------------------
M__test__/test.json | 4+++-
Rchangelog.d/+dotted_keys.misc -> changelog.d/+dotted_keys.feat | 0
Achangelog.d/+get_values.misc | 2++
Achangelog.d/+overloaded_value_exists.feat | 2++
Mdeps/json.c | 182+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
8 files changed, 243 insertions(+), 24 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml @@ -17,7 +17,13 @@ napi-derive = "2.12.2" yara = { version = "0.21.0", features = ["yara-static"] } [target.x86_64-pc-windows-msvc.dependencies] -yara = { version = "0.21.0", features = ["yara-static", "vendored"] } +yara = { version = "0.21.0", features = [ + "yara-static", + "vendored", + "module-cuckoo", + "module-macho", + "module-hash", +] } [build-dependencies] napi-build = "2.0.1" diff --git a/__test__/index.spec.mjs b/__test__/index.spec.mjs @@ -174,6 +174,24 @@ if (process.platform !== "win32") { metadatas: [], tags: [], strings: [] + }, { + identifier: "get_string", + namespace: "default", + metadatas: [], + tags: [], + strings: [] + }, { + identifier: "get_integer", + namespace: "default", + metadatas: [], + tags: [], + strings: [] + }, { + identifier: "get_float", + namespace: "default", + metadatas: [], + tags: [], + strings: [] } ]) }); diff --git a/__test__/json_test.yara b/__test__/json_test.yara @@ -2,44 +2,44 @@ import "json" rule string_array_includes { condition: - json.string_array_includes("strArray", "one") and - json.string_array_includes("strArray", "two") and - json.string_array_includes("strArray", "three") + json.array_includes("strArray", "one") and + json.array_includes("strArray", "two") and + json.array_includes("strArray", "three") } rule string_array_includes_nested { condition: - json.string_array_includes("string.strArray", "one") and - json.string_array_includes("string.strArray", "two") and - json.string_array_includes("string.strArray", "three") + json.array_includes("string.strArray", "one") and + json.array_includes("string.strArray", "two") and + json.array_includes("string.strArray", "three") } rule integer_array_includes { condition: - json.integer_array_includes("intArray", 1) and - json.integer_array_includes("intArray", 2) and - json.integer_array_includes("intArray", 3) + json.array_includes("intArray", 1) and + json.array_includes("intArray", 2) and + json.array_includes("intArray", 3) } rule integer_array_includes_nested { condition: - json.integer_array_includes("integer.intArray", 1) and - json.integer_array_includes("integer.intArray", 2) and - json.integer_array_includes("integer.intArray", 3) + json.array_includes("integer.intArray", 1) and + json.array_includes("integer.intArray", 2) and + json.array_includes("integer.intArray", 3) } rule float_array_includes { condition: - json.float_array_includes("floatArray", 1.0) and - json.float_array_includes("floatArray", 2.0) and - json.float_array_includes("floatArray", 3.0) + json.array_includes("floatArray", 1.0) and + json.array_includes("floatArray", 2.0) and + json.array_includes("floatArray", 3.0) } rule float_array_includes_nested { condition: - json.float_array_includes("float.floatArray", 1.0) and - json.float_array_includes("float.floatArray", 2.0) and - json.float_array_includes("float.floatArray", 3.0) + json.array_includes("float.floatArray", 1.0) and + json.array_includes("float.floatArray", 2.0) and + json.array_includes("float.floatArray", 3.0) } rule dotted_key { @@ -55,4 +55,19 @@ rule dotted_key_sub { rule has_key_normal { condition: json.key_exists("normal_key") +} + +rule get_string { + condition: + json.get_string_value("keykey") == "valuevalue" +} + +rule get_integer { + condition: + json.get_integer_value("integer_number") == 42 +} + +rule get_float { + condition: + json.get_float_value("float_number") == 42.42 } \ No newline at end of file diff --git a/__test__/test.json b/__test__/test.json @@ -50,5 +50,7 @@ "dot.key": { "subkey": {} }, - "normal_key": {} + "normal_key": {}, + "integer_number": 42, + "float_number": 42.42 } \ No newline at end of file diff --git a/changelog.d/+dotted_keys.misc b/changelog.d/+dotted_keys.feat diff --git a/changelog.d/+get_values.misc b/changelog.d/+get_values.misc @@ -0,0 +1 @@ +Add get_X_value methods to json module to get the value of a key +\ No newline at end of file diff --git a/changelog.d/+overloaded_value_exists.feat b/changelog.d/+overloaded_value_exists.feat @@ -0,0 +1 @@ +Overload the value_exists function to have less function duplication on the frontend of the json module +\ No newline at end of file diff --git a/deps/json.c b/deps/json.c @@ -359,6 +359,10 @@ define_function(string_array_includes) json_t *array = iter; bool isArray = json_is_array(array); + if (!isArray) + { + return_integer(0); + } size_t index; json_t *val; @@ -382,6 +386,7 @@ define_function(string_array_includes) return_integer(0); } + // Integer Array includes define_function(integer_array_includes) { @@ -448,13 +453,13 @@ define_function(integer_array_includes) free(array); free(key); - free(value); free(prevToken); free(token); free(realToken); return_integer(0); } + // Float Array includes define_function(float_array_includes) { @@ -527,6 +532,172 @@ define_function(float_array_includes) return_integer(0); } +// Get String value +define_function(string_get_value) +{ + char *key = strdup(string_argument(1)); + + json_t *json = yr_module()->data; + if (json == NULL) + { + return_string(YR_UNDEFINED); + } + + // Split key into possible subcomponents - separated by '.' + json_t *iter = json; + char *token = strtok(key, "."); + char *prevToken = strdup(token); + char previousChar = '\0'; + char *realToken = strdup(token); + + while (token != NULL) + { + previousChar = token[strlen(token)-1]; + if (previousChar == '\\') { + realToken[strlen(realToken)-1] = '.'; + token = strtok(NULL, "."); + strcat(realToken, token); + } + + iter = json_object_get(iter, realToken); + if (iter == NULL) + { + return_string(YR_UNDEFINED); + } + + strcpy(prevToken, token); + token = strtok(NULL, "."); + if (token != NULL) { + strcpy(realToken, token); + } + } + + const char *found = json_string_value(iter); + if (found == NULL) + { + printf("no string value could be obtained from value at key\n"); + return_string(YR_UNDEFINED); + } + + free(key); + free(prevToken); + free(token); + free(realToken); + + return_string(found); +} + +// Get integer value +define_function(integer_get_value) +{ + char *key = strdup(string_argument(1)); + + json_t *json = yr_module()->data; + if (json == NULL) + { + return_integer(YR_UNDEFINED); + } + + // Split key into possible subcomponents - separated by '.' + json_t *iter = json; + char *token = strtok(key, "."); + char *prevToken = strdup(token); + char previousChar = '\0'; + char *realToken = strdup(token); + + while (token != NULL) + { + previousChar = token[strlen(token)-1]; + if (previousChar == '\\') { + realToken[strlen(realToken)-1] = '.'; + token = strtok(NULL, "."); + strcat(realToken, token); + } + + iter = json_object_get(iter, realToken); + if (iter == NULL) + { + return_integer(YR_UNDEFINED); + } + + strcpy(prevToken, token); + token = strtok(NULL, "."); + if (token != NULL) { + strcpy(realToken, token); + } + } + + double foundNumber = json_number_value(iter); + if (foundNumber == 0.0) + { + printf("no integer value could be obtained from value at key\n"); + return_integer(YR_UNDEFINED); + } + int found = (int)foundNumber; + + free(key); + free(prevToken); + free(token); + free(realToken); + + return_integer(found); +} + +// Get float value +define_function(float_get_value) +{ + char *key = strdup(string_argument(1)); + + json_t *json = yr_module()->data; + if (json == NULL) + { + return_float(YR_UNDEFINED); + } + + // Split key into possible subcomponents - separated by '.' + json_t *iter = json; + char *token = strtok(key, "."); + char *prevToken = strdup(token); + char previousChar = '\0'; + char *realToken = strdup(token); + + while (token != NULL) + { + previousChar = token[strlen(token)-1]; + if (previousChar == '\\') { + realToken[strlen(realToken)-1] = '.'; + token = strtok(NULL, "."); + strcat(realToken, token); + } + + iter = json_object_get(iter, realToken); + if (iter == NULL) + { + return_float(YR_UNDEFINED); + } + + strcpy(prevToken, token); + token = strtok(NULL, "."); + if (token != NULL) { + strcpy(realToken, token); + } + } + + double foundNumber = json_number_value(iter); + if (foundNumber == 0.0) + { + printf("no float value could be obtained from value at key\n"); + return_float(YR_UNDEFINED); + } + + free(key); + free(prevToken); + free(token); + free(realToken); + + return_float(foundNumber); +} + begin_declarations; declare_function("key_exists", "s", "i", key_exists); @@ -534,9 +705,12 @@ declare_function("value_exists", "ss", "i", value_exists_string); declare_function("value_exists", "si", "i", value_exists_integer); declare_function("value_exists", "sr", "i", value_exists_regex); declare_function("value_exists", "sf", "i", value_exists_float); -declare_function("string_array_includes", "ss", "i", string_array_includes); -declare_function("integer_array_includes", "si", "i", integer_array_includes); -declare_function("float_array_includes", "sf", "i", float_array_includes); +declare_function("array_includes", "ss", "i", string_array_includes); +declare_function("array_includes", "si", "i", integer_array_includes); +declare_function("array_includes", "sf", "i", float_array_includes); +declare_function("get_string_value", "s", "s", string_get_value); +declare_function("get_integer_value", "s", "i", integer_get_value); +declare_function("get_float_value", "s", "f", float_get_value); end_declarations; int module_initialize(YR_MODULE *module)