diff --git a/Makefile b/Makefile index 02a17c8..123ad52 100644 --- a/Makefile +++ b/Makefile @@ -7,12 +7,23 @@ # This file is licensed under MIT License. # -CFLAGS := -W -Wall -Wno-discarded-qualifiers -Wno-int-conversion -Wno-unused-parameter -Wno-unused-function -Wno-unused-result -fpie -pie -fPIC -g3 -ggdb -I../../include -I./include/sflib/ -I./include -I../../include/ -Wno-incompatible-pointer-types -fstack-protector-all -Wl,-z,relro,-z,now -DPACKAGE -DPACKAGE_VERSION -masm=intel -rdynamic -D_FORTIFY_SOURCE=2 -O2 +COMPILER_VERSION := $(shell $(CC) --version) +ifneq '' '$(findstring clang,$(COMPILER_VERSION))' + ASAN := -fsanitize=address -static-libsan +else + ASAN := -fsanitize=address -static-libasan +endif + +CFLAGS := -W -Wall -Wno-discarded-qualifiers -Wno-int-conversion -Wno-unused-parameter -Wno-unused-function -Wno-unused-result -fpie -pie -fPIC -g3 -ggdb -I../../include -I./include/sflib/ -I./include -I../../include/ -Wno-incompatible-pointer-types -fstack-protector-all -Wl,-z,relro,-z,now -DPACKAGE -DPACKAGE_VERSION -masm=intel -rdynamic -D_FORTIFY_SOURCE=2 -O2 + all: mkdir -p bin cd src && make CFLAGS=" $(CFLAGS)" +asan: CFLAGS += $(ASAN) +asan: all + documentation: cd src && doxygen ./tex/project.cfg cd doc/latex && make && cp refman.pdf ../WCC_internal_documentation.pdf diff --git a/README.md b/README.md index 795a8c1..1529a6e 100644 --- a/README.md +++ b/README.md @@ -19,23 +19,9 @@ The Witchcraft Compiler Collection requires the following software to be install capstone, glibc, libbfd, libdl, zlib, libelf, libreadline, libgsl, make ### Installation Requirements on Ubuntu/Debian -Under Ubuntu/Debian those dependencies can be installed with the following commands (tested on Ubuntu 14.04): +Under Ubuntu/Debian those dependencies can be installed with the following commands (tested on Ubuntu 22.04): - # Required for add-apt-repository - sudo apt-get install python-software-properties software-properties-common - - # Add repo for clang - sudo add-apt-repository ppa:kxstudio-team/builds - sudo apt-get update - - # Install dependencies - sudo apt-get install binutils-dev clang libelf-dev libgsl0-dev libiberty-dev libreadline6 libreadline6-dev make uthash-dev - - # Install latest capstone and capstone-dev from "Ubuntu 14.04 - DEB packages" http://www.capstone-engine.org/download.html - wget http://www.capstone-engine.org/download/3.0.4/ubuntu-14.04/libcapstone3_3.0.4-0.1ubuntu1_amd64.deb - sudo dpkg -i libcapstone3_3.0.4-0.1ubuntu1_amd64.deb - wget http://www.capstone-engine.org/download/3.0.4/ubuntu-14.04/libcapstone-dev_3.0.4-0.1ubuntu1_amd64.deb - sudo dpkg -i libcapstone-dev_3.0.4-0.1ubuntu1_amd64.deb + sudo apt-get install -y clang libbfd-dev uthash-dev libelf-dev libcapstone-dev libreadline-dev libiberty-dev libgsl-dev build-essential git debootstrap file ## Building and Installing: @@ -76,14 +62,13 @@ The following commands constitute the core of the Witchcraft Compiler Collection wld takes an ELF executable as an input and modifies it to create a shared library. #### wld command line options jonathan@blackbox:~$ wld - Witchcraft Compiler Collection (WCC) version:0.0.1 (23:11:13 Jul 21 2016) - - Usage: wld [options] file - - options: + Witchcraft Compiler Collection (WCC) version:0.0.6 (18:10:51 May 10 2024) - -libify Set Class to ET_DYN in input ELF file. + Usage: wld -libify [-noinit] file + Options: + -libify Transform executable into shared library. + -noinit Ignore constructors and desctructors in output library. jonathan@blackbox:~$ #### Example usage of wld The following example libifies the executable /bin/ls into a shared library named /tmp/ls.so. @@ -100,7 +85,7 @@ The wcc compiler takes binaries (ELF, PE, ...) as an input and creates valid ELF #### wcc command line options jonathan@blackbox:~$ wcc - Witchcraft Compiler Collection (WCC) version:0.0.1 (01:47:53 Jul 29 2016) + Witchcraft Compiler Collection (WCC) version:0.0.6 (18:10:50 May 10 2024) Usage: wcc [options] file @@ -125,6 +110,7 @@ The wcc compiler takes binaries (ELF, PE, ...) as an input and creates valid ELF -v, --verbose -V, --version + jonathan@blackbox:~$ #### Example usage of wcc @@ -148,13 +134,15 @@ The witchcraft shell accepts ELF shared libraries, ELF ET_DYN executables and Wi #### wsh command line options jonathan@blackbox:~$ wsh -h - Usage: wsh [script] [options] [binary1] [binary2] ... [-x] [script_arg1] [script_arg2] ... + Usage: wsh [script] [-h|-q|-v|-V|-g] [binary1] [binary2] ... [-x [script_arg1] [script_arg2] ...] Options: - -x, --args Optional script argument separator. - -v, --verbose - -V, --version + -x, --args Optional script argument separator + -q, --quiet Display less output + -v, --verbose Display more output + -g, --global Bind symbols globally + -V, --version Display version and build, then exit Script: @@ -168,6 +156,7 @@ The witchcraft shell accepts ELF shared libraries, ELF ET_DYN executables and Wi jonathan@blackbox:~$ + #### Example usage of wsh The following command loads the /usr/sbin/apache2 executable within wsh, calls the ap_get_server_banner() function within apache to retrieve its banner and displays it within the wsh interpreter. diff --git a/src/wsh/include/libwitch/wsh.h b/src/wsh/include/libwitch/wsh.h index 4cc85ce..5845950 100644 --- a/src/wsh/include/libwitch/wsh.h +++ b/src/wsh/include/libwitch/wsh.h @@ -357,6 +357,8 @@ static int shdrs(lua_State * L); static int verbose(lua_State * L); static int xalloc(lua_State * L); static int ralloc(lua_State * L); +static int getptr(lua_State * L); +static int mkptr(lua_State * L); static int headers(lua_State * L); static int prototypes(lua_State * L); diff --git a/src/wsh/include/libwitch/wsh_functions.h b/src/wsh/include/libwitch/wsh_functions.h index 0d1a532..c8e5678 100644 --- a/src/wsh/include/libwitch/wsh_functions.h +++ b/src/wsh/include/libwitch/wsh_functions.h @@ -120,7 +120,9 @@ char *default_options[] = { "script", "enablecore", "disablecore", -"gencore" +"gencore", +"getptr", +"mkptr" }; // All lua 5.3 Functions and global variables @@ -382,7 +384,9 @@ tuple_t exposed[] = { {wsh_appear, "appear"}, {wsh_hide, "hide"}, {wsh_appear, "unhide"}, -{wsh_hide, "unappear"} +{wsh_hide, "unappear"}, +{getptr, "getptr"}, +{mkptr, "mkptr"} }; range_t ranges[] = { diff --git a/src/wsh/wsh.c b/src/wsh/wsh.c index ab2893a..7bc608c 100644 --- a/src/wsh/wsh.c +++ b/src/wsh/wsh.c @@ -36,14 +36,26 @@ #include #include #include // For basename() +#include // address sanitizer macro : disable a function by prepending ATTRIBUTE_NO_SANITIZE_ADDRESS to its definition #if defined(__clang__) || defined (__GNUC__) -# define ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address)) +# define ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address)) __attribute__((disable_sanitizer_instrumentation)) #else # define ATTRIBUTE_NO_SANITIZE_ADDRESS #endif +#if defined(__has_feature) +# if __has_feature(address_sanitizer) // clang +# define __SANITIZE_ADDRESS__ // GCC +# endif +#endif + +#if defined(__SANITIZE_ADDRESS__) +#define HAS_ASAN 1 +#endif + + #ifndef __amd64__ #define REG_RIP 16 #endif @@ -2226,6 +2238,35 @@ void print_syscall(pid_t child, int syscall_req) { } */ +#ifdef HAS_ASAN +ATTRIBUTE_NO_SANITIZE_ADDRESS +size_t mystrlen(char *ptr) +{ + unsigned int ret = 0; + + while(ptr[ret] != 0){ ret++;} + + return ret; +} + +ATTRIBUTE_NO_SANITIZE_ADDRESS +void *mymemset(void *s, int c, size_t n) +{ + unsigned int i = 0; + char *ptr = 0; + + ptr = s; + for(i = 0; i < n ; i++){ + ptr[i] = c; + } + + return s; +} +#else +#define mystrlen strlen +#define mymemset memset +#endif + /** * Main wrapper around a library call. * This function returns 9 values: ret (returned by library call), errno, firstsignal, total number of signals, firstsicode, firsterrno, faultaddr, reason, context @@ -2388,17 +2429,21 @@ static int libcall(lua_State * L) // is it a string ? char *ptr = ret; - for (j = 0; j < strlen(ret); j++) { + for (j = 0; j < mystrlen(ret); j++) { if (!isascii((ptr[j]))) { notascii = 1; break; } } +#ifdef HAS_ASAN + if ((!notascii)&&(mystrlen(ret) >= 1)) { +#else if (!notascii) { +#endif lua_pushstring(L, ret); // Ascii : push string } else { - lua_pushinteger(L, ret); // Push as a number + lua_pushinteger(L, ret);// Push as a number } } else { lua_pushinteger(L, ret); // Push as a number @@ -4084,10 +4129,10 @@ int ralloc(lua_State * L) mprotect(ptr, sz, PROT_EXEC | PROT_READ | PROT_WRITE); - memset(ptr, poison ? poison : default_poison + global_xalloc, sz); // map with default poison bytes + mymemset(ptr, poison ? poison : default_poison + global_xalloc, sz); // map with default poison bytes global_xalloc++; - memset(ptr,poison, size % 4096); + mymemset(ptr,poison, size % 4096); mprotect(ptr, sz, PROT_READ); @@ -4143,7 +4188,7 @@ int xalloc(lua_State * L) mprotect(ptr, sz, PROT_EXEC | PROT_READ | PROT_WRITE); - memset(ptr, poison ? poison : default_poison + global_xalloc, sz); // map with default poison bytes + mymemset(ptr, poison ? poison : default_poison + global_xalloc, sz); // map with default poison bytes global_xalloc++; if(!poison){ // If autoref, overwrite all the content with address of our own buffer @@ -5604,3 +5649,122 @@ static void initialize_wsh() { setenv("MALLOC_CHECK_", "3", 1); } + +/** +* Methods for manipulating arrays of strings from lua +* + + +// metatable method for handling "array[index]" +static int array_index (lua_State* L) { + int** parray = luaL_checkudata(L, 1, "array"); + int index = luaL_checkinteger(L, 2); + lua_pushnumber(L, (*parray)[index-1]); + return 1; +} + +// metatable method for handle "array[index] = value" +static int array_newindex (lua_State* L) { + int** parray = luaL_checkudata(L, 1, "array"); + int index = luaL_checkinteger(L, 2); + int value = luaL_checkinteger(L, 3); + (*parray)[index-1] = value; + return 0; +} + +void luaL_openlib(lua_State *L, const char *libname, const luaL_Reg *l, int nup) { + + if ( libname ) { + lua_getglobal(L, libname); + if (lua_isnil(L, -1)) { + lua_pop(L, 1); + lua_newtable(L); + } + } + luaL_setfuncs(L, l, 0); + if ( libname ) lua_setglobal(L, libname); +} + +// create a metatable for our array type +static void create_array_type(lua_State* L) { + static const struct luaL_reg array[] = { + { "__index", array_index }, + { "__newindex", array_newindex }, + NULL, NULL + }; + luaL_newmetatable(L, "array"); + luaL_openlib(L, NULL, array, 0); +} + +// expose an array to lua, by storing it in a userdata with the array metatable +static int expose_array(lua_State* L, int array[]) { + int** parray = lua_newuserdata(L, sizeof(int**)); + *parray = array; + luaL_getmetatable(L, "array"); + lua_setmetatable(L, -2); + return 1; +} + +// test data +int mydata[] = { 1, 2, 3, 4 }; + +// test routine which exposes our test array to Lua +static int getarray (lua_State* L) { + return expose_array( L, mydata ); +} + +int luaopen_array (lua_State* L) { + create_array_type(L); + + // make our test routine available to Lua + lua_register(L, "array", getarray); + return 0; +} + +*/ + + + + + +/** +* Get a pointer to a variable +*/ +int getptr(lua_State * L) +{ + char *vname = 0; + + read_arg1(vname); + if(!vname){ + printf("ERROR: missing name of variable\n"); + return 0; + } + + lua_pushlightuserdata(L, vname); + + return 1; +} + +/** +* Create a pointer to a variable +*/ +int mkptr(lua_State * L) +{ + char *vname = 0; + char **newptr = 0; + + read_arg1(vname); + if(!vname){ + printf("ERROR: missing name of variable\n"); + return 0; + } + + newptr = calloc(1, sizeof(char*)); + newptr[0] = vname; + + lua_pushinteger(L, newptr); + + return 1; +} + +