Skip to content

Back to the catalog

dfir.chwriteup

Shell Script Compiler (shc)

A DFIR.ch analysis of shc (Shell Script Compiler), an open-source tool noted by Microsoft as being used by threat actors to compile shell-based backdoors into obfuscated, encrypted binaries. The post breaks down shc's anti-debugging technique — calling ptrace(PTRACE_TRACEME) so the binary self-kills if already traced by strace — and shows it can be bypassed by attaching a tracer after execution. It also demonstrates that despite the obfuscation, forensic artifacts such as process listings and /proc/<pid>/cmdline still expose the original decrypted command.

TL;DR Analysis of shc-compiled backdoor binaries: ptrace-based anti-debugging can be bypassed, and /proc/<pid>/cmdline still leaks the original shell command.
Document

What it is

An analysis of shc (Shell Script Compiler, github.com/neurobin/shc), the open-source tool Microsoft flagged as used by threat actors to turn shell-script backdoors into stripped, encrypted binaries. shc is not a real compiler: it wraps the script's encrypted bytes in generated C, compiles that to a native binary, and at runtime decrypts and runs the script via sh -c.

How it works

The attacker builds the "untraceable" variant with the -U flag:

shc -U -f script.sh -o binary

-U inserts a ptrace anti-debug guard. The child process calls ptrace(PTRACE_TRACEME, 0, 0, 0); if that returns < 0 — meaning a debugger is already attached — it sends itself an uncatchable SIGKILL:

if (ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) {
    kill(getpid(), SIGKILL);
    _exit(1);
}

Under strace ./binary the process dies (Operation not permitted, killed by SIGKILL) before doing anything useful.

What to do

The ptrace check only runs at startup, so the guard is defeated by attaching after the process is already running rather than launching under the tracer:

strace -p <pid>

For dead-box / live triage, the plaintext script survives despite the "encrypted at rest" binary once the process is live — read it from the running process:

cat /proc/<pid>/cmdline

The original decrypted command also shows up in the process list. Treat a stripped binary that spawns sh -c with an obfuscated body, plus a -U-style ptrace/SIGKILL sequence, as a hunting signature.

Caveats

The page states its own limits: the anti-debug bypass works only when you attach after execution, not before — launching the binary under strace still gets you killed. The forensic recovery of the script depends on catching the process while it is running; the binary remains obfuscated at rest. The author's testing used a netcat bind shell generated from revshells.com, not real captured malware.

Organisations named here

  • PTRACE_TRACEME
  • SIGKILL

Technologies named here

  • shc
  • strace
  • revshells.com
  • Netcat

Techniques named here

  • Shell script compilation/obfuscation via shc
  • Anti-debugging via ptrace
  • Ptrace check bypass
  • Forensic recovery via process list and /proc/<pid>/cmdline
  • Anti-debugging