## Disclaimer

If you are an academic C teacher, your feelings may be hurt by what you are going to read in this page and what we are doing to your very dear and beautiful language for the purpose of binary wizardry. #Enjoy

## 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.

## How is Punk C different from C ?

Punk C is not compiled but interpreted. Punk C has no types declarations, does not enforce functions prototypes (wtf?) nor any of the notorious C nightmares. Think C without the problems.

The control statements such as loop iterrators are inherited from lua and do not ressemble those of C.

Note/TODO: Can we hack this last statement by modifying the lua grammars ? :)

### 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$ 

Conventionally, wsh scripts names end with the ".wsh" extension.

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.

#### Running a Witchraft shell script as a wsh argument

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

#### Running a Witchcraft shell script as a standalone program

Let us start by making the read.wsh script executable:


	jonathan@blackbox:/usr/share/wcc/scripts$ sudo chmod +x read.wsh
	jonathan@blackbox:/usr/share/wcc/scripts$ 


We can now execute this script on any ELF executable or shared library by passing it as an argument to the script:


	jonathan@blackbox:/usr/share/wcc/scripts$ ./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$




### Registering a custom binfmt for .wsh scripts

Linux allows to define a binfmt so that the interpreter path can be ommited in wsh scripts. Any file named with the ".wsh" extension and executed will then be executed via the wsh interpreter automatically.

This is achieve via the following command:

	sudo update-binfmts --package wsh --install wsh /usr/bin/wsh --extension wsh


You can verify if this command worked by viewing the corresponding entry under /proc :

	jonathan@blackbox:~$ cat /proc/sys/fs/binfmt_misc/wsh 
	enabled
	interpreter /usr/bin/wsh
	flags: 
	extension .wsh
	jonathan@blackbox:~$ 



We can now run .wsh scripts directly within wsh without specifying an interpreter :


	jonathan@blackbox:~$ echo 'printf("Hello %s !\n", "World"); exit(3);' >/tmp/hello.wsh
	jonathan@blackbox:~$ 
	jonathan@blackbox:~$ chmod +x /tmp/hello.wsh 
	jonathan@blackbox:~$ 
	jonathan@blackbox:~$ cat /tmp/hello.wsh 
	printf("Hello %s !\n", "World"); exit(3);
	jonathan@blackbox:~$ 
	jonathan@blackbox:~$ /tmp/hello.wsh /usr/sbin/apache2
	Hello World !
	jonathan@blackbox:~$ echo $?
	3
	jonathan@blackbox:~$ 
