这个命令怎么会返回 "GET A LIFE!"?

How come is this command returning "GET A LIFE!"?

当我偶然发现这个时,我正在浏览 Funny UNIX Commands 的列表:

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

我从来没有读过 dc 命令,所以我浏览了 Wiki 页面并设法学会了做一些小事情,比如:

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

但是,命令 [q]sa[ln0=aln256%Pln256/snlbx]sb3135071790101768542287578439snlbxq 对我来说听起来太过分了。有没有办法以一种可以理解的方式解释它(并让我的生活恢复)?

… the command [q]sa[ln0=aln256%Pln256/snlbx]sb3135071790101768542287578439snlbxq sounds like too much to me. Is there any way to have it interpreted in an understandable way …

man dc的相关部分:

Entering a number pushes it on the stack.
[characters]
Makes a string containing characters (contained between balanced [ and ] characters), and pushes it on the stack.
sr
Pop the value off the top of the stack and store it into register r.
lr
Copy the value in register r and push it onto the stack.
x
Pops a value off the stack and executes it as a macro.
=r
Pops two values off the stack and compares them assuming they are numbers, executing the contents of register r as a macro if the two numbers popped are equal.
/
Pops two values, divides the second one popped from the first one popped, and pushes the result.
%
Pops two values, computes the remainder of the division that the / command would do, and pushes that.
P
Pops off the value on top of the stack. If it it a string, it is simply printed without a trailing newline. Otherwise it is a number, and the integer portion of its absolute value is printed out as a "base (UCHAR_MAX+1)" byte stream.
q
exits from a macro and also from the macro which invoked it. If called from the top level, or from a macro which was called directly from the top level, the q command will cause dc to exit.

所以,

  • [q]sa 将字符串 q 存储到寄存器 a.
  • [ln0=aln256%Pln256/snlbx]sb 将字符串 ln0=aln256%Pln256/snlbx 存储到寄存器 b.
  • 3135071790101768542287578439sn 将数字 3135071790101768542287578439 存储到 n.
  • lbx 从寄存器 b.
  • 执行字符串 ln0=aln256%Pln256/snlbx
  • ln0=a 执行,如果 n 等于零,来自寄存器 a 的字符串 q,i。 e.退出宏。
  • ln256%P 打印出字节 n mod 256,最开始是 71,也就是 ASCII G.
  • ln256/snn除以256,从而截掉最后一个字节。
  • lbx 循环执行寄存器 b 中的字符串 ln0=aln256%Pln256/snlbx。重复执行产生 ASCII 字节 E T </code> <code>A </code> <code>L I F E ! \n 先后

UNIX fun stuff - echo and dc - obfuscate/garble a string sort of 中,您可以找到像这样混淆字符串的脚本,以及如何使用它的说明:

If you save the following script in a file named 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=''
a="$a"' !"#$%&'"'"'()*+,-./0123456789:;<=>?@'
a="$a"'ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~7'

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] = [=10=]
}
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

make it executable with:

chmod +x obfuscate

and execute the command:

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

then the command:

echo "$string"

will give you:

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

and the command:

echo "$string"|dc

will give you:

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

(...) If won't work with characters that aren't in the 7-bit ASCII character set and it won't work if the text you want to obfuscate contains any NUL bytes, and on many systems it won't work if line in files you want to obfuscate are longer than LINE_MAX bytes and if the output produced by obfuscate produces a string longer than LINE_MAX, dc may not be able to decrypt it for you on some systems.