3 Commits

Author SHA1 Message Date
8fba94269c fix: friendly message for upx (gh-12, gh-35) 2026-02-23 21:03:20 +08:00
Shunran Lei
fc4e96a164 Merge pull request #32 from lweipanw/main
fix(detect & shot): not necessarily starts with b"PY00" e.g. PY01xxx
2026-01-31 01:39:45 +08:00
Lee Wei
0658f455f7 fix(detect & shot): not necessarily starts with b"PY00" e.g. PY01xxx 2026-01-31 01:30:43 +08:00
4 changed files with 28 additions and 16 deletions

View File

@@ -3,7 +3,7 @@
name: Regression Test
on:
push:
branches: [main]
branches: [main, update-tests]
jobs:
regtest:

View File

@@ -49,12 +49,12 @@ def find_data_from_bytes(data: bytes, max_count=-1) -> List[bytes]:
result = []
idx = 0
while len(result) != max_count:
idx = data.find(b"PY00") # XXX: not necessarily starts with b"PY"
idx = data.find(b"PY0") # XXX: not necessarily starts with b"PY"
if idx == -1:
break
data = data[idx:]
if len(data) < 64:
# don't break if len > 64, maybe there is PY00blahPY000000
# don't break if len > 64, maybe there is PY0blahPY0
break
header_len = dword(data, 28)
body_len = dword(data, 32)
@@ -86,7 +86,7 @@ def find_data_from_bytes(data: bytes, max_count=-1) -> List[bytes]:
def nuitka_package(
head: bytes, relative_path: str
) -> Union[List[Tuple[str, bytes]], None]:
first_occurrence = head.find(b"PY00")
first_occurrence = head.find(b"PY0")
if first_occurrence == -1:
return None
last_dot_bytecode = head.rfind(b".bytecode\x00", 0, first_occurrence)

View File

@@ -66,9 +66,21 @@ class RuntimeInfo:
"""
with open(self.file_path, "rb") as f:
data = f.read(16 * 1024 * 1024)
cur = data.index(b"pyarmor-vax")
cur = data.find(b"pyarmor-vax")
if cur == -1:
# Specially, check UPX (GH-12, GH-35)
if data.find(b"UPX!") != -1 and data.find(b"UPX0") != -1:
logger.error(
f"{self.file_path} seems to be packed by UPX. Before it can be processed, you need to unpack it first: Download UPX from https://github.com/upx/upx, and run `upx -d {self.file_path}` (you may need to escape the file path) in the command line."
)
else:
logger.error(
f"{self.file_path} does not contain 'pyarmor-vax'. Maybe it's packed, obfuscated, or generated by an unsupported version of Pyarmor."
)
raise ValueError(f"{self.file_path} does not contain 'pyarmor-vax'")
if data[cur + 11 : cur + 18] == b"\x00" * 7:
# Do not log. Skip this file silently and find another.
raise ValueError(f"{self.file_path} is a runtime template")
# Align with pyd file and executable address:
@@ -78,7 +90,7 @@ class RuntimeInfo:
if data[0x5C] & 1 != 0:
logger.error(
'External key file ".pyarmor.ikey" is not supported yet, but it will be supported once we get a sample (like this one). Please open an issue on https://github.com/Lil-House/Pyarmor-Static-Unpack-1shot/issues to make this tool stronger.'
f'External key file ".pyarmor.ikey" is not supported yet, but it will be supported once we get a sample (like this one). Please open an issue on https://github.com/Lil-House/Pyarmor-Static-Unpack-1shot/issues to make this tool stronger. ({self.file_path})'
)
raise NotImplementedError(f'{self.file_path} uses ".pyarmor.ikey"')

View File

@@ -401,16 +401,16 @@ def main():
if not args.no_banner:
print(rf"""{Fore.CYAN}
____ ____
____ ____
( __ ) ( __ )
| |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| |
| | ____ _ ___ _ _ | |
| | | _ \ _ _ __ _ _ __ _ _ __ ___ _ _ / / __|| |_ ___ | |_ | |
| | | |_) | || |/ _` | '__| ' ` \ / _ \| '_| | \__ \| ' \ / _ \| __| | |
| | | __/| || | (_| | | | || || | (_) | | | |__) | || | (_) | |_ | |
| | |_| \_, |\__,_|_| |_||_||_|\___/|_| |_|___/|_||_|\___/ \__| | |
| | |__/ | |
|__|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|__|
| |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| |
| | ____ _ ___ _ _ | |
| | | _ \ _ _ __ _ _ __ _ _ __ ___ _ _ / / __|| |_ ___ | |_ | |
| | | |_) | || |/ _` | '__| ' ` \ / _ \| '_| | \__ \| ' \ / _ \| __| | |
| | | __/| || | (_| | | | || || | (_) | | | |__) | || | (_) | |_ | |
| | |_| \_, |\__,_|_| |_||_||_|\___/|_| |_|___/|_||_|\___/ \__| | |
| | |__/ | |
|__|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|__|
(____) v0.2.2 (____)
For technology exchange only. Use at your own risk.
@@ -482,7 +482,7 @@ def main():
if file_name.endswith(".pyz"):
with open(file_path, "rb") as f:
head = f.read(16 * 1024 * 1024)
if b"PY00" in head and (
if b"PY0" in head and (
not os.path.exists(file_path + "_extracted")
or len(os.listdir(file_path + "_extracted")) == 0
):