There’s this really cool process hacking series on YouTube by Keist Zenon. He
uses the programming language Common Lisp to interact with processes on his
Linux machine. I tried following the tutorial on my Mac, but macOS does not have
the same ptrace
commands and system call interfaces as Linux so this did not
work out. However, I have VirtualBox set up on my Mac with a Debian VM which I
use whenever I need Linux.
Here’s the idea: is it possible to hack processes on my Linux VM from Emacs on my Mac? I found out that it’s not only possible, but it’s actually surprisingly easy.
Configuring the Virtual Machine
First you’ll need to set up a Bridged Adapter on your VirtualBox VM to allow your host machine to connect to it via SSH. This YouTube tutorial was pretty helpful. You’ll just have to change how you enable the SSH service on your Linux VM—I’m on Debian so I had to run the command
systemctl status ssh | cat | grep active
Active: active (running) since Fri 2020-03-13 18:24:14 EDT; 33s ago
to see if SSH was enabled.
To attach and manipulate this process, we need to use the ptrace
function. You
can see the documentation for it with the command man 2 ptrace
(2 stands for
the second section of the manual, since we want the C system call function for
ptrace
instead of the general UNIX command). We could use C for process
hacking, but it’s a lot nicer to use an interactive language like Lisp. Plus,
it’s possible to interact with a remote Lisp REPL from your host machine’s local
Emacs instance through SSH. Common Lisp is pretty amazing—I don’t know if many
other programming languages have these features.
Clone Keist’s GitHub repo to your VM to get his Common Lisp library for process
hacking with ptrace
. The code here is essentially the same as the tutorial,
except you might have to remove the line that says
(:file "cl-ptrace/async-functions")
since that file doesn’t exist in the repo for some reason. Install your Common
Lisp implementation of choice (I use sbcl
since it’s well-supported on most
platforms) and follow the instructions on the Quicklisp website to install
Quicklisp. Quicklisp is the unofficial package manager for Common Lisp.
Once you’ve successfully installed Quicklisp, you need to set up a Lisp REPL on
the remote VM so it can talk to your local Emacs editor. Quit out of your sbcl
repl and run it as root. We need Lisp to run as root since the ptrace
system
calls need root access.
sudo sbcl
In his tutorial, Kaiste avoided this problem by running Emacs as root since he was hacking processes from the same machine. However, we don’t want to do this since running Emacs as root can be dangerous, plus we are trying to hack processes on our remote machine from our local (host) Emacs editor, so running Emacs locally as root wouldn’t really be useful.
Use Quicklisp to load/install ASDF
and slynk
, and then create a slynk
server on port 4006. You can use the default port 4005 if it’s open.
(ql:quickload :asdf)
(ql:quickload :slynk)
(slynk:create-server :port 4006)
If you get stuck, follow the instructions in the SLY manual, but I think Quicklisp makes this process a bit easier.
Now fire up a new terminal and get your VM’s ip address. On Debian, the command is
hostname -I
After that, SSH into your VM from your host machine to create an SSH tunnel that we’ll take advantage of later.
ssh -L4006:localhost:4006 <username>@<ip-address>
Change 4006
to the port that slynk
is using to run your Lisp server, and
change the <username>
and <ip-address>
fields. Remember to run this command
from your host machine, not the VM.
Once your SSH tunnel is set up, follow the instructions in section 8.1.3 of the
SLY manual (linked above) to configure Emacs to translate filenames between the
remote and host machines. Make sure you have TRAMP installed and working in
Emacs. Now you can connect to your VM from your host machine’s Emacs using
TRAMP. C-x C-f /ssh:<username>@<ip-address>
should do the trick. Now you can
navigate to the cl-ptrace
repo.
The setup is pretty much over: now we can start hacking. Compile the spam.c
file in the cl-ptrace
repo on your VM into the executable spam
and run it.
gcc spam.c -o spam
./spam
We want to get the process id (pid
) of this spam
program so we can interact
with it. To do this, run the command
ps -a | grep spam | awk '{ print $1 }'
1543
We can then display information about the process with top
. You can get a
nicer output by using the htop
program.
top -p $PID
We can even limit the output of top
to just get the CPU usage. The sed
commands are just for making the output nicer.
top -p $PID -n 2 -b | grep Cpu | sed 's/\:/\: /' | sed 's/us,.*/ /'
%Cpu(s): | 53.6 |
---|---|
%Cpu(s): | 100.0 |
Notice that the spam
program is taking up over 90% of the CPU since it’s an
infinite while
loop in a single-threaded process.
Hacking in Emacs
Next, switch back to Emacs (on the host machine) and make sure you’re in the
remote cl-ptrace
repo via TRAMP. We want to connect to the remote Lisp server
from Emacs, so run the command M-x sly-connect
, keep the default host as
localhost
, and change the port to the slynk
server port.
Now you have a local Lisp REPL that is connected to your VM via the SSH tunnel
we created earlier. Load the file cl-ptrace.asd
with the command M-x sly-load-file
. The file is on the remote VM, but this isn’t a problem because
TRAMP should be configured to handle the remote filenames (we did this earlier).
This should load the file into the sly
REPL. Then run (asdf:load-system "cl-ptrace")
to load the cl-ptrace
library into the REPL, and run
(in-package :cl-ptrace)
to start using the library.
Make sure that you’re root by running the function (am-i-root?)
. It should
return T
. Now you’ve successfully created a mechanism to hack remote processes
from your local machine using Common Lisp and Emacs. Go ahead and follow along
with the rest of Kaiste’s videos—they’re amazing.