Commit 95702bb3 by Victor M. Alvarez

Refactor yara_callback.

This function has grown too much, so it was split in multiple functions in order to make it easier to understand.
parent a8011dd0
...@@ -519,8 +519,6 @@ PyObject* convert_structure_to_python( ...@@ -519,8 +519,6 @@ PyObject* convert_structure_to_python(
PyObject* convert_array_to_python( PyObject* convert_array_to_python(
YR_OBJECT_ARRAY* array) YR_OBJECT_ARRAY* array)
{ {
int i;
PyObject* py_object; PyObject* py_object;
PyObject* py_list = PyList_New(0); PyObject* py_list = PyList_New(0);
...@@ -531,7 +529,7 @@ PyObject* convert_array_to_python( ...@@ -531,7 +529,7 @@ PyObject* convert_array_to_python(
if (array->items == NULL) if (array->items == NULL)
return py_list; return py_list;
for (i = 0; i < array->items->length; i++) for (int i = 0; i < array->items->length; i++)
{ {
py_object = convert_object_to_python(array->items->objects[i]); py_object = convert_object_to_python(array->items->objects[i]);
...@@ -549,8 +547,6 @@ PyObject* convert_array_to_python( ...@@ -549,8 +547,6 @@ PyObject* convert_array_to_python(
PyObject* convert_dictionary_to_python( PyObject* convert_dictionary_to_python(
YR_OBJECT_DICTIONARY* dictionary) YR_OBJECT_DICTIONARY* dictionary)
{ {
int i;
PyObject* py_object; PyObject* py_object;
PyObject* py_dict = PyDict_New(); PyObject* py_dict = PyDict_New();
...@@ -561,7 +557,7 @@ PyObject* convert_dictionary_to_python( ...@@ -561,7 +557,7 @@ PyObject* convert_dictionary_to_python(
if (dictionary->items == NULL) if (dictionary->items == NULL)
return py_dict; return py_dict;
for (i = 0; i < dictionary->items->used; i++) for (int i = 0; i < dictionary->items->used; i++)
{ {
py_object = convert_object_to_python(dictionary->items->objects[i].obj); py_object = convert_object_to_python(dictionary->items->objects[i].obj);
...@@ -580,117 +576,155 @@ PyObject* convert_dictionary_to_python( ...@@ -580,117 +576,155 @@ PyObject* convert_dictionary_to_python(
} }
#define CALLBACK_MATCHES 0x01 static int handle_import_module(
#define CALLBACK_NON_MATCHES 0x02 YR_MODULE_IMPORT* module_import,
#define CALLBACK_ALL CALLBACK_MATCHES | CALLBACK_NON_MATCHES CALLBACK_DATA* data)
int yara_callback(
YR_SCAN_CONTEXT* context,
int message,
void* message_data,
void* user_data)
{ {
YR_STRING* string; if (data->modules_data == NULL)
YR_MATCH* m; return CALLBACK_CONTINUE;
YR_META* meta;
YR_RULE* rule;
YR_MODULE_IMPORT* module_import;
const char* tag; PyGILState_STATE gil_state = PyGILState_Ensure();
PyObject* tag_list = NULL; PyObject* module_data = PyDict_GetItemString(
PyObject* string_list = NULL; data->modules_data,
PyObject* meta_list = NULL; module_import->module_name);
PyObject* match;
PyObject* callback_dict;
PyObject* object;
PyObject* tuple;
PyObject* matches = ((CALLBACK_DATA*) user_data)->matches;
PyObject* callback = ((CALLBACK_DATA*) user_data)->callback;
PyObject* modules_data = ((CALLBACK_DATA*) user_data)->modules_data;
PyObject* modules_callback = ((CALLBACK_DATA*) user_data)->modules_callback;
PyObject* warning_callback = ((CALLBACK_DATA*) user_data)->warning_callback;
PyObject* module_data;
PyObject* callback_result;
PyObject* module_info_dict;
PyObject* identifier;
PyObject* warning_type;
int which = ((CALLBACK_DATA*) user_data)->which; #if PY_MAJOR_VERSION >= 3
if (module_data != NULL && PyBytes_Check(module_data))
#else
if (module_data != NULL && PyString_Check(module_data))
#endif
{
Py_ssize_t data_size;
Py_ssize_t data_size; #if PY_MAJOR_VERSION >= 3
PyGILState_STATE gil_state; PyBytes_AsStringAndSize(
module_data,
(char**) &module_import->module_data,
&data_size);
#else
PyString_AsStringAndSize(
module_data,
(char**) &module_import->module_data,
&data_size);
#endif
int result = CALLBACK_CONTINUE; module_import->module_data_size = data_size;
}
// If the rule doesn't match and the user has not specified that they want to PyGILState_Release(gil_state);
// see non-matches then nothing to do here.
if (message == CALLBACK_MSG_RULE_NOT_MATCHING && callback != NULL &&
(which & CALLBACK_NON_MATCHES) != CALLBACK_NON_MATCHES)
return CALLBACK_CONTINUE;
if (message == CALLBACK_MSG_SCAN_FINISHED) return CALLBACK_CONTINUE;
return CALLBACK_CONTINUE; }
if (message == CALLBACK_MSG_IMPORT_MODULE && modules_data == NULL)
return CALLBACK_CONTINUE;
if (message == CALLBACK_MSG_MODULE_IMPORTED && modules_callback == NULL) static int handle_module_imported(
void* message_data,
CALLBACK_DATA* data)
{
if (data->modules_callback == NULL)
return CALLBACK_CONTINUE; return CALLBACK_CONTINUE;
if (message == CALLBACK_MSG_IMPORT_MODULE) PyGILState_STATE gil_state = PyGILState_Ensure();
PyObject* module_info_dict = convert_structure_to_python(
object_as_structure(message_data));
if (module_info_dict == NULL)
{ {
gil_state = PyGILState_Ensure(); PyGILState_Release(gil_state);
module_import = (YR_MODULE_IMPORT*) message_data; return CALLBACK_CONTINUE;
}
module_data = PyDict_GetItemString( PyObject* object = PY_STRING(object_as_structure(message_data)->identifier);
modules_data, PyDict_SetItemString(module_info_dict, "module", object);
module_import->module_name); Py_DECREF(object);
Py_INCREF(data->modules_callback);
PyObject* callback_result = PyObject_CallFunctionObjArgs(
data->modules_callback,
module_info_dict,
NULL);
int result = CALLBACK_CONTINUE;
if (callback_result != NULL)
{
#if PY_MAJOR_VERSION >= 3 #if PY_MAJOR_VERSION >= 3
if (module_data != NULL && PyBytes_Check(module_data)) if (PyLong_Check(callback_result))
#else #else
if (module_data != NULL && PyString_Check(module_data)) if (PyLong_Check(callback_result) || PyInt_Check(callback_result))
#endif #endif
{ {
#if PY_MAJOR_VERSION >= 3 result = (int) PyLong_AsLong(callback_result);
PyBytes_AsStringAndSize(
module_data,
(char**) &module_import->module_data,
&data_size);
#else
PyString_AsStringAndSize(
module_data,
(char**) &module_import->module_data,
&data_size);
#endif
module_import->module_data_size = data_size;
} }
PyGILState_Release(gil_state);
return CALLBACK_CONTINUE;
} }
else
{
result = CALLBACK_ERROR;
}
Py_XDECREF(callback_result);
Py_DECREF(module_info_dict);
Py_DECREF(data->modules_callback);
PyGILState_Release(gil_state);
return result;
}
static int handle_too_many_matches(
YR_SCAN_CONTEXT* context,
YR_STRING* string,
CALLBACK_DATA* data)
{
PyGILState_STATE gil_state = PyGILState_Ensure();
PyObject* warning_type = NULL;
PyObject* identifier = NULL;
int result = CALLBACK_CONTINUE;
if (message == CALLBACK_MSG_MODULE_IMPORTED) if (data->warning_callback == NULL)
{ {
gil_state = PyGILState_Ensure(); char message[200];
module_info_dict = convert_structure_to_python( snprintf(
object_as_structure(message_data)); message,
sizeof(message),
"too many matches for string %s in rule \"%s\"",
string->identifier,
context->rules->rules_table[string->rule_idx].identifier);
if (module_info_dict == NULL) if (PyErr_WarnEx(PyExc_RuntimeWarning, message, 1) == -1)
return CALLBACK_CONTINUE; result = CALLBACK_ERROR;
}
else
{
Py_INCREF(data->warning_callback);
object = PY_STRING(object_as_structure(message_data)->identifier); identifier = PyBytes_FromString(string->identifier);
PyDict_SetItemString(module_info_dict, "module", object);
Py_DECREF(object);
Py_INCREF(modules_callback); if (identifier == NULL)
{
result = CALLBACK_ERROR;
goto _exit;
}
callback_result = PyObject_CallFunctionObjArgs( warning_type = PyLong_FromLong(CALLBACK_MSG_TOO_MANY_MATCHES);
modules_callback,
module_info_dict, if (warning_type == NULL)
{
result = CALLBACK_ERROR;
goto _exit;
}
PyObject* callback_result = PyObject_CallFunctionObjArgs(
data->warning_callback,
warning_type,
identifier,
NULL); NULL);
if (callback_result != NULL) if (callback_result != NULL)
...@@ -703,99 +737,77 @@ int yara_callback( ...@@ -703,99 +737,77 @@ int yara_callback(
{ {
result = (int) PyLong_AsLong(callback_result); result = (int) PyLong_AsLong(callback_result);
} }
Py_DECREF(callback_result);
} }
else else
{ {
result = CALLBACK_ERROR; result = CALLBACK_ERROR;
} }
Py_DECREF(module_info_dict); Py_XDECREF(callback_result);
Py_DECREF(modules_callback);
PyGILState_Release(gil_state);
return result;
} }
if (message == CALLBACK_MSG_TOO_MANY_MATCHES) _exit:
{
gil_state = PyGILState_Ensure();
if (warning_callback == NULL) Py_XDECREF(identifier);
{ Py_XDECREF(warning_type);
char message[200]; Py_XDECREF(data->warning_callback);
string = (YR_STRING*) message_data; PyGILState_Release(gil_state);
snprintf( return result;
message, }
sizeof(message),
"too many matches for string %s in rule \"%s\"",
string->identifier,
context->rules->rules_table[string->rule_idx].identifier);
result = PyErr_WarnEx(PyExc_RuntimeWarning, message, 1);
if (result == -1) #define CALLBACK_MATCHES 0x01
result = CALLBACK_ERROR; #define CALLBACK_NON_MATCHES 0x02
else #define CALLBACK_ALL CALLBACK_MATCHES | CALLBACK_NON_MATCHES
result = CALLBACK_CONTINUE;
PyGILState_Release(gil_state);
return result;
}
else
{
identifier = PyBytes_FromString(((YR_STRING*) message_data)->identifier);
if (identifier == NULL) int yara_callback(
{ YR_SCAN_CONTEXT* context,
PyGILState_Release(gil_state); int message,
return CALLBACK_ERROR; void* message_data,
} void* user_data)
{
YR_STRING* string;
YR_MATCH* m;
YR_META* meta;
YR_RULE* rule;
warning_type = PyLong_FromLong(CALLBACK_MSG_TOO_MANY_MATCHES); const char* tag;
if (warning_type == NULL)
{
Py_DECREF(identifier);
PyGILState_Release(gil_state);
return CALLBACK_ERROR;
}
Py_INCREF(warning_callback); PyObject* tag_list = NULL;
PyObject* string_list = NULL;
PyObject* meta_list = NULL;
PyObject* match;
PyObject* callback_dict;
PyObject* object;
PyObject* tuple;
PyObject* matches = ((CALLBACK_DATA*) user_data)->matches;
PyObject* callback = ((CALLBACK_DATA*) user_data)->callback;
PyObject* callback_result;
callback_result = PyObject_CallFunctionObjArgs( int which = ((CALLBACK_DATA*) user_data)->which;
warning_callback,
warning_type,
identifier,
NULL);
if (callback_result != NULL) // If the rule doesn't match and the user has not specified that they want to
{ // see non-matches then nothing to do here.
#if PY_MAJOR_VERSION >= 3 if (message == CALLBACK_MSG_RULE_NOT_MATCHING && callback != NULL &&
if (PyLong_Check(callback_result)) (which & CALLBACK_NON_MATCHES) != CALLBACK_NON_MATCHES)
#else return CALLBACK_CONTINUE;
if (PyLong_Check(callback_result) || PyInt_Check(callback_result))
#endif
{
result = (int) PyLong_AsLong(callback_result);
}
Py_DECREF(callback_result); switch(message)
} {
else case CALLBACK_MSG_IMPORT_MODULE:
{ return handle_import_module(message_data, user_data);
result = CALLBACK_ERROR;
}
Py_DECREF(identifier); case CALLBACK_MSG_MODULE_IMPORTED:
Py_DECREF(warning_type); return handle_module_imported(message_data, user_data);
Py_DECREF(warning_callback);
PyGILState_Release(gil_state); case CALLBACK_MSG_TOO_MANY_MATCHES:
return CALLBACK_CONTINUE; return handle_too_many_matches(context, message_data, user_data);
}
case CALLBACK_MSG_SCAN_FINISHED:
return CALLBACK_CONTINUE;
} }
// At this point we have handled all the other cases of when this callback // At this point we have handled all the other cases of when this callback
...@@ -807,9 +819,12 @@ int yara_callback( ...@@ -807,9 +819,12 @@ int yara_callback(
// //
// In both cases, we need to create the data that will be either passed back // In both cases, we need to create the data that will be either passed back
// to the python callback or stored in the matches list. // to the python callback or stored in the matches list.
int result = CALLBACK_CONTINUE;
rule = (YR_RULE*) message_data; rule = (YR_RULE*) message_data;
gil_state = PyGILState_Ensure(); PyGILState_STATE gil_state = PyGILState_Ensure();
tag_list = PyList_New(0); tag_list = PyList_New(0);
string_list = PyList_New(0); string_list = PyList_New(0);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment