如何在 perl 中完成这个字节修改?
How to accomplish this byte munging in perl?
背景:
我正在尝试使用 here 中的 perl 脚本来解密 android 备份。不幸的是,校验和验证失败。
玩完 this (Python) script 之后,问题似乎是我需要对主密钥进行一些额外的修改(n.b。[=64= 中的 masterKeyJavaConversion
] 脚本)。
问题:
我需要取一包字节并执行以下转换步骤:
- 从 signed char 符号扩展到 signed short
- 将结果从 UTF16(BE?)转换为 UTF-8
例如(所有字节均为十六进制):
- 3x → 3x
- 7x → 7x
- ax -> ef 是 ax
- bx -> ef 为 bx
- cx -> ef bf 8x
- dx -> ef bf 9x
- ex -> ef bf ax
- fx -> ef bf bx
(x
始终保持不变。)
更具体地说,给定一个位序列1abc defg
,我需要输出1110 1111 1011 111a 10bc defg
。 (对于 0abc defg
,输出只是 0abc defg
,即不变。)
答案可以使用UTF转换,也可以直接进行位操作;我不在乎,只要它有效(这不是性能关键)。子程序形式的答案是理想的。 (我的主要问题是我对 Perl 的了解还不够危险。如果这是 C/C++,我不需要帮助,但是用另一种语言重写整个脚本将是一项重大任务,或者将 Python 脚本修改为不需要将整个输入读入内存。)
1110 1111 1011 111a 10bc defg
将是有效的 UTF-8 编码。
++++-------------------------- Start of three byte sequence
|||| ++------------------- Continuation byte
|||| || ++---------- Continuation byte
|||| || ||
11101111 1011111a 10bcdefg
|||| |||||| ||||||
++++---++++++---++++++---- 1111 1111 1abc defg
这只是将 8 位有符号数扩展为 16 位,转换为无符号数,并被视为 Unicode 代码点。
所以,不看代码,我想你想要
sub encode_utf8 {
my ($s) = @_;
utf8::encode($s);
return $s;
}
sub munge {
return
encode_utf8 # "\x30\x70\xEF\xBE\xA0..."
pack 'W*', # "\x{0030}\x{0x0070}\x{0xFFA0}..."
unpack 'S*', # 0x0030, 0x0070, 0xFFA0, ...
pack 's*', # "\x30\x00\x70\x00\xA0\xFF..." (on a LE machine)
unpack 'c*', # 48, 112, -96, ...
$_[0]; # "\x30\x70\xA0..."
}
my $s = "\x30\x70\xA0\xB0\xC0\xD0\xE0\xF0";
my $munged = munge($s);
如果删除评论,您会得到以下内容:
sub munge {
my $s = pack 'W*', unpack 'S*', pack 's*', unpack 'c*', $_[0];
utf8::encode($s);
return $s;
}
这里有很多 faster 解决方案:
my @map = (
( map chr($_), 0x00..0x7F ),
( map "\xEF\xBE".chr($_), 0x80..0xBF ),
( map "\xEF\xBF".chr($_), 0xC0..0xFF ),
);
sub munge { join '', @map[ unpack 'C*', $_[0] ] }
这可能不如 ikegami's answer 优雅,但它确实有效:
sub munge_mk
{
my $out;
foreach(unpack('C*', $_[0])) {
if($_ < 128) {
$out .= chr($_);
} else {
my $hi = 0xbc | (($_ & 0xc0) >> 6);
my $lo = 0x80 | ($_ & 0x3f);
$out .= chr(0xef) . chr($hi) . chr($lo);
}
}
return $out;
}
背景:
我正在尝试使用 here 中的 perl 脚本来解密 android 备份。不幸的是,校验和验证失败。
玩完 this (Python) script 之后,问题似乎是我需要对主密钥进行一些额外的修改(n.b。[=64= 中的 masterKeyJavaConversion
] 脚本)。
问题:
我需要取一包字节并执行以下转换步骤:
- 从 signed char 符号扩展到 signed short
- 将结果从 UTF16(BE?)转换为 UTF-8
例如(所有字节均为十六进制):
- 3x → 3x
- 7x → 7x
- ax -> ef 是 ax
- bx -> ef 为 bx
- cx -> ef bf 8x
- dx -> ef bf 9x
- ex -> ef bf ax
- fx -> ef bf bx
(x
始终保持不变。)
更具体地说,给定一个位序列1abc defg
,我需要输出1110 1111 1011 111a 10bc defg
。 (对于 0abc defg
,输出只是 0abc defg
,即不变。)
答案可以使用UTF转换,也可以直接进行位操作;我不在乎,只要它有效(这不是性能关键)。子程序形式的答案是理想的。 (我的主要问题是我对 Perl 的了解还不够危险。如果这是 C/C++,我不需要帮助,但是用另一种语言重写整个脚本将是一项重大任务,或者将 Python 脚本修改为不需要将整个输入读入内存。)
1110 1111 1011 111a 10bc defg
将是有效的 UTF-8 编码。
++++-------------------------- Start of three byte sequence
|||| ++------------------- Continuation byte
|||| || ++---------- Continuation byte
|||| || ||
11101111 1011111a 10bcdefg
|||| |||||| ||||||
++++---++++++---++++++---- 1111 1111 1abc defg
这只是将 8 位有符号数扩展为 16 位,转换为无符号数,并被视为 Unicode 代码点。
所以,不看代码,我想你想要
sub encode_utf8 {
my ($s) = @_;
utf8::encode($s);
return $s;
}
sub munge {
return
encode_utf8 # "\x30\x70\xEF\xBE\xA0..."
pack 'W*', # "\x{0030}\x{0x0070}\x{0xFFA0}..."
unpack 'S*', # 0x0030, 0x0070, 0xFFA0, ...
pack 's*', # "\x30\x00\x70\x00\xA0\xFF..." (on a LE machine)
unpack 'c*', # 48, 112, -96, ...
$_[0]; # "\x30\x70\xA0..."
}
my $s = "\x30\x70\xA0\xB0\xC0\xD0\xE0\xF0";
my $munged = munge($s);
如果删除评论,您会得到以下内容:
sub munge {
my $s = pack 'W*', unpack 'S*', pack 's*', unpack 'c*', $_[0];
utf8::encode($s);
return $s;
}
这里有很多 faster 解决方案:
my @map = (
( map chr($_), 0x00..0x7F ),
( map "\xEF\xBE".chr($_), 0x80..0xBF ),
( map "\xEF\xBF".chr($_), 0xC0..0xFF ),
);
sub munge { join '', @map[ unpack 'C*', $_[0] ] }
这可能不如 ikegami's answer 优雅,但它确实有效:
sub munge_mk
{
my $out;
foreach(unpack('C*', $_[0])) {
if($_ < 128) {
$out .= chr($_);
} else {
my $hi = 0xbc | (($_ & 0xc0) >> 6);
my $lo = 0x80 | ($_ & 0x3f);
$out .= chr(0xef) . chr($hi) . chr($lo);
}
}
return $out;
}