Skip to content

Commit 93a3250

Browse files
committed
Exposing the process memory iterator interface to Python.
This also updates the yara submodule to 41591cb25f9bd425bd7e58ca6f52a2523b4ed293.
1 parent e65477d commit 93a3250

File tree

2 files changed

+190
-1
lines changed

2 files changed

+190
-1
lines changed

yara-python.c

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ limitations under the License.
2828

2929
#include <time.h>
3030
#include <yara.h>
31+
#include <yara/proc.h>
3132

3233
#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
3334
typedef int Py_ssize_t;
@@ -2082,6 +2083,187 @@ static PyObject* yara_load(
20822083
return (PyObject*) rules;
20832084
}
20842085

2086+
typedef struct
2087+
{
2088+
PyObject_HEAD
2089+
PyObject* externals;
2090+
YR_MEMORY_BLOCK_ITERATOR* block_iterator;
2091+
YR_MEMORY_BLOCK* block;
2092+
} ProcessMemoryIterator;
2093+
2094+
static PyObject* ProcessMemoryIterator_getattro(
2095+
PyObject* self,
2096+
PyObject* name)
2097+
{
2098+
return PyObject_GenericGetAttr(self, name);
2099+
}
2100+
2101+
static void ProcessMemoryIterator_dealloc(PyObject* self);
2102+
2103+
static PyObject* ProcessMemoryIterator_next(PyObject* self);
2104+
2105+
static PyTypeObject ProcessMemoryIterator_Type = {
2106+
PyVarObject_HEAD_INIT(NULL, 0)
2107+
"yara.ProcessMemoryIterator", /*tp_name*/
2108+
sizeof(ProcessMemoryIterator), /*tp_basicsize*/
2109+
0, /*tp_itemsize*/
2110+
(destructor) ProcessMemoryIterator_dealloc, /*tp_dealloc*/
2111+
0, /*tp_print*/
2112+
0, /*tp_getattr*/
2113+
0, /*tp_setattr*/
2114+
0, /*tp_compare*/
2115+
0, /*tp_repr*/
2116+
0, /*tp_as_number*/
2117+
0, /*tp_as_sequence*/
2118+
0, /*tp_as_mapping*/
2119+
0, /*tp_hash */
2120+
0, /*tp_call*/
2121+
0, /*tp_str*/
2122+
ProcessMemoryIterator_getattro, /*tp_getattro*/
2123+
0, /*tp_setattro*/
2124+
0, /*tp_as_buffer*/
2125+
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
2126+
"ProcessMemoryIterator", /* tp_doc */
2127+
0, /* tp_traverse */
2128+
0, /* tp_clear */
2129+
0, /* tp_richcompare */
2130+
0, /* tp_weaklistoffset */
2131+
PyObject_SelfIter, /* tp_iter */
2132+
(iternextfunc) ProcessMemoryIterator_next, /* tp_iternext */
2133+
0, /* tp_methods */ // TODO????
2134+
0, /* tp_members */
2135+
0, /* tp_getset */
2136+
0, /* tp_base */
2137+
0, /* tp_dict */
2138+
0, /* tp_descr_get */
2139+
0, /* tp_descr_set */
2140+
0, /* tp_dictoffset */
2141+
0, /* tp_init */
2142+
0, /* tp_alloc */
2143+
0, /* tp_new */
2144+
};
2145+
2146+
static ProcessMemoryIterator* ProcessMemoryIterator_NEW(void)
2147+
{
2148+
ProcessMemoryIterator* it = PyObject_NEW(ProcessMemoryIterator, &ProcessMemoryIterator_Type);
2149+
if (it == NULL)
2150+
return NULL;
2151+
2152+
it->block_iterator = NULL;
2153+
it->block = NULL;
2154+
2155+
return it;
2156+
}
2157+
2158+
static void ProcessMemoryIterator_dealloc(
2159+
PyObject* self)
2160+
{
2161+
ProcessMemoryIterator* it = (ProcessMemoryIterator*) self;
2162+
2163+
if (it->block_iterator != NULL)
2164+
{
2165+
yr_process_close_iterator(it->block_iterator);
2166+
PyMem_Free(it->block_iterator);
2167+
it->block_iterator = NULL;
2168+
}
2169+
PyObject_Del(self);
2170+
}
2171+
2172+
static PyObject* ProcessMemoryIterator_next(
2173+
PyObject* self)
2174+
{
2175+
ProcessMemoryIterator* it = (ProcessMemoryIterator*) self;
2176+
int err;
2177+
2178+
// This indicates that the iterator has been used.
2179+
if (it->block_iterator == NULL)
2180+
{
2181+
PyErr_SetNone(PyExc_StopIteration);
2182+
return NULL;
2183+
}
2184+
2185+
// During the first invocation, we need to use get_first_memory_block.
2186+
if (it->block == NULL)
2187+
it->block = yr_process_get_first_memory_block(it->block_iterator);
2188+
else
2189+
it->block = yr_process_get_next_memory_block(it->block_iterator);
2190+
2191+
if (it->block == NULL)
2192+
{
2193+
PyErr_SetNone(PyExc_StopIteration);
2194+
return NULL;
2195+
}
2196+
2197+
uint8_t* data_ptr = yr_process_fetch_memory_block_data(it->block);
2198+
if (data_ptr == NULL)
2199+
{
2200+
// This is how we are notified that the process is done.
2201+
it->block = NULL;
2202+
err = yr_process_close_iterator(it->block_iterator);
2203+
PyMem_Free(it->block_iterator);
2204+
it->block_iterator = NULL;
2205+
if (err != 0)
2206+
{
2207+
return handle_error(err, NULL);
2208+
}
2209+
2210+
PyErr_SetNone(PyExc_StopIteration);
2211+
return NULL;
2212+
}
2213+
2214+
return PyBytes_FromStringAndSize(
2215+
(const char*) data_ptr,
2216+
it->block->size);
2217+
}
2218+
2219+
static PyObject* yara_process_memory_iterator(
2220+
PyObject* self,
2221+
PyObject* args,
2222+
PyObject* keywords)
2223+
{
2224+
static char *kwlist[] = {
2225+
"pid", NULL};
2226+
2227+
unsigned int pid = UINT_MAX;
2228+
int err;
2229+
2230+
ProcessMemoryIterator *result;
2231+
2232+
if (!PyArg_ParseTupleAndKeywords(
2233+
args,
2234+
keywords,
2235+
"|I",
2236+
kwlist,
2237+
&pid))
2238+
{
2239+
return PyErr_Format(
2240+
PyExc_TypeError,
2241+
"Error parsing arguments.");
2242+
}
2243+
2244+
result = ProcessMemoryIterator_NEW();
2245+
2246+
result->block_iterator = PyMem_Malloc(sizeof(YR_MEMORY_BLOCK_ITERATOR));
2247+
if (result->block_iterator == NULL)
2248+
return PyErr_NoMemory();
2249+
2250+
// Fail early if we can't access the process with the given pid.
2251+
err = yr_process_open_iterator(pid, result->block_iterator);
2252+
if (err != 0)
2253+
{
2254+
PyMem_Free(result->block_iterator);
2255+
return handle_error(err, NULL);
2256+
}
2257+
2258+
result->block = yr_process_get_first_memory_block(result->block_iterator);
2259+
if (result->block == NULL)
2260+
{
2261+
PyMem_Free(result->block_iterator);
2262+
result->block_iterator = NULL;
2263+
return PyErr_NoMemory();
2264+
}
2265+
return (PyObject *) result;
2266+
}
20852267

20862268
void finalize(void)
20872269
{
@@ -2102,6 +2284,13 @@ static PyMethodDef yara_methods[] = {
21022284
METH_VARARGS | METH_KEYWORDS,
21032285
"Loads a previously saved YARA rules file and returns an instance of class Rules"
21042286
},
2287+
{
2288+
"process_memory_iterator",
2289+
(PyCFunction) yara_process_memory_iterator,
2290+
METH_VARARGS | METH_KEYWORDS,
2291+
"Returns an iterator over blocks of memory of a process.\n"
2292+
"Signature: process_memory_iterator(pid=None)"
2293+
},
21052294
{ NULL, NULL }
21062295
};
21072296

0 commit comments

Comments
 (0)