4 Commits

Author SHA1 Message Date
8c46b62352 opt: head msg 2025-10-12 21:11:19 +08:00
d0d3f74733 feat: default runtime (000000) 2025-10-12 20:42:39 +08:00
ec8581104d release v0.2.1 2025-10-12 20:13:49 +08:00
236233bb17 fix: keep bcc callsite args 2025-10-12 19:48:36 +08:00
4 changed files with 49 additions and 14 deletions

View File

@@ -85,6 +85,33 @@ class RuntimeInfo:
def mix_str_aes_nonce(self) -> bytes:
return self.part_3[:12]
@classmethod
def default(cls) -> 'RuntimeInfo':
instance = cls.__new__(cls)
instance.file_path = '<default>'
instance.part_1 = b'pyarmor-vax-000000\x00\x00'
instance.part_2 = bytes.fromhex('''
30 81 89 02 81 81 00 A8 ED 64 F4 83 49 13 FC 0F
86 6F 00 5A 8F E4 91 AA ED 1C EA D4 BB 4C 3F 7C
24 21 01 A8 D0 7D 93 F4 BF E7 FB 8C 06 57 88 6A
2E 9B 54 53 D5 7B 8F F6 83 DF 72 00 42 A3 2D 18
30 AD 3A E4 F1 E4 3A 3C 8C EA F5 46 F3 BB 75 62
11 84 FB 3F 3B 4C 35 61 4E 46 A1 E0 9E 3C B6 7A
BA 52 C5 B6 40 F6 AD AB BC D5 CF 5B 40 CB 8D 13
C4 28 B8 90 93 C4 76 01 09 8E 05 1E 61 FA 90 4C
BF 67 D4 A7 D5 82 C1 02 03 01 00 01
''')
instance.part_3 = bytes.fromhex('''
69 2E 6E 6F 6E 2D 70 72 6F 66 69 74 73 E7 5A 41
9B DC 77 53 CA 1D E7 04 EB EF DA C9 A3 6C 0F 7B
00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00
''')
instance.serial_number = '000000'
instance.runtime_aes_key = instance.calc_aes_key()
return instance
if __name__ == '__main__':
import sys

View File

@@ -122,7 +122,7 @@ async def decrypt_process_async(runtimes: Dict[str, RuntimeInfo], sequences: Lis
bcc_architecture_id = int.from_bytes(bcc_aes_decrypted[8:12], 'little')
bcc_next_segment_offset = int.from_bytes(bcc_aes_decrypted[12:16], 'little')
bcc_architecture = bcc_architecture_mapping.get(bcc_architecture_id, f'0x{bcc_architecture_id:x}')
bcc_file_path = f'{dest_path}.1shot.bcc.{bcc_architecture}.elf'
bcc_file_path = f'{dest_path}.1shot.bcc.{bcc_architecture}.so'
with open(bcc_file_path, 'wb') as f:
f.write(bcc_aes_decrypted[bcc_segment_offset:bcc_segment_offset+bcc_segment_length])
logger.info(f'{Fore.GREEN}Extracted BCC mode native part: {bcc_file_path}{Style.RESET_ALL}')
@@ -288,7 +288,7 @@ def main():
| | |_| \_, |\__,_|_| |_||_||_|\___/|_| |_|___/|_||_|\___/ \__| | |
| | |__/ | |
|__|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|__|
(____) v0.2.0+ (____)
(____) v0.2.1 (____)
For technology exchange only. Use at your own risk.
GitHub: https://github.com/Lil-House/Pyarmor-Static-Unpack-1shot
@@ -300,7 +300,7 @@ def main():
runtimes = {specified_runtime.serial_number: specified_runtime}
else:
specified_runtime = None
runtimes = {}
runtimes = {'000000': RuntimeInfo.default()}
sequences: List[Tuple[str, bytes]] = []

View File

@@ -170,7 +170,11 @@ void CallOrPyarmorBuiltins(FastStack &stack, PycRef<ASTBlock> &curblock, PycModu
return;
PycRef<PycString> func_name = call->func().cast<ASTObject>()->object().try_cast<PycString>();
if (func_name == nullptr || !func_name->startsWith("__pyarmor_"))
if (
func_name == nullptr
|| !func_name->startsWith("__pyarmor_")
|| func_name->startsWith("__pyarmor_bcc_")
)
return;
const std::string& name = func_name->strValue();

View File

@@ -7,7 +7,7 @@
#include "ASTree.h"
const char* VERSION = "v0.2.0+";
const char* VERSION = "v0.2.1";
int main(int argc, char* argv[])
{
@@ -76,12 +76,15 @@ int main(int argc, char* argv[])
const char* dispname = strrchr(infile, PATHSEP);
dispname = (dispname == NULL) ? infile : dispname + 1;
const char* disp_prefix = strrchr(prefix_name.c_str(), PATHSEP);
disp_prefix = (disp_prefix == NULL) ? prefix_name.c_str() : disp_prefix + 1;
formatted_print(
das_out_file,
R"(# Disassembly generated by Pyarmor-Static-Unpack-1shot (%s), powered by pycdas
# File: %s (Python %d.%d)
R"(# File: %s (Python %d.%d)
# Disassembly generated by Pyarmor-Static-Unpack-1shot (%s), powered by pycdas
# ================================
# Pyarmor notes:
# - Pyarmor bytecode and code objects match standard Python, but special calls to Pyarmor runtime functions exist.
# - Calls on strings are not mistakes but markers, which are processed by Pyarmor at runtime.
@@ -89,18 +92,19 @@ int main(int argc, char* argv[])
# Decompilation guidance (without runtime):
# 1. Ignore encrypted bytes after `#`; use only the string before `#`.
# 2. Remove `"__pyarmor_enter_xxx__"(b"<COAddr>...")` and `"__pyarmor_leave_xxx__"(b"<COAddr>...")` (prologue/epilogue).
# 3. For `"__pyarmor_assert_xxx__"(A)`, it is not a real assert statement.
# 3. `"__pyarmor_assert_xxx__"(A)` is not a real assert statement.
# - If `A` is a name or readable string: replace with `A`.
# - If `A` is `(X, "Y")`: replace with `X.Y`.
# - If `A` is `(X, "Y", Z)`: replace with `X.Y = Z`.
# - Otherwise: choose the most reasonable replacement.
# 4. `"__pyarmor_bcc_xxx__"(...)` indicates native code; function body is not available. Add a comment.
# ================================
)",
VERSION,
dispname,
mod.majorVer(),
mod.minorVer()
mod.minorVer(),
VERSION
);
try {
output_object(mod.code().try_cast<PycObject>(), &mod, 0, disasm_flags,
@@ -115,18 +119,18 @@ int main(int argc, char* argv[])
formatted_print(
dc_out_file,
R"(# Source generated by Pyarmor-Static-Unpack-1shot (%s), powered by Decompyle++ (pycdc)
# File: %s (Python %d.%d)
R"(# File: %s (Python %d.%d)
# Source generated by Pyarmor-Static-Unpack-1shot (%s), powered by Decompyle++ (pycdc)
# Note: Decompiled code can be incomplete and incorrect.
# Please also check the correct and complete disassembly file: %s.das
)",
VERSION,
dispname,
mod.majorVer(),
mod.minorVer(),
prefix_name.c_str()
VERSION,
disp_prefix
);
try {
decompyle(mod.code(), &mod, dc_out_file);