unixcommanddc

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


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)?


Solution

  • … 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,


    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.