난독화 퍼즐:이 Perl 함수가 무엇을 하는지 알아낼 수 있나요?[닫은]
-
01-07-2019 - |
문제
sub foo {[$#{$_[!$||$|]}*@{$_[!!$_^!$_]}?@{$_[!$..!!$.]}[$_[@--@+]%
@{$_[$==~/(?=)//!$`]}..$#{$_[$??!!$?:!$?]},($)?!$):!!$))..$_[$--$-]%@{
$_[$]/$]]}-(!!$++!$+)]:@{$_[!!$^^^!$^^]}]}
업데이트:나는 "퍼즐"이라는 단어가 이것을 암시할 것이라고 생각했지만, 나 그것이 무엇을 하는지 알아라 - 내가 썼다.퍼즐에 관심이 없다면 시간을 낭비하지 마세요.
해결책
이 서브루틴을 난독화 해제하는 방법을 알아내는 방법은 다음과 같습니다.
길이가 아쉽네요
먼저 코드를 정리하고 유용한 주석을 추가해 보겠습니다.
sub foo {
[
(
# ($#{$_[1]})
$#{
$_[
! ( $| | $| )
# $OUTPUT_AUTOFLUSH === $|
# $| is usually 0
# ! ( $| | $| )
# ! ( 0 | 0 )
# ! ( 0 )
# 1
]
}
*
# @{$_[1]}
@{
$_[
!!$_ ^ !$_
# !! 1 ^ ! 1
# ! 0 ^ 0
# 1 ^ 0
# 1
# !! 0 ^ ! 0
# ! 1 ^ 1
# 0 ^ 1
# 1
]
}
)
?
# @{$_[1]}
@{
$_[
!$. . !!$.
# $INPUT_LINE_NUMBER === $.
# $. starts at 1
# !$. . !!$.
# ! 1 . !! 1
# 0 . ! 0
# 0 . 1
# 01
]
}
[
# $_[0]
$_[
# @LAST_MATCH_START - @LAST_MATCH_END
# 0
@- - @+
]
%
# @{$_[1]}
@{
$_[
$= =~ /(?=)/ / !$` #( fix highlighting )`/
# $= is usually 60
# /(?=)/ will match, returns 1
# $` will be ''
# 1 / ! ''
# 1 / ! 0
# 1 / 1
# 1
]
}
..
# $#{$_[1]}
$#{
$_[
$? ? !!$? : !$?
# $CHILD_ERROR === $?
# $? ? !!$? : !$?
# 0 ? !! 0 : ! 0
# 0 ? 0 : 1
# 1
# 1 ? !! 1 : ! 1
# 1 ? 1 : 0
# 1
]
}
,
# ( 0 )
(
$) ? !$) : !!$)
# $EFFECTIVE_GROUP_ID === $)
# $) ? !$) : !!$)
# 0 ? ! 0 : !! 0
# 0 ? 1 : 0
# 0
# 1 ? ! 1 : !! 1
# 1 ? 0 : 1
# 0
)
..
# $_[0]
$_[
$- - $- # 0
# $LAST_PAREN_MATCH = $-
# 1 - 1 == 0
# 5 - 5 == 0
]
%
# @{$_[1]}
@{
$_[
$] / $]
# $] === The version + patchlevel / 1000 of the Perl interpreter.
# 1 / 1 == 1
# 5 / 5 == 1
]
}
-
# ( 1 )
(
!!$+ + !$+
# !! 1 + ! 1
# ! 0 + 0
# 1 + 0
# 1
)
]
:
# @{$_[1]}
@{
$_[
!!$^^ ^ !$^^
# !! 1 ^ ! 1
# ! 0 ^ 0
# 1 ^ 0
# 1
# !! 0 ^ ! 0
# ! 1 ^ 1
# 0 ^ 1
# 1
]
}
]
}
이제 일부 난독화를 제거해 보겠습니다.
sub foo{
[
(
$#{$_[1]} * @{$_[1]}
)
?
@{$_[1]}[
( $_[0] % @{$_[1]} ) .. $#{$_[1]}
,
0 .. ( $_[0] % @{$_[1]} - 1 )
]
:
@{$_[1]}
]
}
이제 무슨 일이 일어나고 있는지 알았으니 변수 이름을 지정해 보겠습니다.
sub foo{
my( $item_0, $arr_1 ) = @_;
my $len_1 = @$arr_1;
[
# This essentially just checks that the length of $arr_1 is greater than 1
( ( $len_1 -1 ) * $len_1 )
# ( ( $len_1 -1 ) * $len_1 )
# ( ( 5 -1 ) * 5 )
# 4 * 5
# 20
# 20 ? 1 : 0 == 1
# ( ( $len_1 -1 ) * $len_1 )
# ( ( 2 -1 ) * 2 )
# 1 * 2
# 2
# 2 ? 1 : 0 == 1
# ( ( $len_1 -1 ) * $len_1 )
# ( ( 1 -1 ) * 1 )
# 0 * 1
# 0
# 0 ? 1 : 0 == 0
# ( ( $len_1 -1 ) * $len_1 )
# ( ( 0 -1 ) * 0 )
# -1 * 0
# 0
# 0 ? 1 : 0 == 0
?
@{$arr_1}[
( $item_0 % $len_1 ) .. ( $len_1 -1 ),
0 .. ( $item_0 % $len_1 - 1 )
]
:
# If we get here, @$arr_1 is either empty or has only one element
@$arr_1
]
}
코드를 좀 더 읽기 쉽게 리팩터링해 보겠습니다.
sub foo{
my( $item_0, $arr_1 ) = @_;
my $len_1 = @$arr_1;
if( $len_1 > 1 ){
return [
@{$arr_1}[
( $item_0 % $len_1 ) .. ( $len_1 -1 ),
0 .. ( $item_0 % $len_1 - 1 )
]
];
}elsif( $len_1 ){
return [ @$arr_1 ];
}else{
return [];
}
}
다른 팁
다른 답변을 작업할 때 이 명령이 도움이 된다는 것을 알았습니다.
perl -MO=Concise,foo,-terse,-compact obpuz.pl > obpuz.out
두 개의 arrayref를 사용하고 두 번째 부분이 첫 번째 부분 앞에 오도록 재정렬된 두 번째 배열의 내용을 사용하여 새 arrayref를 반환하고 첫 번째 배열의 메모리 위치를 기준으로 한 지점에서 분할합니다.두 번째 배열이 비어 있거나 하나의 항목을 포함하는 경우 두 번째 배열의 복사본을 반환합니다.다음과 동일합니다.
sub foo {
my ($list1, $list2) = @_;
my @output;
if (@$list2 > 0) {
my $split = $list1 % @$list2;
@output = @$list2[$split .. $#$list2, 0 .. ($split - 1)];
} else {
@output = @$list2;
}
return \@output;
}
$list1 % @$list2
본질적으로 배열을 분할할 임의의 장소를 선택합니다. $list
숫자 컨텍스트에서 평가할 때 $list의 메모리 주소로 평가됩니다.
원본은 대부분 난독화를 위해 구두점 변수와 관련된 많은 동어반복을 사용합니다.예를 들어
!$| | $|
항상 1이다@- - @+
항상 0이다
다음 사항을 참고하도록 업데이트되었습니다. perltidy
여기서 해독하는 데 매우 도움이 되었지만 숨이 막혔습니다. !!$^^^!$^^
, 이는 다음과 같이 다시 포맷됩니다. !!$^ ^ ^ !$^ ^
, 이는 유효하지 않은 Perl입니다.그것은해야한다 !!$^^ ^ !$^^
.이것이 RWendi의 컴파일 오류의 원인일 수 있습니다.