I solved this by combining a shell interpreter (such as BusyBox) and the shell script into a single static binary. Because the shell script is never passed to the operating system's /bin/sh or /bin/bash, it remains invisible even when monitoring the kernel.
I also added LLVM-based obfuscation and anti-debugging to make reverse engineering more difficult.