Python如何使用特殊字符密码解压7z文件?

5

我正在尝试使用7z.exe解压一个文件,该文件的密码中包含特殊字符。

例如:&)kra932(lk0¤23

通过执行以下命令:

subprocess.call(['7z.exe', 'x', '-y', '-ps^&)kratsaslkd932(lkasdf930¤23', 'file.zip'])

7z.exe能够正常启动,但是显示密码错误。

这是我创建的一个文件,让我感到很烦恼。

如果在Windows命令行上运行该命令,则可以正常运行。

7z.exe x -y -ps^&)kratsaslkd932(lkasdf930¤23 file.zip

如何让Python转义&字符?


@Wim,问题出现在密码中,因为当我执行时会出现&

7z.exe x -y -ps^&)kratsaslkd932(lkasdf930¤23 file.zip 

错误提示为“无效命令 ')kratsaslkd932(lkasdf930¤23'”,我正在使用Python 2.76,由于公司工具仅能在2.76上运行,因此无法升级至3.x版本。


听起来像是Python 2.7!如果是的话:subprocess.call(['7z.exe', 'x', '-y', u'-ps^&)kratsaslkd932(lkasdf930¤23', 'file.zip']) - Kroltan
1
你的密码从哪个字符开始?示例密码与实际使用的不同。 - wim
Python的哪个版本?有什么特殊字符,例如非字母数字、Unicode、bash转义字符?我在你的示例中看到了这三个。 - dimo414
顺便说一下,我认为你的问题是¤字符,而不是&。Kroltan上面的建议可能会起作用! - wim
如果在Python3上运行是一个选项,那么你的代码可能也可以直接运行。 - wim
@wim 这个问题发生在密码上,因为当我执行以下命令时7z.exe x -y -ps^&)kratsaslkd932(lkasdf930¤23 file.zip它会显示无效的命令')kratsaslkd932(lkasdf930¤23'我正在使用 Python 2.76,由于公司工具只能在2.76上运行,所以无法升级到3.x。 - Barecool
3个回答

1
在命令行中传递密码存在很大的安全风险。具有管理员权限时,可以检索该信息(启动信息对象)并提取密码。更好的解决方案是将7zip作为进程打开,并将密码输入其标准输入。以下是将“source.txt”压缩为“dest.7z”的命令行示例:
CMD = ['c:\\Program Files\\7-Zip\\7z.exe', 'a', '-t7z', '-p', 'c:\\source.txt', 'd:\\dest.7z']
PASSWORD = "Nj@8G86Tuj#a"

首先,您需要将密码转换为输入字符串。请注意,7-zip希望密码在终端中输入。只要这些特殊字符可以在您的终端中表示,就可以使用它们。终端的编码很重要!例如,在匈牙利Windows上,您可能想使用“cp1250”编码。在所有情况下,标准输入是一个二进制文件,并且它期望一个二进制字符串(Python 3中的“bytes”)。如果您想保险起见,可以将密码限制为纯ASCII,并像这样创建您的输入:
input = (PASSWORD + "\r\n").encode("ascii")

如果您知道终端的编码方式,那么可以将密码转换为该编码方式。您还可以检测密码是否无法与系统的编码方式兼容。(顺便提一下,这意味着它也无法交互使用。)
(上次我检查时,Windows 上不同区域设置的终端编码是不同的。也许有一些技巧可以将其更改为 UTF-8,但我不确定如何操作。)
以下是执行命令的方法:
import subprocess
import typing

def execute(cmd : typing.List[str], input: typing.Optional[bytes] = None, verbose=False, debug=False, normal_priority=False):
    if verbose:
        print(cmd)
    creationflags = subprocess.CREATE_NO_WINDOW
    if normal_priority:
        creationflags |= subprocess.NORMAL_PRIORITY_CLASS
    else:
        creationflags |= subprocess.BELOW_NORMAL_PRIORITY_CLASS

    if debug:
        process = subprocess.Popen(cmd, shell=False, stdout=sys.stdout, stderr=sys.stderr, stdin=subprocess.PIPE,
                                   creationflags=creationflags)
    else:
        process = subprocess.Popen(cmd, shell=False, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
                                   stdin=subprocess.PIPE, creationflags=creationflags)
    if input:
        process.stdin.write(input)
        process.stdin.flush()
    returncode = process.wait()
    if returncode:
        raise OSError(returncode)


CMD = ['c:\\Program Files\\7-Zip\\7z.exe', 'a', '-t7z', '-p', 'c:\\source.txt', 'd:\\dest.7z']
PASSWORD = "Nj@8G86Tuj#a"
input = (PASSWORD + "\r\n").encode("ascii")
execute(CMD, input)

这还展示了如何降低进程优先级(在压缩大量数据时通常是一个好主意),它还展示了如何将标准输出和标准错误转发到控制台。
绝对正确的解决方案是加载7-zip DLL并使用其API。(我没有检查,但可能可以使用8位二进制密码字符串。)
注意:此示例适用于Python 3,但可以使用Python 2完成相同的操作。

0
我建议使用原始字符串和shlex模块(特别是在Windows上),不支持除ASCII以外的任何编码。
import shlex
import subprocess

cmd = r'7z.exe x -y -p^&moreASCIIpasswordchars file.zip'
subprocess.call(shlex.split(cmd))

回到非ASCII字符问题...

我相信在Python版本< 3中,您根本无法使用非ASCII字符。虽然我不是C语言专家,但请注意2.73.3之间的区别。前者使用“标准”字符,而后者使用宽字符。


-1

尝试在密码之间加双引号,否则命令解析器会将任何特殊字符解析为密码的一部分,而不是作为特殊字符处理。

例如,7z.exe x -y -ps^&)kratsaslkd932(lkasdf930¤23 file.zip 无法工作。

但是 7z.exe x -y -p"s^&)kratsaslkd932(lkasdf930¤23" file.zip 一定可以正常工作。


这是完全错误的,因为没有涉及到 shell。如果有 shell=True,那么这将是必要且有用的;但是现在并没有。请参见 https://dev59.com/lHA75IYBdhLWcg3wqK__。 - tripleee

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接