I was going through a list of Funny UNIX Commands when I stumbled with this one:
$ echo '[q]sa[ln0=aln256%Pln256/snlbx]sb3135071790101768542287578439snlbxq'|dc
GET A LIFE!
I had never read about the dc
command, so I went through the Wiki page and managed to learn to do little things like:
$ echo "4 5 + p" | dc
9
$ echo "2 10 ^ p" | dc
1024
However, 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 (and get my life back)?
… 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 …
Relevant parts of 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.
So,
[q]sa
stores the string q
into register a
.[ln0=aln256%Pln256/snlbx]sb
stores the string ln0=aln256%Pln256/snlbx
into register b
.3135071790101768542287578439sn
stores the number 3135071790101768542287578439
into n
.lbx
executes the string ln0=aln256%Pln256/snlbx
from register b
.ln0=a
executes, if n
equals zero, the string q
from register a
, i. e. exits from the macro.ln256%P
prints out the byte n
mod 256, at first 71, which is ASCII G
.ln256/sn
divides n
by 256, thereby cutting off the last byte.lbx
recurringly executes the string ln0=aln256%Pln256/snlbx
from register b
. The recurring executions yield the ASCII bytes E
T
A
L
I
F
E
!
\n
successively.In UNIX fun stuff - echo and dc - obfuscate/garble a string sort of you can find the script to obfuscate strings like this, together with an explanation on how to use it:
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='\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
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.