Skip to content

wsh the Punk C language

Jonathan Brossard edited this page Aug 12, 2016 · 29 revisions

What is Punk-C ?

Punk-C is the language wsh implements by extending a core lua interpreter with the API "reflected" from all the executables and shared libraries loaded in its address space.

What is lua ?

Lua is an amazing open source programming language and implementation. Its interpreter is very tiny yet very powerful. For more information on the Lua language, feel free to visit : https://www.lua.org/

How does binary "reflection" work ?

We use quotes around the word "reflected" because strictly speaking there is no Virtual Machine. wsh and the loaded programs share the same address space. The functionality is made possible by parsing the struct link_map returned by dlopen() when loading a binary. It alows in particular dumping all the symbols known by the dynamic linker and their respective addresses in the address space. This allows providing reflection like functionalities on raw binaries.

From a user perspective, this mechanism is transparent. We can call all of the C API present in memory directly from lua. In particular pass arguments to a C function and retrieve its return value.

Punk-C by example

The following commands examplify how to start wsh by loading the OpenSSH in memory from the path /usr/sbin/sshd. Wsh is then instructed to call the getpid() and getenv() functions and print their results. Those two functions do not exist in the Lua API : they are really made available directly from the libc by wsh's reflection mechanism.

jonathan@blackbox:~$ wsh /usr/sbin/sshd 
> a = getpid()
> print(a)
22453
> b = getenv("PWD")
> print(b)
/home/jonathan
> exit(3)
jonathan@blackbox:~$ echo $?
3
jonathan@blackbox:~$ 

It is worth noticing that the exit() function was too called here via reflection from the C library loaded as an OpenSSH server depedency, and its parameter returned to the parent shell as expected.

Example witchcraft shell scripts

If you installed the Witchrcaft Compiler Collection on your computer, the directory /usr/share/wcc/scripts should contain example scripts.

Let's take a look at the following script:

jonathan@blackbox:/usr/share/wcc/scripts$ cat read.wsh
#!/usr/bin/wsh

 fname="/etc/passwd"
 printf("\n ** Reading file %s\n", fname)
 mem = malloc(1024)
 nread = read(open(fname), mem, 100) -- Composition works
 printf(" ** Displaying content (%u bytes) of file %s:\x0a\x0a%s\n", nread, fname, mem)
 free(mem)
 c = close(fd)
 exit(0);

jonathan@blackbox:/usr/share/wcc/scripts$ 

This script attempts to open the /etc/password file and read 100 bytes of its content into a buffer of 1024 bytes pre allocated in the heap. This content is then displayed, the allocated heap memory freed and the opened file descriptor closed, before exiting with return value 0 (success, no errors).

The first line of the script instructs the linux kernel where to find the interpreter to execute it. We set this line to the full path of wsh.

A few things are worth noticing : the open function is only given one parameter when the POSIX standard specifies 2 or 3 :

Posix prototypes for function open():

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

This is made possible by the fact that wsh doesn't need to know the exact type of a function to craft arguments to call it and invoke it. Non provided arguments are implicitely casted to the value 0.

It is also worth noticing that arguments have no explicit types. This is made possible by the Lua typing mechanism.

Comments start with the "--" marker, and end with the line return as in lua.

Let us now call this script with wsh, using sshd (and its dependancies) as the API provided for all the functions we will use:

jonathan@blackbox:/usr/share/wcc/scripts$ wsh ./read.wsh /usr/sbin/sshd 

 ** Reading file /etc/passwd
 ** Displaying content (100 bytes) of file /etc/passwd:

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/
jonathan@blackbox:/usr/share/wcc/scripts$ 

We just invoked C functions from wsh dynamically, without compilation, and without knowing their prototypes ! #Witchcraft

Contribute

The Witchcraft Compiler Collection is Licensed under the MIT License.

Feel free to contribute :)

Clone this wiki locally