Почему эта команда возвращает "ПОЛУЧИТЕ ЖИЗНЬ!"?

Я просматривал список Забавных Команд UNIX, когда наткнулся на эту:

$ echo '[q]sa[ln0=aln256%Pln256/snlbx]sb3135071790101768542287578439snlbxq'|dc
GET A LIFE!

Я никогда не читал о dc команда, поэтому я прошел страницу вики и сумел научиться делать такие мелочи, как:

$ echo "4 5 + p" | dc
9
$ echo "2 10 ^ p" | dc
1024

Тем не менее, команда [q]sa[ln0=aln256%Pln256/snlbx]sb3135071790101768542287578439snlbxq звучит слишком много для меня. Есть ли способ объяснить это понятным образом (и вернуть мою жизнь)?

1 ответ

Решение

… команда [q]sa[ln0=aln256%Pln256/snlbx]sb3135071790101768542287578439snlbxq звучит слишком много для меня. Есть ли способ объяснить это понятным образом...

Соответствующие части man dc:

Ввод числа помещает его в стек.
[ персонажи ]
Создает строку, содержащую символы (содержащиеся между сбалансированными символами [ и ]), и помещает ее в стек.
с р
Выкиньте значение из верхней части стека и сохраните его в регистре r.
л р
Скопируйте значение в регистр r и поместите его в стек.
Икс
Вытаскивает значение из стека и выполняет его как макрос.
= г
Вытаскивает два значения из стека и сравнивает их, предполагая, что они являются числами, выполняя содержимое регистра r как макрос, если два выдвинутых числа равны.
/
Выдвигает два значения, делит второе, извлеченное из первого, и выталкивает результат.
%
Получает два значения, вычисляет остаток от деления, которое будет выполнять команда /, и выталкивает это.
п
Выскакивает значение в верхней части стека. Если это строка, она просто печатается без завершающей строки. В противном случае это число, и целочисленная часть его абсолютного значения выводится в виде потока байтов "base (UCHAR_MAX+1)".
Q
выходит из макроса, а также из макроса, который его вызвал. При вызове с верхнего уровня или из макроса, который был вызван непосредственно с верхнего уровня, команда q вызовет выход dc.

Так,

  • [q]sa хранит строку q в реестр a,
  • [ln0=aln256%Pln256/snlbx]sb хранит строку ln0=aln256%Pln256/snlbx в реестр b,
  • 3135071790101768542287578439sn хранит номер 3135071790101768542287578439 в n,
  • lbx выполняет строку ln0=aln256%Pln256/snlbx из реестра b,
  • ln0=a выполняет, если n равно нулю, строка q из реестра a т.е. выходит из макроса.
  • ln256%P распечатывает байт n мод 256, сначала 71, что является ASCII G,
  • ln256/sn водоразделы n на 256, тем самым обрезая последний байт.
  • lbx периодически выполняет строку ln0=aln256%Pln256/snlbx из реестра b, Повторяющиеся исполнения дают байты ASCII ETALIFE!\n последовательно.

В увлекательных материалах UNIX - echo и dc - obfuscate/garble - строка, в которой вы можете найти скрипт для обфускации строк, например, вместе с объяснением того, как его использовать:

Если вы сохраните следующий скрипт в файле с именем obfuscate:

#!/bin/ksh
# NAME:       obfuscate -- obfuscate text read from one or more files into a
#              string that can be decrypted by the dc utility
#
# SYNOPSIS:   obfuscate file...
#
# OPERANDS:   file    The name of a text file containing text to be
#         obfuscated or "-" to obfuscate text read from
#         standard input.
#
# APPLICATION USAGE:
# To decrypt the obfuscated string produced by obfuscate, use:
#     obfuscate file | read string    # Get obfuscated text
#     Note: Do not use "read -r string" in the above command!
#     printf '%s\n' "$string"     # Show obfuscated text
#     echo "$string" | dc     # Decrypt obfuscated text
#
# Although dc can produce artibrary length output, feeding the objuscated
# string back into dc for decryption may be limited by {LINE_MAX} and/or
# {ARG_MAX} restrictions.

# Initialize a to ASCII character set (skipping NUL)...
a='\1\2\3\4\5\6\7\10\11\12\13\14\15\16\17\20\21\22\23\24\25\26\27\30\31\32\33'
a="$a"'\34\35\36\37 !"#$%&'"'"'()*+,-./0123456789:;<=>?@'
a="$a"'ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\377'

awk -v A="$a" '
function cline(inline,        i) {
  printf("256*%d+\n", index(A, "\n"))
  for(i = length(inline); i; i--) {
      printf("256*%d+\n", index(A, substr(inline, i, 1)))
  }
}
BEGIN {   print 0
}
{ line[NR] = $0
}
END { for(i = NR; i; i--)
      cline(line[i])
  printf("[[q]sa[ln0=aln256%%Pln256/snlbx]sb]Pn[snlbxq\n]Pq\n")
}' "$@" | tee .dc_input | dc

сделать его исполняемым с помощью:

chmod +x obfuscate

и выполните команду:

printf "Hello World.\nAre we there yet?\nLet's go home, now!\n" | ./obfuscate - | read string

тогда команда:

echo "$string"

дам тебе:

[q]sa[ln0=aln256%Pln256/snlbx]sb26160072918627741401952510855241017735603346265259888938898171600856988789569756293233903076568696999873394858335331444040snlbxq

и команда:

echo "$string"|dc

дам тебе:

Hello World.
Are we there yet?
Let's go home, now!

(...) Если не будет работать с символами, которых нет в 7-битном наборе символов ASCII, и не будет работать, если текст, который вы хотите обфусцировать, содержит байты NUL, а во многих системах он не будет сработает, если строка в файлах, которые вы хотите запутать, длиннее, чем байты LINE_MAX, и если вывод, созданный obfuscate, создает строку длиннее, чем LINE_MAX, dc может не иметь возможности расшифровать ее для вас в некоторых системах.

Другие вопросы по тегам