From 766647f40b9b6421fe6314cc5ca00941f947ea94 Mon Sep 17 00:00:00 2001 From: Lil-Ran Date: Tue, 18 Nov 2025 03:29:59 +0800 Subject: [PATCH] feat: add no banner option --- README.md | 2 +- oneshot/shot.py | 21 +++++++++++++++++---- pycdc/pyarmor-1shot.cpp | 20 ++++++++++++++++---- 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 92104fc..1b502cb 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ Feel free to open an issue if you have any questions, suggestions, or problems. ## Todo (PR Welcome!) - [ ] Documentation (Do not accept PR about this) -- [ ] Regenerate pyc for other backend decompilers (discussion in GH-24, GH-30) +- [ ] Regenerate pyc for other backend decompilers (discussion in [GH-24](https://github.com/Lil-House/Pyarmor-Static-Unpack-1shot/issues/24), [GH-30](https://github.com/Lil-House/Pyarmor-Static-Unpack-1shot/issues/30)) - [ ] BCC Mode native part analysis tool - [ ] Verify support for different obfuscating options - [ ] Verify support for pyarmor_runtime executable on different platforms diff --git a/oneshot/shot.py b/oneshot/shot.py index 8f98479..1852468 100644 --- a/oneshot/shot.py +++ b/oneshot/shot.py @@ -76,14 +76,20 @@ async def run_pycdc_async( exe_path: str, seq_file_path: str, path_for_log: str, + *, + no_banner: bool = False, show_all: bool = False, show_err_opcode: bool = False, show_warn_stack: bool = False, ): logger = logging.getLogger("shot") try: + options = [] + if no_banner: + options.append("--no-banner") process = await asyncio.create_subprocess_exec( exe_path, + *options, seq_file_path, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, @@ -238,9 +244,10 @@ async def decrypt_process_async( exe_path, seq_file_path, relative_path, - args.show_all, - args.show_err_opcode, - args.show_warn_stack, + no_banner=args.no_banner, + show_all=args.show_all, + show_err_opcode=args.show_err_opcode, + show_warn_stack=args.show_warn_stack, ) except Exception as e: @@ -370,6 +377,11 @@ def parse_args(): help="path to the pyarmor-1shot executable to use", type=str, ) + parser.add_argument( + "--no-banner", + help="do not show banner in console and output files", + action="store_true", + ) return parser.parse_args() @@ -381,7 +393,8 @@ def main(): ) logger = logging.getLogger("shot") - print(rf"""{Fore.CYAN} + if not args.no_banner: + print(rf"""{Fore.CYAN} ____ ____ ( __ ) ( __ ) | |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| | diff --git a/pycdc/pyarmor-1shot.cpp b/pycdc/pyarmor-1shot.cpp index e0faf09..2164fd3 100644 --- a/pycdc/pyarmor-1shot.cpp +++ b/pycdc/pyarmor-1shot.cpp @@ -7,12 +7,13 @@ #include "ASTree.h" -const char* VERSION = "v0.2.1"; +const char* VERSION = "v0.2.1+"; int main(int argc, char* argv[]) { const char* infile = nullptr; unsigned disasm_flags = 0; + bool banner = true; std::ofstream dc_out_file; std::ofstream das_out_file; @@ -26,13 +27,20 @@ int main(int argc, char* argv[]) fputs("Options:\n", stderr); fputs(" --pycode-extra Show extra fields in PyCode object dumps\n", stderr); fputs(" --show-caches Don't suprress CACHE instructions in Python 3.11+ disassembly\n", stderr); + fputs(" --no-banner Don't output banner\n", stderr); fputs(" --help Show this help text and then exit\n", stderr); return 0; + } else if (strcmp(argv[arg], "--no-banner") == 0) { + banner = false; } else if (argv[arg][0] == '-') { fprintf(stderr, "Error: Unrecognized argument %s\n", argv[arg]); return 1; - } else { + } else if (!infile) { infile = argv[arg]; + } else { + fprintf(stderr, "Error: Only one input file allowed, got %s and %s\n", + infile, argv[arg]); + return 1; } } @@ -79,7 +87,7 @@ int main(int argc, char* argv[]) const char* disp_prefix = strrchr(prefix_name.c_str(), PATHSEP); disp_prefix = (disp_prefix == NULL) ? prefix_name.c_str() : disp_prefix + 1; - formatted_print( + banner && formatted_print( das_out_file, R"(# File: %s (Python %d.%d) # Disassembly generated by Pyarmor-Static-Unpack-1shot (%s), powered by pycdas @@ -111,13 +119,15 @@ int main(int argc, char* argv[]) das_out_file); } catch (std::exception& ex) { fprintf(stderr, "Error disassembling %s: %s\n", infile, ex.what()); + das_out_file.flush(); + das_out_file.close(); return 1; } das_out_file.flush(); das_out_file.close(); - formatted_print( + banner && formatted_print( dc_out_file, R"(# File: %s (Python %d.%d) # Source generated by Pyarmor-Static-Unpack-1shot (%s), powered by Decompyle++ (pycdc) @@ -136,6 +146,8 @@ int main(int argc, char* argv[]) decompyle(mod.code(), &mod, dc_out_file); } catch (std::exception& ex) { fprintf(stderr, "Error decompyling %s: %s\n", infile, ex.what()); + dc_out_file.flush(); + dc_out_file.close(); return 1; }