From 24c48b8f7cb57be8c6fbbab886d79a05383dac4e Mon Sep 17 00:00:00 2001 From: chkp-eyalit Date: Wed, 28 Apr 2021 15:32:50 +0300 Subject: [PATCH 01/30] [cleanup] Minor updates to test file Update the return code from main, and fix a few comments. --- tests/exploit_me.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/exploit_me.c b/tests/exploit_me.c index 4387fa3..3a600c5 100644 --- a/tests/exploit_me.c +++ b/tests/exploit_me.c @@ -12,7 +12,7 @@ void print_addresses() { - printf("Here is the list of symbols that Scout needs for his embedded PIC context:\n"); + printf("Here is the list of symbols that Scout needs for the embedded PIC context:\n"); printf("symbol_memcpy \t\t= %p\n", memcpy); printf("symbol_memset \t\t= %p\n", memset); printf("symbol_malloc \t\t= %p\n", malloc); @@ -98,7 +98,7 @@ int main(int argc, char** argv) /* First, print the addresses to the user */ print_addresses(); - /* Second, wait for his approval */ + /* Second, wait for the user's approval */ printf("Press ENTER to continue (loading and executing the file)\n"); fgetc(stdin); @@ -106,5 +106,5 @@ int main(int argc, char** argv) load_and_execute(path); printf("Should not reach this print line...\n"); - return 1; + return 0; } From cfa481071a43c822a8f12b7b6c534973fc7a21a1 Mon Sep 17 00:00:00 2001 From: chkp-eyalit Date: Wed, 28 Apr 2021 16:21:42 +0300 Subject: [PATCH 02/30] [Cleanup] Minor fixes Mainly indentations and typos. --- scout/arc/intel.c | 2 +- scout/external_deps.h | 13 ++++++------- scout/pic/pic_wrapper.h | 4 ++-- scout/pic/scout_plt.h | 6 +++--- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/scout/arc/intel.c b/scout/arc/intel.c index dda952f..f8ea73a 100644 --- a/scout/arc/intel.c +++ b/scout/arc/intel.c @@ -8,7 +8,7 @@ void flush_cache(uint8_t * buffer, uint32_t size) (void)buffer; (void)size; - /* Intel has no caches thAt we need to flush :) */ + /* Intel has no caches that we need to flush :) */ } #endif /* SCOUT_ARCH_INTEL */ diff --git a/scout/external_deps.h b/scout/external_deps.h index 4cb7c45..11cf65c 100644 --- a/scout/external_deps.h +++ b/scout/external_deps.h @@ -23,7 +23,6 @@ void free(void * ptr); /* GLIBC Constants */ #define SOCK_STREAM 1 -#define SOCK_DGRAM 2 /* uCLIBC Constants */ //#define SOCK_STREAM 2 @@ -69,14 +68,14 @@ void close(sock_fd fd); /** MMap Dependencies **/ /*************************/ -#define PROT_READ 0x1 -#define PROT_WRITE 0x2 -#define PROT_EXEC 0x4 +#define PROT_READ 0x01 +#define PROT_WRITE 0x02 +#define PROT_EXEC 0x04 /* GLIBC Constants */ -#define MAP_PRIVATE 0x02 -#define MAP_FIXED 0x10 -#define MAP_ANONYMOUS 0x20 +#define MAP_PRIVATE 0x02 +#define MAP_FIXED 0x10 +#define MAP_ANONYMOUS 0x20 /* uCLIBC Constants */ //#define MAP_ANONYMOUS 0x800 diff --git a/scout/pic/pic_wrapper.h b/scout/pic/pic_wrapper.h index 05de4d9..e38fba4 100644 --- a/scout/pic/pic_wrapper.h +++ b/scout/pic/pic_wrapper.h @@ -28,8 +28,8 @@ typedef struct __pic_full_got typedef struct __pic_full_vars { - pic_vars_t scout; - project_vars_t project; + pic_vars_t scout; + project_vars_t project; } pic_full_vars_t; typedef struct __pic_context diff --git a/scout/pic/scout_plt.h b/scout/pic/scout_plt.h index 828f433..93188f6 100644 --- a/scout/pic/scout_plt.h +++ b/scout/pic/scout_plt.h @@ -27,9 +27,9 @@ typedef struct __pic_got addr_t close; #ifdef SCOUT_MMAP /* MMap */ - addr_t mmap; - addr_t mprotect; - addr_t munmap; + addr_t mmap; + addr_t mprotect; + addr_t munmap; #endif /* SCOUT_MMAP */ } pic_got_t; From d5f221b93593e0e1cb70c892883320aa2630e821 Mon Sep 17 00:00:00 2001 From: chkp-eyalit Date: Wed, 28 Apr 2021 16:27:11 +0300 Subject: [PATCH 03/30] [Refactor] Change the Proxy interface Instead of a duplicate function, the proxy will be the one implementing the original instruction handler, which won't exist in Proxy mode. --- kernel_scout/user_mode/scout_user.c | 2 +- scout/scout_api.c | 2 ++ scout/scout_api.h | 17 +---------------- scout/tcp_server.c | 4 ---- 4 files changed, 4 insertions(+), 21 deletions(-) diff --git a/kernel_scout/user_mode/scout_user.c b/kernel_scout/user_mode/scout_user.c index c7ca957..373a56b 100644 --- a/kernel_scout/user_mode/scout_user.c +++ b/kernel_scout/user_mode/scout_user.c @@ -21,7 +21,7 @@ void register_specific_instructions(void) /* No instruction to be registerred */ } -int32_t proxy_handle_instruction(void * ctx, scout_header_t * header, uint8_t * instruction) +int32_t handle_instruction(void * ctx, scout_header_t * header, uint8_t * instruction) { int32_t status; output_data_t * output = (output_data_t *)ctx; diff --git a/scout/scout_api.c b/scout/scout_api.c index 211c585..63a16a7 100644 --- a/scout/scout_api.c +++ b/scout/scout_api.c @@ -43,6 +43,7 @@ int32_t parse_header(uint8_t * buffer, uint32_t length, scout_header_t * header, return STATUS_OK; } +#ifndef SCOUT_PROXY int32_t handle_instruction(void * ctx, scout_header_t * header, uint8_t * buffer) { uint16_t index = 0; @@ -77,6 +78,7 @@ int32_t handle_instruction(void * ctx, scout_header_t * header, uint8_t * buffer mark_status(ctx, status); return status; } +#endif /* SCOUT_PROXY */ uint16_t get_instruction_count(void) { diff --git a/scout/scout_api.h b/scout/scout_api.h index db6c70f..d15d678 100644 --- a/scout/scout_api.h +++ b/scout/scout_api.h @@ -79,7 +79,7 @@ typedef struct __scout_instruction int32_t parse_header(uint8_t * buffer, uint32_t length, scout_header_t * header, bool validateLen); /** - * Verifies and Handles the given instruction + * Verifies and Handles the given instruction (could be a proxy) * * @author eyalit (07/03/2018) * @@ -91,21 +91,6 @@ int32_t parse_header(uint8_t * buffer, uint32_t length, scout_header_t * header, */ int32_t handle_instruction(void * ctx, scout_header_t * header, uint8_t * buffer); -#ifdef SCOUT_PROXY -/** - * Passes the instruction to the real instruction handler - * - * @author eyalit (07/03/2018) - * - * @param ctx - general context - * @param header - scout header as extracted from the buffer - * @param buffer - instruction raw buffer - * - * @return int32_t - success status - */ -int32_t proxy_handle_instruction(void * ctx, scout_header_t * header, uint8_t * buffer); -#endif /* SCOUT_PROXY */ - /********************************/ /** Instruction Registration **/ /********************************/ diff --git a/scout/tcp_server.c b/scout/tcp_server.c index c2e1ff0..900250b 100644 --- a/scout/tcp_server.c +++ b/scout/tcp_server.c @@ -216,11 +216,7 @@ int32_t start_server_loop(sock_fd serverSock) } /* Pass the instruction onward */ -#ifndef SCOUT_PROXY handle_instruction(&ctx, &header, &recvBuffer[SCOUT_HEADER_SIZE]); -#else /* SCOUT_PROXY */ - proxy_handle_instruction(&ctx, &header, &recvBuffer[SCOUT_HEADER_SIZE]); -#endif /* ! SCOUT_PROXY */ writeHead = outputHeader; pack_uint32( &writeHead, ctx.status ); From 37b0e5588ab390394793448ada66f704e2da5500 Mon Sep 17 00:00:00 2001 From: chkp-eyalit Date: Wed, 28 Apr 2021 16:54:20 +0300 Subject: [PATCH 04/30] [Cleanup] Update .gitignore for SlickEdit's files Ignore SlickEdit's project files --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index b8643e2..3e4e7df 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,10 @@ scout/loaders/*.o scout/loaders/*.S scout/pic/*.o scout/pic/*.S +scout/Scout.vpj +scout/Scout.vpw +scout/Scout.vpwhist +scout/Scout.vtg # Compiled embedded scout embedded_scout/*.o From 4a1d4b132480c823518937fd9646a6c53466e8fb Mon Sep 17 00:00:00 2001 From: chkp-eyalit Date: Wed, 28 Apr 2021 16:55:04 +0300 Subject: [PATCH 05/30] [refactor] Revert to using proper "main" function No need for the PIC entry point of "scout_main" --- embedded_scout/arm_scout.c | 2 +- scout/loaders/tcp_client_loader.c | 2 +- scout/loaders/tcp_server_loader.c | 2 +- scout/pic/arm_pic_wrapper.c | 2 +- scout/pic/intel_pic_wrapper.c | 2 +- scout/pic/mips_pic_wrapper.c | 2 +- scout/pic/pic_wrapper.h | 4 ++-- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/embedded_scout/arm_scout.c b/embedded_scout/arm_scout.c index 7a590c3..85569ff 100644 --- a/embedded_scout/arm_scout.c +++ b/embedded_scout/arm_scout.c @@ -2,7 +2,7 @@ #include "scout/tcp_server.h" #include "scout/pic/pic_wrapper.h" -void scout_main() +void main() { sock_fd serverSock; int32_t status; diff --git a/scout/loaders/tcp_client_loader.c b/scout/loaders/tcp_client_loader.c index 43d84bf..237d2fa 100644 --- a/scout/loaders/tcp_client_loader.c +++ b/scout/loaders/tcp_client_loader.c @@ -6,7 +6,7 @@ /* External API function */ extern void flush_cache(uint8_t * buffer, uint32_t size); -void scout_main() +void main() { sock_fd clientSock; int32_t status; diff --git a/scout/loaders/tcp_server_loader.c b/scout/loaders/tcp_server_loader.c index ac6b694..26030a8 100644 --- a/scout/loaders/tcp_server_loader.c +++ b/scout/loaders/tcp_server_loader.c @@ -6,7 +6,7 @@ /* External API function */ extern void flush_cache(uint8_t * buffer, uint32_t size); -void scout_main() +void main() { struct sockaddr_in clientAddr; socklen_t clientAddrSize = sizeof(clientAddr); diff --git a/scout/pic/arm_pic_wrapper.c b/scout/pic/arm_pic_wrapper.c index 809eaf3..4b509ce 100644 --- a/scout/pic/arm_pic_wrapper.c +++ b/scout/pic/arm_pic_wrapper.c @@ -25,7 +25,7 @@ void _start() { - scout_main(); + main(); } void * get_live_address(const void * address) diff --git a/scout/pic/intel_pic_wrapper.c b/scout/pic/intel_pic_wrapper.c index 51749fe..b6e0144 100644 --- a/scout/pic/intel_pic_wrapper.c +++ b/scout/pic/intel_pic_wrapper.c @@ -71,7 +71,7 @@ void * get_live_address(const void * address) void code_start() { - scout_main(); + main(); } #endif /* SCOUT_ARCH_INTEL */ diff --git a/scout/pic/mips_pic_wrapper.c b/scout/pic/mips_pic_wrapper.c index 502bb0e..f1885b2 100644 --- a/scout/pic/mips_pic_wrapper.c +++ b/scout/pic/mips_pic_wrapper.c @@ -12,7 +12,7 @@ void __start() { - scout_main(); + main(); } addr_t get_pc() diff --git a/scout/pic/pic_wrapper.h b/scout/pic/pic_wrapper.h index e38fba4..37523c6 100644 --- a/scout/pic/pic_wrapper.h +++ b/scout/pic/pic_wrapper.h @@ -43,11 +43,11 @@ typedef struct __pic_context /***********/ /** - * API function that signals the "main" function of scout projects + * API function that signals the "main" function of PIC scout projects * * @author eyalit (22/03/2018) */ -void scout_main(); +void main(); /*****************/ /** Functions **/ From 922290e43a0e6ae1984ba3573953d34b3843909a Mon Sep 17 00:00:00 2001 From: chkp-eyalit Date: Wed, 28 Apr 2021 17:09:50 +0300 Subject: [PATCH 06/30] [refactor] Refactor how the loader loads the payload No need for duplicate code lines, using a shared header and proper macros instead. --- scout/loaders/loader.h | 24 ++++++++++++++++++++++++ scout/loaders/tcp_client_loader.c | 12 ++++-------- scout/loaders/tcp_client_loader.h | 2 +- scout/loaders/tcp_server_loader.c | 12 ++++-------- scout/loaders/tcp_server_loader.h | 2 +- 5 files changed, 34 insertions(+), 18 deletions(-) create mode 100644 scout/loaders/loader.h diff --git a/scout/loaders/loader.h b/scout/loaders/loader.h new file mode 100644 index 0000000..275f93d --- /dev/null +++ b/scout/loaders/loader.h @@ -0,0 +1,24 @@ +#ifndef __SCOUT__LOADER__H__ +#define __SCOUT__LOADER__H__ +#ifdef SCOUT_LOADER + +#include "scout/scout.h" +#ifdef SCOUT_PIC_CODE +#include "scout/pic/pic_wrapper.h" +#endif /* SCOUT_PIC_CODE */ + +/***************/ +/** Defines **/ +/***************/ + +#if defined(SCOUT_LOADING_THUMB_CODE) +#define PAYLOAD_START(_X_) ((_X_) + 1) +#else +#define PAYLOAD_START(_X_) (_X_) +#endif /* SCOUT_LOADING_THUMB_CODE */ + +#define INVOKE_PAYLOAD(_X_) ((void (*)(void))PAYLOAD_START(_X_))() + + +#endif /* SCOUT_LOADER */ +#endif /* __SCOUT__LOADER__H__ */ diff --git a/scout/loaders/tcp_client_loader.c b/scout/loaders/tcp_client_loader.c index 237d2fa..7865ed5 100644 --- a/scout/loaders/tcp_client_loader.c +++ b/scout/loaders/tcp_client_loader.c @@ -1,7 +1,6 @@ #include "scout/loaders/tcp_client_loader.h" #include "scout/tcp_server.h" #include "scout/pack.h" -#include "scout/pic/pic_wrapper.h" /* External API function */ extern void flush_cache(uint8_t * buffer, uint32_t size); @@ -13,10 +12,11 @@ void main() uint32_t size; uint8_t * receiveBuffer; -#ifdef SCOUT_RESTORE_FLOW + /* Try to reduce unneeded instructions, in we are tight in space */ +#if defined(SCOUT_RESTORE_FLOW) && defined(SCOUT_PIC_CODE) clientSock = 0; receiveBuffer = NULL; -#endif /* SCOUT_RESTORE_FLOW */ +#endif /* SCOUT_RESTORE_FLOW && PIC_CODE */ /* Open the TCP server */ status = connect_to_tcp_server(&clientSock, SCOUT_SERVER_IP, SCOUT_LOADER_PORT); @@ -58,11 +58,7 @@ void main() #endif /* SCOUT_MMAP */ /* Jump into the buffer */ -#if defined(SCOUT_LOADING_THUMB_CODE) - ((void (*)(void))receiveBuffer + 1)(); -#else - ((void (*)(void))receiveBuffer)(); -#endif /* SCOUT_LOADING_THUMB_CODE */ + INVOKE_PAYLOAD(receiveBuffer); free_resources: #ifdef SCOUT_RESTORE_FLOW diff --git a/scout/loaders/tcp_client_loader.h b/scout/loaders/tcp_client_loader.h index 04b6f91..2112c0d 100644 --- a/scout/loaders/tcp_client_loader.h +++ b/scout/loaders/tcp_client_loader.h @@ -1,7 +1,7 @@ #ifndef __SCOUT__TCP__CLIENT__LOADER__H__ #define __SCOUT__TCP__CLIENT__LOADER__H__ -#include "scout/scout.h" +#include "loader.h" /***************/ /** Defines **/ diff --git a/scout/loaders/tcp_server_loader.c b/scout/loaders/tcp_server_loader.c index 26030a8..9e2228a 100644 --- a/scout/loaders/tcp_server_loader.c +++ b/scout/loaders/tcp_server_loader.c @@ -1,7 +1,6 @@ #include "scout/loaders/tcp_server_loader.h" #include "scout/tcp_server.h" #include "scout/pack.h" -#include "scout/pic/pic_wrapper.h" /* External API function */ extern void flush_cache(uint8_t * buffer, uint32_t size); @@ -16,12 +15,13 @@ void main() uint32_t size; uint8_t * receiveBuffer; -#ifdef SCOUT_RESTORE_FLOW + /* Try to reduce unneeded instructions, in we are tight in space */ +#if defined(SCOUT_RESTORE_FLOW) && defined(SCOUT_PIC_CODE) clientAddrSize = 0; clientSock = 0; serverSock = 0; receiveBuffer = NULL; -#endif /* SCOUT_RESTORE_FLOW */ +#endif /* SCOUT_RESTORE_FLOW && PIC_CODE */ /* Open the TCP server */ status = open_tcp_server(&serverSock, SCOUT_LOADER_PORT); @@ -70,11 +70,7 @@ void main() #endif /* SCOUT_MMAP */ /* Jump into the buffer */ -#if defined(SCOUT_LOADING_THUMB_CODE) - ((void (*)(void))receiveBuffer + 1)(); -#else - ((void (*)(void))receiveBuffer)(); -#endif /* SCOUT_LOADING_THUMB_CODE */ + INVOKE_PAYLOAD(receiveBuffer); free_resources: #ifdef SCOUT_RESTORE_FLOW diff --git a/scout/loaders/tcp_server_loader.h b/scout/loaders/tcp_server_loader.h index 054e68d..18aef3f 100644 --- a/scout/loaders/tcp_server_loader.h +++ b/scout/loaders/tcp_server_loader.h @@ -1,6 +1,6 @@ #ifndef __SCOUT__TCP__SERVER__LOADER__H__ #define __SCOUT__TCP__SERVER__LOADER__H__ -#include "scout/scout.h" +#include "loader.h" #endif /* __SCOUT__TCP__SERVER__LOADER__H__ */ From 51be058a992d228fa8acfad18ff5be9d4f0efc45 Mon Sep 17 00:00:00 2001 From: chkp-eyalit Date: Wed, 28 Apr 2021 17:18:13 +0300 Subject: [PATCH 07/30] [refactor] Mask the get_live_address() in scout_api Remove the code duplication when invoking a scout instruction and there needs to be different logic for PIC / non-PIC code. Now masked behind a macro that embeds this logic behind the scenes. --- scout/scout_api.c | 6 +----- scout/scout_api.h | 8 ++++++++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/scout/scout_api.c b/scout/scout_api.c index 63a16a7..b98d156 100644 --- a/scout/scout_api.c +++ b/scout/scout_api.c @@ -67,11 +67,7 @@ int32_t handle_instruction(void * ctx, scout_header_t * header, uint8_t * buffer } /* Can now handle the instruction */ -#ifdef SCOUT_PIC_CODE - status = ((instrHandler)get_live_address(instr->handler))(ctx, buffer, header->length); -#else - status = instr->handler(ctx, buffer, header->length); -#endif /* SCOUT_PIC_CODE */ + status = INVOKE_HANDLER(instr, ctx, buffer, header->length); break; } diff --git a/scout/scout_api.h b/scout/scout_api.h index d15d678..391433e 100644 --- a/scout/scout_api.h +++ b/scout/scout_api.h @@ -59,6 +59,14 @@ typedef struct __scout_instruction #define SCOUT_HEADER_SIZE (sizeof(uint16_t) + sizeof(uint32_t)) #define SCOUT_MAX_INSTRS (10) +#ifdef SCOUT_PIC_CODE +#define GET_HANDLER(_X_) ((instrHandler)get_live_address((_X_)->handler)) +#else +#define GET_HANDLER(_X_) ((_X_)->handler) +#endif /* SCOUT_PIC_CODE */ + +#define INVOKE_HANDLER(_X_, _C_, _B_, _L_) GET_HANDLER(_X_)(_C_, _B_, _L_) + #include "scout/scout.h" // Now we can safely include this file, even in PIC mode /******************************/ From 0430bddcfa143667a68fae55715bd0cd0979c71e Mon Sep 17 00:00:00 2001 From: chkp-eyalit Date: Wed, 28 Apr 2021 18:45:00 +0300 Subject: [PATCH 08/30] [refactor] Remove the SCOUT_EMBEDDED_ENV symbol Properly separated between the restrictions of a PIC code and the effects of it (SCOUT_ISOLATED_ENV), hoping to remove confusing terms. In a similar fashion, SCOUT_KERNEL_MODE also defines a flag for high privileges, which is what needed when flushing the cache. --- docs/Compilation Modes.md | 36 +++---- docs/PIC Compilation.md | 12 +-- embedded_scout/compile_scout.py | 10 +- kernel_scout/driver/flags.h | 1 - kernel_scout/user_mode/compile_scout.py | 4 +- kernel_scout/user_mode/flags.h | 1 - scout/arc/arm.c | 5 +- scout/arc/arm.h | 2 +- scout/arc/intel.c | 3 +- scout/arc/intel.h | 2 +- scout/arc/mips.c | 5 +- scout/arc/mips.h | 2 +- scout/architecture.h | 44 +++----- scout/external_deps.h | 6 +- scout/loaders/loader.h | 5 +- scout/loaders/tcp_client_loader.c | 6 +- scout/loaders/tcp_server_loader.c | 6 +- scout/pack.c | 4 +- scout/pack.h | 6 +- scout/pic/arm_pic_wrapper.c | 2 +- scout/pic/intel_pic_wrapper.c | 4 +- scout/pic/mips_pic_wrapper.c | 2 +- scout/pic/pic_wrapper.h | 2 +- scout/pic/scout_globals.c | 2 +- scout/pic/scout_plt.c | 2 +- scout/pic/scout_plt.h | 2 +- scout/scout.h | 28 +++-- scout/scout_api.c | 8 +- scout/scout_api.h | 2 +- scout/tcp_server.c | 2 +- scout/tcp_server.h | 6 +- utils/scout_compiler.py | 136 +++++++++++------------- 32 files changed, 155 insertions(+), 203 deletions(-) diff --git a/docs/Compilation Modes.md b/docs/Compilation Modes.md index d66c7d4..41c6d50 100644 --- a/docs/Compilation Modes.md +++ b/docs/Compilation Modes.md @@ -1,11 +1,12 @@ Compilation Modes ================= -Scout is a configurable debugger, that could bedeployed in several different environments: +Scout is a configurable debugger, that could be deployed in several different environments: * Linux User-Mode Process - "User Mode" * Linux Kernel Driver - "Kernel Mode" * Linux In-Process Debugging - "User Mode" + "PIC Mode" -* Embedded "In-Process" Debugging - "PIC Mode" + "Embedded Mode" +* Embedded "In-Process" Debugging (low privileges) - "PIC Mode" + "User Mode" +* Embedded "In-Process" Debugging (high privileges) - "PIC Mode" + "Kernel Mode" To decide what will be the suitable compilation mode / architecture flags, one should check the following parameters. Each of the defined parameters is a C MACRO (define) that controls the behavior (and compilation) of the resulting binary. @@ -38,46 +39,33 @@ If none are defined the base library will define "SCOUT_ARCH_INTEL" on it's own. **Additional Flags:** * SCOUT_ARM_THUMB - Scout will be executed on an ARM cpu in Thumb mode. Can only be used together with the "SCOUT_ARCH_ARM" flag. -The flags is needed only in PIC mode, in which we use inline assembly. +The flags are needed only in PIC mode, in which we use inline assembly. Target Permission Level ----------------------- -* SCOUT_MODE_USER - Scout is executed in User-Mode -* SCOUT_MODE_KERNEL - Scout is executed in Kernel-Mode +* SCOUT_MODE_USER - Scout is executed in User-Mode (& low CPU privileges) +* SCOUT_MODE_KERNEL - Scout is executed in Kernel-Mode (& high CPU privileges) Only one of above flags can be defined. If none are defined the base library will define "SCOUT_MODE_USER" on it's own. -**Note:** These flags are used only in a Linux PC Environment, and are not used in an Embedded Environment. - -Target Loading Environment --------------------------- -* SCOUT_PC_ENV - Scout is executed as a standard process (user) or driver (kernel) on a Linux machine -* SCOUT_EMBEDDED_ENV - Scout is injected to the address space of a given executable - -Only one of above flags can be defined. -If none are defined the base library will define "SCOUT_PC_ENV" on it's own. - -**Note:** SCOUT_EMBEDDED_ENV has many use cases, including: -1. Injecting a debugger into a debuggee Linux process -2. Injecting a debugger into a debuggee firmware (if the executable's API matches the basic POSIX based API of Scout) - -**Note:** At the current moment, "SCOUT_EMBEDDED_ENV" must be used with "SCOUT_PIC_CODE", although in the future a linker script could help an embedded scout access external functions without the PIC context. +"SCOUT_MODE_KERNEL" will also be the right choice for an RTOS (Real-time OS) in which every task / our task has high privileges. The flag will lead to the definition of "SCOUT_HIGH_PRIVILEGES" by the compilation environment. Position Independent Mode - SCOUT_PIC_CODE ------------------------------------------ Scout will be compiled for full Position Independent Code (PIC) mode. Any access to an external function / global variable will pass through a unique "Context" object. Read the section about "PIC Compilation" for more information. -**Note:** Can only be used with "SCOUT_EMBEDDED_ENV". + +"SCOUT_PIC_CODE" will lead to the definition of "SCOUT_ISOLATED_ENV" by the compilation environment, because a PIC blob will always be isolated from the environment, and won't have the luxory of a proper executable loader such as "ld.so". Loader Flags ------------ * SCOUT_LOADER - We are now compiling a loader (that might be using it's own pic plt / globals). * SCOUT_LOADING_THUMB_CODE - The loader will load a Scout that was compiled to be executed on an ARM cpu in Thumb mode. -* SCOUT_RESTORE_FLOW - The default loaders (```tcp_client_server.c```, ```tcp_loader_server.c```) will clean-up after themselves if the loaded scout will finish his endless loop. +* SCOUT_RESTORE_FLOW - The default loaders (```tcp_client_server.c```, ```tcp_loader_server.c```) will clean-up after themselves if the loaded scout will finish the endless loop. Additional Flags: ----------------- * SCOUT_INSTRUCTIONS - Scout is going to use the instructions api (using the TCP server for instance) -* SCOUT_DYNAMIC_BUFFERS - Scout will dynamically malloc() buffers to be used by the tcp server. Otherwise static buffers will be used. +* SCOUT_DYNAMIC_BUFFERS - Scout will dynamically ```malloc()``` buffers to be used by the tcp server. Otherwise static buffers will be used. * SCOUT_PROXY - Scout is going to act as a proxy (user scout passing instructions to a kernel driver for instance) -* SCOUT_MMAP - Should scout's loaders use mmap() and mprotect() when loading (if defined) or should they simply use malloc (if undefined) +* SCOUT_MMAP - Should scout's loaders use ```mmap()``` and ```mprotect()``` when loading (if defined) or should they simply use ```malloc()``` (if undefined) diff --git a/docs/PIC Compilation.md b/docs/PIC Compilation.md index 4a81c6a..8af9e36 100644 --- a/docs/PIC Compilation.md +++ b/docs/PIC Compilation.md @@ -1,6 +1,6 @@ Position Independent Code (PIC) Mode ==================================== -In PIC mode Scout is no longer loaded using the native loader of the operating system, since it is injected into a running executable. This means that Scout is compiled to be fully independent so it will work no matter where it was injected. +In PIC mode Scout is no longer loaded using the native loader of the operating system, since it is injected into a running executable. This means that Scout is compiled to be fully independent, enabling it to work no matter where it was injected to. Entry Point ----------- @@ -8,7 +8,7 @@ The entry point to our executable blob is at offset 0, meaning that we can liter **IMPORATNT:** This can only be achieved if the ```*_pic_wrapper.c``` file will be linked as the FIRST file in the list of files. In case there are any errors it is always recommended to check if the compiled files were compiled in a different order. -From the project's point of view, the main function is called ```scout_main```, since this is the function that will be executed by the start stub at offset 0. +From the project's point of view, the main function is called ```main``` (as usual), since this is the function that will be executed by the start stub at offset 0. The Context ----------- @@ -18,7 +18,7 @@ The PIC Context consists of 4 parts: * Base scout "Globals" * Project "Globals" -The code is compiled so that any access to an external function (library call) will pass through an indirection layer (named after the ELF's "PLT"). This "PLT" will locate Scout's context object, and will lookup the wanted address in the context's "GOT". +The code is compiled so that any call to an external function (library call) will pass through an indirection layer (named after the ELF's "PLT"). This "PLT" will locate Scout's context object, and will lookup the wanted address in the context's "GOT". In a similar fashion, the code is compiled (and developed) so that any access to a global variable will pass through an indirection layer. This layer will locate the scout's context object, and will find the offset of the global variable inside the PIC context. @@ -26,11 +26,11 @@ Locating the Context -------------------- Our code can be compiled so that it will access the PIC context instead of being linked as an ordinary ELF. Now we only need to tell our code how to be able to locate the context's address in runtime, using a PIC way. The context itself will be embedded INSIDE the full executed binary blob, so that it will be stored in a known relative offset from our code. The final step of deriving the absolute address of the context will be solved using an assembly layer: ```*_pic_wrapper.c```. -**Important Note:** Locatiing the context is done in assembly, hence this is the only part that is depends on the CPU's architecture on which we will be executed. +**Important Note:** Locating the context is done in assembly, hence this is the only part that depends on the architecture on which we will be executed. Expanding the Context --------------------- -In order to be able to use additional symbols (functions) or globals (global variables), we need to add them to the respective ```project_plt.c``` and ```project_globals.c files```, accordingly. Please make sure that the compilation script will be notified of these additions, so that the GOT will contain the needed addresses and the globals section will be of the correct size. +In order to be able to use additional symbols (functions) or globals (global variables), we need to add them to the respective ```project_plt.c``` and ```project_globals.c``` files, accordingly. Please make sure that the compilation script will be notified of these additions, so that the GOT will contain the needed addresses and the globals section will be of the correct size. Testing - exploit_me -------------------- @@ -39,4 +39,4 @@ The ```exploit_me.c``` module in the testing folder lets you test your PIC scout Known Gaps ---------- 1) In PIC mode our globals will need to be initialized manually as we will have no "init" methods that will be executed before our main function. -2) RWX flags: Since the context is embedded inside the compiled binary, that has executable (X) permissions, it means that the PIC Scout assumes it is loaded into a memory area with RWX permissions. \ No newline at end of file +2) RWX flags: Since the context is embedded inside the compiled binary, that has executable (X) permissions, it means that the PIC Scout assumes it is loaded into a memory area with RWX permissions so to be able to update global variables. \ No newline at end of file diff --git a/embedded_scout/compile_scout.py b/embedded_scout/compile_scout.py index e4fdbd2..e427b67 100644 --- a/embedded_scout/compile_scout.py +++ b/embedded_scout/compile_scout.py @@ -62,7 +62,7 @@ def setTargetFlags(logger): setScoutArc(TARGET_ARCH, is_32_bits=TARGET_BITNESS, is_little_endian=TARGET_ENDIANNESS, logger=logger) # 2. Set the environment - setScoutEnv(is_pc=False) + setScoutEnv(is_executable=False) # 3. Set the permission mode setScoutMode(is_user=False) @@ -89,7 +89,7 @@ def compileScoutLoader(logger): # 6. Compile an embedded scout logger.info('Starting to compile the scout loader') - compileEmbeddedScout(compilation_files, compile_flags, link_flags, SCOUT_LOADER_ELF, SCOUT_LOADER_BIN, logger) + compilePICScout(compilation_files, compile_flags, link_flags, SCOUT_LOADER_ELF, SCOUT_LOADER_BIN, logger) # 7. Place the PIC context in the resulting binary file generateGOT(symbol_memcpy, symbol_memset, symbol_malloc, symbol_free, symbol_socket, symbol_bind, @@ -126,9 +126,9 @@ def compileScout(logger): # 5. Generate the list of compiled files compilation_files = [os.path.join(SCOUT_DIR, f) for f in scout_all_files] + project_files - # 6. Compile an embedded scout - logger.info('Starting to compile the embedded scout') - compileEmbeddedScout(compilation_files, compile_flags, link_flags, EMBEDDED_SCOUT_ELF, EMBEDDED_SCOUT_BIN, logger) + # 6. Compile a PIC scout + logger.info('Starting to compile the PIC scout') + compilePICScout(compilation_files, compile_flags, link_flags, EMBEDDED_SCOUT_ELF, EMBEDDED_SCOUT_BIN, logger) # 7. Place the PIC context in the resulting binary file generateGOT(symbol_memcpy, symbol_memset, symbol_malloc, symbol_free, symbol_socket, symbol_bind, diff --git a/kernel_scout/driver/flags.h b/kernel_scout/driver/flags.h index b22abf6..2766715 100644 --- a/kernel_scout/driver/flags.h +++ b/kernel_scout/driver/flags.h @@ -8,7 +8,6 @@ #define SCOUT_ARCH_INTEL #define SCOUT_LITTLE_ENDIAN #define SCOUT_MODE_KERNEL -#define SCOUT_PC_ENV #define SCOUT_INSTRUCTIONS #endif /* __KERNEL__SCOUT__FLAGS__H__ */ diff --git a/kernel_scout/user_mode/compile_scout.py b/kernel_scout/user_mode/compile_scout.py index 3b2742d..0b39f00 100644 --- a/kernel_scout/user_mode/compile_scout.py +++ b/kernel_scout/user_mode/compile_scout.py @@ -33,7 +33,7 @@ def setTargetFlags(logger): setScoutArc(TARGET_ARCH, is_32_bits=TARGET_BITNESS, is_little_endian=TARGET_ENDIANNESS, logger=logger) # 2. Set the environment - setScoutEnv(is_pc=True) + setScoutEnv(is_executable=True) # 3. Set the permission mode setScoutMode(is_user=True) @@ -62,7 +62,7 @@ def compileScout(logger): # 6. Compile the PC (user mode proxy) scout logger.info('Starting to compile the user scout') - compilePCScout(compilation_files, compile_flags, link_flags, USER_SCOUT_BIN, logger) + compileExecutableScout(compilation_files, compile_flags, link_flags, USER_SCOUT_BIN, logger) # Finished :) return diff --git a/kernel_scout/user_mode/flags.h b/kernel_scout/user_mode/flags.h index b7f1de6..907a38b 100644 --- a/kernel_scout/user_mode/flags.h +++ b/kernel_scout/user_mode/flags.h @@ -7,7 +7,6 @@ #define SCOUT_LITTLE_ENDIAN #define SCOUT_BITS_64 #define SCOUT_PROXY -#define SCOUT_PC_ENV #define SCOUT_DYNAMIC_BUFFERS #define SCOUT_INSTRUCTIONS diff --git a/scout/arc/arm.c b/scout/arc/arm.c index 5c2e924..6ed062f 100644 --- a/scout/arc/arm.c +++ b/scout/arc/arm.c @@ -1,11 +1,10 @@ #include "scout/arc/arm.h" -#include "scout/pic/pic_wrapper.h" #ifdef SCOUT_ARCH_ARM void flush_cache(uint8_t * buffer, uint32_t size) { -#if defined(SCOUT_MODE_KERNEL) || defined(SCOUT_EMBEDDED_ENV) +#if defined(SCOUT_HIGH_PRIVILEGES) asm(" MOV R2, R0 "); asm(" ADR R0, flush_cache_inner "); asm(" BX R0 "); @@ -34,4 +33,4 @@ void flush_cache(uint8_t * buffer, uint32_t size) #endif } -#endif /* SCOUT_ARCH_ARM */ +#endif /* SCOUT_ARCH_ARM */ \ No newline at end of file diff --git a/scout/arc/arm.h b/scout/arc/arm.h index 8796779..98ec5e3 100644 --- a/scout/arc/arm.h +++ b/scout/arc/arm.h @@ -21,4 +21,4 @@ void flush_cache(uint8_t * buffer, uint32_t size); #endif /* SCOUT_ARCH_ARM */ -#endif /* __SCOUT__ARC__ARM__H__ */ +#endif /* __SCOUT__ARC__ARM__H__ */ \ No newline at end of file diff --git a/scout/arc/intel.c b/scout/arc/intel.c index f8ea73a..7c2ec1f 100644 --- a/scout/arc/intel.c +++ b/scout/arc/intel.c @@ -1,5 +1,4 @@ #include "scout/arc/intel.h" -#include "scout/pic/pic_wrapper.h" #ifdef SCOUT_ARCH_INTEL @@ -11,4 +10,4 @@ void flush_cache(uint8_t * buffer, uint32_t size) /* Intel has no caches that we need to flush :) */ } -#endif /* SCOUT_ARCH_INTEL */ +#endif /* SCOUT_ARCH_INTEL */ \ No newline at end of file diff --git a/scout/arc/intel.h b/scout/arc/intel.h index 2de7ceb..6436114 100644 --- a/scout/arc/intel.h +++ b/scout/arc/intel.h @@ -21,4 +21,4 @@ void flush_cache(uint8_t * buffer, uint32_t size); #endif /* SCOUT_ARCH_INTEL */ -#endif /* __SCOUT__ARC__INTEL__H__ */ +#endif /* __SCOUT__ARC__INTEL__H__ */ \ No newline at end of file diff --git a/scout/arc/mips.c b/scout/arc/mips.c index c147c31..d6afab5 100644 --- a/scout/arc/mips.c +++ b/scout/arc/mips.c @@ -1,15 +1,14 @@ #include "scout/arc/mips.h" -#include "scout/pic/pic_wrapper.h" #ifdef SCOUT_ARCH_MIPS void flush_cache(uint8_t * buffer, uint32_t size) { -#if defined(SCOUT_MODE_KERNEL) || defined(SCOUT_EMBEDDED_ENV) +#if defined(SCOUT_HIGH_PRIVILEGES) #error "Not supported yet. Had no way to check if it works :(" #else /* No permissions to perform these operations :( */ #endif } -#endif /* SCOUT_ARCH_MIPS */ +#endif /* SCOUT_ARCH_MIPS */ \ No newline at end of file diff --git a/scout/arc/mips.h b/scout/arc/mips.h index e385119..9e22a35 100644 --- a/scout/arc/mips.h +++ b/scout/arc/mips.h @@ -21,4 +21,4 @@ void flush_cache(uint8_t * buffer, uint32_t size); #endif /* SCOUT_ARCH_MIPS */ -#endif /* __SCOUT__ARC__MIPS__H__ */ +#endif /* __SCOUT__ARC__MIPS__H__ */ \ No newline at end of file diff --git a/scout/architecture.h b/scout/architecture.h index 03b65cc..ce5b683 100644 --- a/scout/architecture.h +++ b/scout/architecture.h @@ -3,11 +3,11 @@ #include "flags.h" -#if defined(SCOUT_MODE_KERNEL) && defined(SCOUT_PC_ENV) +#if defined(SCOUT_MODE_KERNEL) && !defined(SCOUT_PIC_CODE) #include #else #include -#endif /* SCOUT_MODE_KERNEL && SCOUT_PC_ENV */ +#endif /* SCOUT_MODE_KERNEL && !SCOUT_PIC_CODE */ /******************/ /** Endianness **/ @@ -76,9 +76,9 @@ typedef uint64_t addr_t; #define SCOUT_ARCH_INTEL #endif -/******************/ -/** User Level **/ -/******************/ +/******************************/ +/** User Mode / Privileges **/ +/******************************/ /* Sanity check */ #if defined(SCOUT_MODE_USER) && defined(SCOUT_MODE_KERNEL) @@ -90,32 +90,18 @@ typedef uint64_t addr_t; #define SCOUT_MODE_USER #endif -/****************/ -/** Embedded **/ -/****************/ - -/* Sanity check */ -#if defined(SCOUT_EMBEDDED_ENV) && defined(SCOUT_PC_ENV) - #error "Both embedded environment AND PC environment are defined!" +/* Mainly used for readability */ +#if defined(SCOUT_MODE_KERNEL) + #define SCOUT_HIGH_PRIVILEGES #endif -/* Default values */ -#if !defined(SCOUT_EMBEDDED_ENV) && !defined(SCOUT_PC_ENV) - #define SCOUT_PC_ENV -#endif +/***************************************/ +/** Excutable / Injected (PIC) Code **/ +/***************************************/ -/****************/ -/** PIC Code **/ -/****************/ - -/* Sanity check */ -#if defined(SCOUT_PIC_CODE) && !defined(SCOUT_EMBEDDED_ENV) - #error "PIC code can only be used in an embedded environment!" -#endif - -/* Sanity check */ -#if !defined(SCOUT_PIC_CODE) && defined(SCOUT_EMBEDDED_ENV) - #error "For now, embedded environment must be used only with PIC code" +/* Mainly used for readability */ +#if defined(SCOUT_PIC_CODE) + #define SCOUT_ISOLATED_ENV #endif -#endif // __SCOUT__ARCHITECTURE__H__ +#endif // __SCOUT__ARCHITECTURE__H__ \ No newline at end of file diff --git a/scout/external_deps.h b/scout/external_deps.h index 11cf65c..094ff92 100644 --- a/scout/external_deps.h +++ b/scout/external_deps.h @@ -4,6 +4,8 @@ #include "flags.h" /* Project defined, must come first */ #include "scout/architecture.h" /* Important architecture defines */ +#ifdef SCOUT_ISOLATED_ENV + /*************************/ /** LibC Dependencies **/ /*************************/ @@ -83,4 +85,6 @@ void * mmap(void * addr, size_t length, int prot, int flags, int fd, off_t offse int mprotect(void * addr, size_t len, int prot); int munmap(void * addr, size_t length); -#endif // __SCOUT__EXTERNAL__DEPS__H__ +#endif /* SCOUT_ISOLATED_ENV */ + +#endif // __SCOUT__EXTERNAL__DEPS__H__ \ No newline at end of file diff --git a/scout/loaders/loader.h b/scout/loaders/loader.h index 275f93d..fa65edf 100644 --- a/scout/loaders/loader.h +++ b/scout/loaders/loader.h @@ -3,9 +3,6 @@ #ifdef SCOUT_LOADER #include "scout/scout.h" -#ifdef SCOUT_PIC_CODE -#include "scout/pic/pic_wrapper.h" -#endif /* SCOUT_PIC_CODE */ /***************/ /** Defines **/ @@ -21,4 +18,4 @@ #endif /* SCOUT_LOADER */ -#endif /* __SCOUT__LOADER__H__ */ +#endif /* __SCOUT__LOADER__H__ */ \ No newline at end of file diff --git a/scout/loaders/tcp_client_loader.c b/scout/loaders/tcp_client_loader.c index 7865ed5..33e3508 100644 --- a/scout/loaders/tcp_client_loader.c +++ b/scout/loaders/tcp_client_loader.c @@ -13,10 +13,10 @@ void main() uint8_t * receiveBuffer; /* Try to reduce unneeded instructions, in we are tight in space */ -#if defined(SCOUT_RESTORE_FLOW) && defined(SCOUT_PIC_CODE) +#if defined(SCOUT_RESTORE_FLOW) clientSock = 0; receiveBuffer = NULL; -#endif /* SCOUT_RESTORE_FLOW && PIC_CODE */ +#endif /* SCOUT_RESTORE_FLOW */ /* Open the TCP server */ status = connect_to_tcp_server(&clientSock, SCOUT_SERVER_IP, SCOUT_LOADER_PORT); @@ -79,4 +79,4 @@ void main() } #endif /* SCOUT_RESTORE_FLOW */ return; -} +} \ No newline at end of file diff --git a/scout/loaders/tcp_server_loader.c b/scout/loaders/tcp_server_loader.c index 9e2228a..4aecc85 100644 --- a/scout/loaders/tcp_server_loader.c +++ b/scout/loaders/tcp_server_loader.c @@ -16,12 +16,12 @@ void main() uint8_t * receiveBuffer; /* Try to reduce unneeded instructions, in we are tight in space */ -#if defined(SCOUT_RESTORE_FLOW) && defined(SCOUT_PIC_CODE) +#if defined(SCOUT_RESTORE_FLOW) clientAddrSize = 0; clientSock = 0; serverSock = 0; receiveBuffer = NULL; -#endif /* SCOUT_RESTORE_FLOW && PIC_CODE */ +#endif /* SCOUT_RESTORE_FLOW */ /* Open the TCP server */ status = open_tcp_server(&serverSock, SCOUT_LOADER_PORT); @@ -96,4 +96,4 @@ void main() } #endif /* SCOUT_RESTORE_FLOW */ return; -} +} \ No newline at end of file diff --git a/scout/pack.c b/scout/pack.c index 366b9a6..fc9b236 100644 --- a/scout/pack.c +++ b/scout/pack.c @@ -106,7 +106,7 @@ addr_t unpack_addr(uint8_t ** buffer) #endif /* SCOUT_LOADER */ -#ifdef SCOUT_EMBEDDED_ENV +#ifdef SCOUT_ISOLATED_ENV uint16_t htons(uint16_t value) { @@ -170,4 +170,4 @@ uint64_t ntohq(uint64_t value) #endif /* SCOUT_LITTLE_ENDIAN */ } -#endif /* SCOUT_EMBEDDED_ENV */ +#endif /* SCOUT_ISOLATED_ENV */ \ No newline at end of file diff --git a/scout/pack.h b/scout/pack.h index fb4cc7d..9643b2f 100644 --- a/scout/pack.h +++ b/scout/pack.h @@ -121,7 +121,7 @@ uint64_t unpack_uint64(uint8_t ** buffer); */ addr_t unpack_addr(uint8_t ** buffer); -#ifdef SCOUT_EMBEDDED_ENV +#ifdef SCOUT_ISOLATED_ENV /** * Converts the given value from host order to network order @@ -189,6 +189,6 @@ uint32_t ntohl(uint32_t value); */ uint64_t ntohq(uint64_t value); -#endif /* SCOUT_EMBEDDED_ENV */ +#endif /* SCOUT_ISOLATED_ENV */ -#endif // __SCOUT__PACK__H__ +#endif // __SCOUT__PACK__H__ \ No newline at end of file diff --git a/scout/pic/arm_pic_wrapper.c b/scout/pic/arm_pic_wrapper.c index 4b509ce..07a531b 100644 --- a/scout/pic/arm_pic_wrapper.c +++ b/scout/pic/arm_pic_wrapper.c @@ -69,4 +69,4 @@ void dummy_context() } #endif /* SCOUT_ARCH_ARM */ -#endif /* SCOUT_PIC_CODE */ +#endif /* SCOUT_PIC_CODE */ \ No newline at end of file diff --git a/scout/pic/intel_pic_wrapper.c b/scout/pic/intel_pic_wrapper.c index b6e0144..3fd91ca 100644 --- a/scout/pic/intel_pic_wrapper.c +++ b/scout/pic/intel_pic_wrapper.c @@ -40,7 +40,6 @@ pic_context_t * get_context() #endif /* SCOUT_BITS_32 */ } -#ifdef SCOUT_INSTRUCTIONS void * get_live_address(const void * address) { #ifdef SCOUT_BITS_32 @@ -67,7 +66,6 @@ void * get_live_address(const void * address) asm("pop %rbx "); #endif /* SCOUT_BITS_32 */ } -#endif /* SCOUT_INSTRUCTIONS */ void code_start() { @@ -75,4 +73,4 @@ void code_start() } #endif /* SCOUT_ARCH_INTEL */ -#endif /* SCOUT_PIC_CODE */ +#endif /* SCOUT_PIC_CODE */ \ No newline at end of file diff --git a/scout/pic/mips_pic_wrapper.c b/scout/pic/mips_pic_wrapper.c index f1885b2..738d3b0 100644 --- a/scout/pic/mips_pic_wrapper.c +++ b/scout/pic/mips_pic_wrapper.c @@ -55,4 +55,4 @@ pic_context_t * get_context() } #endif /* SCOUT_ARCH_MIPS */ -#endif /* SCOUT_PIC_CODE */ +#endif /* SCOUT_PIC_CODE */ \ No newline at end of file diff --git a/scout/pic/pic_wrapper.h b/scout/pic/pic_wrapper.h index 37523c6..1f37cb6 100644 --- a/scout/pic/pic_wrapper.h +++ b/scout/pic/pic_wrapper.h @@ -81,4 +81,4 @@ void * get_live_address(const void * address); #endif /* SCOUT_PIC_CODE */ -#endif // __SCOUT__PIC__WRAPPER__H__ +#endif // __SCOUT__PIC__WRAPPER__H__ \ No newline at end of file diff --git a/scout/pic/scout_globals.c b/scout/pic/scout_globals.c index adbc870..821085f 100644 --- a/scout/pic/scout_globals.c +++ b/scout/pic/scout_globals.c @@ -29,4 +29,4 @@ uint8_t * global_SendBuffer() #endif /* SCOUT_INSTRUCTIONS */ -#endif /* SCOUT_PIC_CODE */ +#endif /* SCOUT_PIC_CODE */ \ No newline at end of file diff --git a/scout/pic/scout_plt.c b/scout/pic/scout_plt.c index bf1c4c8..5ece5be 100644 --- a/scout/pic/scout_plt.c +++ b/scout/pic/scout_plt.c @@ -83,4 +83,4 @@ int munmap(void * addr, size_t length) #endif /* SCOUT_MMAP */ -#endif /* SCOUT_PIC_CODE */ +#endif /* SCOUT_PIC_CODE */ \ No newline at end of file diff --git a/scout/pic/scout_plt.h b/scout/pic/scout_plt.h index 93188f6..fb584e2 100644 --- a/scout/pic/scout_plt.h +++ b/scout/pic/scout_plt.h @@ -35,4 +35,4 @@ typedef struct __pic_got #endif /* SCOUT_PIC_CODE */ -#endif // __SCOUT__PIC__PLT__H__ +#endif // __SCOUT__PIC__PLT__H__ \ No newline at end of file diff --git a/scout/scout.h b/scout/scout.h index e21a282..913681e 100644 --- a/scout/scout.h +++ b/scout/scout.h @@ -5,7 +5,17 @@ #include "scout/architecture.h" /* Important architecture defines */ #include "scout/errors.h" /* Error statuses */ -#ifdef SCOUT_PC_ENV +#ifdef SCOUT_PIC_CODE +#include "scout/pic/pic_wrapper.h" +#else +#define GLOBAL(_V_) g##_V_ +#endif /* SCOUT_PIC_CODE */ + +#ifdef SCOUT_ISOLATED_ENV + +#include "scout/external_deps.h" /* All external dependencies that should be found in libraries on a PC */ + +#else /* !SCOUT_ISOLATED_ENV */ #ifdef SCOUT_USER_MODE #include @@ -14,18 +24,6 @@ #include #endif /* SCOUT_USER_MODE */ -#else /* SCOUT_EMBEDDED_ENV */ - -#include "scout/external_deps.h" /* All external dependencies that should be found in libraries on a PC */ - -#ifdef SCOUT_PIC_CODE -#include "scout/pic/pic_wrapper.h" -#endif /* SCOUT_PIC_CODE */ - -#endif /* SCOUT_PC_ENV */ - -#ifndef SCOUT_PIC_CODE -#define GLOBAL(_V_) g##_V_ -#endif /* !SCOUT_PIC_CODE */ +#endif /* SCOUT_ISOLATED_ENV */ -#endif // __SCOUT__H__ +#endif // __SCOUT__H__ \ No newline at end of file diff --git a/scout/scout_api.c b/scout/scout_api.c index b98d156..5ab1181 100644 --- a/scout/scout_api.c +++ b/scout/scout_api.c @@ -110,11 +110,11 @@ void register_instruction(uint16_t instrID, uint32_t minLength, uint32_t maxLeng void register_basic_instructions(void) { -#ifdef SCOUT_EMBEDDED_ENV - /* Prepare the globals (won't be set on embedded environments */ +#ifdef SCOUT_PIC_CODE + /* Prepare the globals (won't be set without an executable's loader) */ *GLOBAL(pNumInstructions) = 0; memset(GLOBAL(Instructions), 0, SCOUT_MAX_INSTRS * sizeof(scout_instruction_t)); -#endif /* SCOUT_EMBEDDED_ENV */ +#endif /* SCOUT_PIC_CODE */ /* Can now quietly register the basic instructions */ register_instruction(SCOUT_INST_NOP, INSTR_NOP_MIN_SIZE, INSTR_NOP_MAX_SIZE, INSTR_NOP_HANDLER); @@ -166,4 +166,4 @@ int32_t instruction_mem_write(void * ctx, uint8_t * instruction, uint32_t length return STATUS_OK; } -#endif /* SCOUT_INSTRUCTIONS */ +#endif /* SCOUT_INSTRUCTIONS */ \ No newline at end of file diff --git a/scout/scout_api.h b/scout/scout_api.h index 391433e..d9619c7 100644 --- a/scout/scout_api.h +++ b/scout/scout_api.h @@ -228,4 +228,4 @@ int32_t instruction_mem_write(void * ctx, uint8_t * instruction, uint32_t length #endif /* SCOUT_INSTRUCTIONS */ -#endif // __SCOUT__API__H__ +#endif // __SCOUT__API__H__ \ No newline at end of file diff --git a/scout/tcp_server.c b/scout/tcp_server.c index 900250b..8b221d5 100644 --- a/scout/tcp_server.c +++ b/scout/tcp_server.c @@ -263,4 +263,4 @@ int32_t start_server_loop(sock_fd serverSock) return ctx.status; } -#endif /* SCOUT_INSTRUCTIONS */ +#endif /* SCOUT_INSTRUCTIONS */ \ No newline at end of file diff --git a/scout/tcp_server.h b/scout/tcp_server.h index c89b16b..85bc6a8 100644 --- a/scout/tcp_server.h +++ b/scout/tcp_server.h @@ -12,7 +12,7 @@ #include "scout/scout.h" // Depdendecy cycle in PIC mode forces us to include this file only at this line -#ifdef SCOUT_PC_ENV +#ifndef SCOUT_ISOLATED_ENV #include #include #include @@ -21,7 +21,7 @@ #include typedef int sock_fd; -#endif /* SCOUT_PC_ENV */ +#endif /* !SCOUT_ISOLATED_ENV */ /***************/ /** Structs **/ @@ -101,4 +101,4 @@ uint32_t full_net_recv(sock_fd sock, uint8_t * buffer, uint32_t length); */ uint32_t full_net_send(sock_fd sock, uint8_t * buffer, uint32_t length); -#endif // __SCOUT__TCP__SERVER__H__ +#endif // __SCOUT__TCP__SERVER__H__ \ No newline at end of file diff --git a/utils/scout_compiler.py b/utils/scout_compiler.py index b4fda3a..3ca73e7 100644 --- a/utils/scout_compiler.py +++ b/utils/scout_compiler.py @@ -31,13 +31,13 @@ intel_objcopy_flags = [] # Compile & Link flags -basic_compile_flags = ['fno-builtin', 'Wno-int-to-pointer-cast', 'Wno-pointer-to-int-cast'] -basic_pc_compile_flags = ['O2'] -basic_embedded_compile_flags = ['Os', 'nostdlib', 'fno-toplevel-reorder'] -intel_embedded_compile_flags = [] -arm_embedded_compile_flags = ['fno-jump-tables', 'mapcs-frame'] -mips_embedded_compile_flags = ['fno-jump-tables', 'mno-shared', 'mplt'] -basic_link_flags = [] +common_compile_flags = ['fno-builtin', 'Wno-int-to-pointer-cast', 'Wno-pointer-to-int-cast'] +common_executable_compile_flags = ['O2'] +common_pic_compile_flags = ['Os', 'nostdlib', 'fno-toplevel-reorder'] +intel_pic_compile_flags = [] +arm_pic_compile_flags = ['fno-jump-tables', 'mapcs-frame'] +mips_pic_compile_flags = ['fno-jump-tables', 'mno-shared', 'mplt'] +common_link_flags = [] ############################# ## Static Configurations ## @@ -57,8 +57,6 @@ flag_arc_thumb = 'SCOUT_ARM_THUMB' flag_mode_user = 'SCOUT_MODE_USER' flag_mode_kernel = 'SCOUT_MODE_KERNEL' -flag_env_embedded = 'SCOUT_EMBEDDED_ENV' -flag_env_pc = 'SCOUT_PC_ENV' flag_pic_code = 'SCOUT_PIC_CODE' flag_instructions = 'SCOUT_INSTRUCTIONS' flag_restore_flow = 'SCOUT_RESTORE_FLOW' @@ -83,6 +81,13 @@ ARC_ARM: flag_arc_arm, ARC_MIPS: flag_arc_mips, } + +arc_pic_flags = \ + { + ARC_INTEL: intel_pic_compile_flags, + ARC_ARM: arm_pic_compile_flags, + ARC_MIPS: mips_pic_compile_flags, + } # scout file list scout_arc_files = ['arc/arm.c', 'arc/mips.c', 'arc/intel.c'] @@ -106,7 +111,6 @@ config_bitness = None config_endianness = None config_arc = None -config_env = None config_mode = None config_pic = None config_flags = [] @@ -144,16 +148,15 @@ def setScoutArc(arc, is_32_bits, is_little_endian, logger, is_native=False): config_endianness = flag_little_endian if is_little_endian else flag_big_endian config_arc = arc_configs[arc] -def setScoutEnv(is_pc): +def setScoutEnv(is_executable): """Sets the target's environment flags Args: - is_pc (bool): True iff the environment is a standard PC, otherwise it will be an embedded environment + is_executable (bool): True iff the environment is a standard executable, otherwise it will be a PIC environment """ - global config_env, config_pic + global config_pic - config_env = flag_env_pc if is_pc else flag_env_embedded - config_pic = flag_pic_code if not is_pc else '' + config_pic = flag_pic_code if not is_executable else '' def setScoutMode(is_user): """Sets the target's permission level @@ -228,10 +231,6 @@ def verifyScoutFlags(logger): logger.error("Missing Scout flag: unknown architecture") return False - if config_env is None: - logger.error("Missing Scout flag: unknown environment") - return False - if config_mode is None: logger.error("Missing Scout flag: unknown permission mode") return False @@ -241,7 +240,7 @@ def verifyScoutFlags(logger): return False # Reaching here means that all was OK - config_flags += [config_bitness, config_endianness, config_arc, config_env, config_mode] + config_flags += [config_bitness, config_endianness, config_arc, config_mode] if len(config_pic) > 0: config_flags += [config_pic] return True @@ -279,72 +278,59 @@ def generateFlagsFile(logger): # can close the file fd.close() -def generateCompilationFlags(compile_flags, link_flags, logger): +def generateCompilationFlags(user_compile_flags, user_link_flags, logger): """Generates the compilation flags that match the configurations flags Args: - copmile_flags (list): list of compiler flags (without the '-' prefix) - link_flags (list) list of linker flags (without the '-' prefix) + user_copmile_flags (list): list of compiler flags (without the '-' prefix) + user_link_flags (list) list of linker flags (without the '-' prefix) logger (logger): (elementals) logger Return Value: (compiler flags string, linker flags string) """ - global basic_compile_flags, basic_link_flags + compile_flags = common_compile_flags + link_flags = common_link_flags - orig_compile_flags = [] + basic_compile_flags - orig_link_flags = [] + basic_link_flags - - # Endianness - Arm + # ARM - Misc (Thumb) & Endianness if config_arc == flag_arc_arm: + # Thumb + compile_flags += ['mthumb'] if (flag_arc_thumb in config_flags) else [] + # Endianness if config_endianness == flag_little_endian: - basic_compile_flags += ['mlittle-endian'] - basic_link_flags += ['EL'] + compile_flags += ['mlittle-endian'] + link_flags += ['EL'] else: - basic_compile_flags += ['mbig-endian'] - basic_link_flags += ['EB'] - # Thumb - basic_compile_flags += ['mthumb'] if (flag_arc_thumb in config_flags) else [] + compile_flags += ['mbig-endian'] + link_flags += ['EB'] - # Endianness - Mips + # Mips - Endianness elif config_arc == flag_arc_mips: if config_endianness == flag_little_endian: - basic_compile_flags += ['EL'] - basic_link_flags += ['EL'] + compile_flags += ['EL'] + link_flags += ['EL'] else: - basic_compile_flags += ['EB'] - basic_link_flags += ['EB'] - - # PC Environment - if config_env == flag_env_pc: - basic_compile_flags += basic_pc_compile_flags - - # Embedded Environment + compile_flags += ['EB'] + link_flags += ['EB'] + + # Intel - Misc (Bitness) + elif config_arc == flag_arc_intel: + if config_bitness == flag_32_bit: + compile_flags += ['m32'] + link_flags += ['melf_i386'] + + # Executable Environment + if config_pic != flag_pic_code: + compile_flags += common_executable_compile_flags + + # PIC Environment else: - basic_compile_flags += basic_embedded_compile_flags - # Intel Arc - if config_arc == flag_arc_intel: - basic_compile_flags += intel_embedded_compile_flags - # Arm Arc - elif config_arc == flag_arc_arm: - basic_compile_flags += arm_embedded_compile_flags - # Mips Arc - else: - basic_compile_flags += mips_embedded_compile_flags - - # Robustness (bitness) flag - if config_bitness == flag_32_bit: - if config_arc == flag_arc_intel: - basic_compile_flags += ['m32'] - basic_link_flags += ['melf_i386'] + compile_flags += common_pic_compile_flags + compile_flags += arc_pic_flags[config_arc] # Final Compile & Link flags - compile_flags = ' '.join(['-' + x for x in basic_compile_flags + compile_flags + ['I' + y for y in include_dirs]]) - link_flags = ' '.join(['-' + x for x in basic_link_flags + link_flags]) - - # Restore the global flags - basic_compile_flags = [] + orig_compile_flags - basic_link_flags = [] + orig_link_flags + compile_flags = ' '.join(['-' + x for x in compile_flags + user_compile_flags + ['I' + y for y in include_dirs]]) + link_flags = ' '.join(['-' + x for x in link_flags + user_link_flags]) return compile_flags, link_flags @@ -358,8 +344,8 @@ def systemLine(line, logger): logger.debug(line) os.system(line) -def compileEmbeddedScout(compilation_files, compile_flags, link_flags, elf_file, final_file, logger): - """Compiles an embedded "Scout" project +def compilePICScout(compilation_files, compile_flags, link_flags, elf_file, final_file, logger): + """Compiles a Position-Independent (PIC) "Scout" project Args: compilation_files (list): list of file paths for all code (*.c) files @@ -372,8 +358,8 @@ def compileEmbeddedScout(compilation_files, compile_flags, link_flags, elf_file, logger.addIndent() # 0. Sanity check - if config_env != flag_env_embedded: - logger.error("Compiling an Embedded scout with PC environment flag. Did you mean: compilePCScout() ?") + if config_pic != flag_pic_code: + logger.error("Compiling a PIC scout without the PIC-CODE Environment flag. Did you mean: compileExecutableScout() ?") logger.removeIndent() return @@ -420,8 +406,8 @@ def compileEmbeddedScout(compilation_files, compile_flags, link_flags, elf_file, logger.removeIndent() -def compilePCScout(compilation_files, compile_flags, link_flags, elf_file, logger): - """Compiles a regular (PC) "Scout" project +def compileExecutableScout(compilation_files, compile_flags, link_flags, elf_file, logger): + """Compiles a regular executable "Scout" project Args: compilation_files (list): list of file paths for all code (*.c) files @@ -431,8 +417,8 @@ def compilePCScout(compilation_files, compile_flags, link_flags, elf_file, logge logger (logger): (elementals) logger """ # 0. Sanity check - if config_env != flag_env_pc: - logger.error("Compiling a PC scout with EMBEDDED environment flag. Did you mean: compileEmbeddedScout() ?") + if config_pic == flag_pic_code: + logger.error("Compiling an Executable scout with PIC-CODE environment flag. Did you mean: compilePICScout() ?") return # 1. Auto-Generate the flags.h file From 6d99d4a358fac8b13f85609d21690ea5b62c0dcf Mon Sep 17 00:00:00 2001 From: chkp-eyalit Date: Wed, 28 Apr 2021 19:11:52 +0300 Subject: [PATCH 09/30] [refactor] Proper symbol for SCOUT_SLIM_SIZE Shrink the size of the binary only when the new SCOUT_SLIM_SIZE symbol is defined: when there is a PIC loader. On a side note, previous changes made it possible for a loader not to be PIC anylonger, so we should check both conditions. --- scout/architecture.h | 9 +++++++++ scout/loaders/tcp_client_loader.c | 4 ++-- scout/loaders/tcp_server_loader.c | 4 ++-- scout/pack.c | 4 ++-- scout/tcp_server.c | 1 - 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/scout/architecture.h b/scout/architecture.h index ce5b683..0a5bad6 100644 --- a/scout/architecture.h +++ b/scout/architecture.h @@ -104,4 +104,13 @@ typedef uint64_t addr_t; #define SCOUT_ISOLATED_ENV #endif +/****************************************/ +/** Loader (Tight memory constraints **/ +/****************************************/ + +/* Mainly used for readability */ +#if defined(SCOUT_LOADER) && defined(SCOUT_PIC_CODE) + #define SCOUT_SLIM_SIZE +#endif + #endif // __SCOUT__ARCHITECTURE__H__ \ No newline at end of file diff --git a/scout/loaders/tcp_client_loader.c b/scout/loaders/tcp_client_loader.c index 33e3508..f4c7b4b 100644 --- a/scout/loaders/tcp_client_loader.c +++ b/scout/loaders/tcp_client_loader.c @@ -13,10 +13,10 @@ void main() uint8_t * receiveBuffer; /* Try to reduce unneeded instructions, in we are tight in space */ -#if defined(SCOUT_RESTORE_FLOW) +#if !defined(SCOUT_SLIM_SIZE) clientSock = 0; receiveBuffer = NULL; -#endif /* SCOUT_RESTORE_FLOW */ +#endif /* !SCOUT_SLIM_SIZE */ /* Open the TCP server */ status = connect_to_tcp_server(&clientSock, SCOUT_SERVER_IP, SCOUT_LOADER_PORT); diff --git a/scout/loaders/tcp_server_loader.c b/scout/loaders/tcp_server_loader.c index 4aecc85..12dab7a 100644 --- a/scout/loaders/tcp_server_loader.c +++ b/scout/loaders/tcp_server_loader.c @@ -16,12 +16,12 @@ void main() uint8_t * receiveBuffer; /* Try to reduce unneeded instructions, in we are tight in space */ -#if defined(SCOUT_RESTORE_FLOW) +#if !defined(SCOUT_SLIM_SIZE) clientAddrSize = 0; clientSock = 0; serverSock = 0; receiveBuffer = NULL; -#endif /* SCOUT_RESTORE_FLOW */ +#endif /* !SCOUT_SLIM_SIZE */ /* Open the TCP server */ status = open_tcp_server(&serverSock, SCOUT_LOADER_PORT); diff --git a/scout/pack.c b/scout/pack.c index fc9b236..e14a283 100644 --- a/scout/pack.c +++ b/scout/pack.c @@ -1,6 +1,6 @@ #include "scout/pack.h" -#ifndef SCOUT_LOADER /* We are short in space when compiling a loader */ +#ifndef SCOUT_SLIM_SIZE /* We are sometimes (loader) short in space */ void pack_uint8(uint8_t ** buffer, uint8_t value) { @@ -104,7 +104,7 @@ addr_t unpack_addr(uint8_t ** buffer) #endif /* SCOUT_BITS_32 */ } -#endif /* SCOUT_LOADER */ +#endif /* !SCOUT_SLIM_SIZE */ #ifdef SCOUT_ISOLATED_ENV diff --git a/scout/tcp_server.c b/scout/tcp_server.c index 8b221d5..817dbd1 100644 --- a/scout/tcp_server.c +++ b/scout/tcp_server.c @@ -2,7 +2,6 @@ #include "scout/tcp_server.h" #include "scout/scout_api.h" #include "scout/pack.h" -#include "scout/pic/scout_globals.h" #ifdef SCOUT_INSTRUCTIONS #ifndef SCOUT_DYNAMIC_BUFFERS From 0f06533978a93621ddbc2c4f5576ba658fe37240 Mon Sep 17 00:00:00 2001 From: chkp-eyalit Date: Wed, 28 Apr 2021 19:26:15 +0300 Subject: [PATCH 10/30] [refactor] Using SCOUT_SLIM_SIZE in the TCP module Should help make a shellcode (PIC) loader smaller, by only including needed TCP features, by demand. --- docs/Compilation Modes.md | 5 +++++ embedded_scout/compile_scout.py | 3 +-- scout/tcp_server.c | 6 ++++++ utils/scout_compiler.py | 3 +++ 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/docs/Compilation Modes.md b/docs/Compilation Modes.md index 41c6d50..cfb8521 100644 --- a/docs/Compilation Modes.md +++ b/docs/Compilation Modes.md @@ -63,6 +63,11 @@ Loader Flags * SCOUT_LOADING_THUMB_CODE - The loader will load a Scout that was compiled to be executed on an ARM cpu in Thumb mode. * SCOUT_RESTORE_FLOW - The default loaders (```tcp_client_server.c```, ```tcp_loader_server.c```) will clean-up after themselves if the loaded scout will finish the endless loop. +If loader will be compiled to be Position Independent (PIC), which is probably the most common use case, it will als define a new flag of "SCOUT_SLIM_SIZE", to help shrink the size of the binary (to server as an effective shellcode. Under this definition the TCP server would expect the following flags (if needed): +* SCOUT_TCP_CLIENT - There is a need to include the feature of a TCP client +* SCOUT_TCP_SERVER - There is a need to include the feature of a TCP server +* SCOUT_TCP_SEND - There is a need to include the ability to reliably send TCP messages + Additional Flags: ----------------- * SCOUT_INSTRUCTIONS - Scout is going to use the instructions api (using the TCP server for instance) diff --git a/embedded_scout/compile_scout.py b/embedded_scout/compile_scout.py index e427b67..0cc75e5 100644 --- a/embedded_scout/compile_scout.py +++ b/embedded_scout/compile_scout.py @@ -75,8 +75,7 @@ def compileScoutLoader(logger): setTargetFlags(logger) # 2. Additional flags: thumb mode (if in ARM), and mmap (in both cases) - # Note: If scout will also be in Thumb mode, add this flag too: flag_load_thumb - setScoutFlags([flag_loader, flag_mmap] + ([flag_arc_thumb] if TARGET_ARCH == ARC_ARM else [])) + setScoutFlags([flag_loader, flag_loader_server, flag_mmap] + ([flag_arc_thumb] if TARGET_ARCH == ARC_ARM else [])) # 3. Define the working directories setWorkingDirs(project_dir='.', scout_dir=SCOUT_DIR) diff --git a/scout/tcp_server.c b/scout/tcp_server.c index 817dbd1..81a2cdc 100644 --- a/scout/tcp_server.c +++ b/scout/tcp_server.c @@ -12,6 +12,7 @@ static uint8_t gSendBuffer[SCOUT_TCP_MAX_MESSAGE]; #endif /* !SCOUT_DYNAMIC_BUFFERS */ #endif /* SCOUT_INSTRUCTIONS */ +#if !defined(SCOUT_SLIM_SIZE) || defined(SCOUT_TCP_CLIENT) int32_t connect_to_tcp_server(sock_fd * clientSock, uint32_t ip, uint16_t port) { struct sockaddr_in addr; @@ -43,7 +44,9 @@ int32_t connect_to_tcp_server(sock_fd * clientSock, uint32_t ip, uint16_t port) /* All was OK */ return STATUS_OK; } +#endif /* !SCOUT_SLIM_SIZE || SCOUT_TCP_CLIENT */ +#if !defined(SCOUT_SLIM_SIZE) || defined(SCOUT_TCP_SERVER) int32_t open_tcp_server(sock_fd * serverSock, uint16_t port) { struct sockaddr_in addr; @@ -81,6 +84,7 @@ int32_t open_tcp_server(sock_fd * serverSock, uint16_t port) /* All was OK */ return STATUS_OK; } +#endif /* !SCOUT_SLIM_SIZE || SCOUT_TCP_SERVER */ uint32_t full_net_recv(sock_fd sock, uint8_t * buffer, uint32_t length) { @@ -98,6 +102,7 @@ uint32_t full_net_recv(sock_fd sock, uint8_t * buffer, uint32_t length) return received; } +#if !defined(SCOUT_SLIM_SIZE) || defined(SCOUT_TCP_SEND) */ uint32_t full_net_send(sock_fd sock, uint8_t * buffer, uint32_t length) { uint32_t sent = 0; @@ -113,6 +118,7 @@ uint32_t full_net_send(sock_fd sock, uint8_t * buffer, uint32_t length) } return sent; } +#endif /* !SCOUT_SLIM_SIZE || SCOUT_TCP_SEND */ #ifdef SCOUT_INSTRUCTIONS diff --git a/utils/scout_compiler.py b/utils/scout_compiler.py index 3ca73e7..e864d0e 100644 --- a/utils/scout_compiler.py +++ b/utils/scout_compiler.py @@ -65,6 +65,9 @@ flag_mmap = 'SCOUT_MMAP' flag_load_thumb = 'SCOUT_LOADING_THUMB_CODE' flag_loader = 'SCOUT_LOADER' +flag_loader_client = 'SCOUT_TCP_CLIENT' +flag_loader_server = 'SCOUT_TCP_SERVER' +flag_loader_transmit= 'SCOUT_TCP_SEND' # Using an enum to support feature extensions ARC_INTEL = 'intel' From 2123d485751650db94dd6cffff2c22e268c86817 Mon Sep 17 00:00:00 2001 From: chkp-eyalit Date: Wed, 28 Apr 2021 19:28:10 +0300 Subject: [PATCH 11/30] [docs] Minor typo fixes Minor typos fixes in the docs --- docs/Compilation Modes.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/Compilation Modes.md b/docs/Compilation Modes.md index cfb8521..c05fe6f 100644 --- a/docs/Compilation Modes.md +++ b/docs/Compilation Modes.md @@ -63,7 +63,8 @@ Loader Flags * SCOUT_LOADING_THUMB_CODE - The loader will load a Scout that was compiled to be executed on an ARM cpu in Thumb mode. * SCOUT_RESTORE_FLOW - The default loaders (```tcp_client_server.c```, ```tcp_loader_server.c```) will clean-up after themselves if the loaded scout will finish the endless loop. -If loader will be compiled to be Position Independent (PIC), which is probably the most common use case, it will als define a new flag of "SCOUT_SLIM_SIZE", to help shrink the size of the binary (to server as an effective shellcode. Under this definition the TCP server would expect the following flags (if needed): +If the loader will be compiled to be Position Independent (PIC), which is probably the most common use case, it will also define a new flag of "SCOUT_SLIM_SIZE", to help shrink the size of the binary (to serve as an effective shellcode. +Under this definition the TCP server would expect the following flags (if needed): * SCOUT_TCP_CLIENT - There is a need to include the feature of a TCP client * SCOUT_TCP_SERVER - There is a need to include the feature of a TCP server * SCOUT_TCP_SEND - There is a need to include the ability to reliably send TCP messages From 450746b67ad984aa7662e6cb0478a21a916dfee3 Mon Sep 17 00:00:00 2001 From: chkp-eyalit Date: Wed, 28 Apr 2021 19:39:08 +0300 Subject: [PATCH 12/30] [refactor] Distinguish between libc implementations Resolves issue #10, by using the proper constants for each libc implementation as instructed by the compilation flags. --- docs/Compilation Modes.md | 6 ++++++ scout/architecture.h | 17 +++++++++++++++++ scout/external_deps.h | 33 +++++++++++++++++++++++++++------ utils/scout_compiler.py | 2 ++ 4 files changed, 52 insertions(+), 6 deletions(-) diff --git a/docs/Compilation Modes.md b/docs/Compilation Modes.md index c05fe6f..851f4ad 100644 --- a/docs/Compilation Modes.md +++ b/docs/Compilation Modes.md @@ -57,6 +57,12 @@ Scout will be compiled for full Position Independent Code (PIC) mode. Any access "SCOUT_PIC_CODE" will lead to the definition of "SCOUT_ISOLATED_ENV" by the compilation environment, because a PIC blob will always be isolated from the environment, and won't have the luxory of a proper executable loader such as "ld.so". +Host LibC Implementation +------------------------ +When injecting our (PIC) code into a host binary, we should make sure to use the proper constants for the matching standard library implementation that is used by the respective binary: +* SCOUT_HOST_GLIBC - The used library is Glibc +* SCOUT_HOST_UCLIBC - The used library is uClibc (or uClibc-NG) + Loader Flags ------------ * SCOUT_LOADER - We are now compiling a loader (that might be using it's own pic plt / globals). diff --git a/scout/architecture.h b/scout/architecture.h index 0a5bad6..cf489bf 100644 --- a/scout/architecture.h +++ b/scout/architecture.h @@ -104,6 +104,23 @@ typedef uint64_t addr_t; #define SCOUT_ISOLATED_ENV #endif +/*********************************************/ +/** LibC versions used by host executable **/ +/*********************************************/ + +#ifdef SCOUT_ISOLATED_ENV + +#if defined(SCOUT_HOST_GLIBC) && !defined(SCOUT_HOST_UCLIBC) + #error "The host process could only use one LibC implementation: glibc or uClibc!" +#endif + + +#if !defined(SCOUT_HOST_GLIBC) && !defined(SCOUT_HOST_UCLIBC) + #define SCOUT_HOST_GLIBC +#endif + +#endif /* SCOUT_ISOLATED_ENV */ + /****************************************/ /** Loader (Tight memory constraints **/ /****************************************/ diff --git a/scout/external_deps.h b/scout/external_deps.h index 094ff92..c49d854 100644 --- a/scout/external_deps.h +++ b/scout/external_deps.h @@ -23,11 +23,19 @@ void free(void * ptr); /** Socket Dependencies **/ /***************************/ -/* GLIBC Constants */ +#if defined(SCOUT_HOST_GLIBC) + #define SOCK_STREAM 1 -/* uCLIBC Constants */ -//#define SOCK_STREAM 2 +#define AF_INET 2 + +#define IPPROTO_TCP 6 +#define IPPROTO_UDP 17 +#define INADDR_ANY 0 + +#elif defined(SCOUT_HOST_UCLIBC) + +#define SOCK_STREAM 2 #define AF_INET 2 #define IPPROTO_TCP 6 @@ -35,6 +43,8 @@ void free(void * ptr); #define INADDR_ANY 0 +#endif + struct in_addr { uint32_t s_addr; @@ -69,17 +79,28 @@ void close(sock_fd fd); /*************************/ /** MMap Dependencies **/ /*************************/ +#if defined(SCOUT_HOST_GLIBC) #define PROT_READ 0x01 #define PROT_WRITE 0x02 #define PROT_EXEC 0x04 -/* GLIBC Constants */ + #define MAP_PRIVATE 0x02 #define MAP_FIXED 0x10 #define MAP_ANONYMOUS 0x20 -/* uCLIBC Constants */ -//#define MAP_ANONYMOUS 0x800 + +#elif defined(SCOUT_HOST_UCLIBC) + +#define PROT_READ 0x01 +#define PROT_WRITE 0x02 +#define PROT_EXEC 0x04 + +#define MAP_PRIVATE 0x02 +#define MAP_FIXED 0x10 +#define MAP_ANONYMOUS 0x800 + +#endif void * mmap(void * addr, size_t length, int prot, int flags, int fd, off_t offset); int mprotect(void * addr, size_t len, int prot); diff --git a/utils/scout_compiler.py b/utils/scout_compiler.py index e864d0e..d7ca222 100644 --- a/utils/scout_compiler.py +++ b/utils/scout_compiler.py @@ -58,6 +58,8 @@ flag_mode_user = 'SCOUT_MODE_USER' flag_mode_kernel = 'SCOUT_MODE_KERNEL' flag_pic_code = 'SCOUT_PIC_CODE' +flag_host_glibc = 'SCOUT_HOST_GLIBC' +flag_host_uclibc = 'SCOUT_HOST_UCLIBC' flag_instructions = 'SCOUT_INSTRUCTIONS' flag_restore_flow = 'SCOUT_RESTORE_FLOW' flag_dynamic_buffers= 'SCOUT_DYNAMIC_BUFFERS' From 8a527c37f0975694fa11be0ae51d265c9380bc86 Mon Sep 17 00:00:00 2001 From: chkp-eyalit Date: Thu, 29 Apr 2021 11:23:42 +0300 Subject: [PATCH 13/30] [Cleanup] Minor fixes typo fixed and missing default flag in documentation was added --- docs/Compilation Modes.md | 2 ++ scout/pic/arm_pic_wrapper.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/Compilation Modes.md b/docs/Compilation Modes.md index 851f4ad..e2dc056 100644 --- a/docs/Compilation Modes.md +++ b/docs/Compilation Modes.md @@ -63,6 +63,8 @@ When injecting our (PIC) code into a host binary, we should make sure to use the * SCOUT_HOST_GLIBC - The used library is Glibc * SCOUT_HOST_UCLIBC - The used library is uClibc (or uClibc-NG) +If none are defined the base library will define "SCOUT_HOST_GLIBC" on it's own. + Loader Flags ------------ * SCOUT_LOADER - We are now compiling a loader (that might be using it's own pic plt / globals). diff --git a/scout/pic/arm_pic_wrapper.c b/scout/pic/arm_pic_wrapper.c index 07a531b..2e0e6d7 100644 --- a/scout/pic/arm_pic_wrapper.c +++ b/scout/pic/arm_pic_wrapper.c @@ -18,7 +18,7 @@ #endif /* ELF_START */ #ifdef SCOUT_ARM_THUMB -#define STATIC_FUNC_ADDR (ELF_START + 0x10) // It sounds wierd, but with +0xC it had an offset of 4 bytes... +#define STATIC_FUNC_ADDR (ELF_START + 0x10) // It sounds weird, but with +0xC it had an offset of 4 bytes... #else #define STATIC_FUNC_ADDR (ELF_START + 0x10) #endif /* SCOUT_ARM_THUMB */ From ac7a6b23878d6121221b8e592418d02b659a7d1c Mon Sep 17 00:00:00 2001 From: chkp-eyalit Date: Thu, 29 Apr 2021 16:42:41 +0300 Subject: [PATCH 14/30] [refactor] Major refactor of the folder structure Folder structure should now separate between Scout infrastructure, that shouldn't be changed by the project, and extensions written by the project and that are located in separate folders. --- .gitignore | 55 +- CONTRIBUTING.md | 43 ++ README.md | 17 +- compilers.txt | 5 + dependencies.txt | 5 - docs/User Guide.md | 12 +- embedded_scout/flags.h | 14 - .../manager/embedded_scout_api.py | 45 ++ examples/embedded_scout/manager/manager.py | 68 +++ .../embedded_scout/src}/Makefile | 66 +-- .../embedded_scout/src}/arm_scout.c | 1 - .../embedded_scout/src}/arm_scout.h | 0 .../embedded_scout/src}/compile_scout.py | 13 +- .../embedded_scout/src}/loader_globals.c | 2 +- .../embedded_scout/src}/loader_globals.h | 0 .../embedded_scout/src}/loader_plt.c | 0 .../embedded_scout/src}/loader_plt.h | 0 .../embedded_scout/src}/project_globals.c | 0 .../embedded_scout/src}/project_globals.h | 0 .../src}/project_instructions.c | 5 + .../src}/project_instructions.h | 11 +- .../embedded_scout/src}/project_plt.c | 2 +- .../embedded_scout/src}/project_plt.h | 0 .../kernel_scout}/driver/Makefile | 4 +- .../kernel_scout}/driver/flags.h | 2 +- .../kernel_scout}/driver/scout_driver.c | 2 +- .../driver/scout_kernel_instructions.c | 2 +- .../driver/scout_kernel_instructions.h | 2 +- .../kernel_scout/manager}/kernel_scout_api.py | 123 ++-- .../kernel_scout/manager}/manager.py | 8 +- .../kernel_scout}/user_mode/Makefile | 46 +- .../kernel_scout}/user_mode/compile_scout.py | 9 +- .../kernel_scout}/user_mode/flags.h | 0 .../kernel_scout}/user_mode/scout_user.c | 3 +- .../kernel_scout}/user_mode/scout_user.h | 0 setup.cfg | 3 + setup.py | 26 + {scout => src/scout}/arc/arm.c | 0 {scout => src/scout}/arc/arm.h | 0 {scout => src/scout}/arc/intel.c | 24 +- {scout => src/scout}/arc/intel.h | 46 +- {scout => src/scout}/arc/mips.c | 0 {scout => src/scout}/arc/mips.h | 0 {scout => src/scout}/architecture.h | 264 ++++----- {scout => src/scout}/errors.h | 44 +- {scout => src/scout}/external_deps.h | 0 {scout => src/scout}/loaders/loader.h | 0 .../scout}/loaders/tcp_client_loader.c | 0 .../scout}/loaders/tcp_client_loader.h | 0 .../scout}/loaders/tcp_server_loader.c | 0 .../scout}/loaders/tcp_server_loader.h | 0 {scout => src/scout}/pack.c | 344 +++++------ {scout => src/scout}/pack.h | 0 {scout => src/scout}/pic/arm_pic_wrapper.c | 0 {scout => src/scout}/pic/intel_pic_wrapper.c | 0 {scout => src/scout}/pic/mips_pic_wrapper.c | 0 {scout => src/scout}/pic/pic_wrapper.h | 0 {scout => src/scout}/pic/scout_globals.c | 0 {scout => src/scout}/pic/scout_globals.h | 0 {scout => src/scout}/pic/scout_plt.c | 0 {scout => src/scout}/pic/scout_plt.h | 0 {scout => src/scout}/scout.h | 56 +- {scout => src/scout}/scout_api.c | 336 +++++------ {scout => src/scout}/scout_api.h | 460 +++++++-------- {scout => src/scout}/tcp_server.c | 540 +++++++++--------- {scout => src/scout}/tcp_server.h | 206 +++---- src/utils/__init__.py | 6 + {utils => src/utils}/context_creator.py | 0 {manager => src/utils}/scout_api.py | 249 ++++---- {utils => src/utils}/scout_compiler.py | 0 {manager => src/utils}/scout_network.py | 182 +++--- tests.py | 23 + 72 files changed, 1789 insertions(+), 1585 deletions(-) create mode 100644 CONTRIBUTING.md create mode 100644 compilers.txt delete mode 100644 dependencies.txt delete mode 100644 embedded_scout/flags.h create mode 100644 examples/embedded_scout/manager/embedded_scout_api.py create mode 100644 examples/embedded_scout/manager/manager.py rename {embedded_scout => examples/embedded_scout/src}/Makefile (92%) rename {embedded_scout => examples/embedded_scout/src}/arm_scout.c (93%) rename {embedded_scout => examples/embedded_scout/src}/arm_scout.h (100%) rename {embedded_scout => examples/embedded_scout/src}/compile_scout.py (95%) rename {embedded_scout => examples/embedded_scout/src}/loader_globals.c (71%) rename {embedded_scout => examples/embedded_scout/src}/loader_globals.h (100%) rename {embedded_scout => examples/embedded_scout/src}/loader_plt.c (100%) rename {embedded_scout => examples/embedded_scout/src}/loader_plt.h (100%) rename {embedded_scout => examples/embedded_scout/src}/project_globals.c (100%) rename {embedded_scout => examples/embedded_scout/src}/project_globals.h (100%) rename {embedded_scout => examples/embedded_scout/src}/project_instructions.c (89%) rename {embedded_scout => examples/embedded_scout/src}/project_instructions.h (86%) rename {embedded_scout => examples/embedded_scout/src}/project_plt.c (71%) rename {embedded_scout => examples/embedded_scout/src}/project_plt.h (100%) rename {kernel_scout => examples/kernel_scout}/driver/Makefile (91%) rename {kernel_scout => examples/kernel_scout}/driver/flags.h (86%) rename {kernel_scout => examples/kernel_scout}/driver/scout_driver.c (99%) rename {kernel_scout => examples/kernel_scout}/driver/scout_kernel_instructions.c (99%) rename {kernel_scout => examples/kernel_scout}/driver/scout_kernel_instructions.h (98%) rename {manager => examples/kernel_scout/manager}/kernel_scout_api.py (92%) rename {manager => examples/kernel_scout/manager}/manager.py (91%) rename {kernel_scout => examples/kernel_scout}/user_mode/Makefile (73%) rename {kernel_scout => examples/kernel_scout}/user_mode/compile_scout.py (93%) rename {kernel_scout => examples/kernel_scout}/user_mode/flags.h (100%) rename {kernel_scout => examples/kernel_scout}/user_mode/scout_user.c (99%) rename {kernel_scout => examples/kernel_scout}/user_mode/scout_user.h (100%) create mode 100644 setup.cfg create mode 100644 setup.py rename {scout => src/scout}/arc/arm.c (100%) rename {scout => src/scout}/arc/arm.h (100%) rename {scout => src/scout}/arc/intel.c (95%) rename {scout => src/scout}/arc/intel.h (95%) rename {scout => src/scout}/arc/mips.c (100%) rename {scout => src/scout}/arc/mips.h (100%) rename {scout => src/scout}/architecture.h (96%) rename {scout => src/scout}/errors.h (96%) rename {scout => src/scout}/external_deps.h (100%) rename {scout => src/scout}/loaders/loader.h (100%) rename {scout => src/scout}/loaders/tcp_client_loader.c (100%) rename {scout => src/scout}/loaders/tcp_client_loader.h (100%) rename {scout => src/scout}/loaders/tcp_server_loader.c (100%) rename {scout => src/scout}/loaders/tcp_server_loader.h (100%) rename {scout => src/scout}/pack.c (96%) rename {scout => src/scout}/pack.h (100%) rename {scout => src/scout}/pic/arm_pic_wrapper.c (100%) rename {scout => src/scout}/pic/intel_pic_wrapper.c (100%) rename {scout => src/scout}/pic/mips_pic_wrapper.c (100%) rename {scout => src/scout}/pic/pic_wrapper.h (100%) rename {scout => src/scout}/pic/scout_globals.c (100%) rename {scout => src/scout}/pic/scout_globals.h (100%) rename {scout => src/scout}/pic/scout_plt.c (100%) rename {scout => src/scout}/pic/scout_plt.h (100%) rename {scout => src/scout}/scout.h (96%) rename {scout => src/scout}/scout_api.c (96%) rename {scout => src/scout}/scout_api.h (96%) rename {scout => src/scout}/tcp_server.c (96%) rename {scout => src/scout}/tcp_server.h (96%) create mode 100644 src/utils/__init__.py rename {utils => src/utils}/context_creator.py (100%) rename {manager => src/utils}/scout_api.py (95%) rename {utils => src/utils}/scout_compiler.py (100%) rename {manager => src/utils}/scout_network.py (96%) create mode 100644 tests.py diff --git a/.gitignore b/.gitignore index 3e4e7df..10da5a5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,41 +1,40 @@ # Compiled scout -scout/*.o -scout/*.S -scout/*.bin -scout/*.elf -scout/arc/*.o -scout/arc/*.S -scout/loaders/*.o -scout/loaders/*.S -scout/pic/*.o -scout/pic/*.S -scout/Scout.vpj -scout/Scout.vpw -scout/Scout.vpwhist -scout/Scout.vtg +src/scout/*.o +src/scout/*.S +src/scout/*.bin +src/scout/*.elf +src/scout/arc/*.o +src/scout/arc/*.S +src/scout/loaders/*.o +src/scout/loaders/*.S +src/scout/pic/*.o +src/scout/pic/*.S +src/scout/Scout.vpj +src/scout/Scout.vpw +src/scout/Scout.vpwhist +src/scout/Scout.vtg # Compiled embedded scout -embedded_scout/*.o -embedded_scout/*.S -embedded_scout/*.bin -embedded_scout/*.elf +examples/embedded_scout/*.o +examples/embedded_scout/*.S +examples/embedded_scout/*.bin +examples/embedded_scout/*.elf -# Compiled kernel scout kernel_scout/driver/*.order -kernel_scout/driver/*.symvers -kernel_scout/driver/*.o -kernel_scout/driver/*.ko -kernel_scout/user_mode/*.o -kernel_scout/user_mode/*.S -kernel_scout/user_mode/*.bin -kernel_scout/user_mode/*.elf +# Compiled kernel scout examples/kernel_scout/driver/*.order +examples/kernel_scout/driver/*.symvers +examples/kernel_scout/driver/*.o +examples/kernel_scout/driver/*.ko +examples/kernel_scout/user_mode/*.o +examples/kernel_scout/user_mode/*.S +examples/kernel_scout/user_mode/*.bin +examples/kernel_scout/user_mode/*.elf # Compiled tests tests/exploit_me_32 tests/exploit_me_64 # Compiled python modules -utils/*.pyc -manager/*.pyc +src/utils/*.pyc # Generated docs docs/_build/* diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..4273061 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,43 @@ +How to contribute +================= +First of all, thank you for choosing to contribute to our project. This short guide will describe the required coding conventions, as well as the built-in tests that we use in our project. Following these guidelines will help us merge your pull request into our code base in a fast as smooth manner. + +Submitting changes +------------------ +Please send us a GitHub Pull Request with a clear list of what you've done. Make sure to include a clear log message for your commits, describing the modifications / additions to the code base, and their implications. + +Reporting a bug +--------------- +In order to help us close the bug as quickly as possible, please follow these steps: +1. Make sure there isn't an open issue that already addresses this bug +2. If there isn't, open a new issue and attach as many informative details as you can: + * Architecture & compilation flags in which the bug occurs + * Trace + logs, describing the bug / exception + * As many details as you can in order to help us reproduce and fix this issue + 3. If you already have a fix, please submit it as a pull request, and include the bug details in it's description + +Coding Conventions +------------------ +Start reading our code and we believe you'll get the hang of it. +The important notes are: +* Every function should be documented in a manner that is consistent with the current documentation standard +* Each indentation level should be 4 spaces in width (spaces, not tabs) +* We believe that comments improve the readability, make sure that your code is documented enough to be understood by other developers + +Testing +------- +**Scout** uses the following tools to enforce coding conventions and to help eliminate common python bugs: +* [pydocstyle](http://www.pydocstyle.org/en/2.1.1/usage.html) +* [flake8](https://pypi.org/project/flake8/) + +Testing can be done from the project's home directory: +1. Testing for **pydocstyle**: +```Scout> python tests.py``` +2. Testing for **flake8**: +```Scout> flake8 src``` + +One last note +------------- +We believe that the only way that Open Source tools will help the infosec community in the long term, is to maintain these tools and to make sure they are developed according to the community standards. Each contribution brings as one step further to this goal. + +Thanks :) \ No newline at end of file diff --git a/README.md b/README.md index c6cc9ca..b9f1bb3 100644 --- a/README.md +++ b/README.md @@ -51,13 +51,14 @@ https://scout-debugger.readthedocs.io/ * Any Posix-like operating system (Embedded Mode) ## Folder Structure -* **docs:** Useful tutorials regarding each unique module of the debugger, including documentation of the API used for custom extensions -* **embedded_scout:** Example project for an embedded debugger scenario, i.e. a debugger that is injected into the address space of a debuggee firmware -* **kernel_scout:** Linux kernel driver-based debugger, including a proxy user mode process used for transparent network access -* **manager:** Python layer for communicating with the debuggee (usually over a TCP connection) -* **scout:** C code of the basic scout debugger -* **tests:** A testing utility for PIC based debuggers -* **utils:** Useful python compilation scripts +* **docs:** Documentation files that generated the read-the-docs that was linked above +* **examples:** + * embedded_scout - Use case example for an "Embedded Mode" compilation + * kernel_scout - Use case example for a Linux "Kernel Mode" compilation +* **src** + * scout - Source code for the debugger (core of the server side) + * utils - Python compilation scripts and network API for the client/server +* **tests:** A simple exploit_me.c for checking PIC compiled binaries ## Credits This projects combines together design and compilation tricks that I learned from many fellow researchers during the years. @@ -73,4 +74,4 @@ Scout was developed and used in our following research projects: ## Contact Eyal Itkin (eyalit at checkpoint dot com) -[@EyalItkin](https://twitter.com/EyalItkin) +[@EyalItkin](https://twitter.com/EyalItkin) \ No newline at end of file diff --git a/compilers.txt b/compilers.txt new file mode 100644 index 0000000..669384b --- /dev/null +++ b/compilers.txt @@ -0,0 +1,5 @@ +Used compilers: +=============== +1. GCC compilation to 32 bits on 64 bits linux machines ==> sudo apt-get install gcc-multilib libc6-dev-i386 +2. ARM cross compiler toolchain for Linux ==> sudo apt-get install gcc-arm-none-eabi +3. MIPS cross compiler toolchain for Linux ==> sudo apt-get install gcc-mips-linux-gnu diff --git a/dependencies.txt b/dependencies.txt deleted file mode 100644 index 3ecb443..0000000 --- a/dependencies.txt +++ /dev/null @@ -1,5 +0,0 @@ -List Of Misc Dependencies: -========================== -1. Python pip package "elementals" ==> pip install elementals -2. GCC compilation to 32 bits on 64 bits linux machines ==> sudo apt-get install gcc-multilib libc6-dev-i386 -3. ARM cross compiler toolchain for linux ==> sudo apt-get install gcc-arm-none-eabi diff --git a/docs/User Guide.md b/docs/User Guide.md index 520ca3f..0eed124 100644 --- a/docs/User Guide.md +++ b/docs/User Guide.md @@ -10,12 +10,14 @@ The server is the debugger that is being sent / injected into the debugee, and t Folder Structure ---------------- * docs - This documentation -* embedded_scout - Use case example for an "Embedded Mode" compilation -* kernel_scout - Use case example for a Linux "Kernel Mode" compilation -* manager - Client side code, including the use case example for the Linux kernel use case -* scout - Source code for the debugger (core of the server side) +* examples + * embedded_scout - Use case example for an "Embedded Mode" compilation + * kernel_scout - Use case example for a Linux "Kernel Mode" compilation +* src + * scout - Source code for the debugger (core of the server side) + * utils - Python compilation scripts and network API for the client/server * tests - A simple exploit_me.c for checking PIC compiled binaries -* utils - Python compilation scripts + **Note:** More information on the different compilation modes can be found under the "Compilation Modes" section. diff --git a/embedded_scout/flags.h b/embedded_scout/flags.h deleted file mode 100644 index 48d646d..0000000 --- a/embedded_scout/flags.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef __SCOUT__FLAGS__H__ -#define __SCOUT__FLAGS__H__ - -/* This file is AUTO-GENERATED, please do NOT edit it manually */ -#define SCOUT_EMBEDDED_ENV -#define SCOUT_ARCH_INTEL -#define SCOUT_LITTLE_ENDIAN -#define SCOUT_BITS_64 -#define SCOUT_MODE_KERNEL -#define SCOUT_DYNAMIC_BUFFERS -#define SCOUT_INSTRUCTIONS -#define SCOUT_PIC_CODE - -#endif /* _SCOUT__FLAGS__H__ */ \ No newline at end of file diff --git a/examples/embedded_scout/manager/embedded_scout_api.py b/examples/embedded_scout/manager/embedded_scout_api.py new file mode 100644 index 0000000..ab79c4b --- /dev/null +++ b/examples/embedded_scout/manager/embedded_scout_api.py @@ -0,0 +1,45 @@ +from scout_api import * + +############################## +## Extended API Error Codes ## +############################## + +embedded_error_codes = { # Example for a project-specific error code + 30 : "STATUS_INVALID_FREE", + } + +addErrorCodes(embedded_error_codes) + +############################# +## Camera API Instructions ## +############################# + +EMBEDDED_INST_BASIC_INSTR = SCOUT_MAX_BASIC_INSTR + 1 +EMBEDDED_INST_ALLOC = EMBEDDED_INST_BASIC_INSTR + 0 +EMBEDDED_INST_FREE = EMBEDDED_INST_BASIC_INSTR + 1 + +######################### +## Instruction Factory ## +######################### + +def instrAlloc(size): + """Allocates a memory buffer on the target + + Args: + size (int): size (in bytes) of the desired memory allocation + + Return Value: + string containing the serialized instruction + """ + return addHeader( EMBEDDED_INST_ALLOC, struct.pack("!L", size) ) + +def instrFree(address): + """Frees a memory allocation on the target, on the specified address + + Args: + address (int): memory address of the desired memory allocation + + Return Value: + string containing the serialized instruction + """ + return addHeader( EMBEDDED_INST_FREE, struct.pack("!L", address) ) \ No newline at end of file diff --git a/examples/embedded_scout/manager/manager.py b/examples/embedded_scout/manager/manager.py new file mode 100644 index 0000000..e802694 --- /dev/null +++ b/examples/embedded_scout/manager/manager.py @@ -0,0 +1,68 @@ +#!/usr/bin/python + +from embedded_scout_api import * +from scout.scout_network import * +from elementals import Prompter, hexDump + +import logging +import struct +import time +import socket +import os +import sys + +## +# Main debugging session (example) +## +def startManage(sock_fd, logger): + logger.info('Starting to manage the embedded Scout') + + logger.info('Allocating a remote memory buffer') + data = sendInstr(sock_fd, instrAlloc(0x100), logger) + + memory_addr = struct.unpack('!L', data)[0] + logger.info('The buffer was allocated at address: 0x%08x', memory_addr) + + logger.info('Sending the memory read instruction') + data = sendInstr(sock_fd, instrMemRead(memory_addr, 0x100), logger) + logger.info('The default content of the buffer is:') + logger.addIndent() + logger.info(hexDump(data)) + logger.removeIndent() + +## +# Prints the usage instructions (example) +## +def printUsage(args): + print(f'Usage: {args[0]} ') + print('Exiting') + exit(1) + +## +# Main function (example) +## +def main(args): + # Check the arguments + if len(args) != 1 + 1: + print(f'Wrong amount of arguments, got {len(args) - 1}, expected 1') + printUsage(args) + + # parse the args + server_ip = args[1] + + # open the log + prompter = Prompter('Scout Manager', [('scout_log.txt', 'a', logging.DEBUG)]) + + # connect to the server + sock_fd = socket.create_connection((server_ip, SCOUT_PORT)) + + # configure the scout + setBitness32() + + # start the managing session + startManage(sock_fd, prompter) + + prompter.info('Finished Successfully') + +if __name__ == '__main__': + main(sys.argv) \ No newline at end of file diff --git a/embedded_scout/Makefile b/examples/embedded_scout/src/Makefile similarity index 92% rename from embedded_scout/Makefile rename to examples/embedded_scout/src/Makefile index 703c0e9..7f408b9 100644 --- a/embedded_scout/Makefile +++ b/examples/embedded_scout/src/Makefile @@ -1,33 +1,33 @@ -MAKE=make -RM=rm -OUTFILE=embedded_scout.bin -LOADERFILE=scout_loader.bin -SCOUT_SRC=../scout - -# Build rules -all: $(OUTFILE) $(LOADERFILE) - -$(OUTFILE): - python3 compile_scout.py - -# Rebuild this project -rebuild: cleanall all - -# Clean this project -clean: - $(RM) -f $(OUTFILE) - $(RM) -f $(LOADERFILE) - $(RM) -f *.elf - $(RM) -f *.o - $(RM) -f *.S - $(RM) -f $(SCOUT_SRC)/*.o - $(RM) -f $(SCOUT_SRC)/*.S - $(RM) -f $(SCOUT_SRC)/pic/*.o - $(RM) -f $(SCOUT_SRC)/pic/*.S - $(RM) -f $(SCOUT_SRC)/arc/*.o - $(RM) -f $(SCOUT_SRC)/arc/*.S - $(RM) -f $(SCOUT_SRC)/loaders/*.o - $(RM) -f $(SCOUT_SRC)/loaders/*.S - -# Clean this project and all dependencies -cleanall: clean +MAKE=make +RM=rm +OUTFILE=embedded_scout.bin +LOADERFILE=scout_loader.bin +SCOUT_SRC=../../../src/scout + +# Build rules +all: $(OUTFILE) $(LOADERFILE) + +$(OUTFILE): + python3 compile_scout.py + +# Rebuild this project +rebuild: cleanall all + +# Clean this project +clean: + $(RM) -f $(OUTFILE) + $(RM) -f $(LOADERFILE) + $(RM) -f *.elf + $(RM) -f *.o + $(RM) -f *.S + $(RM) -f $(SCOUT_SRC)/*.o + $(RM) -f $(SCOUT_SRC)/*.S + $(RM) -f $(SCOUT_SRC)/pic/*.o + $(RM) -f $(SCOUT_SRC)/pic/*.S + $(RM) -f $(SCOUT_SRC)/arc/*.o + $(RM) -f $(SCOUT_SRC)/arc/*.S + $(RM) -f $(SCOUT_SRC)/loaders/*.o + $(RM) -f $(SCOUT_SRC)/loaders/*.S + +# Clean this project and all dependencies +cleanall: clean diff --git a/embedded_scout/arm_scout.c b/examples/embedded_scout/src/arm_scout.c similarity index 93% rename from embedded_scout/arm_scout.c rename to examples/embedded_scout/src/arm_scout.c index 85569ff..7002de7 100644 --- a/embedded_scout/arm_scout.c +++ b/examples/embedded_scout/src/arm_scout.c @@ -1,6 +1,5 @@ #include "arm_scout.h" #include "scout/tcp_server.h" -#include "scout/pic/pic_wrapper.h" void main() { diff --git a/embedded_scout/arm_scout.h b/examples/embedded_scout/src/arm_scout.h similarity index 100% rename from embedded_scout/arm_scout.h rename to examples/embedded_scout/src/arm_scout.h diff --git a/embedded_scout/compile_scout.py b/examples/embedded_scout/src/compile_scout.py similarity index 95% rename from embedded_scout/compile_scout.py rename to examples/embedded_scout/src/compile_scout.py index 0cc75e5..d767ca3 100644 --- a/embedded_scout/compile_scout.py +++ b/examples/embedded_scout/src/compile_scout.py @@ -5,17 +5,14 @@ import struct from elementals import Prompter -# Assuming the script is executed from its directory -sys.path.append('../utils') - -from scout_compiler import * -from context_creator import * +from scout.scout_compiler import * +from scout.context_creator import * ############################## ## Dynamic Configurations ## ############################## -SCOUT_DIR = '../scout' +SCOUT_DIR = '../../../src/scout' SCOUT_LOADER_ELF = 'scout_loader.elf' SCOUT_LOADER_BIN = 'scout_loader.bin' @@ -25,7 +22,7 @@ TARGET_ARCH = ARC_INTEL TARGET_ENDIANNESS = True if TARGET_ARCH == ARC_INTEL else False -TARGET_BITNESS = False # is 32 bits ? +TARGET_BITNESS = True # is 32 bits? # Scout Functions (in same order as the c code) symbol_memcpy = 0x80486c0 @@ -171,4 +168,4 @@ def main(args): prompter.info('Finished Successfully') if __name__ == '__main__': - main(sys.argv) + main(sys.argv) \ No newline at end of file diff --git a/embedded_scout/loader_globals.c b/examples/embedded_scout/src/loader_globals.c similarity index 71% rename from embedded_scout/loader_globals.c rename to examples/embedded_scout/src/loader_globals.c index 43686d5..9887a21 100644 --- a/embedded_scout/loader_globals.c +++ b/examples/embedded_scout/src/loader_globals.c @@ -1,4 +1,4 @@ -#include "scout/pic/pic_wrapper.h" +#include "scout/scout.h" #ifdef SCOUT_PIC_CODE diff --git a/embedded_scout/loader_globals.h b/examples/embedded_scout/src/loader_globals.h similarity index 100% rename from embedded_scout/loader_globals.h rename to examples/embedded_scout/src/loader_globals.h diff --git a/embedded_scout/loader_plt.c b/examples/embedded_scout/src/loader_plt.c similarity index 100% rename from embedded_scout/loader_plt.c rename to examples/embedded_scout/src/loader_plt.c diff --git a/embedded_scout/loader_plt.h b/examples/embedded_scout/src/loader_plt.h similarity index 100% rename from embedded_scout/loader_plt.h rename to examples/embedded_scout/src/loader_plt.h diff --git a/embedded_scout/project_globals.c b/examples/embedded_scout/src/project_globals.c similarity index 100% rename from embedded_scout/project_globals.c rename to examples/embedded_scout/src/project_globals.c diff --git a/embedded_scout/project_globals.h b/examples/embedded_scout/src/project_globals.h similarity index 100% rename from embedded_scout/project_globals.h rename to examples/embedded_scout/src/project_globals.h diff --git a/embedded_scout/project_instructions.c b/examples/embedded_scout/src/project_instructions.c similarity index 89% rename from embedded_scout/project_instructions.c rename to examples/embedded_scout/src/project_instructions.c index 2fa9afe..f0b9cf8 100644 --- a/embedded_scout/project_instructions.c +++ b/examples/embedded_scout/src/project_instructions.c @@ -33,6 +33,11 @@ int32_t instruction_free(void * ctx, uint8_t * instruction, uint32_t length) uint32_t addr; addr = unpack_uint32( &readHead ); + /* Sanity check (example for a project-specific status code) */ + if(addr == NULL) + { + return STATUS_INVALID_FREE; + } free((uint8_t *)addr); return STATUS_OK; diff --git a/embedded_scout/project_instructions.h b/examples/embedded_scout/src/project_instructions.h similarity index 86% rename from embedded_scout/project_instructions.h rename to examples/embedded_scout/src/project_instructions.h index fcb0605..efcef98 100644 --- a/embedded_scout/project_instructions.h +++ b/examples/embedded_scout/src/project_instructions.h @@ -3,6 +3,13 @@ #include "scout/scout_api.h" +/******************************/ +/* Instruction Status Codes */ +/******************************/ + +/* Scout API Statuses */ +#define STATUS_INVALID_FREE 30 + /*******************************/ /* Instructions Registration */ /*******************************/ @@ -36,7 +43,7 @@ void register_specific_instructions(void); int32_t instruction_alloc(void * ctx, uint8_t * instruction, uint32_t length); /** - * Memory de-allocaiton (free) instruction + * Memory de-allocation (free) instruction * * @author eyalit (06/05/2018) * @@ -57,4 +64,4 @@ int32_t instruction_free(void * ctx, uint8_t * instruction, uint32_t length); #define INSTR_FREE_MAX_SIZE (sizeof(addr_t)) #define INSTR_FREE_HANDLER instruction_free -#endif // __SCOUT__EMBEDDED__INSTRUCTIONS__H__ +#endif // __SCOUT__EMBEDDED__INSTRUCTIONS__H__ \ No newline at end of file diff --git a/embedded_scout/project_plt.c b/examples/embedded_scout/src/project_plt.c similarity index 71% rename from embedded_scout/project_plt.c rename to examples/embedded_scout/src/project_plt.c index 7490aa8..3ffffd7 100644 --- a/embedded_scout/project_plt.c +++ b/examples/embedded_scout/src/project_plt.c @@ -1,4 +1,4 @@ -#include "scout/pic/pic_wrapper.h" +#include "scout/scout.h" #ifdef SCOUT_PIC_CODE diff --git a/embedded_scout/project_plt.h b/examples/embedded_scout/src/project_plt.h similarity index 100% rename from embedded_scout/project_plt.h rename to examples/embedded_scout/src/project_plt.h diff --git a/kernel_scout/driver/Makefile b/examples/kernel_scout/driver/Makefile similarity index 91% rename from kernel_scout/driver/Makefile rename to examples/kernel_scout/driver/Makefile index 01cb1ce..d0a38bf 100644 --- a/kernel_scout/driver/Makefile +++ b/examples/kernel_scout/driver/Makefile @@ -1,5 +1,5 @@ RM=rm -SCOUT_SRC=../../scout +SCOUT_SRC=../../../src/scout obj-m+=scout.o EXTRA_CFLAGS := -I$(src) -I$(src)/../.. -Wno-incompatible-pointer-types @@ -18,4 +18,4 @@ clean: $(RM) -f $(SCOUT_SRC)/*.o # Clean this project and all dependencies -cleanall: clean +cleanall: clean \ No newline at end of file diff --git a/kernel_scout/driver/flags.h b/examples/kernel_scout/driver/flags.h similarity index 86% rename from kernel_scout/driver/flags.h rename to examples/kernel_scout/driver/flags.h index 2766715..49fbed4 100644 --- a/kernel_scout/driver/flags.h +++ b/examples/kernel_scout/driver/flags.h @@ -10,4 +10,4 @@ #define SCOUT_MODE_KERNEL #define SCOUT_INSTRUCTIONS -#endif /* __KERNEL__SCOUT__FLAGS__H__ */ +#endif /* __KERNEL__SCOUT__FLAGS__H__ */ \ No newline at end of file diff --git a/kernel_scout/driver/scout_driver.c b/examples/kernel_scout/driver/scout_driver.c similarity index 99% rename from kernel_scout/driver/scout_driver.c rename to examples/kernel_scout/driver/scout_driver.c index fae3cd1..3551ae1 100644 --- a/kernel_scout/driver/scout_driver.c +++ b/examples/kernel_scout/driver/scout_driver.c @@ -170,4 +170,4 @@ MODULE_DESCRIPTION("Scout based debug driver"); MODULE_LICENSE("GPL"); module_init(scout_init); -module_exit(scout_exit); +module_exit(scout_exit); \ No newline at end of file diff --git a/kernel_scout/driver/scout_kernel_instructions.c b/examples/kernel_scout/driver/scout_kernel_instructions.c similarity index 99% rename from kernel_scout/driver/scout_kernel_instructions.c rename to examples/kernel_scout/driver/scout_kernel_instructions.c index f3a4737..078c39a 100644 --- a/kernel_scout/driver/scout_kernel_instructions.c +++ b/examples/kernel_scout/driver/scout_kernel_instructions.c @@ -56,4 +56,4 @@ int instruction_leak_addr(void * c, uint8_t * instruction, uint32_t length) printk(KERN_NOTICE "SCOUT-KERNEL: virt addres is 0x%p, phys is 0x%p\n", add_input_randomness, (void *)virt_to_phys(add_input_randomness)); return STATUS_OK; -} +} \ No newline at end of file diff --git a/kernel_scout/driver/scout_kernel_instructions.h b/examples/kernel_scout/driver/scout_kernel_instructions.h similarity index 98% rename from kernel_scout/driver/scout_kernel_instructions.h rename to examples/kernel_scout/driver/scout_kernel_instructions.h index 2fe846d..2d7ee2a 100644 --- a/kernel_scout/driver/scout_kernel_instructions.h +++ b/examples/kernel_scout/driver/scout_kernel_instructions.h @@ -87,4 +87,4 @@ int instruction_leak_addr(void * ctx, uint8_t * instruction, uint32_t length); #define INSTR_LEAK_ADDR_MAX_SIZE 0 #define INSTR_LEAK_ADDR_HANDLER instruction_leak_addr -#endif // __KERNEL__SCOUT__INSTRUCTIONS__H__ +#endif // __KERNEL__SCOUT__INSTRUCTIONS__H__ \ No newline at end of file diff --git a/manager/kernel_scout_api.py b/examples/kernel_scout/manager/kernel_scout_api.py similarity index 92% rename from manager/kernel_scout_api.py rename to examples/kernel_scout/manager/kernel_scout_api.py index 92d4b80..172b0d3 100644 --- a/manager/kernel_scout_api.py +++ b/examples/kernel_scout/manager/kernel_scout_api.py @@ -1,62 +1,61 @@ -from scout_api import * - -############################## -## Extended API Error Codes ## -############################## - -kernel_error_codes = { # Empty for now - } - -addErrorCodes(kernel_error_codes) - -############################# -## Kernel API Instructions ## -############################# - -KERNEL_BASIC_INSTR = SCOUT_MAX_BASIC_INSTR + 1 -SCOUT_INST_PHY_READ = KERNEL_BASIC_INSTR + 0 -SCOUT_INST_PHY_WRITE = KERNEL_BASIC_INSTR + 1 -SCOUT_INST_LEAK_ADDR = KERNEL_BASIC_INSTR + 2 - -######################### -## Instruction Factory ## -######################### - -# kernel instructions -def instrPhyRead(addr, length): - """Builds the Read Physical Memory instruction - - Args: - addr (numeric): physical memory address - length (numeric): number of bytes to be read form the given address - - Return Value: - string containing the serialized instruction - """ - instr = struct.pack( "!QL" if TARGET_BITNESS == 64 else "!LL", addr, length ) - return addHeader( SCOUT_INST_PHY_READ, instr ) - -def instrPhyWrite(addr, content): - """Builds the Write Physical Memory instruction - - Args: - addr (numeric): physical memory address - content (string): binary data to be written to the given address - - Return Value: - string containing the serialized instruction - """ - instr = struct.pack( "!Q" if TARGET_BITNESS == 64 else "!L", addr ) + content - return addHeader( SCOUT_INST_PHY_READ, instr ) - -def instrLeakAddr(): - """Builds the Leak Kernel Address instruction - - Args: - (none) - - Return Value: - string containing the serialized instruction - """ - return addHeader( SCOUT_INST_LEAK_ADDR, b'' ) - +from scout.scout_api import * + +############################## +## Extended API Error Codes ## +############################## + +kernel_error_codes = { # Empty for now + } + +addErrorCodes(kernel_error_codes) + +############################# +## Kernel API Instructions ## +############################# + +KERNEL_BASIC_INSTR = SCOUT_MAX_BASIC_INSTR + 1 +SCOUT_INST_PHY_READ = KERNEL_BASIC_INSTR + 0 +SCOUT_INST_PHY_WRITE = KERNEL_BASIC_INSTR + 1 +SCOUT_INST_LEAK_ADDR = KERNEL_BASIC_INSTR + 2 + +######################### +## Instruction Factory ## +######################### + +# kernel instructions +def instrPhyRead(addr, length): + """Builds the Read Physical Memory instruction + + Args: + addr (numeric): physical memory address + length (numeric): number of bytes to be read form the given address + + Return Value: + string containing the serialized instruction + """ + instr = struct.pack( "!QL" if TARGET_BITNESS == 64 else "!LL", addr, length ) + return addHeader( SCOUT_INST_PHY_READ, instr ) + +def instrPhyWrite(addr, content): + """Builds the Write Physical Memory instruction + + Args: + addr (numeric): physical memory address + content (string): binary data to be written to the given address + + Return Value: + string containing the serialized instruction + """ + instr = struct.pack( "!Q" if TARGET_BITNESS == 64 else "!L", addr ) + content + return addHeader( SCOUT_INST_PHY_READ, instr ) + +def instrLeakAddr(): + """Builds the Leak Kernel Address instruction + + Args: + (none) + + Return Value: + string containing the serialized instruction + """ + return addHeader( SCOUT_INST_LEAK_ADDR, b'' ) \ No newline at end of file diff --git a/manager/manager.py b/examples/kernel_scout/manager/manager.py similarity index 91% rename from manager/manager.py rename to examples/kernel_scout/manager/manager.py index 6ae05de..8ea96bc 100644 --- a/manager/manager.py +++ b/examples/kernel_scout/manager/manager.py @@ -1,8 +1,8 @@ #!/usr/bin/python -from kernel_scout_api import * -from scout_network import * -from elementals import Prompter, hexDump +from kernel_scout_api import * +from scout.scout_network import * +from elementals import Prompter, hexDump import logging import struct @@ -65,4 +65,4 @@ def main(args): prompter.info('Finished Successfully') if __name__ == '__main__': - main(sys.argv) + main(sys.argv) \ No newline at end of file diff --git a/kernel_scout/user_mode/Makefile b/examples/kernel_scout/user_mode/Makefile similarity index 73% rename from kernel_scout/user_mode/Makefile rename to examples/kernel_scout/user_mode/Makefile index 02c30ee..5dd7d1e 100644 --- a/kernel_scout/user_mode/Makefile +++ b/examples/kernel_scout/user_mode/Makefile @@ -1,24 +1,22 @@ -MAKE=make -RM=rm -OUTFILE=scout_user -SCOUT_SRC=../../scout - -# Build rules -all: $(OUTFILE) - -$(OUTFILE): - python3 compile_scout.py - -# Rebuild this project -rebuild: cleanall all - -# Clean this project -clean: - $(RM) -f $(OUTFILE) - $(RM) -f *.o - $(RM) -f $(SCOUT_SRC)/*.o - $(RM) -f $(SCOUT_SRC)/pic/*.o - $(RM) -f $(SCOUT_SRC)/arc/*.o - -# Clean this project and all dependencies -cleanall: clean +MAKE=make +RM=rm +OUTFILE=scout_user +SCOUT_SRC=../../../src/scout + +# Build rules +all: $(OUTFILE) + +$(OUTFILE): + python3 compile_scout.py + +# Rebuild this project +rebuild: cleanall all + +# Clean this project +clean: + $(RM) -f $(OUTFILE) + $(RM) -f *.o + $(RM) -f $(SCOUT_SRC)/*.o + +# Clean this project and all dependencies +cleanall: clean diff --git a/kernel_scout/user_mode/compile_scout.py b/examples/kernel_scout/user_mode/compile_scout.py similarity index 93% rename from kernel_scout/user_mode/compile_scout.py rename to examples/kernel_scout/user_mode/compile_scout.py index 0b39f00..55d460b 100644 --- a/kernel_scout/user_mode/compile_scout.py +++ b/examples/kernel_scout/user_mode/compile_scout.py @@ -5,16 +5,13 @@ import struct from elementals import Prompter -# Assuming the script is executed from its directory -sys.path.append('../../utils') - -from scout_compiler import * +from scout.scout_compiler import * ############################## ## Dynamic Configurations ## ############################## -SCOUT_DIR = '../../scout' +SCOUT_DIR = '../../../src/scout' USER_SCOUT_BIN = 'scout_user' @@ -93,4 +90,4 @@ def main(args) : prompter.info('Finished Successfully') if __name__ == '__main__': - main(sys.argv) + main(sys.argv) \ No newline at end of file diff --git a/kernel_scout/user_mode/flags.h b/examples/kernel_scout/user_mode/flags.h similarity index 100% rename from kernel_scout/user_mode/flags.h rename to examples/kernel_scout/user_mode/flags.h diff --git a/kernel_scout/user_mode/scout_user.c b/examples/kernel_scout/user_mode/scout_user.c similarity index 99% rename from kernel_scout/user_mode/scout_user.c rename to examples/kernel_scout/user_mode/scout_user.c index 373a56b..fee2d2b 100644 --- a/kernel_scout/user_mode/scout_user.c +++ b/examples/kernel_scout/user_mode/scout_user.c @@ -89,4 +89,5 @@ int main(int argc, char** argv) printf("press any key to continue...\n"); fgetc(stdin); -} + return 0; +} \ No newline at end of file diff --git a/kernel_scout/user_mode/scout_user.h b/examples/kernel_scout/user_mode/scout_user.h similarity index 100% rename from kernel_scout/user_mode/scout_user.h rename to examples/kernel_scout/user_mode/scout_user.h diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..fc4119d --- /dev/null +++ b/setup.cfg @@ -0,0 +1,3 @@ +[flake8] +exclude = .git,__init__.py +ignore = E272, E501, E502, E221, E302, E241, E126, E127, E128, E266, E731, F405, F403 \ No newline at end of file diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..81a302d --- /dev/null +++ b/setup.py @@ -0,0 +1,26 @@ +#!/usr/bin/python + +from setuptools import setup, find_packages +from codecs import open + +with open("README.md", "r") as fh: + long_description = fh.read() + +setup(name='Scout', + version='2.0.0', + description='Instruction-based research debugger (a poor man\'s debugger)', + author='Eyal Itkin', + author_email='eyalit@checkpoint.com', + long_description=long_description, + long_description_content_type="text/markdown", + url='https://github.com/CheckPointSW/Scout', + license='MIT', + packages=find_packages(), + install_requires=['elementals'], + test_requires=['pydocstyle', 'flake8', 'click'], + classifiers=[ + "Programming Language :: Python :: 3", + "License :: OSI Approved :: MIT License (MIT License)", + "Operating System :: OS Independent", + ], + zip_safe=False) diff --git a/scout/arc/arm.c b/src/scout/arc/arm.c similarity index 100% rename from scout/arc/arm.c rename to src/scout/arc/arm.c diff --git a/scout/arc/arm.h b/src/scout/arc/arm.h similarity index 100% rename from scout/arc/arm.h rename to src/scout/arc/arm.h diff --git a/scout/arc/intel.c b/src/scout/arc/intel.c similarity index 95% rename from scout/arc/intel.c rename to src/scout/arc/intel.c index 7c2ec1f..67ece80 100644 --- a/scout/arc/intel.c +++ b/src/scout/arc/intel.c @@ -1,13 +1,13 @@ -#include "scout/arc/intel.h" - -#ifdef SCOUT_ARCH_INTEL - -void flush_cache(uint8_t * buffer, uint32_t size) -{ - (void)buffer; - (void)size; - - /* Intel has no caches that we need to flush :) */ -} - +#include "scout/arc/intel.h" + +#ifdef SCOUT_ARCH_INTEL + +void flush_cache(uint8_t * buffer, uint32_t size) +{ + (void)buffer; + (void)size; + + /* Intel has no caches that we need to flush :) */ +} + #endif /* SCOUT_ARCH_INTEL */ \ No newline at end of file diff --git a/scout/arc/intel.h b/src/scout/arc/intel.h similarity index 95% rename from scout/arc/intel.h rename to src/scout/arc/intel.h index 6436114..446651a 100644 --- a/scout/arc/intel.h +++ b/src/scout/arc/intel.h @@ -1,24 +1,24 @@ -#ifndef __SCOUT__ARC__INTEL__H__ -#define __SCOUT__ARC__INTEL__H__ - -#include "scout/scout.h" - -#ifdef SCOUT_ARCH_INTEL - -/*****************/ -/** Functions **/ -/*****************/ - -/** - * Flushes the caches (D-Cache and I-Cache) for the given buffer - * - * @author eyalit (01/04/2018) - * - * @param buffer - pointer to flushed buffer - * @param size - size in bytes of the given buffer - * - */ -void flush_cache(uint8_t * buffer, uint32_t size); - -#endif /* SCOUT_ARCH_INTEL */ +#ifndef __SCOUT__ARC__INTEL__H__ +#define __SCOUT__ARC__INTEL__H__ + +#include "scout/scout.h" + +#ifdef SCOUT_ARCH_INTEL + +/*****************/ +/** Functions **/ +/*****************/ + +/** + * Flushes the caches (D-Cache and I-Cache) for the given buffer + * + * @author eyalit (01/04/2018) + * + * @param buffer - pointer to flushed buffer + * @param size - size in bytes of the given buffer + * + */ +void flush_cache(uint8_t * buffer, uint32_t size); + +#endif /* SCOUT_ARCH_INTEL */ #endif /* __SCOUT__ARC__INTEL__H__ */ \ No newline at end of file diff --git a/scout/arc/mips.c b/src/scout/arc/mips.c similarity index 100% rename from scout/arc/mips.c rename to src/scout/arc/mips.c diff --git a/scout/arc/mips.h b/src/scout/arc/mips.h similarity index 100% rename from scout/arc/mips.h rename to src/scout/arc/mips.h diff --git a/scout/architecture.h b/src/scout/architecture.h similarity index 96% rename from scout/architecture.h rename to src/scout/architecture.h index cf489bf..1f069c9 100644 --- a/scout/architecture.h +++ b/src/scout/architecture.h @@ -1,133 +1,133 @@ -#ifndef __SCOUT__ARCHITECTURE__H__ -#define __SCOUT__ARCHITECTURE__H__ - -#include "flags.h" - -#if defined(SCOUT_MODE_KERNEL) && !defined(SCOUT_PIC_CODE) -#include -#else -#include -#endif /* SCOUT_MODE_KERNEL && !SCOUT_PIC_CODE */ - -/******************/ -/** Endianness **/ -/******************/ - -/* Sanity check */ -#if defined(SCOUT_BIG_ENDIAN) && defined(SCOUT_LITTLE_ENDIAN) - #error "Both big AND little endian are defined!" -#endif - -/* Default values */ -#if !defined(SCOUT_BIG_ENDIAN) && !defined(SCOUT_LITTLE_ENDIAN) - #define SCOUT_LITTLE_ENDIAN -#endif - -/***************/ -/** Bitness **/ -/***************/ - -/* Sanity check */ -#if defined(SCOUT_BITS_32) && defined(SCOUT_BITS_64) - #error "Both 32 AND 64 bits are defined!" -#endif - -/* Default values */ -#if !defined(SCOUT_BITS_32) && !defined(SCOUT_BITS_64) - #define SCOUT_BITS_32 -#endif - -#ifdef SCOUT_BITS_32 -typedef uint32_t addr_t; -#else -typedef uint64_t addr_t; -#endif /* SCOUT_BITS_32 */ - -/************************/ -/** CPU Architecture **/ -/************************/ - -/* Sanity check */ -#undef SCOUT_ARCH -#if defined(SCOUT_ARCH_INTEL) - #define SCOUT_ARCH -#endif -#if defined(SCOUT_ARCH_ARM) - #if defined(SCOUT_ARCH) - #error "Multiple CPU architecture are defined!" - #else - #define SCOUT_ARCH - #endif -#endif -#if defined(SCOUT_ARCH_MIPS) - #if defined(SCOUT_ARCH) - #error "Multiple CPU architecture are defined!" - #else - #define SCOUT_ARCH - #endif -#endif - -#if defined(SCOUT_ARM_THUMB) && !defined(SCOUT_ARCH_ARM) - #error "ARM Thumb-Mode must only be used when ARM CPU architecture is defined!" -#endif - -/* Default values */ -#if !defined(SCOUT_ARCH) - #define SCOUT_ARCH_INTEL -#endif - -/******************************/ -/** User Mode / Privileges **/ -/******************************/ - -/* Sanity check */ -#if defined(SCOUT_MODE_USER) && defined(SCOUT_MODE_KERNEL) - #error "Both user-mode AND kernel-mode are defined!" -#endif - -/* Default values */ -#if !defined(SCOUT_MODE_USER) && !defined(SCOUT_MODE_KERNEL) - #define SCOUT_MODE_USER -#endif - -/* Mainly used for readability */ -#if defined(SCOUT_MODE_KERNEL) - #define SCOUT_HIGH_PRIVILEGES -#endif - -/***************************************/ -/** Excutable / Injected (PIC) Code **/ -/***************************************/ - -/* Mainly used for readability */ -#if defined(SCOUT_PIC_CODE) - #define SCOUT_ISOLATED_ENV -#endif - -/*********************************************/ -/** LibC versions used by host executable **/ -/*********************************************/ - -#ifdef SCOUT_ISOLATED_ENV - -#if defined(SCOUT_HOST_GLIBC) && !defined(SCOUT_HOST_UCLIBC) - #error "The host process could only use one LibC implementation: glibc or uClibc!" -#endif - - -#if !defined(SCOUT_HOST_GLIBC) && !defined(SCOUT_HOST_UCLIBC) - #define SCOUT_HOST_GLIBC -#endif - -#endif /* SCOUT_ISOLATED_ENV */ - -/****************************************/ -/** Loader (Tight memory constraints **/ -/****************************************/ - -/* Mainly used for readability */ -#if defined(SCOUT_LOADER) && defined(SCOUT_PIC_CODE) - #define SCOUT_SLIM_SIZE -#endif - +#ifndef __SCOUT__ARCHITECTURE__H__ +#define __SCOUT__ARCHITECTURE__H__ + +#include "flags.h" + +#if defined(SCOUT_MODE_KERNEL) && !defined(SCOUT_PIC_CODE) +#include +#else +#include +#endif /* SCOUT_MODE_KERNEL && !SCOUT_PIC_CODE */ + +/******************/ +/** Endianness **/ +/******************/ + +/* Sanity check */ +#if defined(SCOUT_BIG_ENDIAN) && defined(SCOUT_LITTLE_ENDIAN) + #error "Both big AND little endian are defined!" +#endif + +/* Default values */ +#if !defined(SCOUT_BIG_ENDIAN) && !defined(SCOUT_LITTLE_ENDIAN) + #define SCOUT_LITTLE_ENDIAN +#endif + +/***************/ +/** Bitness **/ +/***************/ + +/* Sanity check */ +#if defined(SCOUT_BITS_32) && defined(SCOUT_BITS_64) + #error "Both 32 AND 64 bits are defined!" +#endif + +/* Default values */ +#if !defined(SCOUT_BITS_32) && !defined(SCOUT_BITS_64) + #define SCOUT_BITS_32 +#endif + +#ifdef SCOUT_BITS_32 +typedef uint32_t addr_t; +#else +typedef uint64_t addr_t; +#endif /* SCOUT_BITS_32 */ + +/************************/ +/** CPU Architecture **/ +/************************/ + +/* Sanity check */ +#undef SCOUT_ARCH +#if defined(SCOUT_ARCH_INTEL) + #define SCOUT_ARCH +#endif +#if defined(SCOUT_ARCH_ARM) + #if defined(SCOUT_ARCH) + #error "Multiple CPU architecture are defined!" + #else + #define SCOUT_ARCH + #endif +#endif +#if defined(SCOUT_ARCH_MIPS) + #if defined(SCOUT_ARCH) + #error "Multiple CPU architecture are defined!" + #else + #define SCOUT_ARCH + #endif +#endif + +#if defined(SCOUT_ARM_THUMB) && !defined(SCOUT_ARCH_ARM) + #error "ARM Thumb-Mode must only be used when ARM CPU architecture is defined!" +#endif + +/* Default values */ +#if !defined(SCOUT_ARCH) + #define SCOUT_ARCH_INTEL +#endif + +/******************************/ +/** User Mode / Privileges **/ +/******************************/ + +/* Sanity check */ +#if defined(SCOUT_MODE_USER) && defined(SCOUT_MODE_KERNEL) + #error "Both user-mode AND kernel-mode are defined!" +#endif + +/* Default values */ +#if !defined(SCOUT_MODE_USER) && !defined(SCOUT_MODE_KERNEL) + #define SCOUT_MODE_USER +#endif + +/* Mainly used for readability */ +#if defined(SCOUT_MODE_KERNEL) + #define SCOUT_HIGH_PRIVILEGES +#endif + +/***************************************/ +/** Excutable / Injected (PIC) Code **/ +/***************************************/ + +/* Mainly used for readability */ +#if defined(SCOUT_PIC_CODE) + #define SCOUT_ISOLATED_ENV +#endif + +/*********************************************/ +/** LibC versions used by host executable **/ +/*********************************************/ + +#ifdef SCOUT_ISOLATED_ENV + +#if defined(SCOUT_HOST_GLIBC) && !defined(SCOUT_HOST_UCLIBC) + #error "The host process could only use one LibC implementation: glibc or uClibc!" +#endif + + +#if !defined(SCOUT_HOST_GLIBC) && !defined(SCOUT_HOST_UCLIBC) + #define SCOUT_HOST_GLIBC +#endif + +#endif /* SCOUT_ISOLATED_ENV */ + +/****************************************/ +/** Loader (Tight memory constraints **/ +/****************************************/ + +/* Mainly used for readability */ +#if defined(SCOUT_LOADER) && defined(SCOUT_PIC_CODE) + #define SCOUT_SLIM_SIZE +#endif + #endif // __SCOUT__ARCHITECTURE__H__ \ No newline at end of file diff --git a/scout/errors.h b/src/scout/errors.h similarity index 96% rename from scout/errors.h rename to src/scout/errors.h index 92b9c6f..c71e789 100644 --- a/scout/errors.h +++ b/src/scout/errors.h @@ -1,22 +1,22 @@ -#ifndef __SCOUT__ERROR__H__ -#define __SCOUT__ERROR__H__ - -/* General Statuses */ -#define STATUS_OK 0 -#define STATUS_FAILURE 1 -#define STATUS_INVALID_ARGS 2 -#define STATUS_ALLOC_FAILED 3 -#define STATUS_TCP_SOCK_FAILED 4 -#define STATUS_TCP_BIND_FAILED 5 -#define STATUS_TCP_LISTEN_FAILED 6 -#define STATUS_TCP_ACCECPT_FAILED 7 -#define STATUS_TCP_CONNECT_FAILED 8 -#define STATUS_TCP_RECV_FAILED 9 -#define STATUS_TCP_SEND_FAILED 10 - -/* Scout API Statuses */ -#define STATUS_SMALL_HEADER 20 -#define STATUS_ILLEGAL_LENGTH 21 -#define STATUS_ILLEGAL_INSTR_ID 22 - -#endif /* __SCOUT__ERROR__H__ */ +#ifndef __SCOUT__ERROR__H__ +#define __SCOUT__ERROR__H__ + +/* General Statuses */ +#define STATUS_OK 0 +#define STATUS_FAILURE 1 +#define STATUS_INVALID_ARGS 2 +#define STATUS_ALLOC_FAILED 3 +#define STATUS_TCP_SOCK_FAILED 4 +#define STATUS_TCP_BIND_FAILED 5 +#define STATUS_TCP_LISTEN_FAILED 6 +#define STATUS_TCP_ACCECPT_FAILED 7 +#define STATUS_TCP_CONNECT_FAILED 8 +#define STATUS_TCP_RECV_FAILED 9 +#define STATUS_TCP_SEND_FAILED 10 + +/* Scout API Statuses */ +#define STATUS_SMALL_HEADER 20 +#define STATUS_ILLEGAL_LENGTH 21 +#define STATUS_ILLEGAL_INSTR_ID 22 + +#endif /* __SCOUT__ERROR__H__ */ diff --git a/scout/external_deps.h b/src/scout/external_deps.h similarity index 100% rename from scout/external_deps.h rename to src/scout/external_deps.h diff --git a/scout/loaders/loader.h b/src/scout/loaders/loader.h similarity index 100% rename from scout/loaders/loader.h rename to src/scout/loaders/loader.h diff --git a/scout/loaders/tcp_client_loader.c b/src/scout/loaders/tcp_client_loader.c similarity index 100% rename from scout/loaders/tcp_client_loader.c rename to src/scout/loaders/tcp_client_loader.c diff --git a/scout/loaders/tcp_client_loader.h b/src/scout/loaders/tcp_client_loader.h similarity index 100% rename from scout/loaders/tcp_client_loader.h rename to src/scout/loaders/tcp_client_loader.h diff --git a/scout/loaders/tcp_server_loader.c b/src/scout/loaders/tcp_server_loader.c similarity index 100% rename from scout/loaders/tcp_server_loader.c rename to src/scout/loaders/tcp_server_loader.c diff --git a/scout/loaders/tcp_server_loader.h b/src/scout/loaders/tcp_server_loader.h similarity index 100% rename from scout/loaders/tcp_server_loader.h rename to src/scout/loaders/tcp_server_loader.h diff --git a/scout/pack.c b/src/scout/pack.c similarity index 96% rename from scout/pack.c rename to src/scout/pack.c index e14a283..3b5e602 100644 --- a/scout/pack.c +++ b/src/scout/pack.c @@ -1,173 +1,173 @@ -#include "scout/pack.h" - -#ifndef SCOUT_SLIM_SIZE /* We are sometimes (loader) short in space */ - -void pack_uint8(uint8_t ** buffer, uint8_t value) -{ - uint8_t * writeHead = *buffer; - *writeHead++ = value; - *buffer = writeHead; -} - -void pack_uint16(uint8_t ** buffer, uint16_t value) -{ - uint8_t * writeHead = *buffer; - *writeHead++ = GET_BYTE(value, 1); - *writeHead++ = GET_BYTE(value, 0); - *buffer = writeHead; -} - -void pack_uint32(uint8_t ** buffer, uint32_t value) -{ - uint8_t * writeHead = *buffer; - *writeHead++ = GET_BYTE(value, 3); - *writeHead++ = GET_BYTE(value, 2); - *writeHead++ = GET_BYTE(value, 1); - *writeHead++ = GET_BYTE(value, 0); - *buffer = writeHead; -} - -void pack_uint64(uint8_t ** buffer, uint64_t value) -{ - uint8_t * writeHead = *buffer; - *writeHead++ = GET_BYTE(value, 7); - *writeHead++ = GET_BYTE(value, 6); - *writeHead++ = GET_BYTE(value, 5); - *writeHead++ = GET_BYTE(value, 4); - *writeHead++ = GET_BYTE(value, 3); - *writeHead++ = GET_BYTE(value, 2); - *writeHead++ = GET_BYTE(value, 1); - *writeHead++ = GET_BYTE(value, 0); - *buffer = writeHead; -} - -void pack_addr(uint8_t ** buffer, addr_t value) -{ -#ifdef SCOUT_BITS_32 - return pack_uint32( buffer, value ); -#else - return pack_uint64( buffer, value ); -#endif /* SCOUT_BITS_32 */ -} - -uint8_t unpack_uint8(uint8_t ** buffer) -{ - uint8_t value = **buffer; - *buffer += 1; - return value; -} - -uint16_t unpack_uint16(uint8_t ** buffer) -{ - uint16_t value = 0; - uint8_t * readHead = *buffer; - value |= SET_BYTE(*readHead++, 1); - value |= SET_BYTE(*readHead++, 0); - *buffer = readHead; - return value; -} - -uint32_t unpack_uint32(uint8_t ** buffer) -{ - uint32_t value = 0; - uint8_t * readHead = *buffer; - value |= SET_BYTE(*readHead++, 3); - value |= SET_BYTE(*readHead++, 2); - value |= SET_BYTE(*readHead++, 1); - value |= SET_BYTE(*readHead++, 0); - *buffer = readHead; - return value; -} - -uint64_t unpack_uint64(uint8_t ** buffer) -{ - uint64_t value = 0; - uint8_t * readHead = *buffer; - value |= SET_BYTE((uint64_t)*readHead++, 7); - value |= SET_BYTE((uint64_t)*readHead++, 6); - value |= SET_BYTE((uint64_t)*readHead++, 5); - value |= SET_BYTE((uint64_t)*readHead++, 4); - value |= SET_BYTE((uint64_t)*readHead++, 3); - value |= SET_BYTE((uint64_t)*readHead++, 2); - value |= SET_BYTE((uint64_t)*readHead++, 1); - value |= SET_BYTE((uint64_t)*readHead++, 0); - *buffer = readHead; - return value; -} - -addr_t unpack_addr(uint8_t ** buffer) -{ -#ifdef SCOUT_BITS_32 - return unpack_uint32( buffer ); -#else - return unpack_uint64( buffer ); -#endif /* SCOUT_BITS_32 */ -} - -#endif /* !SCOUT_SLIM_SIZE */ - -#ifdef SCOUT_ISOLATED_ENV - -uint16_t htons(uint16_t value) -{ -#ifdef SCOUT_LITTLE_ENDIAN - value = SET_BYTE(GET_BYTE(value, 0), 1) | - SET_BYTE(GET_BYTE(value, 1), 0); -#endif /* SCOUT_LITTLE_ENDIAN */ - return value; -} - -uint32_t htonl(uint32_t value) -{ -#ifdef SCOUT_LITTLE_ENDIAN - value = SET_BYTE(GET_BYTE(value, 0), 3) | - SET_BYTE(GET_BYTE(value, 1), 2) | - SET_BYTE(GET_BYTE(value, 2), 1) | - SET_BYTE(GET_BYTE(value, 3), 0); -#endif /* SCOUT_LITTLE_ENDIAN */ - return value; -} - -uint64_t htonq(uint64_t value) -{ -#ifdef SCOUT_LITTLE_ENDIAN - value = SET_BYTE((uint64_t)GET_BYTE(value, 0), 7) | - SET_BYTE((uint64_t)GET_BYTE(value, 1), 6) | - SET_BYTE((uint64_t)GET_BYTE(value, 2), 5) | - SET_BYTE((uint64_t)GET_BYTE(value, 3), 4) | - SET_BYTE((uint64_t)GET_BYTE(value, 4), 3) | - SET_BYTE((uint64_t)GET_BYTE(value, 5), 2) | - SET_BYTE((uint64_t)GET_BYTE(value, 6), 1) | - SET_BYTE((uint64_t)GET_BYTE(value, 7), 0); -#endif /* SCOUT_LITTLE_ENDIAN */ - return value; -} - -uint16_t ntohs(uint16_t value) -{ -#ifdef SCOUT_LITTLE_ENDIAN - return htons( value ); -#else - return value; -#endif /* SCOUT_LITTLE_ENDIAN */ -} - -uint32_t ntohl(uint32_t value) -{ -#ifdef SCOUT_LITTLE_ENDIAN - return htonl( value ); -#else - return value; -#endif /* SCOUT_LITTLE_ENDIAN */ -} - -uint64_t ntohq(uint64_t value) -{ -#ifdef SCOUT_LITTLE_ENDIAN - return htonq( value ); -#else - return value; -#endif /* SCOUT_LITTLE_ENDIAN */ -} - +#include "scout/pack.h" + +#ifndef SCOUT_SLIM_SIZE /* We are sometimes (loader) short in space */ + +void pack_uint8(uint8_t ** buffer, uint8_t value) +{ + uint8_t * writeHead = *buffer; + *writeHead++ = value; + *buffer = writeHead; +} + +void pack_uint16(uint8_t ** buffer, uint16_t value) +{ + uint8_t * writeHead = *buffer; + *writeHead++ = GET_BYTE(value, 1); + *writeHead++ = GET_BYTE(value, 0); + *buffer = writeHead; +} + +void pack_uint32(uint8_t ** buffer, uint32_t value) +{ + uint8_t * writeHead = *buffer; + *writeHead++ = GET_BYTE(value, 3); + *writeHead++ = GET_BYTE(value, 2); + *writeHead++ = GET_BYTE(value, 1); + *writeHead++ = GET_BYTE(value, 0); + *buffer = writeHead; +} + +void pack_uint64(uint8_t ** buffer, uint64_t value) +{ + uint8_t * writeHead = *buffer; + *writeHead++ = GET_BYTE(value, 7); + *writeHead++ = GET_BYTE(value, 6); + *writeHead++ = GET_BYTE(value, 5); + *writeHead++ = GET_BYTE(value, 4); + *writeHead++ = GET_BYTE(value, 3); + *writeHead++ = GET_BYTE(value, 2); + *writeHead++ = GET_BYTE(value, 1); + *writeHead++ = GET_BYTE(value, 0); + *buffer = writeHead; +} + +void pack_addr(uint8_t ** buffer, addr_t value) +{ +#ifdef SCOUT_BITS_32 + return pack_uint32( buffer, value ); +#else + return pack_uint64( buffer, value ); +#endif /* SCOUT_BITS_32 */ +} + +uint8_t unpack_uint8(uint8_t ** buffer) +{ + uint8_t value = **buffer; + *buffer += 1; + return value; +} + +uint16_t unpack_uint16(uint8_t ** buffer) +{ + uint16_t value = 0; + uint8_t * readHead = *buffer; + value |= SET_BYTE(*readHead++, 1); + value |= SET_BYTE(*readHead++, 0); + *buffer = readHead; + return value; +} + +uint32_t unpack_uint32(uint8_t ** buffer) +{ + uint32_t value = 0; + uint8_t * readHead = *buffer; + value |= SET_BYTE(*readHead++, 3); + value |= SET_BYTE(*readHead++, 2); + value |= SET_BYTE(*readHead++, 1); + value |= SET_BYTE(*readHead++, 0); + *buffer = readHead; + return value; +} + +uint64_t unpack_uint64(uint8_t ** buffer) +{ + uint64_t value = 0; + uint8_t * readHead = *buffer; + value |= SET_BYTE((uint64_t)*readHead++, 7); + value |= SET_BYTE((uint64_t)*readHead++, 6); + value |= SET_BYTE((uint64_t)*readHead++, 5); + value |= SET_BYTE((uint64_t)*readHead++, 4); + value |= SET_BYTE((uint64_t)*readHead++, 3); + value |= SET_BYTE((uint64_t)*readHead++, 2); + value |= SET_BYTE((uint64_t)*readHead++, 1); + value |= SET_BYTE((uint64_t)*readHead++, 0); + *buffer = readHead; + return value; +} + +addr_t unpack_addr(uint8_t ** buffer) +{ +#ifdef SCOUT_BITS_32 + return unpack_uint32( buffer ); +#else + return unpack_uint64( buffer ); +#endif /* SCOUT_BITS_32 */ +} + +#endif /* !SCOUT_SLIM_SIZE */ + +#ifdef SCOUT_ISOLATED_ENV + +uint16_t htons(uint16_t value) +{ +#ifdef SCOUT_LITTLE_ENDIAN + value = SET_BYTE(GET_BYTE(value, 0), 1) | + SET_BYTE(GET_BYTE(value, 1), 0); +#endif /* SCOUT_LITTLE_ENDIAN */ + return value; +} + +uint32_t htonl(uint32_t value) +{ +#ifdef SCOUT_LITTLE_ENDIAN + value = SET_BYTE(GET_BYTE(value, 0), 3) | + SET_BYTE(GET_BYTE(value, 1), 2) | + SET_BYTE(GET_BYTE(value, 2), 1) | + SET_BYTE(GET_BYTE(value, 3), 0); +#endif /* SCOUT_LITTLE_ENDIAN */ + return value; +} + +uint64_t htonq(uint64_t value) +{ +#ifdef SCOUT_LITTLE_ENDIAN + value = SET_BYTE((uint64_t)GET_BYTE(value, 0), 7) | + SET_BYTE((uint64_t)GET_BYTE(value, 1), 6) | + SET_BYTE((uint64_t)GET_BYTE(value, 2), 5) | + SET_BYTE((uint64_t)GET_BYTE(value, 3), 4) | + SET_BYTE((uint64_t)GET_BYTE(value, 4), 3) | + SET_BYTE((uint64_t)GET_BYTE(value, 5), 2) | + SET_BYTE((uint64_t)GET_BYTE(value, 6), 1) | + SET_BYTE((uint64_t)GET_BYTE(value, 7), 0); +#endif /* SCOUT_LITTLE_ENDIAN */ + return value; +} + +uint16_t ntohs(uint16_t value) +{ +#ifdef SCOUT_LITTLE_ENDIAN + return htons( value ); +#else + return value; +#endif /* SCOUT_LITTLE_ENDIAN */ +} + +uint32_t ntohl(uint32_t value) +{ +#ifdef SCOUT_LITTLE_ENDIAN + return htonl( value ); +#else + return value; +#endif /* SCOUT_LITTLE_ENDIAN */ +} + +uint64_t ntohq(uint64_t value) +{ +#ifdef SCOUT_LITTLE_ENDIAN + return htonq( value ); +#else + return value; +#endif /* SCOUT_LITTLE_ENDIAN */ +} + #endif /* SCOUT_ISOLATED_ENV */ \ No newline at end of file diff --git a/scout/pack.h b/src/scout/pack.h similarity index 100% rename from scout/pack.h rename to src/scout/pack.h diff --git a/scout/pic/arm_pic_wrapper.c b/src/scout/pic/arm_pic_wrapper.c similarity index 100% rename from scout/pic/arm_pic_wrapper.c rename to src/scout/pic/arm_pic_wrapper.c diff --git a/scout/pic/intel_pic_wrapper.c b/src/scout/pic/intel_pic_wrapper.c similarity index 100% rename from scout/pic/intel_pic_wrapper.c rename to src/scout/pic/intel_pic_wrapper.c diff --git a/scout/pic/mips_pic_wrapper.c b/src/scout/pic/mips_pic_wrapper.c similarity index 100% rename from scout/pic/mips_pic_wrapper.c rename to src/scout/pic/mips_pic_wrapper.c diff --git a/scout/pic/pic_wrapper.h b/src/scout/pic/pic_wrapper.h similarity index 100% rename from scout/pic/pic_wrapper.h rename to src/scout/pic/pic_wrapper.h diff --git a/scout/pic/scout_globals.c b/src/scout/pic/scout_globals.c similarity index 100% rename from scout/pic/scout_globals.c rename to src/scout/pic/scout_globals.c diff --git a/scout/pic/scout_globals.h b/src/scout/pic/scout_globals.h similarity index 100% rename from scout/pic/scout_globals.h rename to src/scout/pic/scout_globals.h diff --git a/scout/pic/scout_plt.c b/src/scout/pic/scout_plt.c similarity index 100% rename from scout/pic/scout_plt.c rename to src/scout/pic/scout_plt.c diff --git a/scout/pic/scout_plt.h b/src/scout/pic/scout_plt.h similarity index 100% rename from scout/pic/scout_plt.h rename to src/scout/pic/scout_plt.h diff --git a/scout/scout.h b/src/scout/scout.h similarity index 96% rename from scout/scout.h rename to src/scout/scout.h index 913681e..6d1a839 100644 --- a/scout/scout.h +++ b/src/scout/scout.h @@ -1,29 +1,29 @@ -#ifndef __SCOUT__H__ -#define __SCOUT__H__ - -#include "flags.h" /* Project defined, must come first */ -#include "scout/architecture.h" /* Important architecture defines */ -#include "scout/errors.h" /* Error statuses */ - -#ifdef SCOUT_PIC_CODE -#include "scout/pic/pic_wrapper.h" -#else -#define GLOBAL(_V_) g##_V_ -#endif /* SCOUT_PIC_CODE */ - -#ifdef SCOUT_ISOLATED_ENV - -#include "scout/external_deps.h" /* All external dependencies that should be found in libraries on a PC */ - -#else /* !SCOUT_ISOLATED_ENV */ - -#ifdef SCOUT_USER_MODE -#include -#include -#else -#include -#endif /* SCOUT_USER_MODE */ - -#endif /* SCOUT_ISOLATED_ENV */ - +#ifndef __SCOUT__H__ +#define __SCOUT__H__ + +#include "flags.h" /* Project defined, must come first */ +#include "scout/architecture.h" /* Important architecture defines */ +#include "scout/errors.h" /* Error statuses */ + +#ifdef SCOUT_PIC_CODE +#include "scout/pic/pic_wrapper.h" +#else +#define GLOBAL(_V_) g##_V_ +#endif /* SCOUT_PIC_CODE */ + +#ifdef SCOUT_ISOLATED_ENV + +#include "scout/external_deps.h" /* All external dependencies that should be found in libraries on a PC */ + +#else /* !SCOUT_ISOLATED_ENV */ + +#ifdef SCOUT_USER_MODE +#include +#include +#else +#include +#endif /* SCOUT_USER_MODE */ + +#endif /* SCOUT_ISOLATED_ENV */ + #endif // __SCOUT__H__ \ No newline at end of file diff --git a/scout/scout_api.c b/src/scout/scout_api.c similarity index 96% rename from scout/scout_api.c rename to src/scout/scout_api.c index 5ab1181..004aee1 100644 --- a/scout/scout_api.c +++ b/src/scout/scout_api.c @@ -1,169 +1,169 @@ -#include "scout/scout_api.h" -#include "scout/pack.h" -#include "scout/pic/pic_wrapper.h" - -#ifdef SCOUT_INSTRUCTIONS - -/* Global Variables */ - -#ifndef SCOUT_PIC_CODE -static uint16_t gNumInstructions = 0; -static uint16_t * gpNumInstructions = &gNumInstructions; -static scout_instruction_t gInstructions[SCOUT_MAX_INSTRS] = {0}; -#endif /* !SCOUT_PIC_CODE */ - -int32_t parse_header(uint8_t * buffer, uint32_t length, scout_header_t * header, bool validateLen) -{ - uint8_t * readHead; - - /* Sanity Check #1 - buffer is not NULL */ - if (buffer == NULL) - { - return STATUS_INVALID_ARGS; - } - - /* Sanity Check #2 - length is big enough */ - if (length < SCOUT_HEADER_SIZE) - { - return STATUS_SMALL_HEADER; - } - - /* Now parse the fields from the raw header */ - readHead = buffer; - header->instrID = unpack_uint16(&readHead); - header->length = unpack_uint32(&readHead); - - /* Validate the length */ - if (validateLen && header->length != length - SCOUT_HEADER_SIZE) - { - return STATUS_ILLEGAL_LENGTH; - } - - /* All was OK */ - return STATUS_OK; -} - -#ifndef SCOUT_PROXY -int32_t handle_instruction(void * ctx, scout_header_t * header, uint8_t * buffer) -{ - uint16_t index = 0; - int32_t status = STATUS_ILLEGAL_INSTR_ID; - - /* Find and verify the given instruction */ - for (index = 0; index < get_instruction_count() ; index++ ) - { - scout_instruction_t *instr = get_instruction(index); - if (instr->instrID != header->instrID) - { - continue; - } - - /* Found our instruction - now verify it */ - if (header->length < instr->minLength || - instr->maxLength < header->length) - { - status = STATUS_ILLEGAL_LENGTH; - break; - } - - /* Can now handle the instruction */ - status = INVOKE_HANDLER(instr, ctx, buffer, header->length); - break; - } - - mark_status(ctx, status); - return status; -} -#endif /* SCOUT_PROXY */ - -uint16_t get_instruction_count(void) -{ - return (uint16_t)*GLOBAL(pNumInstructions); -} - -scout_instruction_t * get_instruction(uint16_t index) -{ - /* Sanity check #1 - index must be legal */ - if (index >= get_instruction_count()) - { - return NULL; - } - return &GLOBAL(Instructions)[index]; -} - -void register_instruction(uint16_t instrID, uint32_t minLength, uint32_t maxLength, instrHandler handler) -{ - /* Sanity check #1 - array must not be full */ - if (get_instruction_count() >= SCOUT_MAX_INSTRS) - { - return; - } - - /* Fill up the struct */ - GLOBAL(Instructions)[get_instruction_count()].instrID = instrID; - GLOBAL(Instructions)[get_instruction_count()].minLength = minLength; - GLOBAL(Instructions)[get_instruction_count()].maxLength = maxLength; - GLOBAL(Instructions)[get_instruction_count()].handler = handler; - /* Advance the counter */ - *GLOBAL(pNumInstructions) += 1; -} - -void register_basic_instructions(void) -{ -#ifdef SCOUT_PIC_CODE - /* Prepare the globals (won't be set without an executable's loader) */ - *GLOBAL(pNumInstructions) = 0; - memset(GLOBAL(Instructions), 0, SCOUT_MAX_INSTRS * sizeof(scout_instruction_t)); -#endif /* SCOUT_PIC_CODE */ - - /* Can now quietly register the basic instructions */ - register_instruction(SCOUT_INST_NOP, INSTR_NOP_MIN_SIZE, INSTR_NOP_MAX_SIZE, INSTR_NOP_HANDLER); - register_instruction(SCOUT_INST_MEM_READ, INSTR_MEM_READ_MIN_SIZE, INSTR_MEM_READ_MAX_SIZE, INSTR_MEM_READ_HANDLER); - register_instruction(SCOUT_INST_MEM_WRITE, INSTR_MEM_WRITE_MIN_SIZE, INSTR_MEM_WRITE_MAX_SIZE, INSTR_MEM_WRITE_HANDLER); -} - -void register_all_instructions(void) -{ - /* First, register the basic instructions */ - register_basic_instructions(); - /* Now, register the specific instructions */ - register_specific_instructions(); -} - -int32_t instruction_nop(void * ctx, uint8_t * instruction, uint32_t length) -{ - (void)ctx; - (void)instruction; - (void)length; - return STATUS_OK; -} - -int32_t instruction_mem_read(void * ctx, uint8_t * instruction, uint32_t length) -{ - addr_t src; - uint8_t * readHead = instruction; - - src = unpack_addr( &readHead ); - length = unpack_uint32( &readHead ); - - write_output(ctx, (uint8_t *)src, length); - return STATUS_OK; -} - -int32_t instruction_mem_write(void * ctx, uint8_t * instruction, uint32_t length) -{ - addr_t dst; - uint8_t * readHead = instruction; - - (void)ctx; - - dst = unpack_addr( &readHead ); - length = length - sizeof(dst); - - /* Preform the write */ - memcpy((void *)dst, (void *)readHead, length); - - return STATUS_OK; -} - +#include "scout/scout_api.h" +#include "scout/pack.h" +#include "scout/pic/pic_wrapper.h" + +#ifdef SCOUT_INSTRUCTIONS + +/* Global Variables */ + +#ifndef SCOUT_PIC_CODE +static uint16_t gNumInstructions = 0; +static uint16_t * gpNumInstructions = &gNumInstructions; +static scout_instruction_t gInstructions[SCOUT_MAX_INSTRS] = {0}; +#endif /* !SCOUT_PIC_CODE */ + +int32_t parse_header(uint8_t * buffer, uint32_t length, scout_header_t * header, bool validateLen) +{ + uint8_t * readHead; + + /* Sanity Check #1 - buffer is not NULL */ + if (buffer == NULL) + { + return STATUS_INVALID_ARGS; + } + + /* Sanity Check #2 - length is big enough */ + if (length < SCOUT_HEADER_SIZE) + { + return STATUS_SMALL_HEADER; + } + + /* Now parse the fields from the raw header */ + readHead = buffer; + header->instrID = unpack_uint16(&readHead); + header->length = unpack_uint32(&readHead); + + /* Validate the length */ + if (validateLen && header->length != length - SCOUT_HEADER_SIZE) + { + return STATUS_ILLEGAL_LENGTH; + } + + /* All was OK */ + return STATUS_OK; +} + +#ifndef SCOUT_PROXY +int32_t handle_instruction(void * ctx, scout_header_t * header, uint8_t * buffer) +{ + uint16_t index = 0; + int32_t status = STATUS_ILLEGAL_INSTR_ID; + + /* Find and verify the given instruction */ + for (index = 0; index < get_instruction_count() ; index++ ) + { + scout_instruction_t *instr = get_instruction(index); + if (instr->instrID != header->instrID) + { + continue; + } + + /* Found our instruction - now verify it */ + if (header->length < instr->minLength || + instr->maxLength < header->length) + { + status = STATUS_ILLEGAL_LENGTH; + break; + } + + /* Can now handle the instruction */ + status = INVOKE_HANDLER(instr, ctx, buffer, header->length); + break; + } + + mark_status(ctx, status); + return status; +} +#endif /* SCOUT_PROXY */ + +uint16_t get_instruction_count(void) +{ + return (uint16_t)*GLOBAL(pNumInstructions); +} + +scout_instruction_t * get_instruction(uint16_t index) +{ + /* Sanity check #1 - index must be legal */ + if (index >= get_instruction_count()) + { + return NULL; + } + return &GLOBAL(Instructions)[index]; +} + +void register_instruction(uint16_t instrID, uint32_t minLength, uint32_t maxLength, instrHandler handler) +{ + /* Sanity check #1 - array must not be full */ + if (get_instruction_count() >= SCOUT_MAX_INSTRS) + { + return; + } + + /* Fill up the struct */ + GLOBAL(Instructions)[get_instruction_count()].instrID = instrID; + GLOBAL(Instructions)[get_instruction_count()].minLength = minLength; + GLOBAL(Instructions)[get_instruction_count()].maxLength = maxLength; + GLOBAL(Instructions)[get_instruction_count()].handler = handler; + /* Advance the counter */ + *GLOBAL(pNumInstructions) += 1; +} + +void register_basic_instructions(void) +{ +#ifdef SCOUT_PIC_CODE + /* Prepare the globals (won't be set without an executable's loader) */ + *GLOBAL(pNumInstructions) = 0; + memset(GLOBAL(Instructions), 0, SCOUT_MAX_INSTRS * sizeof(scout_instruction_t)); +#endif /* SCOUT_PIC_CODE */ + + /* Can now quietly register the basic instructions */ + register_instruction(SCOUT_INST_NOP, INSTR_NOP_MIN_SIZE, INSTR_NOP_MAX_SIZE, INSTR_NOP_HANDLER); + register_instruction(SCOUT_INST_MEM_READ, INSTR_MEM_READ_MIN_SIZE, INSTR_MEM_READ_MAX_SIZE, INSTR_MEM_READ_HANDLER); + register_instruction(SCOUT_INST_MEM_WRITE, INSTR_MEM_WRITE_MIN_SIZE, INSTR_MEM_WRITE_MAX_SIZE, INSTR_MEM_WRITE_HANDLER); +} + +void register_all_instructions(void) +{ + /* First, register the basic instructions */ + register_basic_instructions(); + /* Now, register the specific instructions */ + register_specific_instructions(); +} + +int32_t instruction_nop(void * ctx, uint8_t * instruction, uint32_t length) +{ + (void)ctx; + (void)instruction; + (void)length; + return STATUS_OK; +} + +int32_t instruction_mem_read(void * ctx, uint8_t * instruction, uint32_t length) +{ + addr_t src; + uint8_t * readHead = instruction; + + src = unpack_addr( &readHead ); + length = unpack_uint32( &readHead ); + + write_output(ctx, (uint8_t *)src, length); + return STATUS_OK; +} + +int32_t instruction_mem_write(void * ctx, uint8_t * instruction, uint32_t length) +{ + addr_t dst; + uint8_t * readHead = instruction; + + (void)ctx; + + dst = unpack_addr( &readHead ); + length = length - sizeof(dst); + + /* Preform the write */ + memcpy((void *)dst, (void *)readHead, length); + + return STATUS_OK; +} + #endif /* SCOUT_INSTRUCTIONS */ \ No newline at end of file diff --git a/scout/scout_api.h b/src/scout/scout_api.h similarity index 96% rename from scout/scout_api.h rename to src/scout/scout_api.h index d9619c7..f45b919 100644 --- a/scout/scout_api.h +++ b/src/scout/scout_api.h @@ -1,231 +1,231 @@ -#ifndef __SCOUT__API__H__ -#define __SCOUT__API__H__ - -#include "scout/architecture.h" // There is a dependency issue in PIC mode, so we can't include "scout.h" yet -#include - -#ifdef SCOUT_INSTRUCTIONS - -/*****************************/ -/** API defined functions **/ -/*****************************/ - -/** - * Appends the given data to the output (data) stream - * - * @author eyalit (07/03/2018) - * - * @param ctx - general context - * @param buffer - data to be appended to the output - * @param length - number of bytes in the data buffer - */ -void write_output(void * ctx, uint8_t * buffer, uint32_t length); - -/** - * Marks the success status of the command and writes it to the - * (control) stream - * - * @author eyalit (07/03/2018) - * - * @param ctx - general context - * @param status - command success status - */ -void mark_status(void * ctx, int32_t status); - -/***************/ -/** Structs **/ -/***************/ - -typedef struct __scout_header -{ - uint16_t instrID; - uint32_t length; -} scout_header_t; - -typedef int32_t (*instrHandler)(void * ctx, uint8_t * instruction, uint32_t length); - -typedef struct __scout_instruction -{ - uint16_t instrID; - uint32_t minLength; - uint32_t maxLength; - instrHandler handler; -} scout_instruction_t; - -/***************/ -/** Defines **/ -/***************/ - -#define SCOUT_HEADER_SIZE (sizeof(uint16_t) + sizeof(uint32_t)) -#define SCOUT_MAX_INSTRS (10) - -#ifdef SCOUT_PIC_CODE -#define GET_HANDLER(_X_) ((instrHandler)get_live_address((_X_)->handler)) -#else -#define GET_HANDLER(_X_) ((_X_)->handler) -#endif /* SCOUT_PIC_CODE */ - -#define INVOKE_HANDLER(_X_, _C_, _B_, _L_) GET_HANDLER(_X_)(_C_, _B_, _L_) - -#include "scout/scout.h" // Now we can safely include this file, even in PIC mode - -/******************************/ -/** Instruction Processing **/ -/******************************/ - -/** - * Parses the command's header from the raw buffer - * - * @author eyalit (07/03/2018) - * - * @param buffer - raw command buffer - * @param length - length in bytes of the raw command buffer - * @param header - commadn header struct to be initialized - * - * @return int32_t - success status - */ -int32_t parse_header(uint8_t * buffer, uint32_t length, scout_header_t * header, bool validateLen); - -/** - * Verifies and Handles the given instruction (could be a proxy) - * - * @author eyalit (07/03/2018) - * - * @param ctx - general context - * @param header - scout header as extracted from the buffer - * @param buffer - instruction raw buffer - * - * @return int32_t - success status - */ -int32_t handle_instruction(void * ctx, scout_header_t * header, uint8_t * buffer); - -/********************************/ -/** Instruction Registration **/ -/********************************/ - -/** - * Retrieves the number of registerred instructions - * - * @author eyalit (07/03/2018) - * - * @return uint16_t - number of registerred instruction - */ -uint16_t get_instruction_count(void); - -/** - * Retrieves the instruction at the given index - * - * @author eyalit (07/03/2018) - * - * @param index - index of the wanted instruction - * - * @return scout_instruction_t * - pointer to the wanted - * instruction (NULL in case of error) - */ -scout_instruction_t * get_instruction(uint16_t index); - -/** - * Registers the given instructions. - * Assumption: - * The operation will silently fail if the maximum number of - * instructions was already reached. - * - * @author eyalit (07/03/2018) - * - * @param instrID - instruction ID - * @param minLength - minimal instruction input length - * @param maxLength - maximal instruction input length - * @param handler - handler for the instruction - */ -void register_instruction(uint16_t instrID, uint32_t minLength, uint32_t maxLength, instrHandler handler); - -/** - * Registers all of the basic instructions - * - * @author eyalit (07/03/2018) - */ -void register_basic_instructions(void); - -/** - * Registers the project specific instructions. - * NOTE: - * Should be implemented by the project - * - * @author eyalit (06/05/2018) - */ -void register_specific_instructions(void); - -/** - * Registers all of the instructions - * - * @author eyalit (06/05/2018) - */ -void register_all_instructions(void); - -/**************************/ -/** Basic Instructions **/ -/**************************/ - -#define SCOUT_INST_NOP 0 -#define SCOUT_INST_MEM_READ 1 -#define SCOUT_INST_MEM_WRITE 2 - -#define SCOUT_MAX_BASIC_INSTR SCOUT_INST_MEM_WRITE - -/** - * The NOP instruction - does nothing, returns OK. - * - * @author eyalit (07/03/2018) - * - * @param ctx - general context - * @param instruction - raw instruction buffer - * @param length - number of bytes in the instruction buffer - * - * @return int32_t - success status - */ -int32_t instruction_nop(void * ctx, uint8_t * instruction, uint32_t length); - -/** - * Reads basic memory (usually virtual RAM memory) and writes it - * to the output. - * - * @author eyalit (07/03/2018) - * - * @param ctx - general context - * @param instruction - raw instruction buffer - * @param length - number of bytes in the instruction buffer - * - * @return int32_t - success status - */ -int32_t instruction_mem_read(void * ctx, uint8_t * instruction, uint32_t length); - -/** - * Basic memory update (usually virtual RAM memory) with given - * input. - * - * @author eyalit (07/03/2018) - * - * @param ctx - general context - * @param instruction - raw instruction buffer - * @param length - number of bytes in the instruction buffer - * - * @return int32_t - success status - */ -int32_t instruction_mem_write(void * ctx, uint8_t * instruction, uint32_t length); - -/* The instruction records */ -#define INSTR_NOP_MIN_SIZE 0 -#define INSTR_NOP_MAX_SIZE 0 -#define INSTR_NOP_HANDLER instruction_nop - -#define INSTR_MEM_READ_MIN_SIZE (sizeof(addr_t) + sizeof(uint32_t)) -#define INSTR_MEM_READ_MAX_SIZE (sizeof(addr_t) + sizeof(uint32_t)) -#define INSTR_MEM_READ_HANDLER instruction_mem_read - -#define INSTR_MEM_WRITE_MIN_SIZE (sizeof(addr_t)) -#define INSTR_MEM_WRITE_MAX_SIZE (sizeof(addr_t) + 256) -#define INSTR_MEM_WRITE_HANDLER instruction_mem_write - -#endif /* SCOUT_INSTRUCTIONS */ - +#ifndef __SCOUT__API__H__ +#define __SCOUT__API__H__ + +#include "scout/architecture.h" // There is a dependency issue in PIC mode, so we can't include "scout.h" yet +#include + +#ifdef SCOUT_INSTRUCTIONS + +/*****************************/ +/** API defined functions **/ +/*****************************/ + +/** + * Appends the given data to the output (data) stream + * + * @author eyalit (07/03/2018) + * + * @param ctx - general context + * @param buffer - data to be appended to the output + * @param length - number of bytes in the data buffer + */ +void write_output(void * ctx, uint8_t * buffer, uint32_t length); + +/** + * Marks the success status of the command and writes it to the + * (control) stream + * + * @author eyalit (07/03/2018) + * + * @param ctx - general context + * @param status - command success status + */ +void mark_status(void * ctx, int32_t status); + +/***************/ +/** Structs **/ +/***************/ + +typedef struct __scout_header +{ + uint16_t instrID; + uint32_t length; +} scout_header_t; + +typedef int32_t (*instrHandler)(void * ctx, uint8_t * instruction, uint32_t length); + +typedef struct __scout_instruction +{ + uint16_t instrID; + uint32_t minLength; + uint32_t maxLength; + instrHandler handler; +} scout_instruction_t; + +/***************/ +/** Defines **/ +/***************/ + +#define SCOUT_HEADER_SIZE (sizeof(uint16_t) + sizeof(uint32_t)) +#define SCOUT_MAX_INSTRS (10) + +#ifdef SCOUT_PIC_CODE +#define GET_HANDLER(_X_) ((instrHandler)get_live_address((_X_)->handler)) +#else +#define GET_HANDLER(_X_) ((_X_)->handler) +#endif /* SCOUT_PIC_CODE */ + +#define INVOKE_HANDLER(_X_, _C_, _B_, _L_) GET_HANDLER(_X_)(_C_, _B_, _L_) + +#include "scout/scout.h" // Now we can safely include this file, even in PIC mode + +/******************************/ +/** Instruction Processing **/ +/******************************/ + +/** + * Parses the command's header from the raw buffer + * + * @author eyalit (07/03/2018) + * + * @param buffer - raw command buffer + * @param length - length in bytes of the raw command buffer + * @param header - commadn header struct to be initialized + * + * @return int32_t - success status + */ +int32_t parse_header(uint8_t * buffer, uint32_t length, scout_header_t * header, bool validateLen); + +/** + * Verifies and Handles the given instruction (could be a proxy) + * + * @author eyalit (07/03/2018) + * + * @param ctx - general context + * @param header - scout header as extracted from the buffer + * @param buffer - instruction raw buffer + * + * @return int32_t - success status + */ +int32_t handle_instruction(void * ctx, scout_header_t * header, uint8_t * buffer); + +/********************************/ +/** Instruction Registration **/ +/********************************/ + +/** + * Retrieves the number of registerred instructions + * + * @author eyalit (07/03/2018) + * + * @return uint16_t - number of registerred instruction + */ +uint16_t get_instruction_count(void); + +/** + * Retrieves the instruction at the given index + * + * @author eyalit (07/03/2018) + * + * @param index - index of the wanted instruction + * + * @return scout_instruction_t * - pointer to the wanted + * instruction (NULL in case of error) + */ +scout_instruction_t * get_instruction(uint16_t index); + +/** + * Registers the given instructions. + * Assumption: + * The operation will silently fail if the maximum number of + * instructions was already reached. + * + * @author eyalit (07/03/2018) + * + * @param instrID - instruction ID + * @param minLength - minimal instruction input length + * @param maxLength - maximal instruction input length + * @param handler - handler for the instruction + */ +void register_instruction(uint16_t instrID, uint32_t minLength, uint32_t maxLength, instrHandler handler); + +/** + * Registers all of the basic instructions + * + * @author eyalit (07/03/2018) + */ +void register_basic_instructions(void); + +/** + * Registers the project specific instructions. + * NOTE: + * Should be implemented by the project + * + * @author eyalit (06/05/2018) + */ +void register_specific_instructions(void); + +/** + * Registers all of the instructions + * + * @author eyalit (06/05/2018) + */ +void register_all_instructions(void); + +/**************************/ +/** Basic Instructions **/ +/**************************/ + +#define SCOUT_INST_NOP 0 +#define SCOUT_INST_MEM_READ 1 +#define SCOUT_INST_MEM_WRITE 2 + +#define SCOUT_MAX_BASIC_INSTR SCOUT_INST_MEM_WRITE + +/** + * The NOP instruction - does nothing, returns OK. + * + * @author eyalit (07/03/2018) + * + * @param ctx - general context + * @param instruction - raw instruction buffer + * @param length - number of bytes in the instruction buffer + * + * @return int32_t - success status + */ +int32_t instruction_nop(void * ctx, uint8_t * instruction, uint32_t length); + +/** + * Reads basic memory (usually virtual RAM memory) and writes it + * to the output. + * + * @author eyalit (07/03/2018) + * + * @param ctx - general context + * @param instruction - raw instruction buffer + * @param length - number of bytes in the instruction buffer + * + * @return int32_t - success status + */ +int32_t instruction_mem_read(void * ctx, uint8_t * instruction, uint32_t length); + +/** + * Basic memory update (usually virtual RAM memory) with given + * input. + * + * @author eyalit (07/03/2018) + * + * @param ctx - general context + * @param instruction - raw instruction buffer + * @param length - number of bytes in the instruction buffer + * + * @return int32_t - success status + */ +int32_t instruction_mem_write(void * ctx, uint8_t * instruction, uint32_t length); + +/* The instruction records */ +#define INSTR_NOP_MIN_SIZE 0 +#define INSTR_NOP_MAX_SIZE 0 +#define INSTR_NOP_HANDLER instruction_nop + +#define INSTR_MEM_READ_MIN_SIZE (sizeof(addr_t) + sizeof(uint32_t)) +#define INSTR_MEM_READ_MAX_SIZE (sizeof(addr_t) + sizeof(uint32_t)) +#define INSTR_MEM_READ_HANDLER instruction_mem_read + +#define INSTR_MEM_WRITE_MIN_SIZE (sizeof(addr_t)) +#define INSTR_MEM_WRITE_MAX_SIZE (sizeof(addr_t) + 256) +#define INSTR_MEM_WRITE_HANDLER instruction_mem_write + +#endif /* SCOUT_INSTRUCTIONS */ + #endif // __SCOUT__API__H__ \ No newline at end of file diff --git a/scout/tcp_server.c b/src/scout/tcp_server.c similarity index 96% rename from scout/tcp_server.c rename to src/scout/tcp_server.c index 81a2cdc..d2b26ed 100644 --- a/scout/tcp_server.c +++ b/src/scout/tcp_server.c @@ -1,271 +1,271 @@ -#include -#include "scout/tcp_server.h" -#include "scout/scout_api.h" -#include "scout/pack.h" - -#ifdef SCOUT_INSTRUCTIONS -#ifndef SCOUT_DYNAMIC_BUFFERS -#ifndef SCOUT_PIC_CODE -static uint8_t gRecvBuffer[SCOUT_HEADER_SIZE + SCOUT_TCP_MAX_MESSAGE]; -static uint8_t gSendBuffer[SCOUT_TCP_MAX_MESSAGE]; -#endif /* !SCOUT_PIC_CODE */ -#endif /* !SCOUT_DYNAMIC_BUFFERS */ -#endif /* SCOUT_INSTRUCTIONS */ - -#if !defined(SCOUT_SLIM_SIZE) || defined(SCOUT_TCP_CLIENT) -int32_t connect_to_tcp_server(sock_fd * clientSock, uint32_t ip, uint16_t port) -{ - struct sockaddr_in addr; - - /* Sanity Check #1 - serverSock should be valid */ - if (clientSock == NULL) - { - return STATUS_INVALID_ARGS; - } - - /* Creat the socket */ - *clientSock = socket(AF_INET, SOCK_STREAM, 0); - if (*clientSock == -1) - { - return STATUS_TCP_SOCK_FAILED; - } - - /* Bind to the server's address */ - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons( port ); - addr.sin_addr.s_addr = htonl( ip ); - - if (connect(*clientSock, (struct sockaddr *)&addr, sizeof(addr)) < 0) - { - return STATUS_TCP_CONNECT_FAILED; - } - - /* All was OK */ - return STATUS_OK; -} -#endif /* !SCOUT_SLIM_SIZE || SCOUT_TCP_CLIENT */ - -#if !defined(SCOUT_SLIM_SIZE) || defined(SCOUT_TCP_SERVER) -int32_t open_tcp_server(sock_fd * serverSock, uint16_t port) -{ - struct sockaddr_in addr; - - /* Sanity Check #1 - serverSock should be valid */ - if (serverSock == NULL) - { - return STATUS_INVALID_ARGS; - } - - /* Creat the socket */ - *serverSock = socket(AF_INET, SOCK_STREAM, 0); - if (*serverSock == -1) - { - return STATUS_TCP_SOCK_FAILED; - } - - /* Bind to the server's address */ - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons( port ); - addr.sin_addr.s_addr = htonl( INADDR_ANY ); - - if (bind(*serverSock, (struct sockaddr *)&addr, sizeof(addr)) < 0) - { - return STATUS_TCP_BIND_FAILED; - } - - /* Set up the listen queue */ - if (listen(*serverSock, SCOUT_LISTEN_BACKLOG) < 0) - { - return STATUS_TCP_LISTEN_FAILED; - } - - /* All was OK */ - return STATUS_OK; -} -#endif /* !SCOUT_SLIM_SIZE || SCOUT_TCP_SERVER */ - -uint32_t full_net_recv(sock_fd sock, uint8_t * buffer, uint32_t length) -{ - uint32_t received = 0; - int res = 0; - while(length > received) - { - res = recv(sock, &buffer[received], length - received, 0); - if(res <= 0) - { - return 0; - } - received += (uint32_t)res; - } - return received; -} - -#if !defined(SCOUT_SLIM_SIZE) || defined(SCOUT_TCP_SEND) */ -uint32_t full_net_send(sock_fd sock, uint8_t * buffer, uint32_t length) -{ - uint32_t sent = 0; - int res = 0; - while(length > sent) - { - res = send(sock, &buffer[sent], length - sent, 0); - if(res <= 0) - { - return 0; - } - sent += (uint32_t)res; - } - return sent; -} -#endif /* !SCOUT_SLIM_SIZE || SCOUT_TCP_SEND */ - -#ifdef SCOUT_INSTRUCTIONS - -void write_output(void * c, uint8_t * buffer, uint32_t length) -{ - output_data_t * ctx = (output_data_t *)c; - uint32_t usedSize = length < ctx->size - ctx->offset ? length : ctx->size - ctx->offset; - - /* Append it to the send buffer */ - memcpy(ctx->output + ctx->offset, buffer, usedSize); - ctx->offset += usedSize; -} - -void mark_status(void * c, int32_t status) -{ - output_data_t * ctx = (output_data_t *)c; - ctx->status = status; -} - -int32_t start_server_loop(sock_fd serverSock) -{ - struct sockaddr_in clientAddr; - socklen_t clientAddrSize = sizeof(clientAddr); - sock_fd clientSock = 0; - int res; - scout_header_t header; - output_data_t ctx; - uint8_t outputHeader[sizeof(ctx.status) + sizeof(ctx.size)]; - uint8_t * writeHead; - -#ifndef SCOUT_DYNAMIC_BUFFERS - uint8_t * recvBuffer = GLOBAL(RecvBuffer); - uint8_t * sendBuffer = GLOBAL(SendBuffer); -#else /* SCOUT_DYNAMIC_BUFFERS */ - uint8_t * recvBuffer = (uint8_t *)malloc(SCOUT_HEADER_SIZE + SCOUT_TCP_MAX_MESSAGE); - uint8_t * sendBuffer = (uint8_t *)malloc(SCOUT_TCP_MAX_MESSAGE); - ctx.status = STATUS_OK; - - /* Sanity check */ - if(recvBuffer == NULL || sendBuffer == NULL) - { - ctx.status = STATUS_ALLOC_FAILED; - goto exit_loop; - } -#endif /* ! SCOUT_DYNAMIC_BUFFERS */ - - /* Prepare the recv buffer */ - memset(recvBuffer, 0, SCOUT_HEADER_SIZE + SCOUT_TCP_MAX_MESSAGE); - memset(sendBuffer, 0, SCOUT_TCP_MAX_MESSAGE); - memset(outputHeader, 0, sizeof(outputHeader)); - - /* Endless server loop */ - while(true) - { - /* Accept the new client */ - clientSock = accept(serverSock, (struct sockaddr *)&clientAddr, &clientAddrSize); - if (clientSock < 0) - { - ctx.status = STATUS_TCP_ACCECPT_FAILED; - goto exit_loop; - } - ctx.status = STATUS_OK; - - /* Client loop */ - while (ctx.status == STATUS_OK) - { - /* Prepare the context */ - ctx.output = sendBuffer; - ctx.offset = 0; - ctx.size = SCOUT_TCP_MAX_MESSAGE; - ctx.status = STATUS_FAILURE; - - /* Receive the instruction header */ - if (full_net_recv(clientSock, recvBuffer, SCOUT_HEADER_SIZE) != SCOUT_HEADER_SIZE) - { - ctx.status = STATUS_TCP_RECV_FAILED; - continue; - } - - /* Parse the header to learn the length */ - ctx.status = parse_header(recvBuffer, SCOUT_HEADER_SIZE, &header, false); - if (ctx.status != STATUS_OK) - { - continue; - } - - /* Basic sanitation */ - if (header.length > SCOUT_TCP_MAX_MESSAGE) - { - ctx.status = STATUS_ILLEGAL_LENGTH; - continue; - } - - /* Receive the entire instruction */ - if (header.length > 0 && - full_net_recv(clientSock, &recvBuffer[SCOUT_HEADER_SIZE], header.length) != header.length) - { - ctx.status = STATUS_TCP_RECV_FAILED; - continue; - } - - /* Pass the instruction onward */ - handle_instruction(&ctx, &header, &recvBuffer[SCOUT_HEADER_SIZE]); - - writeHead = outputHeader; - pack_uint32( &writeHead, ctx.status ); - pack_uint32( &writeHead, ctx.offset ); - - /* Send the response back - header */ - if (full_net_send(clientSock, outputHeader, sizeof(outputHeader)) != sizeof(outputHeader)) - { - ctx.status = STATUS_TCP_SEND_FAILED; - continue; - } - /* Send the response back - data */ - if (ctx.offset > 0 && full_net_send(clientSock, ctx.output, ctx.offset) != ctx.offset) - { - ctx.status = STATUS_TCP_SEND_FAILED; - continue; - } - } - - /* Close the current client */ - close(clientSock); - clientSock = 0; - } - -exit_loop: - - /* Free resources */ - if(clientSock != 0) - { - close(clientSock); - clientSock = 0; - } - - if(serverSock != 0) - { - close(serverSock); - serverSock = 0; - } - -#ifdef SCOUT_DYNAMIC_BUFFERS - free(recvBuffer); - free(sendBuffer); -#endif /* SCOUT_DYNAMIC_BUFFERS */ - - return ctx.status; -} +#include +#include "scout/tcp_server.h" +#include "scout/scout_api.h" +#include "scout/pack.h" + +#ifdef SCOUT_INSTRUCTIONS +#ifndef SCOUT_DYNAMIC_BUFFERS +#ifndef SCOUT_PIC_CODE +static uint8_t gRecvBuffer[SCOUT_HEADER_SIZE + SCOUT_TCP_MAX_MESSAGE]; +static uint8_t gSendBuffer[SCOUT_TCP_MAX_MESSAGE]; +#endif /* !SCOUT_PIC_CODE */ +#endif /* !SCOUT_DYNAMIC_BUFFERS */ +#endif /* SCOUT_INSTRUCTIONS */ + +#if !defined(SCOUT_SLIM_SIZE) || defined(SCOUT_TCP_CLIENT) +int32_t connect_to_tcp_server(sock_fd * clientSock, uint32_t ip, uint16_t port) +{ + struct sockaddr_in addr; + + /* Sanity Check #1 - serverSock should be valid */ + if (clientSock == NULL) + { + return STATUS_INVALID_ARGS; + } + + /* Creat the socket */ + *clientSock = socket(AF_INET, SOCK_STREAM, 0); + if (*clientSock == -1) + { + return STATUS_TCP_SOCK_FAILED; + } + + /* Bind to the server's address */ + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons( port ); + addr.sin_addr.s_addr = htonl( ip ); + + if (connect(*clientSock, (struct sockaddr *)&addr, sizeof(addr)) < 0) + { + return STATUS_TCP_CONNECT_FAILED; + } + + /* All was OK */ + return STATUS_OK; +} +#endif /* !SCOUT_SLIM_SIZE || SCOUT_TCP_CLIENT */ + +#if !defined(SCOUT_SLIM_SIZE) || defined(SCOUT_TCP_SERVER) +int32_t open_tcp_server(sock_fd * serverSock, uint16_t port) +{ + struct sockaddr_in addr; + + /* Sanity Check #1 - serverSock should be valid */ + if (serverSock == NULL) + { + return STATUS_INVALID_ARGS; + } + + /* Creat the socket */ + *serverSock = socket(AF_INET, SOCK_STREAM, 0); + if (*serverSock == -1) + { + return STATUS_TCP_SOCK_FAILED; + } + + /* Bind to the server's address */ + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons( port ); + addr.sin_addr.s_addr = htonl( INADDR_ANY ); + + if (bind(*serverSock, (struct sockaddr *)&addr, sizeof(addr)) < 0) + { + return STATUS_TCP_BIND_FAILED; + } + + /* Set up the listen queue */ + if (listen(*serverSock, SCOUT_LISTEN_BACKLOG) < 0) + { + return STATUS_TCP_LISTEN_FAILED; + } + + /* All was OK */ + return STATUS_OK; +} +#endif /* !SCOUT_SLIM_SIZE || SCOUT_TCP_SERVER */ + +uint32_t full_net_recv(sock_fd sock, uint8_t * buffer, uint32_t length) +{ + uint32_t received = 0; + int res = 0; + while(length > received) + { + res = recv(sock, &buffer[received], length - received, 0); + if(res <= 0) + { + return 0; + } + received += (uint32_t)res; + } + return received; +} + +#if !defined(SCOUT_SLIM_SIZE) || defined(SCOUT_TCP_SEND) */ +uint32_t full_net_send(sock_fd sock, uint8_t * buffer, uint32_t length) +{ + uint32_t sent = 0; + int res = 0; + while(length > sent) + { + res = send(sock, &buffer[sent], length - sent, 0); + if(res <= 0) + { + return 0; + } + sent += (uint32_t)res; + } + return sent; +} +#endif /* !SCOUT_SLIM_SIZE || SCOUT_TCP_SEND */ + +#ifdef SCOUT_INSTRUCTIONS + +void write_output(void * c, uint8_t * buffer, uint32_t length) +{ + output_data_t * ctx = (output_data_t *)c; + uint32_t usedSize = length < ctx->size - ctx->offset ? length : ctx->size - ctx->offset; + + /* Append it to the send buffer */ + memcpy(ctx->output + ctx->offset, buffer, usedSize); + ctx->offset += usedSize; +} + +void mark_status(void * c, int32_t status) +{ + output_data_t * ctx = (output_data_t *)c; + ctx->status = status; +} + +int32_t start_server_loop(sock_fd serverSock) +{ + struct sockaddr_in clientAddr; + socklen_t clientAddrSize = sizeof(clientAddr); + sock_fd clientSock = 0; + int res; + scout_header_t header; + output_data_t ctx; + uint8_t outputHeader[sizeof(ctx.status) + sizeof(ctx.size)]; + uint8_t * writeHead; + +#ifndef SCOUT_DYNAMIC_BUFFERS + uint8_t * recvBuffer = GLOBAL(RecvBuffer); + uint8_t * sendBuffer = GLOBAL(SendBuffer); +#else /* SCOUT_DYNAMIC_BUFFERS */ + uint8_t * recvBuffer = (uint8_t *)malloc(SCOUT_HEADER_SIZE + SCOUT_TCP_MAX_MESSAGE); + uint8_t * sendBuffer = (uint8_t *)malloc(SCOUT_TCP_MAX_MESSAGE); + ctx.status = STATUS_OK; + + /* Sanity check */ + if(recvBuffer == NULL || sendBuffer == NULL) + { + ctx.status = STATUS_ALLOC_FAILED; + goto exit_loop; + } +#endif /* ! SCOUT_DYNAMIC_BUFFERS */ + + /* Prepare the recv buffer */ + memset(recvBuffer, 0, SCOUT_HEADER_SIZE + SCOUT_TCP_MAX_MESSAGE); + memset(sendBuffer, 0, SCOUT_TCP_MAX_MESSAGE); + memset(outputHeader, 0, sizeof(outputHeader)); + + /* Endless server loop */ + while(true) + { + /* Accept the new client */ + clientSock = accept(serverSock, (struct sockaddr *)&clientAddr, &clientAddrSize); + if (clientSock < 0) + { + ctx.status = STATUS_TCP_ACCECPT_FAILED; + goto exit_loop; + } + ctx.status = STATUS_OK; + + /* Client loop */ + while (ctx.status == STATUS_OK) + { + /* Prepare the context */ + ctx.output = sendBuffer; + ctx.offset = 0; + ctx.size = SCOUT_TCP_MAX_MESSAGE; + ctx.status = STATUS_FAILURE; + + /* Receive the instruction header */ + if (full_net_recv(clientSock, recvBuffer, SCOUT_HEADER_SIZE) != SCOUT_HEADER_SIZE) + { + ctx.status = STATUS_TCP_RECV_FAILED; + continue; + } + + /* Parse the header to learn the length */ + ctx.status = parse_header(recvBuffer, SCOUT_HEADER_SIZE, &header, false); + if (ctx.status != STATUS_OK) + { + continue; + } + + /* Basic sanitation */ + if (header.length > SCOUT_TCP_MAX_MESSAGE) + { + ctx.status = STATUS_ILLEGAL_LENGTH; + continue; + } + + /* Receive the entire instruction */ + if (header.length > 0 && + full_net_recv(clientSock, &recvBuffer[SCOUT_HEADER_SIZE], header.length) != header.length) + { + ctx.status = STATUS_TCP_RECV_FAILED; + continue; + } + + /* Pass the instruction onward */ + handle_instruction(&ctx, &header, &recvBuffer[SCOUT_HEADER_SIZE]); + + writeHead = outputHeader; + pack_uint32( &writeHead, ctx.status ); + pack_uint32( &writeHead, ctx.offset ); + + /* Send the response back - header */ + if (full_net_send(clientSock, outputHeader, sizeof(outputHeader)) != sizeof(outputHeader)) + { + ctx.status = STATUS_TCP_SEND_FAILED; + continue; + } + /* Send the response back - data */ + if (ctx.offset > 0 && full_net_send(clientSock, ctx.output, ctx.offset) != ctx.offset) + { + ctx.status = STATUS_TCP_SEND_FAILED; + continue; + } + } + + /* Close the current client */ + close(clientSock); + clientSock = 0; + } + +exit_loop: + + /* Free resources */ + if(clientSock != 0) + { + close(clientSock); + clientSock = 0; + } + + if(serverSock != 0) + { + close(serverSock); + serverSock = 0; + } + +#ifdef SCOUT_DYNAMIC_BUFFERS + free(recvBuffer); + free(sendBuffer); +#endif /* SCOUT_DYNAMIC_BUFFERS */ + + return ctx.status; +} #endif /* SCOUT_INSTRUCTIONS */ \ No newline at end of file diff --git a/scout/tcp_server.h b/src/scout/tcp_server.h similarity index 96% rename from scout/tcp_server.h rename to src/scout/tcp_server.h index 85bc6a8..1053896 100644 --- a/scout/tcp_server.h +++ b/src/scout/tcp_server.h @@ -1,104 +1,104 @@ -#ifndef __SCOUT__TCP__SERVER__H__ -#define __SCOUT__TCP__SERVER__H__ - -/***********************/ -/** Network Configs **/ -/***********************/ - -#define SCOUT_PORT 0x2562 -#define SCOUT_LOADER_PORT 0x2561 -#define SCOUT_LISTEN_BACKLOG 5 -#define SCOUT_TCP_MAX_MESSAGE 0x1000 - -#include "scout/scout.h" // Depdendecy cycle in PIC mode forces us to include this file only at this line - -#ifndef SCOUT_ISOLATED_ENV -#include -#include -#include -#include -#include -#include - -typedef int sock_fd; -#endif /* !SCOUT_ISOLATED_ENV */ - -/***************/ -/** Structs **/ -/***************/ - -typedef struct __output_data -{ - uint8_t * output; - uint32_t offset; - uint32_t size; - int32_t status; -} output_data_t; - -/*****************/ -/** Functions **/ -/*****************/ - -/** - * Connects to a remote TCP server - * - * @author eyalit (03/05/2018) - * - * @param serverSock - pointer to the created server socket - * @param ip - remote ip to be used - * @param port - tcp port to be used - * - * @return int32_t - success status - */ -int32_t connect_to_tcp_server(sock_fd * serverSock, uint32_t ip, uint16_t port); - -/** - * Creates a TCP server for receiving instructions - * - * @author eyalit (08/03/2018) - * - * @param serverSock - pointer to the created server socket - * @param port - tcp port to be used - * - * @return int32_t - success status - */ -int32_t open_tcp_server(sock_fd * serverSock, uint16_t port); - -/** - * Starts the endless loop of the server socket. - * - * @author eyalit (08/03/2018) - * - * @param serverSock - socket descriptor for the server - * - * @return int32_t - success status - */ -int32_t start_server_loop(sock_fd serverSock); - -/** - * A reliable packet receive over a stream. - * - * @author eyalit (08/03/2018) - * - * @param sock - socket descriptor for the stream - * @param buffer - buffer for the incoming data - * @param length - number of bytes to be received - * - * @return uint32_t - number of received bytes - */ -uint32_t full_net_recv(sock_fd sock, uint8_t * buffer, uint32_t length); - -/** - * A reliable packet send over a stream. - * - * @author eyalit (08/03/2018) - * - * @param sock - socket descriptor for the stream - * @param buffer - buffer for the outgoing data - * @param length - number of bytes to be sent - * - * @return uint32_t - number of sent bytes - */ -uint32_t full_net_send(sock_fd sock, uint8_t * buffer, uint32_t length); - +#ifndef __SCOUT__TCP__SERVER__H__ +#define __SCOUT__TCP__SERVER__H__ + +/***********************/ +/** Network Configs **/ +/***********************/ + +#define SCOUT_PORT 0x2562 +#define SCOUT_LOADER_PORT 0x2561 +#define SCOUT_LISTEN_BACKLOG 5 +#define SCOUT_TCP_MAX_MESSAGE 0x1000 + +#include "scout/scout.h" // Depdendecy cycle in PIC mode forces us to include this file only at this line + +#ifndef SCOUT_ISOLATED_ENV +#include +#include +#include +#include +#include +#include + +typedef int sock_fd; +#endif /* !SCOUT_ISOLATED_ENV */ + +/***************/ +/** Structs **/ +/***************/ + +typedef struct __output_data +{ + uint8_t * output; + uint32_t offset; + uint32_t size; + int32_t status; +} output_data_t; + +/*****************/ +/** Functions **/ +/*****************/ + +/** + * Connects to a remote TCP server + * + * @author eyalit (03/05/2018) + * + * @param serverSock - pointer to the created server socket + * @param ip - remote ip to be used + * @param port - tcp port to be used + * + * @return int32_t - success status + */ +int32_t connect_to_tcp_server(sock_fd * serverSock, uint32_t ip, uint16_t port); + +/** + * Creates a TCP server for receiving instructions + * + * @author eyalit (08/03/2018) + * + * @param serverSock - pointer to the created server socket + * @param port - tcp port to be used + * + * @return int32_t - success status + */ +int32_t open_tcp_server(sock_fd * serverSock, uint16_t port); + +/** + * Starts the endless loop of the server socket. + * + * @author eyalit (08/03/2018) + * + * @param serverSock - socket descriptor for the server + * + * @return int32_t - success status + */ +int32_t start_server_loop(sock_fd serverSock); + +/** + * A reliable packet receive over a stream. + * + * @author eyalit (08/03/2018) + * + * @param sock - socket descriptor for the stream + * @param buffer - buffer for the incoming data + * @param length - number of bytes to be received + * + * @return uint32_t - number of received bytes + */ +uint32_t full_net_recv(sock_fd sock, uint8_t * buffer, uint32_t length); + +/** + * A reliable packet send over a stream. + * + * @author eyalit (08/03/2018) + * + * @param sock - socket descriptor for the stream + * @param buffer - buffer for the outgoing data + * @param length - number of bytes to be sent + * + * @return uint32_t - number of sent bytes + */ +uint32_t full_net_send(sock_fd sock, uint8_t * buffer, uint32_t length); + #endif // __SCOUT__TCP__SERVER__H__ \ No newline at end of file diff --git a/src/utils/__init__.py b/src/utils/__init__.py new file mode 100644 index 0000000..51f6f60 --- /dev/null +++ b/src/utils/__init__.py @@ -0,0 +1,6 @@ +# Network API / Utils +import scout_api +import scout_network +# Compilation Scripts +import context_creator +import scout_compiler \ No newline at end of file diff --git a/utils/context_creator.py b/src/utils/context_creator.py similarity index 100% rename from utils/context_creator.py rename to src/utils/context_creator.py diff --git a/manager/scout_api.py b/src/utils/scout_api.py similarity index 95% rename from manager/scout_api.py rename to src/utils/scout_api.py index 97410fe..dc652c9 100644 --- a/manager/scout_api.py +++ b/src/utils/scout_api.py @@ -1,125 +1,124 @@ -import struct - -#################### -## Configurations ## -#################### - -TARGET_BITNESS = 32 - -########################### -## Basic API Error Codes ## -########################### - -error_codes = { # General errors - 0 : "STATUS_OK", - 1 : "STATUS_FAILURE", - 2 : "STATUS_INVALID_ARGS", - 3 : "STATUS_ALLOC_FAILED", - 4 : "STATUS_TCP_SOCK_FAILED", - 5 : "STATUS_TCP_BIND_FAILED", - 6 : "STATUS_TCP_LISTEN_FAILED", - 7 : "STATUS_TCP_ACCEPT_FAILED", - 8 : "STATUS_TCP_CONNECT_FAILED", - 9 : "STATUS_TCP_RECV_FAILED", - 10 : "STATUS_TCP_SEND_FAILED", - - # Scout API - 20 : "STATUS_SMALL_HEADER", - 21 : "STATUS_ILLEGAL_LENGTH", - 22 : "STATUS_ILLEGAL_INSTR_ID" - } - -############################ -## Basic API Instructions ## -############################ - -SCOUT_INST_NOP = 0 -SCOUT_INST_MEM_READ = 1 -SCOUT_INST_MEM_WRITE = 2 - -SCOUT_MAX_BASIC_INSTR = SCOUT_INST_MEM_WRITE - -############################## -## Network API Instructions ## -############################## - -LOADER_PORT = 0x2561 -SCOUT_PORT = 0x2562 - -####################### -## Configuration API ## -####################### - -def setBitness32(): - """Sets the module's bitness to match a 32 bit server""" - global TARGET_BITNESS - - TARGET_BITNESS = 32 - -def setBitness64(): - """Sets the module's bitness to match a 64 bit server""" - global TARGET_BITNESS - - TARGET_BITNESS = 64 - -def addErrorCodes(errors): - """Adds the given error codes to the supported dictionary - - Args: - errors (dict): new supported error codes in the form: : - """ - global error_codes - - for k, v in errors.items(): - error_codes[k] = v - -######################### -## Instruction Factory ## -######################### - -def addHeader(opcode, raw_instr): - """Adds the protocol's header to the given instruction - - Args: - opcode (numeric): instruction opcode ID - raw_instr (string): binary data of the wanted instruction - Return Value: - string containing the complete serialized instruction - """ - return struct.pack( "!HL", opcode, len( raw_instr )) + raw_instr - -# basic instructions -def instrNop(): - """Builds the NOP (Pong) instruction - - Args: - (none) - Return Value: - string containing the serialized instruction - """ - return addHeader( SCOUT_INST_NOP, b'' ) - -def instrMemRead(addr, length): - """Builds the Read (Virtual) Memory instruction - - Args: - addr (numeric): (virtual) memory address - length (numeric): number of bytes to be read form the given address - Return Value: - string containing the serialized instruction - """ - instr = struct.pack( "!QL" if TARGET_BITNESS == 64 else "!LL", addr, length ) - return addHeader( SCOUT_INST_MEM_READ, instr ) - -def instrMemWrite(addr, content): - """Builds the Write (Virtual) Memory instruction - - Args: - addr (numeric): (virtual) memory address - content (string): binary data to be written to the given address - Return Value: - string containing the serialized instruction - """ - instr = struct.pack( "!Q" if TARGET_BITNESS == 64 else "!L", addr ) + content - return addHeader( SCOUT_INST_MEM_WRITE, instr ) - +import struct + +#################### +## Configurations ## +#################### + +TARGET_BITNESS = 32 + +########################### +## Basic API Error Codes ## +########################### + +error_codes = { # General errors + 0 : "STATUS_OK", + 1 : "STATUS_FAILURE", + 2 : "STATUS_INVALID_ARGS", + 3 : "STATUS_ALLOC_FAILED", + 4 : "STATUS_TCP_SOCK_FAILED", + 5 : "STATUS_TCP_BIND_FAILED", + 6 : "STATUS_TCP_LISTEN_FAILED", + 7 : "STATUS_TCP_ACCEPT_FAILED", + 8 : "STATUS_TCP_CONNECT_FAILED", + 9 : "STATUS_TCP_RECV_FAILED", + 10 : "STATUS_TCP_SEND_FAILED", + + # Scout API + 20 : "STATUS_SMALL_HEADER", + 21 : "STATUS_ILLEGAL_LENGTH", + 22 : "STATUS_ILLEGAL_INSTR_ID" + } + +############################ +## Basic API Instructions ## +############################ + +SCOUT_INST_NOP = 0 +SCOUT_INST_MEM_READ = 1 +SCOUT_INST_MEM_WRITE = 2 + +SCOUT_MAX_BASIC_INSTR = SCOUT_INST_MEM_WRITE + +############################## +## Network API Instructions ## +############################## + +LOADER_PORT = 0x2561 +SCOUT_PORT = 0x2562 + +####################### +## Configuration API ## +####################### + +def setBitness32(): + """Sets the module's bitness to match a 32 bit server""" + global TARGET_BITNESS + + TARGET_BITNESS = 32 + +def setBitness64(): + """Sets the module's bitness to match a 64 bit server""" + global TARGET_BITNESS + + TARGET_BITNESS = 64 + +def addErrorCodes(errors): + """Adds the given error codes to the supported dictionary + + Args: + errors (dict): new supported error codes in the form: : + """ + global error_codes + + for k, v in errors.items(): + error_codes[k] = v + +######################### +## Instruction Factory ## +######################### + +def addHeader(opcode, raw_instr): + """Adds the protocol's header to the given instruction + + Args: + opcode (numeric): instruction opcode ID + raw_instr (string): binary data of the wanted instruction + Return Value: + string containing the complete serialized instruction + """ + return struct.pack( "!HL", opcode, len( raw_instr )) + raw_instr + +# basic instructions +def instrNop(): + """Builds the NOP (Pong) instruction + + Args: + (none) + Return Value: + string containing the serialized instruction + """ + return addHeader( SCOUT_INST_NOP, b'' ) + +def instrMemRead(addr, length): + """Builds the Read (Virtual) Memory instruction + + Args: + addr (numeric): (virtual) memory address + length (numeric): number of bytes to be read form the given address + Return Value: + string containing the serialized instruction + """ + instr = struct.pack( "!QL" if TARGET_BITNESS == 64 else "!LL", addr, length ) + return addHeader( SCOUT_INST_MEM_READ, instr ) + +def instrMemWrite(addr, content): + """Builds the Write (Virtual) Memory instruction + + Args: + addr (numeric): (virtual) memory address + content (string): binary data to be written to the given address + Return Value: + string containing the serialized instruction + """ + instr = struct.pack( "!Q" if TARGET_BITNESS == 64 else "!L", addr ) + content + return addHeader( SCOUT_INST_MEM_WRITE, instr ) \ No newline at end of file diff --git a/utils/scout_compiler.py b/src/utils/scout_compiler.py similarity index 100% rename from utils/scout_compiler.py rename to src/utils/scout_compiler.py diff --git a/manager/scout_network.py b/src/utils/scout_network.py similarity index 96% rename from manager/scout_network.py rename to src/utils/scout_network.py index 0323bc6..d74e0d2 100644 --- a/manager/scout_network.py +++ b/src/utils/scout_network.py @@ -1,91 +1,91 @@ -from scout_api import * -import struct -import socket - -SCOUT_HEADER_FORMAT = "!LL" -SCOUT_HEADER_SIZE = struct.Struct(SCOUT_HEADER_FORMAT).size - -def sendInstr(sock, instr, logger): - """Sends an instruction to the (debuggee) server. - - Args: - sock (socket): (TCP) socket to the server - instr (string): serialized instruction - logger (logger): (elementals) logger - - Return Value: - string containing the instruction's output, or None if error - """ - logger.addIndent() - - sock.send(instr) - # receive the header (stats, size) - header = sock.recv(SCOUT_HEADER_SIZE) - if len(header) != SCOUT_HEADER_SIZE: - logger.error(f"Failed to receive the header, got {len(header)} bytes") - logger.removeIndent() - return None - - status, size = struct.unpack(SCOUT_HEADER_FORMAT, header) - if status not in error_codes: - logger.error(f"Received invalid status: {status}") - logger.removeIndent() - return None - if status != 0: - logger.warning(f"Received status is: {error_codes[status]}") - else: - logger.debug("Status was OK") - - logger.debug(f"Output data size is: {size}") - data = bytes() - while size - len(data) > 0: - data += sock.recv(size - len(data)) - logger.debug(f"Received {len(data)} output bytes") - - logger.removeIndent() - return data - -def remoteLoad(sock, full_scout): - """Sends TCP loader the loading instruction for the full scout. - - Args: - sock (socket): (TCP) socket to the remote loader - full_scout (bin): binary (list of bytes) for the full scout - """ - sock.send(struct.pack("!L", len(full_scout)) + full_scout) - -def remoteLoadServer(ip, full_scout, logger, port=LOADER_PORT): - """Connects to the remote TCP loader, and sends the full scout to be loaded. - - Args: - ip (ip address): ip address of the remote scout loader - full_scout (bin): binary (list of bytes) for the full scout - logger (logger): (elementals) logger - port (int, optional): TCP port for the remote loader (LODAER_PORT by default) - """ - logger.info(f"Attempting to connect to the remote loader: {ip}:{port}") - sock = socket.create_connection((ip, port)) - logger.info("Connected to the remote loader") - remoteLoad(sock, full_scout) - logger.info("Sent the loading instructions to the remote loader") - sock.close() - -def remoteLoadClient(ip, full_scout, logger, port=LOADER_PORT): - """Creates a local TCP server for which the remote loader could connect, and sends it the full scout. - - Args: - ip (ip address): ip address for our server - full_scout (bin): binary (list of bytes) for the full scout - logger (logger): (elementals) logger - port (int, optional): TCP port for the remote loader (LODAER_PORT by default) - """ - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) - sock.bind((ip, port)) - sock.listen(1) - logger.info(f"Created the local TCP server: {ip}:{port}") - - loader_sock, loader_addr = sock.accept() - logger.info(f"Accepted the remote loader from: {loader_addr[0]}") - remoteLoad(loader_sock, full_scout) - logger.info("Sent the loading instructions to the remote loader") - sock.close() +from scout_api import * +import struct +import socket + +SCOUT_HEADER_FORMAT = "!LL" +SCOUT_HEADER_SIZE = struct.Struct(SCOUT_HEADER_FORMAT).size + +def sendInstr(sock, instr, logger): + """Sends an instruction to the (debuggee) server. + + Args: + sock (socket): (TCP) socket to the server + instr (string): serialized instruction + logger (logger): (elementals) logger + + Return Value: + string containing the instruction's output, or None if error + """ + logger.addIndent() + + sock.send(instr) + # receive the header (stats, size) + header = sock.recv(SCOUT_HEADER_SIZE) + if len(header) != SCOUT_HEADER_SIZE: + logger.error(f"Failed to receive the header, got {len(header)} bytes") + logger.removeIndent() + return None + + status, size = struct.unpack(SCOUT_HEADER_FORMAT, header) + if status not in error_codes: + logger.error(f"Received invalid status: {status}") + logger.removeIndent() + return None + if status != 0: + logger.warning(f"Received status is: {error_codes[status]}") + else: + logger.debug("Status was OK") + + logger.debug(f"Output data size is: {size}") + data = bytes() + while size - len(data) > 0: + data += sock.recv(size - len(data)) + logger.debug(f"Received {len(data)} output bytes") + + logger.removeIndent() + return data + +def remoteLoad(sock, full_scout): + """Sends TCP loader the loading instruction for the full scout. + + Args: + sock (socket): (TCP) socket to the remote loader + full_scout (bin): binary (list of bytes) for the full scout + """ + sock.send(struct.pack("!L", len(full_scout)) + full_scout) + +def remoteLoadServer(ip, full_scout, logger, port=LOADER_PORT): + """Connects to the remote TCP loader, and sends the full scout to be loaded. + + Args: + ip (ip address): ip address of the remote scout loader + full_scout (bin): binary (list of bytes) for the full scout + logger (logger): (elementals) logger + port (int, optional): TCP port for the remote loader (LODAER_PORT by default) + """ + logger.info(f"Attempting to connect to the remote loader: {ip}:{port}") + sock = socket.create_connection((ip, port)) + logger.info("Connected to the remote loader") + remoteLoad(sock, full_scout) + logger.info("Sent the loading instructions to the remote loader") + sock.close() + +def remoteLoadClient(ip, full_scout, logger, port=LOADER_PORT): + """Creates a local TCP server for which the remote loader could connect, and sends it the full scout. + + Args: + ip (ip address): ip address for our server + full_scout (bin): binary (list of bytes) for the full scout + logger (logger): (elementals) logger + port (int, optional): TCP port for the remote loader (LODAER_PORT by default) + """ + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) + sock.bind((ip, port)) + sock.listen(1) + logger.info(f"Created the local TCP server: {ip}:{port}") + + loader_sock, loader_addr = sock.accept() + logger.info(f"Accepted the remote loader from: {loader_addr[0]}") + remoteLoad(loader_sock, full_scout) + logger.info("Sent the loading instructions to the remote loader") + sock.close() \ No newline at end of file diff --git a/tests.py b/tests.py new file mode 100644 index 0000000..54faf08 --- /dev/null +++ b/tests.py @@ -0,0 +1,23 @@ +#!/usr/bin/python + +import pydocstyle +import os +from glob import glob + +SRC_DIR = "src" + +def fileList(): + return filter(lambda z: not z.endswith("__init__.py"), [y for x in os.walk(SRC_DIR) for y in glob(os.path.join(x[0], '*.py'))]) + + +file_list = fileList() + +passed = True + +# Documentation tests +for check in pydocstyle.check(file_list, ignore=["D100", "D104", "D413", "D213", "D203", "D402", "D407", "D416", "D417"]): + print(check) + passed = False + +# last status +exit(0 if passed else 1) \ No newline at end of file From 064a74cd77d5da9c183b9136b79299f21448b430 Mon Sep 17 00:00:00 2001 From: chkp-eyalit Date: Thu, 29 Apr 2021 16:54:59 +0300 Subject: [PATCH 15/30] [docs] Bump version to 2.0.0 This is a major (breaking) change, bump the version accordingly. --- docs/conf.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 24a99ea..fe557a2 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -20,13 +20,13 @@ # -- Project information ----------------------------------------------------- project = u'Scout' -copyright = u'2019, Eyal Itkin' +copyright = u'2021, Eyal Itkin' author = u'Eyal Itkin' # The short X.Y version -version = u'' +version = u'2.0.0' # The full version, including alpha/beta/rc tags -release = u'' +release = u'2.0.0' # -- General configuration --------------------------------------------------- From 1fcede1e1334058d0fd572a34bfdce416aefb13b Mon Sep 17 00:00:00 2001 From: chkp-eyalit Date: Thu, 29 Apr 2021 20:13:23 +0300 Subject: [PATCH 16/30] [refactor] Scout's compiler was re-organized The compilation was split to multiple architectures and is now based on a main class that will store all information and use it when needed. Still need to work on the PIC context, but the example files now look way better. --- examples/embedded_scout/src/compile_scout.py | 90 ++- .../kernel_scout/user_mode/compile_scout.py | 45 +- src/utils/__init__.py | 12 +- src/utils/compilation/__init__.py | 6 + src/utils/compilation/arc_arm.py | 63 ++ src/utils/compilation/arc_intel.py | 26 + src/utils/compilation/arc_mips.py | 43 ++ src/utils/compilation/scout_files.py | 16 + src/utils/compilation/scout_flags.py | 31 + src/utils/compilation/target_arc.py | 41 ++ src/utils/scout_compiler.py | 669 +++++++----------- 11 files changed, 540 insertions(+), 502 deletions(-) create mode 100644 src/utils/compilation/__init__.py create mode 100644 src/utils/compilation/arc_arm.py create mode 100644 src/utils/compilation/arc_intel.py create mode 100644 src/utils/compilation/arc_mips.py create mode 100644 src/utils/compilation/scout_files.py create mode 100644 src/utils/compilation/scout_flags.py create mode 100644 src/utils/compilation/target_arc.py diff --git a/examples/embedded_scout/src/compile_scout.py b/examples/embedded_scout/src/compile_scout.py index d767ca3..49a9aa7 100644 --- a/examples/embedded_scout/src/compile_scout.py +++ b/examples/embedded_scout/src/compile_scout.py @@ -20,9 +20,11 @@ EMBEDDED_SCOUT_ELF = 'embedded_scout.elf' EMBEDDED_SCOUT_BIN = 'embedded_scout.bin' -TARGET_ARCH = ARC_INTEL +TARGET_ARCH = ARC_ARM +# Is Little Endian TARGET_ENDIANNESS = True if TARGET_ARCH == ARC_INTEL else False -TARGET_BITNESS = True # is 32 bits? +# Is 32 bits? +TARGET_BITNESS = True if TARGET_ARCH != ARC_INTEL else False # Scout Functions (in same order as the c code) symbol_memcpy = 0x80486c0 @@ -55,50 +57,52 @@ # Sets the basic architecture flags for our target ## def setTargetFlags(logger): - # 1. Set the architecture - setScoutArc(TARGET_ARCH, is_32_bits=TARGET_BITNESS, is_little_endian=TARGET_ENDIANNESS, logger=logger) - - # 2. Set the environment - setScoutEnv(is_executable=False) - - # 3. Set the permission mode - setScoutMode(is_user=False) + # 0. Create the compiler instance + compiler = scoutCompiler(logger) + + # 1. Set the architecture + compiler.setArc(TARGET_ARCH, is_pic=True, is_32_bits=TARGET_BITNESS, is_little_endian=TARGET_ENDIANNESS) + + # 2. Set the permission mode (User & low CPU permissions, Kernel & High CPU permissions) + compiler.setScoutMode(is_user=True) + + # 3. Set the working directories + compiler.setWorkingDirs(project_dir='.', scout_dir=SCOUT_DIR) + + return compiler ## # Compiles the scout loader (TCP Server loader) ## def compileScoutLoader(logger): # 1. Set the target flags - setTargetFlags(logger) - - # 2. Additional flags: thumb mode (if in ARM), and mmap (in both cases) - setScoutFlags([flag_loader, flag_loader_server, flag_mmap] + ([flag_arc_thumb] if TARGET_ARCH == ARC_ARM else [])) - - # 3. Define the working directories - setWorkingDirs(project_dir='.', scout_dir=SCOUT_DIR) + compiler = setTargetFlags(logger) - # 4. Generate the used compilation flags (we will rely on the defaults) - compile_flags, link_flags=generateCompilationFlags(compile_flags=[], link_flags=[], logger=logger) + # 2. Additional flags: + # * flag_loader - Compiling a loader + # * flag_loader_server - Compiling a TCP server loader + # * flag_mmap - The loader will use mmap() instead of malloc() + # X flag_load_thumb - If will be loading a Thumb code full Scout + # X flag_loader_transmit - If the loader will need to be able to send TCP messages + compiler.addScoutFlags([flag_loader, flag_loader_server, flag_mmap]) - # 5. Generate the list of compiled files - compilation_files = [os.path.join(SCOUT_DIR, f) for f in scout_loader_deps + [scout_server_loader]] + loader_pic_files + # 3. Add custom compilation flags (not needed) + # compiler.addCompilationFlags(compile_flags=[], link_flags=[]) - # 6. Compile an embedded scout + # 4. Compile an embedded scout logger.info('Starting to compile the scout loader') - compilePICScout(compilation_files, compile_flags, link_flags, SCOUT_LOADER_ELF, SCOUT_LOADER_BIN, logger) + compiler.compilePICScout(scout_server_loader_deps, loader_pic_files, SCOUT_LOADER_ELF, SCOUT_LOADER_BIN) - # 7. Place the PIC context in the resulting binary file + # 5. Place the PIC context in the resulting binary file generateGOT(symbol_memcpy, symbol_memset, symbol_malloc, symbol_free, symbol_socket, symbol_bind, symbol_listen, symbol_accept, symbol_connect, symbol_recv, symbol_send, symbol_close, symbol_mmap, symbol_mprotect, symbol_munmap, project_got=loader_got, is_thumb=TARGET_ARCH == ARC_ARM) - # 8. Setup the sizes for the global variables (No variables used at all) + # 6. Setup the sizes for the global variables (No variables used at all) generateGlobals(scout_vars_size=0, project_vars_size=0) - # 9. Generate the PIC context, and place it in the binary blob + # 7. Generate the PIC context, and place it in the binary blob placeContext(SCOUT_LOADER_BIN, SCOUT_LOADER_BIN, TARGET_ENDIANNESS, TARGET_BITNESS, logger) - - # 10. Finished :) return ## @@ -106,38 +110,30 @@ def compileScoutLoader(logger): ## def compileScout(logger): # 1. Set the target flags - setTargetFlags(logger) + compiler = setTargetFlags(logger) # 2. Add additional flags: - # a) Will use the TCP server for instructions - # b) Will use dynamic buffers (malloc) for the received instructions - setScoutFlags([flag_instructions, flag_dynamic_buffers]) - - # 3. Define the working directories - setWorkingDirs(project_dir='.', scout_dir=SCOUT_DIR) + # * flag_instructions - Will use the TCP server for instructions + # * flag_dynamic_buffers - Will use dynamic buffers (malloc) for the received instructions + compiler.addScoutFlags([flag_instructions, flag_dynamic_buffers]) - # 4. Generate the used compilation flags (we will rely on the defaults) - compile_flags, link_flags = generateCompilationFlags(compile_flags=[], link_flags=[], logger=logger) + # 3. Add custom compilation flags (not needed) + # compiler.addCompilationFlags(compile_flags=[], link_flags=[]) - # 5. Generate the list of compiled files - compilation_files = [os.path.join(SCOUT_DIR, f) for f in scout_all_files] + project_files - - # 6. Compile a PIC scout + # 4. Compile a PIC scout logger.info('Starting to compile the PIC scout') - compilePICScout(compilation_files, compile_flags, link_flags, EMBEDDED_SCOUT_ELF, EMBEDDED_SCOUT_BIN, logger) + compiler.compilePICScout(scout_all_files, project_files, EMBEDDED_SCOUT_ELF, EMBEDDED_SCOUT_BIN, logger) - # 7. Place the PIC context in the resulting binary file + # 5. Place the PIC context in the resulting binary file generateGOT(symbol_memcpy, symbol_memset, symbol_malloc, symbol_free, symbol_socket, symbol_bind, symbol_listen, symbol_accept, symbol_connect, symbol_recv, symbol_send, symbol_close, project_got=project_got) - # 8. Setup the sizes for the global variables + # 6. Setup the sizes for the global variables generateGlobals(scout_vars_size=scout_instructions_globals_32_size if TARGET_BITNESS else scout_instructions_globals_64_size, project_vars_size=0) - # 9. Generate the PIC context, and place it in the binary blob + # 7. Generate the PIC context, and place it in the binary blob placeContext(EMBEDDED_SCOUT_BIN, EMBEDDED_SCOUT_BIN, TARGET_ENDIANNESS, TARGET_BITNESS, logger) - - # 10. Finished :) return ## diff --git a/examples/kernel_scout/user_mode/compile_scout.py b/examples/kernel_scout/user_mode/compile_scout.py index 55d460b..19c60f0 100644 --- a/examples/kernel_scout/user_mode/compile_scout.py +++ b/examples/kernel_scout/user_mode/compile_scout.py @@ -16,8 +16,6 @@ USER_SCOUT_BIN = 'scout_user' TARGET_ARCH = ARC_INTEL -TARGET_ENDIANNESS = True # is little endian ? -TARGET_BITNESS = False # is 32 bits ? # project files list project_files = ['scout_user.c'] @@ -26,42 +24,39 @@ # Sets the bsaic architecture flags for our target ## def setTargetFlags(logger): + # 0. Create the compiler instance + compiler = scoutCompiler(logger, is_pic=False) + # 1. Set the architecture - setScoutArc(TARGET_ARCH, is_32_bits=TARGET_BITNESS, is_little_endian=TARGET_ENDIANNESS, logger=logger) + compiler.setArc(TARGET_ARCH) - # 2. Set the environment - setScoutEnv(is_executable=True) - - # 3. Set the permission mode - setScoutMode(is_user=True) + # 2. Set the permission mode (User & low CPU permissions, Kernel & High CPU permissions) + compiler.setScoutMode(is_user=True) + + # 3. Set the working directories + compiler.setWorkingDirs(project_dir='.', scout_dir=SCOUT_DIR) + + return compiler ## # Compiles the user scout ## def compileScout(logger): # 1. Set the target flags - setTargetFlags(logger) + compiler = setTargetFlags(logger) # 2. Add additional flags: - # a) Will use the TCP server for instructions - # b) Will use dynamic buffers (malloc) for the received instructions - # c) Will act as a proxy scout, only passing on the instructions to the driver - setScoutFlags([flag_instructions, flag_dynamic_buffers, flag_proxy]) - - # 3. Define the working directories - setWorkingDirs(project_dir='.', scout_dir = SCOUT_DIR) + # * flag_instructions - Will use the TCP server for instructions + # * flag_dynamic_buffers - Will use dynamic buffers (malloc) for the received instructions + # * flag_proxy - Will act as a proxy scout, only passing on the instructions to the driver + compiler.setScoutFlags([flag_instructions, flag_dynamic_buffers, flag_proxy]) - # 4. Generate the used compilation flags (we will rely on the defaults) - compile_flags, link_flags=generateCompilationFlags(compile_flags=[], link_flags=[], logger=logger) + # 3. Add custom compilation flags (not needed) + # compiler.addCompilationFlags(compile_flags=[], link_flags=[]) - # 5. Generate the list of compiled files - compilation_files = [os.path.join(SCOUT_DIR, f) for f in scout_all_files] + project_files - - # 6. Compile the PC (user mode proxy) scout + # 4. Compile the PC (user mode proxy) scout logger.info('Starting to compile the user scout') - compileExecutableScout(compilation_files, compile_flags, link_flags, USER_SCOUT_BIN, logger) - - # Finished :) + compileExecutableScout(scout_all_files, project_files, USER_SCOUT_BIN, logger) return ## diff --git a/src/utils/__init__.py b/src/utils/__init__.py index 51f6f60..da5f57d 100644 --- a/src/utils/__init__.py +++ b/src/utils/__init__.py @@ -1,6 +1,6 @@ -# Network API / Utils -import scout_api -import scout_network -# Compilation Scripts -import context_creator -import scout_compiler \ No newline at end of file +from .scout_files import * +from .scout_flags import * +from .target_arc import * +from .arc_intel import * +from .arc_arm import * +from .arc_mips import * \ No newline at end of file diff --git a/src/utils/compilation/__init__.py b/src/utils/compilation/__init__.py new file mode 100644 index 0000000..51f6f60 --- /dev/null +++ b/src/utils/compilation/__init__.py @@ -0,0 +1,6 @@ +# Network API / Utils +import scout_api +import scout_network +# Compilation Scripts +import context_creator +import scout_compiler \ No newline at end of file diff --git a/src/utils/compilation/arc_arm.py b/src/utils/compilation/arc_arm.py new file mode 100644 index 0000000..25c5945 --- /dev/null +++ b/src/utils/compilation/arc_arm.py @@ -0,0 +1,63 @@ +from target_arc import targetArc + +class arcArm(targetArc): + # Arm Toolchain + arm_compiler_path = '/usr/bin/arm-none-eabi-gcc' + arm_linker_path = '/usr/bin/arm-none-eabi-ld' + arm_objcopy_path = '/usr/bin/arm-none-eabi-objcopy' + arm_objcopy_flags = ('--section-alignment 4',) + + arm_pic_compile_flags = ('fno-jump-tables', 'mapcs-frame') + + def __init__(self, is_pic): + super(arcArm, self).__init__(is_pic) + # Arc specific PIC flags + if is_pic: + self.compile_flags += arm_pic_compile_flags + + @staticmethod + def name(): + """Get the architecture's name + + Return Value: + String name for the architecture + """ + return "Arm" + + # Overridden base function + def setNotNative(self): + self.setToolchain(arm_compiler_path, arm_linker_path, arm_objcopy_path, arm_objcopy_flags) + + # Overridden base function + def setEndianness(self, is_little): + if is_little: + self.compile_flags += ('mlittle-endian',) + self.link_flags += ('EL',) + else: + self.compile_flags += ('mbig-endian',) + self.link_flags += ('EB',) + + # Overridden base function + def setBitness(self, is_32_bits): + if not is_32_bits: + raise NotImplementedError("Didn't yet implement the logic for 64 bits ARM") + +class arcArmThumb(arcArm): + def __init__(self, is_pic): + super(arcArmThumb, self).__init__(is_pic) + # Arc specific flags + self.compile_flags += ('mthumb',) + + @staticmethod + def name(): + """Get the architecture's name + + Return Value: + String name for the architecture + """ + return "Arm-Thumb" + + # Overridden base function + def setBitness(self, is_32_bits): + if not is_32_bits: + raise Exception("Not sure if ARM-Thumb even supports 64 bits") \ No newline at end of file diff --git a/src/utils/compilation/arc_intel.py b/src/utils/compilation/arc_intel.py new file mode 100644 index 0000000..fff537f --- /dev/null +++ b/src/utils/compilation/arc_intel.py @@ -0,0 +1,26 @@ +from target_arc import targetArc + +class arcIntel(targetArc): + def __init__(self, is_pic): + super(arcIntel, self).__init__(is_pic) + + @staticmethod + def name(): + """Get the architecture's name + + Return Value: + String name for the architecture + """ + return "Intel" + + # Overridden base function + def setEndianness(self, is_little): + if not is_32_bits: + raise Exception("Intel doesn't support Big Endian :(") + + # Overridden base function + def setBitness(self, is_32_bits): + if not is_32_bits: + return + self.compile_flags += ('m32',) + self.link_flags += ('melf_i386',) \ No newline at end of file diff --git a/src/utils/compilation/arc_mips.py b/src/utils/compilation/arc_mips.py new file mode 100644 index 0000000..088945c --- /dev/null +++ b/src/utils/compilation/arc_mips.py @@ -0,0 +1,43 @@ +from target_arc import targetArc + +class arcMips(targetArc): + # Mips Toolchain + mips_compiler_path = '/usr/bin/mips-linux-gnu-gcc' + mips_linker_path = '/usr/bin/mips-linux-gnu-ld' + mips_objcopy_path = '/usr/bin/mips-linux-gnu-objcopy' + mips_objcopy_flags = ('--section-alignment 4',) + + mips_pic_compile_flags = ('fno-jump-tables', 'mno-shared', 'mplt') + + def __init__(self, is_pic): + super(arcMips, self).__init__(is_pic) + # Arc specific PIC flags + if is_pic: + self.compile_flags += mips_pic_compile_flags + + @staticmethod + def name(): + """Get the architecture's name + + Return Value: + String name for the architecture + """ + return "Mips" + + # Overridden base function + def setNotNative(self): + self.setToolchain(mips_compiler_path, mips_linker_path, mips_objcopy_path, mips_objcopy_flags) + + # Overridden base function + def setEndianness(self, is_little): + if is_little: + self.compile_flags += ('EL',) + self.link_flags += ('EL',) + else: + self.compile_flags += ('EB',) + self.link_flags += ('EB',) + + # Overridden base function + def setBitness(self, is_32_bits): + if not is_32_bits: + raise NotImplementedError("Didn't yet implement the logic for 64 bits Mips") \ No newline at end of file diff --git a/src/utils/compilation/scout_files.py b/src/utils/compilation/scout_files.py new file mode 100644 index 0000000..e2910f4 --- /dev/null +++ b/src/utils/compilation/scout_files.py @@ -0,0 +1,16 @@ +############################ +## Files Configurations ## +############################ + +# scout file list +scout_arc_files = ['arc/arm.c', 'arc/mips.c', 'arc/intel.c'] +scout_pic_files = ['pic/arm_pic_wrapper.c', 'pic/mips_pic_wrapper.c', 'pic/intel_pic_wrapper.c', 'pic/scout_plt.c', 'pic/scout_globals.c'] +# PIC files vanish upon compilation without the SCOUT_PIC_CODE flag +scout_loader_deps = scout_pic_files + ['pack.c', 'tcp_server.c'] + scout_arc_files +scout_all_files = scout_pic_files + ['pack.c', 'scout_api.c', 'tcp_server.c'] + scout_arc_files + +scout_server_loader = 'loaders/tcp_server_loader.c' +scout_client_loader = 'loaders/tcp_client_loader.c' + +scout_server_loader_deps = scout_loader_deps + [scout_server_loader] +scout_client_loader_deps = scout_loader_deps + [scout_client_loader] diff --git a/src/utils/compilation/scout_flags.py b/src/utils/compilation/scout_flags.py new file mode 100644 index 0000000..e353bb6 --- /dev/null +++ b/src/utils/compilation/scout_flags.py @@ -0,0 +1,31 @@ +############################# +## Static Configurations ## +############################# + +# flags files +FLAGS_FILE_NAME = 'flags.h' + +# configuration compile flags +flag_32_bit = 'SCOUT_BITS_32' +flag_64_bit = 'SCOUT_BITS_64' +flag_big_endian = 'SCOUT_BIG_ENDIAN' +flag_little_endian = 'SCOUT_LITTLE_ENDIAN' +flag_arc_intel = 'SCOUT_ARCH_INTEL' +flag_arc_arm = 'SCOUT_ARCH_ARM' +flag_arc_thumb = 'SCOUT_ARM_THUMB' +flag_arc_mips = 'SCOUT_ARCH_MIPS' +flag_mode_user = 'SCOUT_MODE_USER' +flag_mode_kernel = 'SCOUT_MODE_KERNEL' +flag_pic_code = 'SCOUT_PIC_CODE' +flag_host_glibc = 'SCOUT_HOST_GLIBC' +flag_host_uclibc = 'SCOUT_HOST_UCLIBC' +flag_instructions = 'SCOUT_INSTRUCTIONS' +flag_restore_flow = 'SCOUT_RESTORE_FLOW' +flag_dynamic_buffers= 'SCOUT_DYNAMIC_BUFFERS' +flag_proxy = 'SCOUT_PROXY' +flag_mmap = 'SCOUT_MMAP' +flag_load_thumb = 'SCOUT_LOADING_THUMB_CODE' +flag_loader = 'SCOUT_LOADER' +flag_loader_client = 'SCOUT_TCP_CLIENT' +flag_loader_server = 'SCOUT_TCP_SERVER' +flag_loader_transmit= 'SCOUT_TCP_SEND' \ No newline at end of file diff --git a/src/utils/compilation/target_arc.py b/src/utils/compilation/target_arc.py new file mode 100644 index 0000000..fd7f898 --- /dev/null +++ b/src/utils/compilation/target_arc.py @@ -0,0 +1,41 @@ +class targetArc: + native_compiler_path = 'gcc' + native_linker_path = 'ld' + native_objcopy_path = 'objcopy' + native_objcopy_flags = () + + base_compile_flags = ('fno-builtin', 'Wno-int-to-pointer-cast', 'Wno-pointer-to-int-cast') + base_executable_compile_flags = ('O2',) + base_pic_compile_flags = ('Os', 'nostdlib', 'fno-toplevel-reorder') + base_link_flags = () + + def __init__(self, is_pic): + self.compiler_path = native_compiler_path + self.linker_path = native_linker_path + self.objcopy_path = native_objcopy_path + self.objcopy_flags = list(native_objcopy_flags) + + self.compile_flags = list(base_compile_flags) + self.link_flags = list(base_link_flags) + + self.compile_flags += base_pic_compile_flags if is_pic else base_executable_compile_flags + + def setToolchain(self, compiler_path, linker_path, objcopy_path, objcopy_flags): + self.compiler_path = compiler_path + self.linker_path = linker_path + self.objcopy_path = objcopy_path + self.objcopy_flags = [] + objcopy_flags + + def setNotNative(self): + raise NotImplementedError("Subclasses should implement this!") + + def setEndianness(self, is_little): + raise NotImplementedError("Subclasses should implement this!") + + def setBitness(self, is_32_bits): + raise NotImplementedError("Subclasses should implement this!") + + def prepareFlags(self): + compile_flags = ' '.join(['-' + x for x in self.compile_flags]) + link_flags = ' '.join(['-' + x for x in self.link_flags]) + return compile_flags, link_flags \ No newline at end of file diff --git a/src/utils/scout_compiler.py b/src/utils/scout_compiler.py index d7ca222..514018f 100644 --- a/src/utils/scout_compiler.py +++ b/src/utils/scout_compiler.py @@ -3,435 +3,256 @@ import time import struct -############################## -## Default Configurations ## -############################## - -# Native Compiler -native_compiler_path = 'gcc' -native_linker_path = 'ld' -native_objcopy_path = 'objcopy' - -# Arm Compiler -arm_compiler_path = '/usr/bin/arm-none-eabi-gcc' -arm_linker_path = '/usr/bin/arm-none-eabi-ld' -arm_objcopy_path = '/usr/bin/arm-none-eabi-objcopy' -arm_objcopy_flags = ['--section-alignment 4'] - -# Mips Compiler -mips_compiler_path = '/usr/bin/mips-linux-gnu-gcc' -mips_linker_path = '/usr/bin/mips-linux-gnu-ld' -mips_objcopy_path = '/usr/bin/mips-linux-gnu-objcopy' -mips_objcopy_flags = ['--section-alignment 4'] - -# Intel Compiler -intel_compiler_path = 'gcc' -intel_linker_path = 'ld' -intel_objcopy_path = 'objcopy' -intel_objcopy_flags = [] - -# Compile & Link flags -common_compile_flags = ['fno-builtin', 'Wno-int-to-pointer-cast', 'Wno-pointer-to-int-cast'] -common_executable_compile_flags = ['O2'] -common_pic_compile_flags = ['Os', 'nostdlib', 'fno-toplevel-reorder'] -intel_pic_compile_flags = [] -arm_pic_compile_flags = ['fno-jump-tables', 'mapcs-frame'] -mips_pic_compile_flags = ['fno-jump-tables', 'mno-shared', 'mplt'] -common_link_flags = [] - -############################# -## Static Configurations ## -############################# - -# flags files -FLAGS_FILE_NAME = 'flags.h' - -# configuration compile flags -flag_32_bit = 'SCOUT_BITS_32' -flag_64_bit = 'SCOUT_BITS_64' -flag_big_endian = 'SCOUT_BIG_ENDIAN' -flag_little_endian = 'SCOUT_LITTLE_ENDIAN' -flag_arc_arm = 'SCOUT_ARCH_ARM' -flag_arc_mips = 'SCOUT_ARCH_MIPS' -flag_arc_intel = 'SCOUT_ARCH_INTEL' -flag_arc_thumb = 'SCOUT_ARM_THUMB' -flag_mode_user = 'SCOUT_MODE_USER' -flag_mode_kernel = 'SCOUT_MODE_KERNEL' -flag_pic_code = 'SCOUT_PIC_CODE' -flag_host_glibc = 'SCOUT_HOST_GLIBC' -flag_host_uclibc = 'SCOUT_HOST_UCLIBC' -flag_instructions = 'SCOUT_INSTRUCTIONS' -flag_restore_flow = 'SCOUT_RESTORE_FLOW' -flag_dynamic_buffers= 'SCOUT_DYNAMIC_BUFFERS' -flag_proxy = 'SCOUT_PROXY' -flag_mmap = 'SCOUT_MMAP' -flag_load_thumb = 'SCOUT_LOADING_THUMB_CODE' -flag_loader = 'SCOUT_LOADER' -flag_loader_client = 'SCOUT_TCP_CLIENT' -flag_loader_server = 'SCOUT_TCP_SERVER' -flag_loader_transmit= 'SCOUT_TCP_SEND' +from .compilation.scout_flags import * +from .compilation.scout_files import * +from .compilation.arc_intel import arcIntel +from .compilation.arc_arm import arcArm, arcArmThumb +from .compilation.arc_mips import arcMips + +################################### +## Architecture Configurations ## +################################### # Using an enum to support feature extensions -ARC_INTEL = 'intel' -ARC_ARM = 'arm' -ARC_MIPS = 'mips' - -arc_setups = { - ARC_INTEL: (intel_compiler_path, intel_linker_path, intel_objcopy_path, intel_objcopy_flags), - ARC_ARM: (arm_compiler_path, arm_linker_path, arm_objcopy_path, arm_objcopy_flags), - ARC_MIPS: (mips_compiler_path, mips_linker_path, mips_objcopy_path, mips_objcopy_flags), - } -arc_configs = { - ARC_INTEL: flag_arc_intel, - ARC_ARM: flag_arc_arm, - ARC_MIPS: flag_arc_mips, +ARC_INTEL = arcIntel.name() +ARC_ARM = arcArm.name() +ARC_ARM_THUMB = arcArmThumb.name() +ARC_MIPS = arcMips.name() + +arc_factory = { + ARC_INTEL: arcIntel, + ARC_ARM: arcArm, + ARC_ARM_THUMB: arcArmThumb, + ARC_MIPS: arcMips, } -arc_pic_flags = \ - { - ARC_INTEL: intel_pic_compile_flags, - ARC_ARM: arm_pic_compile_flags, - ARC_MIPS: mips_pic_compile_flags, - } - -# scout file list -scout_arc_files = ['arc/arm.c', 'arc/mips.c', 'arc/intel.c'] -scout_pic_files = ['pic/arm_pic_wrapper.c', 'pic/mips_pic_wrapper.c', 'pic/intel_pic_wrapper.c', 'pic/scout_plt.c', 'pic/scout_globals.c'] -scout_server_loader = 'loaders/tcp_server_loader.c' -scout_client_loader = 'loaders/tcp_client_loader.c' -scout_loader_deps = scout_pic_files + ['pack.c', 'tcp_server.c'] + scout_arc_files -scout_all_files = scout_pic_files + ['pack.c', 'scout_api.c', 'tcp_server.c'] + scout_arc_files - -######################## -## Global Variables ## -######################## - -# User compiler & linker -compiler_path = None -linker_path = None -objcopy_path = None -objcopy_flags = None - -# Scout configurations flags -config_bitness = None -config_endianness = None -config_arc = None -config_mode = None -config_pic = None -config_flags = [] - -# Paths -project_folder = None -scout_folder = None -include_dirs = None - -def setScoutArc(arc, is_32_bits, is_little_endian, logger, is_native=False): - """Sets the target's architecture specifications - - Args: - arc (string, enum): name of the target architecture (should be a key of arc_setups) - is_32_bits (bool): True iff the architecture is 32 bit, otherwise it will be 64 bits - is_little_endian (bool): True iff the architecture is little endian, otherwise it will be big endian - logger (logger): (elementals) logger - is_native (bool, optional): True iff should use the native compilation programs, regardless of the arc (False by default) - """ - global compiler_path, linker_path, objcopy_path, objcopy_flags, config_bitness, config_endianness, config_arc - - # Sanity check - if arc not in arc_setups.keys(): - logger.error("Unknown architecture: \"%s\". Supported options are: \"%s\"", arc, ', '.join(arc_setups.keys())) - - # Apply the chosen settings - compiler_path, linker_path, objcopy_path, objcopy_flags = arc_setups[arc] - if is_native: - compiler_path = native_compiler_path - linker_path = native_linker_path - objcopy_path = native_objcopy_path - - # Store the values for the configuration flags - config_bitness = flag_32_bit if is_32_bits else flag_64_bit - config_endianness = flag_little_endian if is_little_endian else flag_big_endian - config_arc = arc_configs[arc] - -def setScoutEnv(is_executable): - """Sets the target's environment flags - - Args: - is_executable (bool): True iff the environment is a standard executable, otherwise it will be a PIC environment - """ - global config_pic - - config_pic = flag_pic_code if not is_executable else '' - -def setScoutMode(is_user): - """Sets the target's permission level - - Args: - is_user (bool): True iff the scout will run in user mode, otherwise it will assume kernel mode permissions - """ - global config_mode - - config_mode = flag_mode_user if is_user else flag_mode_kernel - -def setScoutFlags(flags): - """Sets the flags regarding the target's specifications - - Args: - flags (list): list of configuration flags (strings) - """ - global config_flags - - config_flags = [] + flags - -def setWorkingDirs(project_dir, scout_dir): - """Sets the paths for the used directories - - Args: - project_dir (string): path to the project's directory - scout_dir (string): path to the directory of the basic Scout - """ - global project_folder, scout_folder, include_dirs - - project_folder = project_dir - scout_folder = scout_dir - - if scout_folder.endswith(os.path.sep + "scout"): - main_folder = os.path.sep.join(scout_folder.split(os.path.sep)[:-1]) - else: - main_folder = scout_folder + os.path.sep + ".." - - # Can update the include directories - include_dirs = [project_folder, main_folder] - -def addIncludeDirs(dirs): - """Adds additional include directories for the compilation - - Args: - dirs (list): list of additional include directories - """ - global include_dirs - - include_dirs += dirs - -def verifyScoutFlags(logger): - """Checks that all of the configuration flags are set correctly - - Args: - logger (logger): (elementals) logger - - Return Value: - True iff all configuration flags are set to a valid value, False otherwise - """ - global config_flags - - if config_bitness is None: - logger.error("Missing Scout flag: unknown bitness") - return False - - if config_endianness is None: - logger.error("Missing Scout flag: unknown endianness") - return False - - if config_arc is None: - logger.error("Missing Scout flag: unknown architecture") - return False - - if config_mode is None: - logger.error("Missing Scout flag: unknown permission mode") - return False - - if config_pic is None: - logger.error("Missing Scout flag: should decide if compiling in PIC mode") - return False - - # Reaching here means that all was OK - config_flags += [config_bitness, config_endianness, config_arc, config_mode] - if len(config_pic) > 0: - config_flags += [config_pic] - return True - -def generateFlagsFile(logger): - """Generates the architecture's "flags.h" file - - Args: - logger (logger): (elementals) logger - """ - # Verify the flags - if not verifyScoutFlags(logger): - return - - # Verify we know where to store this file - if project_folder is None: - logger.error("Working directories are NOT defined...") - return - - flag_path = os.path.join(project_folder, FLAGS_FILE_NAME) - logger.info(f"Generating the {flag_path} file") - fd = open(flag_path, "w") - # file prefix - fd.write("#ifndef __SCOUT__FLAGS__H__\n") - fd.write("#define __SCOUT__FLAGS__H__\n") - fd.write('\n') - # auto-generation comment - fd.write("/* This file is AUTO-GENERATED, please do NOT edit it manually */\n") - # The actual flags - for flag in set(config_flags): - fd.write(f"#define {flag}\n") - # file suffix - fd.write("\n") - fd.write("#endif /* _SCOUT__FLAGS__H__ */") - # can close the file - fd.close() - -def generateCompilationFlags(user_compile_flags, user_link_flags, logger): - """Generates the compilation flags that match the configurations flags - - Args: - user_copmile_flags (list): list of compiler flags (without the '-' prefix) - user_link_flags (list) list of linker flags (without the '-' prefix) - logger (logger): (elementals) logger - - Return Value: - (compiler flags string, linker flags string) - """ - compile_flags = common_compile_flags - link_flags = common_link_flags - - # ARM - Misc (Thumb) & Endianness - if config_arc == flag_arc_arm: - # Thumb - compile_flags += ['mthumb'] if (flag_arc_thumb in config_flags) else [] - # Endianness - if config_endianness == flag_little_endian: - compile_flags += ['mlittle-endian'] - link_flags += ['EL'] - else: - compile_flags += ['mbig-endian'] - link_flags += ['EB'] - - # Mips - Endianness - elif config_arc == flag_arc_mips: - if config_endianness == flag_little_endian: - compile_flags += ['EL'] - link_flags += ['EL'] - else: - compile_flags += ['EB'] - link_flags += ['EB'] +arc_flags = { + ARC_INTEL: (flag_arc_intel,), + ARC_ARM: (flag_arc_arm,), + ARC_ARM_THUMB: (flag_arc_arm, flag_arc_thumb), + ARC_MIPS: (flag_arc_mips,), + } + +################# +## Utilities ## +################# - # Intel - Misc (Bitness) - elif config_arc == flag_arc_intel: - if config_bitness == flag_32_bit: - compile_flags += ['m32'] - link_flags += ['melf_i386'] - - # Executable Environment - if config_pic != flag_pic_code: - compile_flags += common_executable_compile_flags - - # PIC Environment - else: - compile_flags += common_pic_compile_flags - compile_flags += arc_pic_flags[config_arc] - - # Final Compile & Link flags - compile_flags = ' '.join(['-' + x for x in compile_flags + user_compile_flags + ['I' + y for y in include_dirs]]) - link_flags = ' '.join(['-' + x for x in link_flags + user_link_flags]) - - return compile_flags, link_flags - def systemLine(line, logger): - """Issues and debug trace a systen line - - Args: - line (string): cmd line to be executed - logger (logger): (elementals) logger - """ - logger.debug(line) - os.system(line) - -def compilePICScout(compilation_files, compile_flags, link_flags, elf_file, final_file, logger): - """Compiles a Position-Independent (PIC) "Scout" project - - Args: - compilation_files (list): list of file paths for all code (*.c) files - compile_flags (string): compilation flags to be passed to the compiler - link_flags (string): linker flags to be passed to the linker - elf_file (string): path to the (created) compiled ELF file - final_file (string): path to the (created) PIC binary file - logger (logger): (elementals) logger - """ - logger.addIndent() - - # 0. Sanity check - if config_pic != flag_pic_code: - logger.error("Compiling a PIC scout without the PIC-CODE Environment flag. Did you mean: compileExecutableScout() ?") - logger.removeIndent() - return - - # 1. Auto-Generate the flags.h file - generateFlagsFile(logger) - - # 2. Generate all of the *.S files - logger.info("Compiling the *.c files") - s_files = [] - for c_file in compilation_files: - local_out_file = ".".join(c_file.split(".")[:-1]) + ".S" - systemLine(f"{compiler_path} -S -c {compile_flags} {c_file} -o {local_out_file}", logger) - s_files.append(local_out_file) - - # 3. Work-around GCC's bugs - logger.info("Fixing the *.S files to work around GCC's bugs") - for s_file in s_files: - fd = open(s_file, "r") - content = fd.read() - fd.close() - content = content.replace(".space #", ".space ").replace(".space $", ".space ") - # convert the calls to relative (PIC) - if config_arc == flag_arc_mips: - content = content.replace("\tjal\t", "\tbal\t").replace("\tj\t", "\tb\t") - fd = open(s_file, "w") - fd.write(content) + """Issues (and debug trace) a systen line + + Args: + logger (logger, elementals): logger to be used by the function (elementals) + line (string): cmd line to be executed + """ + logger.debug(line) + os.system(line) + +############################### +## The full Scout Compiler ## +############################### + +class scoutCompiler: + def __init__(self, logger): + self.logger = logger + self.target_arc = None + self.project_folder = None + self.scout_folder = None + self.config_flags = [] + + def setArc(self, arc, is_pic, is_32_bits=True, is_little_endian=True, is_native=False): + """Sets the target's architecture specifications + + Args: + arc (string, enum): name of the target architecture (should be a key of arc_factory) + is_pic (bool): True iff compiling a position independent blob + is_32_bits (bool, optional): True iff the architecture is 32 bit, otherwise it will be 64 bits (True by default) + is_little_endian (bool, optional): True iff the architecture is little endian, otherwise it will be big endian (True by default) + is_native (bool, optional): True iff should use the native compilation programs, regardless of the arc (False by default) + """ + # Sanity check + if arc not in arc_factory.keys(): + self.logger.error("Unknown architecture: \"%s\". Supported options are: \"%s\"", arc, ', '.join(arc_factory.keys())) + + # Apply the chosen settings + self.target_arc = arc_factory[arc](is_pic) + if not is_native: + target_arc.setNotNative() + + # Configure the architecture + target_arc.setEndianness(is_little_endian) + target_arc.setBitness(is_32_bits) + + # Store the values for the configuration flags + self.config_flags.append(flag_32_bit if is_32_bits else flag_64_bit) + self.config_flags.append(flag_little_endian if is_little_endian else flag_big_endian) + if is_pic: + self.config_flags.append(flag_pic_code) + + def setScoutMode(self, is_user): + """Sets the target's permission level + + Args: + is_user (bool): True iff the scout will run in user mode, otherwise it will assume kernel mode permissions + """ + self.config_flags.append(flag_mode_user if is_user else flag_mode_kernel) + + def setWorkingDirs(self, project_dir, scout_dir, include_dirs=[]): + """Sets the paths for the used directories + + Args: + project_dir (string): path to the project's directory + scout_dir (string): path to the directory of the basic Scout (Example: ".../src/scout") + include_dirs (list, optional): list of additional include directories + """ + self.project_folder = project_dir + self.scout_folder = scout_dir + + # Ends with "/scout" (and not "/scout/") + if scout_dir.endswith(os.path.sep + "scout"): + main_folder = os.path.sep.join(scout_dir.split(os.path.sep)[:-1]) + else: + main_folder = scout_dir + os.path.sep + ".." + + self.target_arc.compile_flags += ['I' + x for x in [project_folder, main_folder] + include_dirs] + + def addScoutFlags(self, flags): + """Adds the flags regarding the target's specifications + + Args: + flags (list): list of configuration flags (strings) + """ + self.config_flags += flags + + def addCompilationFlags(self, user_compile_flags=[], user_link_flags=[]): + """Add custom compilation / linking flags + + Args: + user_compile_flags (list, optional): list of compiler flags (without the '-' prefix) + user_link_flags (list, optional) list of linker flags (without the '-' prefix) + """ + self.target_arc.compile_flags += user_compile_flags + self.target_arc.link_flags += user_link_flags + + def verifyScoutFlags(self): + """Checks that all of the configuration flags are set correctly""" + if flag_mode_user is not in self.config_flags and flag_mode_kernel is not in self.config_files: + self.logger.warning("Missing Scout flag - unknown permission mode. Defaulting to USER-MODE (low privileges)") + + def generateFlagsFile(self): + """Generates the architecture's "flags.h" file""" + # Verify the flags + verifyScoutFlags() + + # Verify we know where to store this file + if self.project_folder is None: + self.logger.error("Working directories are NOT defined...") + return + + flag_path = os.path.join(self.project_folder, FLAGS_FILE_NAME) + self.logger.info(f"Generating the {flag_path} file") + fd = open(flag_path, "w") + # file prefix + fd.write("#ifndef __SCOUT__FLAGS__H__\n") + fd.write("#define __SCOUT__FLAGS__H__\n") + fd.write('\n') + # auto-generation comment + fd.write("/* This file is AUTO-GENERATED, please do NOT edit it manually */\n") + # The actual flags + for flag in self.config_flags: + fd.write(f"#define {flag}\n") + # file suffix + fd.write("\n") + fd.write("#endif /* _SCOUT__FLAGS__H__ */") + # can close the file fd.close() - # 4. Generate all of the *.o files - logger.info("Compiling the *.S files") - o_files = [] - for s_file in s_files: - local_out_file = ".".join(s_file.split(".")[:-1]) + ".o" - systemLine(f"{compiler_path} -c {compile_flags} {s_file} -o {local_out_file}", logger) - o_files.append(local_out_file) - - # 5. Link together all of the *.o files - logger.info(f"Linking together all of the files, creating: {elf_file}") - systemLine(f"{linker_path} {link_flags} {' '.join(o_files)} -o {elf_file}", logger) - - # 6. Objcopy the content to the actual wanted file - logger.info(f"Extracting the final binary to: {final_file}") - systemLine(f"{objcopy_path} -O binary -j .text -j .rodata {' '.join(objcopy_flags)} {elf_file} {final_file}", logger) - - logger.removeIndent() - -def compileExecutableScout(compilation_files, compile_flags, link_flags, elf_file, logger): - """Compiles a regular executable "Scout" project - - Args: - compilation_files (list): list of file paths for all code (*.c) files - compile_flags (string): compilation flags to be passed to the compiler - link_flags (string): linker flags to be passed to the linker - elf_file (string): path to the (created) compiled ELF file - logger (logger): (elementals) logger - """ - # 0. Sanity check - if config_pic == flag_pic_code: - logger.error("Compiling an Executable scout with PIC-CODE environment flag. Did you mean: compilePICScout() ?") - return - - # 1. Auto-Generate the flags.h file - generateFlagsFile(logger) - - # 2. Re-organize the linker flags - fixed_link_flags = "".join("-Wl," + x for x in link_flags.split("-")[1:]) - - # 3. Compile together all of the file (and that's it) - logger.info(f"Compiling the *.c files, linking them together and creating: {elf_file}") - systemLine(f"{compiler_path} {compile_flags} {' '.join(compilation_files)} {fixed_link_flags} -o {elf_file}", logger) + def compilePICScout(self, scout_files, project_files, elf_file, final_file): + """Compiles a Position-Independent (PIC) "Scout" project + + Args: + scout_files (list): list of file paths for scout's code (*.c) files + proect_files (list): list of file paths for the project's code (*.c) files + elf_file (string): path to the (created) compiled ELF file + final_file (string): path to the (created) PIC binary file + """ + self.logger.addIndent() + + # 0. Sanity check + if flag_pic_code not in self.config_flags: + self.logger.error("Compiling a PIC scout without the PIC-CODE Environment flag. Did you mean: compileExecutableScout() ?") + self.logger.removeIndent() + return + + # 1. Auto-Generate the flags.h file + generateFlagsFile() + + # 2. Prepare the list of compilation files + compilation_files = [os.path.join(self.scout_folder, f) for f in scout_files] + project_files + + # 3. Generate all of the *.S files + self.logger.info("Compiling the *.c files") + compile_flags, link_flags = self.target_arc.prepareFlags() + s_files = [] + for c_file in compilation_files: + local_out_file = ".".join(c_file.split(".")[:-1]) + ".S" + systemLine(f"{target_arc.compiler_path} -S -c {compile_flags} {c_file} -o {local_out_file}", self.logger) + s_files.append(local_out_file) + + # 4. Work-around GCC's bugs + self.logger.info("Fixing the *.S files to work around GCC's bugs") + for s_file in s_files: + fd = open(s_file, "r") + content = fd.read() + fd.close() + content = content.replace(".space #", ".space ").replace(".space $", ".space ") + # Mips: convert the calls to relative (PIC) + if self.target_arc.name() == arcMips.name(): + content = content.replace("\tjal\t", "\tbal\t").replace("\tj\t", "\tb\t") + fd = open(s_file, "w") + fd.write(content) + fd.close() + + # 5. Generate all of the *.o files + self.logger.info("Compiling the *.S files") + o_files = [] + for s_file in s_files: + local_out_file = ".".join(s_file.split(".")[:-1]) + ".o" + systemLine(f"{target_arc.compiler_path} -c {compile_flags} {s_file} -o {local_out_file}", self.logger) + o_files.append(local_out_file) + + # 6. Link together all of the *.o files + self.logger.info(f"Linking together all of the files, creating: {elf_file}") + systemLine(f"{target_arc.linker_path} {link_flags} {' '.join(o_files)} -o {elf_file}", self.logger) + + # 7. Objcopy the content to the actual wanted file + self.logger.info(f"Extracting the final binary to: {final_file}") + systemLine(f"{target_arc.objcopy_path} -O binary -j .text -j .rodata {' '.join(target_arc.objcopy_flags)} {elf_file} {final_file}", self.logger) + + self.logger.removeIndent() + + def compileExecutableScout(self, scout_files, project_files, elf_file): + """Compiles a regular executable "Scout" project + + Args: + scout_files (list): list of file paths for scout's code (*.c) files + proect_files (list): list of file paths for the project's code (*.c) files + elf_file (string): path to the (created) compiled ELF file + """ + # 0. Sanity check + if flag_pic_code in self.config_flags: + logger.error("Compiling an Executable scout with PIC-CODE environment flag. Did you mean: compilePICScout() ?") + return + + # 1. Auto-Generate the flags.h file + generateFlagsFile() + + # 2. Re-organize the linker flags + compile_flags, link_flags = self.target_arc.prepareFlags() + fixed_link_flags = "".join("-Wl," + x for x in link_flags.split("-")[1:]) + + # 3. Prepare the list of compilation files + compilation_files = [os.path.join(self.scout_folder, f) for f in scout_files] + project_files + + # 4. Compile together all of the file (and that's it) + self.logger.info(f"Compiling the *.c files, linking them together and creating: {elf_file}") + systemLine(f"{target_arc.compiler_path} {compile_flags} {' '.join(compilation_files)} {fixed_link_flags} -o {elf_file}", self.logger) \ No newline at end of file From 98957df43706278dc39c8f55680e5dfb368fa4f4 Mon Sep 17 00:00:00 2001 From: chkp-eyalit Date: Sun, 2 May 2021 09:29:28 +0300 Subject: [PATCH 17/30] [loader] Export non-network loader deps Split up the loader deps to "scout_loader_deps" and "scout_net_loader_deps", so advanced integrating projects won't need to be aware of all of our internal files. --- src/utils/compilation/scout_files.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/utils/compilation/scout_files.py b/src/utils/compilation/scout_files.py index e2910f4..6398b7c 100644 --- a/src/utils/compilation/scout_files.py +++ b/src/utils/compilation/scout_files.py @@ -6,11 +6,12 @@ scout_arc_files = ['arc/arm.c', 'arc/mips.c', 'arc/intel.c'] scout_pic_files = ['pic/arm_pic_wrapper.c', 'pic/mips_pic_wrapper.c', 'pic/intel_pic_wrapper.c', 'pic/scout_plt.c', 'pic/scout_globals.c'] # PIC files vanish upon compilation without the SCOUT_PIC_CODE flag -scout_loader_deps = scout_pic_files + ['pack.c', 'tcp_server.c'] + scout_arc_files -scout_all_files = scout_pic_files + ['pack.c', 'scout_api.c', 'tcp_server.c'] + scout_arc_files +scout_loader_deps = scout_pic_files + scout_arc_files + ['pack.c'] +scout_net_loader_deps = scout_loader_deps + ['tcp_server.c'] +scout_all_files = scout_pic_files + scout_arc_files + ['pack.c', 'scout_api.c', 'tcp_server.c'] scout_server_loader = 'loaders/tcp_server_loader.c' scout_client_loader = 'loaders/tcp_client_loader.c' -scout_server_loader_deps = scout_loader_deps + [scout_server_loader] -scout_client_loader_deps = scout_loader_deps + [scout_client_loader] +scout_server_loader_deps = scout_net_loader_deps + [scout_server_loader] +scout_client_loader_deps = scout_net_loader_deps + [scout_client_loader] From 6a2a48db7e0cfb599ce722de55a894055ebdd851 Mon Sep 17 00:00:00 2001 From: chkp-eyalit Date: Sun, 2 May 2021 09:35:50 +0300 Subject: [PATCH 18/30] [flags] Added the "native_compilation" flag Now the code is aware of the compilation-mode and if it is a special toolchain or a plain old GCC. This way the ARM architecture could properly configure the ELF-start address automatically. --- src/scout/pic/arm_pic_wrapper.c | 13 ++++++------- src/utils/compilation/scout_flags.py | 3 ++- src/utils/scout_compiler.py | 4 +++- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/scout/pic/arm_pic_wrapper.c b/src/scout/pic/arm_pic_wrapper.c index 2e0e6d7..c225777 100644 --- a/src/scout/pic/arm_pic_wrapper.c +++ b/src/scout/pic/arm_pic_wrapper.c @@ -8,14 +8,13 @@ * and it mandates the order of the functions in this file. */ -/* Compilation on an intel ubuntu machine, with arm-gcc */ -//#define ELF_START (0x00008000) +#ifdef SCOUT_NATIVE_COMPILATION /* Compilation on a raspberry pi */ -//#define ELF_START (0x00010074) - -#ifndef ELF_START - #error "\"ELF_START\" symbol is missing! Should be defined to the address of the \"_start\ function in the ELF." -#endif /* ELF_START */ + #define ELF_START (0x00010074) +#else /* !SCOUT_NATIVE_COMPILATION */ +/* Compilation on an intel ubuntu machine, with arm-gcc */ + #define ELF_START (0x00008000) +#endif /* SCOUT_NATIVE_COMPILATION */ #ifdef SCOUT_ARM_THUMB #define STATIC_FUNC_ADDR (ELF_START + 0x10) // It sounds weird, but with +0xC it had an offset of 4 bytes... diff --git a/src/utils/compilation/scout_flags.py b/src/utils/compilation/scout_flags.py index e353bb6..0a88193 100644 --- a/src/utils/compilation/scout_flags.py +++ b/src/utils/compilation/scout_flags.py @@ -28,4 +28,5 @@ flag_loader = 'SCOUT_LOADER' flag_loader_client = 'SCOUT_TCP_CLIENT' flag_loader_server = 'SCOUT_TCP_SERVER' -flag_loader_transmit= 'SCOUT_TCP_SEND' \ No newline at end of file +flag_loader_transmit= 'SCOUT_TCP_SEND' +flag_native_compiler= 'SCOUT_NATIVE_COMPILATION' \ No newline at end of file diff --git a/src/utils/scout_compiler.py b/src/utils/scout_compiler.py index 514018f..c389a22 100644 --- a/src/utils/scout_compiler.py +++ b/src/utils/scout_compiler.py @@ -75,7 +75,9 @@ def setArc(self, arc, is_pic, is_32_bits=True, is_little_endian=True, is_native= # Apply the chosen settings self.target_arc = arc_factory[arc](is_pic) - if not is_native: + if is native: + target_arc.config_flags.append(flag_native_compiler) + else: target_arc.setNotNative() # Configure the architecture From b1216bb936a4361c150f4dfacf2f626e1ba756e3 Mon Sep 17 00:00:00 2001 From: chkp-eyalit Date: Sun, 2 May 2021 09:51:12 +0300 Subject: [PATCH 19/30] [refactor] Export only a single copmilation function Instead of exporting two functions and checking that the user didn't call the wrong one, just export a single function that will invoke the wanted logic based on the PIC flag that is stored by the compiler. --- examples/embedded_scout/src/compile_scout.py | 7 +- .../kernel_scout/user_mode/compile_scout.py | 2 +- src/utils/scout_compiler.py | 81 +++++++++---------- 3 files changed, 41 insertions(+), 49 deletions(-) diff --git a/examples/embedded_scout/src/compile_scout.py b/examples/embedded_scout/src/compile_scout.py index 49a9aa7..b1c2aef 100644 --- a/examples/embedded_scout/src/compile_scout.py +++ b/examples/embedded_scout/src/compile_scout.py @@ -15,10 +15,7 @@ SCOUT_DIR = '../../../src/scout' SCOUT_LOADER_ELF = 'scout_loader.elf' -SCOUT_LOADER_BIN = 'scout_loader.bin' - EMBEDDED_SCOUT_ELF = 'embedded_scout.elf' -EMBEDDED_SCOUT_BIN = 'embedded_scout.bin' TARGET_ARCH = ARC_ARM # Is Little Endian @@ -91,7 +88,7 @@ def compileScoutLoader(logger): # 4. Compile an embedded scout logger.info('Starting to compile the scout loader') - compiler.compilePICScout(scout_server_loader_deps, loader_pic_files, SCOUT_LOADER_ELF, SCOUT_LOADER_BIN) + compiler.compile(scout_server_loader_deps, loader_pic_files, SCOUT_LOADER_ELF) # 5. Place the PIC context in the resulting binary file generateGOT(symbol_memcpy, symbol_memset, symbol_malloc, symbol_free, symbol_socket, symbol_bind, @@ -122,7 +119,7 @@ def compileScout(logger): # 4. Compile a PIC scout logger.info('Starting to compile the PIC scout') - compiler.compilePICScout(scout_all_files, project_files, EMBEDDED_SCOUT_ELF, EMBEDDED_SCOUT_BIN, logger) + compiler.compile(scout_all_files, project_files, EMBEDDED_SCOUT_ELF) # 5. Place the PIC context in the resulting binary file generateGOT(symbol_memcpy, symbol_memset, symbol_malloc, symbol_free, symbol_socket, symbol_bind, diff --git a/examples/kernel_scout/user_mode/compile_scout.py b/examples/kernel_scout/user_mode/compile_scout.py index 19c60f0..d444cb9 100644 --- a/examples/kernel_scout/user_mode/compile_scout.py +++ b/examples/kernel_scout/user_mode/compile_scout.py @@ -56,7 +56,7 @@ def compileScout(logger): # 4. Compile the PC (user mode proxy) scout logger.info('Starting to compile the user scout') - compileExecutableScout(scout_all_files, project_files, USER_SCOUT_BIN, logger) + compiler.compile(scout_all_files, project_files, USER_SCOUT_BIN) return ## diff --git a/src/utils/scout_compiler.py b/src/utils/scout_compiler.py index c389a22..48e0481 100644 --- a/src/utils/scout_compiler.py +++ b/src/utils/scout_compiler.py @@ -168,30 +168,48 @@ def generateFlagsFile(self): # can close the file fd.close() - def compilePICScout(self, scout_files, project_files, elf_file, final_file): - """Compiles a Position-Independent (PIC) "Scout" project + def compile(self, scout_files, project_files, elf_file): + """Compiles the "Scout" project, according to the PIC setup that was defined earlier. Args: scout_files (list): list of file paths for scout's code (*.c) files proect_files (list): list of file paths for the project's code (*.c) files elf_file (string): path to the (created) compiled ELF file - final_file (string): path to the (created) PIC binary file + + Note: + If this is a PIC compilation, the final binary file will be named to match the ELF + file. For example: "project.elf" => "project.bin". """ self.logger.addIndent() + # 1. Auto-Generate the flags.h file + generateFlagsFile() + + # 2. Prepare the list of compilation files + compilation_files = [os.path.join(self.scout_folder, f) for f in scout_files] + project_files + + # 3. Prepare the compilation & linking flags + compile_flags, link_flags = self.target_arc.prepareFlags() + + ############################# + ## Compiling an Executable ## + ############################# - # 0. Sanity check if flag_pic_code not in self.config_flags: - self.logger.error("Compiling a PIC scout without the PIC-CODE Environment flag. Did you mean: compileExecutableScout() ?") + # 4. Re-organize the linker flags + fixed_link_flags = "".join("-Wl," + x for x in link_flags.split("-")[1:]) + + # 5. Compile together all of the file (and that's it) + self.logger.info(f"Compiling the *.c files, linking them together and creating: {elf_file}") + systemLine(f"{target_arc.compiler_path} {compile_flags} {' '.join(compilation_files)} {fixed_link_flags} -o {elf_file}", self.logger) + self.logger.removeIndent() return - # 1. Auto-Generate the flags.h file - generateFlagsFile() - - # 2. Prepare the list of compilation files - compilation_files = [os.path.join(self.scout_folder, f) for f in scout_files] + project_files + ########################### + ## Compiling a PIC Scout ## + ########################### - # 3. Generate all of the *.S files + # 4. Generate all of the *.S files self.logger.info("Compiling the *.c files") compile_flags, link_flags = self.target_arc.prepareFlags() s_files = [] @@ -200,7 +218,7 @@ def compilePICScout(self, scout_files, project_files, elf_file, final_file): systemLine(f"{target_arc.compiler_path} -S -c {compile_flags} {c_file} -o {local_out_file}", self.logger) s_files.append(local_out_file) - # 4. Work-around GCC's bugs + # 5. Work-around GCC's bugs self.logger.info("Fixing the *.S files to work around GCC's bugs") for s_file in s_files: fd = open(s_file, "r") @@ -214,7 +232,7 @@ def compilePICScout(self, scout_files, project_files, elf_file, final_file): fd.write(content) fd.close() - # 5. Generate all of the *.o files + # 6. Generate all of the *.o files self.logger.info("Compiling the *.S files") o_files = [] for s_file in s_files: @@ -222,39 +240,16 @@ def compilePICScout(self, scout_files, project_files, elf_file, final_file): systemLine(f"{target_arc.compiler_path} -c {compile_flags} {s_file} -o {local_out_file}", self.logger) o_files.append(local_out_file) - # 6. Link together all of the *.o files + # 7. Link together all of the *.o files self.logger.info(f"Linking together all of the files, creating: {elf_file}") systemLine(f"{target_arc.linker_path} {link_flags} {' '.join(o_files)} -o {elf_file}", self.logger) - # 7. Objcopy the content to the actual wanted file + # 8. Objcopy the content to the actual wanted file + if elf_file.split('.')[0].lower() == "elf": + final_file = '.'.join(elf_file.split('.')[:-1] + ['bin']) + else: + final_file = elf_file + ".bin" self.logger.info(f"Extracting the final binary to: {final_file}") systemLine(f"{target_arc.objcopy_path} -O binary -j .text -j .rodata {' '.join(target_arc.objcopy_flags)} {elf_file} {final_file}", self.logger) - self.logger.removeIndent() - - def compileExecutableScout(self, scout_files, project_files, elf_file): - """Compiles a regular executable "Scout" project - - Args: - scout_files (list): list of file paths for scout's code (*.c) files - proect_files (list): list of file paths for the project's code (*.c) files - elf_file (string): path to the (created) compiled ELF file - """ - # 0. Sanity check - if flag_pic_code in self.config_flags: - logger.error("Compiling an Executable scout with PIC-CODE environment flag. Did you mean: compilePICScout() ?") - return - - # 1. Auto-Generate the flags.h file - generateFlagsFile() - - # 2. Re-organize the linker flags - compile_flags, link_flags = self.target_arc.prepareFlags() - fixed_link_flags = "".join("-Wl," + x for x in link_flags.split("-")[1:]) - - # 3. Prepare the list of compilation files - compilation_files = [os.path.join(self.scout_folder, f) for f in scout_files] + project_files - - # 4. Compile together all of the file (and that's it) - self.logger.info(f"Compiling the *.c files, linking them together and creating: {elf_file}") - systemLine(f"{target_arc.compiler_path} {compile_flags} {' '.join(compilation_files)} {fixed_link_flags} -o {elf_file}", self.logger) \ No newline at end of file + self.logger.removeIndent() \ No newline at end of file From 42237eb2118e48c19247992506b97d28caef9a5d Mon Sep 17 00:00:00 2001 From: chkp-eyalit Date: Sun, 2 May 2021 09:58:40 +0300 Subject: [PATCH 20/30] [cleanup] Tell the project the name of the PIC binary Return the final file name from the compilation function, so the user will be able to use it after it was generated. --- examples/embedded_scout/src/compile_scout.py | 8 ++++---- src/utils/scout_compiler.py | 8 ++++++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/examples/embedded_scout/src/compile_scout.py b/examples/embedded_scout/src/compile_scout.py index b1c2aef..22cd610 100644 --- a/examples/embedded_scout/src/compile_scout.py +++ b/examples/embedded_scout/src/compile_scout.py @@ -88,7 +88,7 @@ def compileScoutLoader(logger): # 4. Compile an embedded scout logger.info('Starting to compile the scout loader') - compiler.compile(scout_server_loader_deps, loader_pic_files, SCOUT_LOADER_ELF) + scout_loader_bin = compiler.compile(scout_server_loader_deps, loader_pic_files, SCOUT_LOADER_ELF) # 5. Place the PIC context in the resulting binary file generateGOT(symbol_memcpy, symbol_memset, symbol_malloc, symbol_free, symbol_socket, symbol_bind, @@ -99,7 +99,7 @@ def compileScoutLoader(logger): generateGlobals(scout_vars_size=0, project_vars_size=0) # 7. Generate the PIC context, and place it in the binary blob - placeContext(SCOUT_LOADER_BIN, SCOUT_LOADER_BIN, TARGET_ENDIANNESS, TARGET_BITNESS, logger) + placeContext(scout_loader_bin, scout_loader_bin, TARGET_ENDIANNESS, TARGET_BITNESS, logger) return ## @@ -119,7 +119,7 @@ def compileScout(logger): # 4. Compile a PIC scout logger.info('Starting to compile the PIC scout') - compiler.compile(scout_all_files, project_files, EMBEDDED_SCOUT_ELF) + embedded_scout_bin = compiler.compile(scout_all_files, project_files, EMBEDDED_SCOUT_ELF) # 5. Place the PIC context in the resulting binary file generateGOT(symbol_memcpy, symbol_memset, symbol_malloc, symbol_free, symbol_socket, symbol_bind, @@ -130,7 +130,7 @@ def compileScout(logger): generateGlobals(scout_vars_size=scout_instructions_globals_32_size if TARGET_BITNESS else scout_instructions_globals_64_size, project_vars_size=0) # 7. Generate the PIC context, and place it in the binary blob - placeContext(EMBEDDED_SCOUT_BIN, EMBEDDED_SCOUT_BIN, TARGET_ENDIANNESS, TARGET_BITNESS, logger) + placeContext(embedded_scout_bin, embedded_scout_bin, TARGET_ENDIANNESS, TARGET_BITNESS, logger) return ## diff --git a/src/utils/scout_compiler.py b/src/utils/scout_compiler.py index 48e0481..ebd195a 100644 --- a/src/utils/scout_compiler.py +++ b/src/utils/scout_compiler.py @@ -179,6 +179,9 @@ def compile(self, scout_files, project_files, elf_file): Note: If this is a PIC compilation, the final binary file will be named to match the ELF file. For example: "project.elf" => "project.bin". + + Return Value: + Name of the PIC binary file (in PIC compilations), None otherwise. """ self.logger.addIndent() # 1. Auto-Generate the flags.h file @@ -203,7 +206,7 @@ def compile(self, scout_files, project_files, elf_file): systemLine(f"{target_arc.compiler_path} {compile_flags} {' '.join(compilation_files)} {fixed_link_flags} -o {elf_file}", self.logger) self.logger.removeIndent() - return + return None ########################### ## Compiling a PIC Scout ## @@ -252,4 +255,5 @@ def compile(self, scout_files, project_files, elf_file): self.logger.info(f"Extracting the final binary to: {final_file}") systemLine(f"{target_arc.objcopy_path} -O binary -j .text -j .rodata {' '.join(target_arc.objcopy_flags)} {elf_file} {final_file}", self.logger) - self.logger.removeIndent() \ No newline at end of file + self.logger.removeIndent() + return final_file \ No newline at end of file From 51b5b17ed7695bc466e6b98f45ed6e87227919d0 Mon Sep 17 00:00:00 2001 From: chkp-eyalit Date: Sun, 2 May 2021 10:58:03 +0300 Subject: [PATCH 21/30] [refactor] Major refactor to the PIC context generation Now API exposed by the compiler, which passes most of the arguments and removes the duplicate passed flags. --- examples/embedded_scout/src/compile_scout.py | 47 +++--- src/utils/__init__.py | 12 +- src/utils/compilation/__init__.py | 12 +- src/utils/context_creator.py | 146 +++++-------------- src/utils/scout_compiler.py | 71 +++++++-- 5 files changed, 130 insertions(+), 158 deletions(-) diff --git a/examples/embedded_scout/src/compile_scout.py b/examples/embedded_scout/src/compile_scout.py index 22cd610..d465f8f 100644 --- a/examples/embedded_scout/src/compile_scout.py +++ b/examples/embedded_scout/src/compile_scout.py @@ -22,6 +22,8 @@ TARGET_ENDIANNESS = True if TARGET_ARCH == ARC_INTEL else False # Is 32 bits? TARGET_BITNESS = True if TARGET_ARCH != ARC_INTEL else False +# Should the loader use mmap()? +LOADER_USE_MMAP = True # False means we will use malloc() for the loader's memory allocation # Scout Functions (in same order as the c code) symbol_memcpy = 0x80486c0 @@ -39,6 +41,13 @@ symbol_mmap = 0x8048740 symbol_mprotect = 0x8048680 symbol_munmap = 0x8048790 +# The order of the symbols is fixed and MUST NOT be changed +scout_base_got = [ symbol_memcpy, symbol_memset, symbol_malloc, symbol_free, + symbol_socket, symbol_bind, symbol_listen, symbol_accept, symbol_connect, symbol_recv, symbol_send, symbol_close, + ] +if LOADER_USE_MMAP: + scout_base_got += [symbol_mmap, symbol_mprotect, symbol_munmap] + # Loader Functions (none for now) loader_got = [] # Project Functions (none for now) @@ -81,25 +90,17 @@ def compileScoutLoader(logger): # * flag_mmap - The loader will use mmap() instead of malloc() # X flag_load_thumb - If will be loading a Thumb code full Scout # X flag_loader_transmit - If the loader will need to be able to send TCP messages - compiler.addScoutFlags([flag_loader, flag_loader_server, flag_mmap]) + compiler.addScoutFlags([flag_loader, flag_loader_server] + ([flag_mmap] if LOADER_USE_MMAP else [])) # 3. Add custom compilation flags (not needed) # compiler.addCompilationFlags(compile_flags=[], link_flags=[]) - # 4. Compile an embedded scout - logger.info('Starting to compile the scout loader') - scout_loader_bin = compiler.compile(scout_server_loader_deps, loader_pic_files, SCOUT_LOADER_ELF) - - # 5. Place the PIC context in the resulting binary file - generateGOT(symbol_memcpy, symbol_memset, symbol_malloc, symbol_free, symbol_socket, symbol_bind, - symbol_listen, symbol_accept, symbol_connect, symbol_recv, symbol_send, symbol_close, - symbol_mmap, symbol_mprotect, symbol_munmap, project_got=loader_got, is_thumb=TARGET_ARCH == ARC_ARM) + # 4. Populate the GOT entries and allcoate the size for the global variables (non used) + compiler.populateGOT(scout_base_got, loader_got) - # 6. Setup the sizes for the global variables (No variables used at all) - generateGlobals(scout_vars_size=0, project_vars_size=0) - - # 7. Generate the PIC context, and place it in the binary blob - placeContext(scout_loader_bin, scout_loader_bin, TARGET_ENDIANNESS, TARGET_BITNESS, logger) + # 5. Compile an embedded scout (with the PIC context) + logger.info('Starting to compile the scout loader') + compiler.compile(scout_server_loader_deps, loader_pic_files, SCOUT_LOADER_ELF) return ## @@ -117,20 +118,12 @@ def compileScout(logger): # 3. Add custom compilation flags (not needed) # compiler.addCompilationFlags(compile_flags=[], link_flags=[]) - # 4. Compile a PIC scout - logger.info('Starting to compile the PIC scout') - embedded_scout_bin = compiler.compile(scout_all_files, project_files, EMBEDDED_SCOUT_ELF) - - # 5. Place the PIC context in the resulting binary file - generateGOT(symbol_memcpy, symbol_memset, symbol_malloc, symbol_free, symbol_socket, symbol_bind, - symbol_listen, symbol_accept, symbol_connect, symbol_recv, symbol_send, symbol_close, - project_got=project_got) + # 4. Populate the GOT entries and allcoate the size for the global variables (non used) + compiler.populateGOT(scout_base_got, project_got, project_vars_size=0) - # 6. Setup the sizes for the global variables - generateGlobals(scout_vars_size=scout_instructions_globals_32_size if TARGET_BITNESS else scout_instructions_globals_64_size, project_vars_size=0) - - # 7. Generate the PIC context, and place it in the binary blob - placeContext(embedded_scout_bin, embedded_scout_bin, TARGET_ENDIANNESS, TARGET_BITNESS, logger) + # 5. Compile a PIC scout (with the PIC context) + logger.info('Starting to compile the PIC scout') + compiler.compile(scout_all_files, project_files, EMBEDDED_SCOUT_ELF) return ## diff --git a/src/utils/__init__.py b/src/utils/__init__.py index da5f57d..51f6f60 100644 --- a/src/utils/__init__.py +++ b/src/utils/__init__.py @@ -1,6 +1,6 @@ -from .scout_files import * -from .scout_flags import * -from .target_arc import * -from .arc_intel import * -from .arc_arm import * -from .arc_mips import * \ No newline at end of file +# Network API / Utils +import scout_api +import scout_network +# Compilation Scripts +import context_creator +import scout_compiler \ No newline at end of file diff --git a/src/utils/compilation/__init__.py b/src/utils/compilation/__init__.py index 51f6f60..da5f57d 100644 --- a/src/utils/compilation/__init__.py +++ b/src/utils/compilation/__init__.py @@ -1,6 +1,6 @@ -# Network API / Utils -import scout_api -import scout_network -# Compilation Scripts -import context_creator -import scout_compiler \ No newline at end of file +from .scout_files import * +from .scout_flags import * +from .target_arc import * +from .arc_intel import * +from .arc_arm import * +from .arc_mips import * \ No newline at end of file diff --git a/src/utils/context_creator.py b/src/utils/context_creator.py index 343348e..6f845e7 100644 --- a/src/utils/context_creator.py +++ b/src/utils/context_creator.py @@ -1,16 +1,11 @@ -#!/usr/bin/python - -import os -import sys -import time import struct ############################# ## Static Configurations ## ############################# -GOT_START_MARKER = struct.pack(">L", 0x11222211) -GOT_END_MARKER = struct.pack(">L", 0x33444433) +GOT_START_MARKER = struct.pack(">L", 0x11222211) +GOT_END_MARKER = struct.pack(">L", 0x33444433) # Variables (sizes only) scout_instructions_globals_32_size = 4 + 10 * 16 @@ -18,125 +13,60 @@ scout_static_buffers_32_size = 0x1006 + 2 + 0x1000 scout_static_buffers_64_size = 0x1006 + 2 + 0x1000 -######################## -## Global Variables ## -######################## - -globals_size = None -full_got = None - -def generateGOT(symbol_memcpy, symbol_memset, symbol_malloc, symbol_free, symbol_socket, symbol_bind, - symbol_listen, symbol_accept, symbol_connect, symbol_recv, symbol_send, symbol_close, - symbol_mmap=None, symbol_mprotect=None, symbol_munmap=None, project_got=[], is_thumb=False): - """Generates the Global Offset Table (GOT) content using the supplied addresses - - Args: - symbol_memcpy (int): (virtual) address of the memcpy() function in the hosting address space - symbol_memset (int): (virtual) address of the memset() function in the hosting address space - symbol_malloc (int): (virtual) address of the malloc() function in the hosting address space - symbol_free (int): (virtual) address of the free() function in the hosting address space - symbol_socket (int): (virtual) address of the socket() function in the hosting address space - symbol_bind (int): (virtual) address of the bind() function in the hosting address space - symbol_listen (int): (virtual) address of the listen() function in the hosting address space - symbol_accept (int): (virtual) address of the accept() function in the hosting address space - symbol_connect (int): (virtual) address of the connect() function in the hosting address space - symbol_recv (int): (virtual) address of the send() function in the hosting address space - symbol_close (int): (virtual) address of the close() function in the hosting address space - symbol_mmap (int, optional): (virtual) address of the mmap() function, or None if unused (None by default) - symbol_mprotect (int, optional): (virtual) address of the mprotect() function, or None if unused (None by default) - symbol_munmap (int, optional): (virtual) address of the munmap() function, or None if unused (None by default) - project_got (list): list of additional memory addresses for symbols used in the project's GOT - is_thumb (bool): True iff the scout was compiled to be executed inside an ARM thumb binary - """ - global full_got - - full_got = [ symbol_memcpy, symbol_memset, symbol_malloc, symbol_free, - symbol_socket, symbol_bind, symbol_listen, symbol_accept, symbol_connect, symbol_recv, symbol_send, symbol_close, - ] - if symbol_mmap is not None: - full_got += [symbol_mmap, symbol_mprotect, symbol_munmap] - - full_got += project_got - - # Check if we need to adjust it - if is_thumb: - full_got = [x + 1 for x in full_got] - -def generateGlobals(scout_vars_size=scout_instructions_globals_32_size, project_vars_size=0): - """Configures the globals blob using the supplied sizes - - Args: - scout_vars_size (numeric): size in bytes of the base scout's globals (scout_instructions_globals_32_size by default) - project_vars_size (numeric): size in bytes of the project's scout globals (0 by default) - """ - global globals_size - - globals_size = scout_vars_size + project_vars_size - -def createContext(is_little_endian, is_32_bit): - """Creates the PIC context matching the target's architecture - - Args: - is_little_endian (bool): True iff the scout was compiled to little endian - is_32_bit (bool): True iff the scout was compiled to 32 bits - """ - got = b'' - # functions - for func in full_got: - got += struct.pack(("<" if is_little_endian else ">") + ("L" if is_32_bit else "Q"), func) - # globals - got += b'\x00' * globals_size - # functions - return got - -def placeContext(compiled_file, shellcode_file, is_little_endian, is_32_bit, logger): +scout_got_base_size = 11 +scout_got_base_size_mmap = scout_got_base_size + 3 +# Scout GOT symbols order: +# * memcpy +# * memset +# * malloc +# * free +# * socket +# * bind +# * listen +# * accept +# * connect +# * recv +# * close +# If compiled using MMAP, we also have the following: +# * mmap +# * mprotect +# * munmap + +def placeContext(got, globals, binary_file, logger): """Embedds the PIC context into the compiled binary blob Args: - compiled_file (string): path to the compiled PIC binary (NOT the ELF) - shellcode_file (string): path to the (created) full PIC shellcode - is_little_endian (bool): True iff the scout was compiled to little endian - is_32_bit (bool): True iff the scout was compiled to 32 bits + got (bytes): Content of the PIC GOT + globals (bytes): Content of the PIC global variables + binary_file (string): path to the PIC binary that will host the context logger (logger): (elementals) logger """ - # 0. Sanity checks - if globals_size is None: - logger.error("Undefined size for the global variables...") - return - - if full_got is None: - logger.error("Undefined function addresses for the GOT...") - return - # 1. Open the file (read) - fd = open(compiled_file, "rb") - raw_shellcode = fd.read() + fd = open(binary_file, "rb") + raw_binary = fd.read() fd.close() # 2. Locate the GOT - got_start = raw_shellcode.find(GOT_START_MARKER) - got_end = raw_shellcode.find(GOT_END_MARKER) + len(GOT_END_MARKER) + got_start = raw_binary.find(GOT_START_MARKER) + got_end = raw_binary.find(GOT_END_MARKER) + len(GOT_END_MARKER) # Sanity check if got_start < 0 or got_end <= got_start: - logger.error("Failed to locate the GOT markers in the shellcode") + logger.error("Failed to locate the GOT markers in the PIC binary") return - # 3. Generate the needed values - logger.info("Generating the context values") - wanted_context = createContext(is_little_endian, is_32_bit) - - # 4. Size checking + # 3. Size checking + wanted_context = got + globals if got_end - got_start != len(wanted_context): logger.error("Mismatching context sizes, found 0x%x and generated 0x%x", got_end - got_start, len(wanted_context)) return - # 5. Update the value + # 4. Update the value logger.info("Placing the generated context in it's place") - shellcode = raw_shellcode[:got_start] + wanted_context + raw_shellcode[got_end:] + pic_binary = raw_binary[:got_start] + wanted_context + raw_binary[got_end:] - # 6. Open the file (write) - fd = open(shellcode_file, "wb") - fd.write(shellcode) + # 5. Open the file (write) + fd = open(binary_file, "wb") + fd.write(pic_binary) fd.close() - logger.info(f"Complete shellcode was saved to: {shellcode_file}") + logger.info(f"Complete PIC binary was saved to: {binary_file}") diff --git a/src/utils/scout_compiler.py b/src/utils/scout_compiler.py index ebd195a..6f8cdcb 100644 --- a/src/utils/scout_compiler.py +++ b/src/utils/scout_compiler.py @@ -1,6 +1,4 @@ import os -import sys -import time import struct from .compilation.scout_flags import * @@ -8,6 +6,7 @@ from .compilation.arc_intel import arcIntel from .compilation.arc_arm import arcArm, arcArmThumb from .compilation.arc_mips import arcMips +from .context_creator import * ################################### ## Architecture Configurations ## @@ -57,7 +56,12 @@ def __init__(self, logger): self.target_arc = None self.project_folder = None self.scout_folder = None - self.config_flags = [] + self.config_flags = [] + self.is_32_bits = True + self.is_little_endian = True + self.is_pic = False + self.full_got = b'' + self.global_vars = b'' def setArc(self, arc, is_pic, is_32_bits=True, is_little_endian=True, is_native=False): """Sets the target's architecture specifications @@ -74,6 +78,7 @@ def setArc(self, arc, is_pic, is_32_bits=True, is_little_endian=True, is_native= self.logger.error("Unknown architecture: \"%s\". Supported options are: \"%s\"", arc, ', '.join(arc_factory.keys())) # Apply the chosen settings + self.is_pic = is_pic self.target_arc = arc_factory[arc](is_pic) if is native: target_arc.config_flags.append(flag_native_compiler) @@ -83,11 +88,13 @@ def setArc(self, arc, is_pic, is_32_bits=True, is_little_endian=True, is_native= # Configure the architecture target_arc.setEndianness(is_little_endian) target_arc.setBitness(is_32_bits) + self.is_32_bits = is_32_bits + self.is_little_endian = is_little_endian # Store the values for the configuration flags self.config_flags.append(flag_32_bit if is_32_bits else flag_64_bit) self.config_flags.append(flag_little_endian if is_little_endian else flag_big_endian) - if is_pic: + if self.is_pic: self.config_flags.append(flag_pic_code) def setScoutMode(self, is_user): @@ -168,6 +175,45 @@ def generateFlagsFile(self): # can close the file fd.close() + def populateGOT(self, scout_got, project_got, project_vars_size=0): + """Populates the PIC context with the GOT entries, and capacity for global variables. + + Args: + scout_got (list): list of (virtual) addresses according to Scout's GOT order + project_got (list): list of additional memory addresses for symbols used in the project's GOT + projects_vars_size (int, optional): size (in bytes) of the project's global variables (0 by default) + """ + # Sanity Check #1 - PIC Compilation + if not self.is_pic: + self.logger.error("Can't populate a PIC context (GOT and globals) for a non-PIC compilation!") + return + + # Sanity Check #2 - GOT Size + expected_size = scout_got_base_size_mmap if flag_mmap in self.config_flags else scout_got_base_size + if len(scout_got) != expected_size: + self.logger.error(f"Wrong size for Scout's GOT: Expected {expected_size} entries, and got {len(scout_got)}!") + return + + format = ("<" if self.is_little_endian else ">") + ("L" if self.is_32_bits else "Q") + is_thumb = self.target_arc.name() == ARC_ARM_THUMB + self.full_got = b''.join([struct.pack(format, func + (1 if is_thumb else 0)) for func in scout_got + project_got]) + + # Calculate the size for the global variables + size_globals = project_vars_size + # The base loaders don't use global variables, only the full scout + if flag_loader not in self.config_flags: + if flag_instructions in self.config_flags: + if self.is_32_bits: + size_globals += scout_instructions_globals_32_size + if flag_dynamic_buffers not in self.config_flags: + size_globals += scout_static_buffers_32_size + else: + size_globals += scout_instructions_globals_64_size + if flag_dynamic_buffers not in self.config_flags: + size_globals += scout_static_buffers_64_size + # Now generate the blob + self.global_vars = b'\x00' * size_globals + def compile(self, scout_files, project_files, elf_file): """Compiles the "Scout" project, according to the PIC setup that was defined earlier. @@ -197,7 +243,7 @@ def compile(self, scout_files, project_files, elf_file): ## Compiling an Executable ## ############################# - if flag_pic_code not in self.config_flags: + if not self.is_pic: # 4. Re-organize the linker flags fixed_link_flags = "".join("-Wl," + x for x in link_flags.split("-")[1:]) @@ -229,7 +275,7 @@ def compile(self, scout_files, project_files, elf_file): fd.close() content = content.replace(".space #", ".space ").replace(".space $", ".space ") # Mips: convert the calls to relative (PIC) - if self.target_arc.name() == arcMips.name(): + if self.target_arc.name() == ARC_MIPS: content = content.replace("\tjal\t", "\tbal\t").replace("\tj\t", "\tb\t") fd = open(s_file, "w") fd.write(content) @@ -249,11 +295,14 @@ def compile(self, scout_files, project_files, elf_file): # 8. Objcopy the content to the actual wanted file if elf_file.split('.')[0].lower() == "elf": - final_file = '.'.join(elf_file.split('.')[:-1] + ['bin']) + binary_file = '.'.join(elf_file.split('.')[:-1] + ['bin']) else: - final_file = elf_file + ".bin" - self.logger.info(f"Extracting the final binary to: {final_file}") - systemLine(f"{target_arc.objcopy_path} -O binary -j .text -j .rodata {' '.join(target_arc.objcopy_flags)} {elf_file} {final_file}", self.logger) + binary_file = elf_file + ".bin" + self.logger.info(f"Extracting the final binary to: {binary_file}") + systemLine(f"{target_arc.objcopy_path} -O binary -j .text -j .rodata {' '.join(target_arc.objcopy_flags)} {elf_file} {binary_file}", self.logger) + + # 9. Place the PIC context inside the file + placeContext(self.full_got, self.global_vars, binary_file, self.logger) self.logger.removeIndent() - return final_file \ No newline at end of file + return binary_file \ No newline at end of file From bfc2eaa1d252846a12a086ddeb04572441caf9ee Mon Sep 17 00:00:00 2001 From: chkp-eyalit Date: Sun, 2 May 2021 11:00:38 +0300 Subject: [PATCH 22/30] [bugfix] Wrong amount of GOT entries Fixed the order (and size) of the base GOT --- src/utils/context_creator.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/utils/context_creator.py b/src/utils/context_creator.py index 6f845e7..8c222d4 100644 --- a/src/utils/context_creator.py +++ b/src/utils/context_creator.py @@ -13,7 +13,7 @@ scout_static_buffers_32_size = 0x1006 + 2 + 0x1000 scout_static_buffers_64_size = 0x1006 + 2 + 0x1000 -scout_got_base_size = 11 +scout_got_base_size = 12 scout_got_base_size_mmap = scout_got_base_size + 3 # Scout GOT symbols order: # * memcpy @@ -26,6 +26,7 @@ # * accept # * connect # * recv +# * send # * close # If compiled using MMAP, we also have the following: # * mmap From dd3aa612714777824b935aad6984df82611c6a56 Mon Sep 17 00:00:00 2001 From: chkp-eyalit Date: Sun, 2 May 2021 11:58:01 +0300 Subject: [PATCH 23/30] [standards] Aligned all files to the coding standards Both docs and the code itself are now complete and adhere to the coding standards in both C and Python files. --- .../manager/embedded_scout_api.py | 14 ++-- examples/embedded_scout/manager/manager.py | 5 +- examples/embedded_scout/src/compile_scout.py | 53 ++++++------ examples/embedded_scout/src/loader_plt.c | 1 - .../embedded_scout/src/project_instructions.h | 2 +- examples/embedded_scout/src/project_plt.c | 1 - examples/kernel_scout/driver/Makefile | 2 +- examples/kernel_scout/driver/flags.h | 2 +- examples/kernel_scout/driver/scout_driver.c | 2 +- .../driver/scout_kernel_instructions.c | 2 +- .../driver/scout_kernel_instructions.h | 2 +- .../kernel_scout/manager/kernel_scout_api.py | 24 +++--- examples/kernel_scout/manager/manager.py | 5 +- .../kernel_scout/user_mode/compile_scout.py | 13 ++- examples/kernel_scout/user_mode/scout_user.c | 2 +- src/scout/arc/arm.c | 2 +- src/scout/arc/arm.h | 2 +- src/scout/arc/intel.c | 2 +- src/scout/arc/intel.h | 2 +- src/scout/arc/mips.c | 2 +- src/scout/arc/mips.h | 2 +- src/scout/architecture.h | 2 +- src/scout/external_deps.h | 2 +- src/scout/loaders/loader.h | 2 +- src/scout/loaders/tcp_client_loader.c | 2 +- src/scout/loaders/tcp_server_loader.c | 2 +- src/scout/pack.c | 2 +- src/scout/pack.h | 2 +- src/scout/pic/arm_pic_wrapper.c | 2 +- src/scout/pic/intel_pic_wrapper.c | 2 +- src/scout/pic/mips_pic_wrapper.c | 2 +- src/scout/pic/pic_wrapper.h | 2 +- src/scout/pic/scout_globals.c | 2 +- src/scout/pic/scout_plt.c | 2 +- src/scout/pic/scout_plt.h | 2 +- src/scout/scout.h | 2 +- src/scout/scout_api.c | 2 +- src/scout/scout_api.h | 2 +- src/scout/tcp_server.c | 2 +- src/scout/tcp_server.h | 2 +- src/utils/compilation/arc_arm.py | 62 ++++++++++++-- src/utils/compilation/arc_intel.py | 32 ++++++-- src/utils/compilation/arc_mips.py | 37 +++++++-- src/utils/compilation/scout_flags.py | 50 +++++------ src/utils/compilation/target_arc.py | 71 ++++++++++++---- src/utils/context_creator.py | 2 +- src/utils/scout_api.py | 66 ++++++++------- src/utils/scout_compiler.py | 82 ++++++++++++------- src/utils/scout_network.py | 10 +-- 49 files changed, 372 insertions(+), 220 deletions(-) diff --git a/examples/embedded_scout/manager/embedded_scout_api.py b/examples/embedded_scout/manager/embedded_scout_api.py index ab79c4b..86ded77 100644 --- a/examples/embedded_scout/manager/embedded_scout_api.py +++ b/examples/embedded_scout/manager/embedded_scout_api.py @@ -1,11 +1,11 @@ -from scout_api import * +from scout.scout_api import * ############################## ## Extended API Error Codes ## ############################## -embedded_error_codes = { # Example for a project-specific error code - 30 : "STATUS_INVALID_FREE", +embedded_error_codes = { # Example for a project-specific error code + 30: "STATUS_INVALID_FREE", } addErrorCodes(embedded_error_codes) @@ -24,22 +24,22 @@ def instrAlloc(size): """Allocates a memory buffer on the target - + Args: size (int): size (in bytes) of the desired memory allocation Return Value: string containing the serialized instruction """ - return addHeader( EMBEDDED_INST_ALLOC, struct.pack("!L", size) ) + return addHeader(EMBEDDED_INST_ALLOC, struct.pack("!L", size)) def instrFree(address): """Frees a memory allocation on the target, on the specified address - + Args: address (int): memory address of the desired memory allocation Return Value: string containing the serialized instruction """ - return addHeader( EMBEDDED_INST_FREE, struct.pack("!L", address) ) \ No newline at end of file + return addHeader(EMBEDDED_INST_FREE, struct.pack("!L", address)) diff --git a/examples/embedded_scout/manager/manager.py b/examples/embedded_scout/manager/manager.py index e802694..b8ee9ae 100644 --- a/examples/embedded_scout/manager/manager.py +++ b/examples/embedded_scout/manager/manager.py @@ -6,9 +6,7 @@ import logging import struct -import time import socket -import os import sys ## @@ -64,5 +62,6 @@ def main(args): prompter.info('Finished Successfully') + if __name__ == '__main__': - main(sys.argv) \ No newline at end of file + main(sys.argv) diff --git a/examples/embedded_scout/src/compile_scout.py b/examples/embedded_scout/src/compile_scout.py index d465f8f..b7ca6e5 100644 --- a/examples/embedded_scout/src/compile_scout.py +++ b/examples/embedded_scout/src/compile_scout.py @@ -1,12 +1,9 @@ #!/usr/bin/python import os import sys -import time -import struct from elementals import Prompter -from scout.scout_compiler import * -from scout.context_creator import * +from scout.scout_compiler import * ############################## ## Dynamic Configurations ## @@ -23,28 +20,27 @@ # Is 32 bits? TARGET_BITNESS = True if TARGET_ARCH != ARC_INTEL else False # Should the loader use mmap()? -LOADER_USE_MMAP = True # False means we will use malloc() for the loader's memory allocation +LOADER_USE_MMAP = True # False means we will use malloc() for the loader's memory allocation # Scout Functions (in same order as the c code) -symbol_memcpy = 0x80486c0 -symbol_memset = 0x8048770 -symbol_malloc = 0x80486f0 -symbol_free = 0x80486b0 -symbol_socket = 0x80487b0 -symbol_bind = 0x8048760 -symbol_listen = 0x80487a0 -symbol_accept = 0x80486e0 -symbol_connect = 0x80487c0 -symbol_recv = 0x80487d0 -symbol_send = 0x80487f0 -symbol_close = 0x80487e0 -symbol_mmap = 0x8048740 -symbol_mprotect = 0x8048680 -symbol_munmap = 0x8048790 +symbol_memcpy = 0x80486c0 +symbol_memset = 0x8048770 +symbol_malloc = 0x80486f0 +symbol_free = 0x80486b0 +symbol_socket = 0x80487b0 +symbol_bind = 0x8048760 +symbol_listen = 0x80487a0 +symbol_accept = 0x80486e0 +symbol_connect = 0x80487c0 +symbol_recv = 0x80487d0 +symbol_send = 0x80487f0 +symbol_close = 0x80487e0 +symbol_mmap = 0x8048740 +symbol_mprotect = 0x8048680 +symbol_munmap = 0x8048790 # The order of the symbols is fixed and MUST NOT be changed -scout_base_got = [ symbol_memcpy, symbol_memset, symbol_malloc, symbol_free, - symbol_socket, symbol_bind, symbol_listen, symbol_accept, symbol_connect, symbol_recv, symbol_send, symbol_close, - ] +scout_base_got = [symbol_memcpy, symbol_memset, symbol_malloc, symbol_free, + symbol_socket, symbol_bind, symbol_listen, symbol_accept, symbol_connect, symbol_recv, symbol_send, symbol_close] if LOADER_USE_MMAP: scout_base_got += [symbol_mmap, symbol_mprotect, symbol_munmap] @@ -65,16 +61,16 @@ def setTargetFlags(logger): # 0. Create the compiler instance compiler = scoutCompiler(logger) - - # 1. Set the architecture + + # 1. Set the architecture compiler.setArc(TARGET_ARCH, is_pic=True, is_32_bits=TARGET_BITNESS, is_little_endian=TARGET_ENDIANNESS) # 2. Set the permission mode (User & low CPU permissions, Kernel & High CPU permissions) compiler.setScoutMode(is_user=True) - + # 3. Set the working directories compiler.setWorkingDirs(project_dir='.', scout_dir=SCOUT_DIR) - + return compiler ## @@ -153,5 +149,6 @@ def main(args): prompter.info('Finished Successfully') + if __name__ == '__main__': - main(sys.argv) \ No newline at end of file + main(sys.argv) diff --git a/examples/embedded_scout/src/loader_plt.c b/examples/embedded_scout/src/loader_plt.c index 7490aa8..924861c 100644 --- a/examples/embedded_scout/src/loader_plt.c +++ b/examples/embedded_scout/src/loader_plt.c @@ -4,5 +4,4 @@ /* No special functions for now */ - #endif /* SCOUT_PIC_CODE */ diff --git a/examples/embedded_scout/src/project_instructions.h b/examples/embedded_scout/src/project_instructions.h index efcef98..d213f21 100644 --- a/examples/embedded_scout/src/project_instructions.h +++ b/examples/embedded_scout/src/project_instructions.h @@ -64,4 +64,4 @@ int32_t instruction_free(void * ctx, uint8_t * instruction, uint32_t length); #define INSTR_FREE_MAX_SIZE (sizeof(addr_t)) #define INSTR_FREE_HANDLER instruction_free -#endif // __SCOUT__EMBEDDED__INSTRUCTIONS__H__ \ No newline at end of file +#endif // __SCOUT__EMBEDDED__INSTRUCTIONS__H__ diff --git a/examples/embedded_scout/src/project_plt.c b/examples/embedded_scout/src/project_plt.c index 3ffffd7..72fcd33 100644 --- a/examples/embedded_scout/src/project_plt.c +++ b/examples/embedded_scout/src/project_plt.c @@ -4,5 +4,4 @@ /* No special functions for now */ - #endif /* SCOUT_PIC_CODE */ diff --git a/examples/kernel_scout/driver/Makefile b/examples/kernel_scout/driver/Makefile index d0a38bf..cb8a2c6 100644 --- a/examples/kernel_scout/driver/Makefile +++ b/examples/kernel_scout/driver/Makefile @@ -18,4 +18,4 @@ clean: $(RM) -f $(SCOUT_SRC)/*.o # Clean this project and all dependencies -cleanall: clean \ No newline at end of file +cleanall: clean diff --git a/examples/kernel_scout/driver/flags.h b/examples/kernel_scout/driver/flags.h index 49fbed4..2766715 100644 --- a/examples/kernel_scout/driver/flags.h +++ b/examples/kernel_scout/driver/flags.h @@ -10,4 +10,4 @@ #define SCOUT_MODE_KERNEL #define SCOUT_INSTRUCTIONS -#endif /* __KERNEL__SCOUT__FLAGS__H__ */ \ No newline at end of file +#endif /* __KERNEL__SCOUT__FLAGS__H__ */ diff --git a/examples/kernel_scout/driver/scout_driver.c b/examples/kernel_scout/driver/scout_driver.c index 3551ae1..fae3cd1 100644 --- a/examples/kernel_scout/driver/scout_driver.c +++ b/examples/kernel_scout/driver/scout_driver.c @@ -170,4 +170,4 @@ MODULE_DESCRIPTION("Scout based debug driver"); MODULE_LICENSE("GPL"); module_init(scout_init); -module_exit(scout_exit); \ No newline at end of file +module_exit(scout_exit); diff --git a/examples/kernel_scout/driver/scout_kernel_instructions.c b/examples/kernel_scout/driver/scout_kernel_instructions.c index 078c39a..f3a4737 100644 --- a/examples/kernel_scout/driver/scout_kernel_instructions.c +++ b/examples/kernel_scout/driver/scout_kernel_instructions.c @@ -56,4 +56,4 @@ int instruction_leak_addr(void * c, uint8_t * instruction, uint32_t length) printk(KERN_NOTICE "SCOUT-KERNEL: virt addres is 0x%p, phys is 0x%p\n", add_input_randomness, (void *)virt_to_phys(add_input_randomness)); return STATUS_OK; -} \ No newline at end of file +} diff --git a/examples/kernel_scout/driver/scout_kernel_instructions.h b/examples/kernel_scout/driver/scout_kernel_instructions.h index 2d7ee2a..2fe846d 100644 --- a/examples/kernel_scout/driver/scout_kernel_instructions.h +++ b/examples/kernel_scout/driver/scout_kernel_instructions.h @@ -87,4 +87,4 @@ int instruction_leak_addr(void * ctx, uint8_t * instruction, uint32_t length); #define INSTR_LEAK_ADDR_MAX_SIZE 0 #define INSTR_LEAK_ADDR_HANDLER instruction_leak_addr -#endif // __KERNEL__SCOUT__INSTRUCTIONS__H__ \ No newline at end of file +#endif // __KERNEL__SCOUT__INSTRUCTIONS__H__ diff --git a/examples/kernel_scout/manager/kernel_scout_api.py b/examples/kernel_scout/manager/kernel_scout_api.py index 172b0d3..4815e54 100644 --- a/examples/kernel_scout/manager/kernel_scout_api.py +++ b/examples/kernel_scout/manager/kernel_scout_api.py @@ -4,7 +4,7 @@ ## Extended API Error Codes ## ############################## -kernel_error_codes = { # Empty for now +kernel_error_codes = { # Empty for now } addErrorCodes(kernel_error_codes) @@ -24,8 +24,8 @@ # kernel instructions def instrPhyRead(addr, length): - """Builds the Read Physical Memory instruction - + """Build the Read Physical Memory instruction. + Args: addr (numeric): physical memory address length (numeric): number of bytes to be read form the given address @@ -33,12 +33,12 @@ def instrPhyRead(addr, length): Return Value: string containing the serialized instruction """ - instr = struct.pack( "!QL" if TARGET_BITNESS == 64 else "!LL", addr, length ) - return addHeader( SCOUT_INST_PHY_READ, instr ) + instr = struct.pack("!QL" if TARGET_BITNESS == 64 else "!LL", addr, length) + return addHeader(SCOUT_INST_PHY_READ, instr) def instrPhyWrite(addr, content): - """Builds the Write Physical Memory instruction - + """Build the Write Physical Memory instruction. + Args: addr (numeric): physical memory address content (string): binary data to be written to the given address @@ -46,16 +46,16 @@ def instrPhyWrite(addr, content): Return Value: string containing the serialized instruction """ - instr = struct.pack( "!Q" if TARGET_BITNESS == 64 else "!L", addr ) + content - return addHeader( SCOUT_INST_PHY_READ, instr ) + instr = struct.pack("!Q" if TARGET_BITNESS == 64 else "!L", addr) + content + return addHeader(SCOUT_INST_PHY_READ, instr) def instrLeakAddr(): - """Builds the Leak Kernel Address instruction - + """Build the Leak Kernel Address instruction. + Args: (none) Return Value: string containing the serialized instruction """ - return addHeader( SCOUT_INST_LEAK_ADDR, b'' ) \ No newline at end of file + return addHeader(SCOUT_INST_LEAK_ADDR, b'') diff --git a/examples/kernel_scout/manager/manager.py b/examples/kernel_scout/manager/manager.py index 8ea96bc..257afd7 100644 --- a/examples/kernel_scout/manager/manager.py +++ b/examples/kernel_scout/manager/manager.py @@ -6,9 +6,7 @@ import logging import struct -import time import socket -import os import sys ## @@ -64,5 +62,6 @@ def main(args): prompter.info('Finished Successfully') + if __name__ == '__main__': - main(sys.argv) \ No newline at end of file + main(sys.argv) diff --git a/examples/kernel_scout/user_mode/compile_scout.py b/examples/kernel_scout/user_mode/compile_scout.py index d444cb9..0c26461 100644 --- a/examples/kernel_scout/user_mode/compile_scout.py +++ b/examples/kernel_scout/user_mode/compile_scout.py @@ -1,8 +1,6 @@ #!/usr/bin/python import os import sys -import time -import struct from elementals import Prompter from scout.scout_compiler import * @@ -26,16 +24,16 @@ def setTargetFlags(logger): # 0. Create the compiler instance compiler = scoutCompiler(logger, is_pic=False) - + # 1. Set the architecture compiler.setArc(TARGET_ARCH) # 2. Set the permission mode (User & low CPU permissions, Kernel & High CPU permissions) compiler.setScoutMode(is_user=True) - + # 3. Set the working directories compiler.setWorkingDirs(project_dir='.', scout_dir=SCOUT_DIR) - + return compiler ## @@ -70,7 +68,7 @@ def printUsage(args): ## # Main function ## -def main(args) : +def main(args): # Check the arguments (None for now) if len(args) != 1 + 0: print(f'Wrong amount of arguments, got {len(args) - 1}, expected 0') @@ -84,5 +82,6 @@ def main(args) : prompter.info('Finished Successfully') + if __name__ == '__main__': - main(sys.argv) \ No newline at end of file + main(sys.argv) diff --git a/examples/kernel_scout/user_mode/scout_user.c b/examples/kernel_scout/user_mode/scout_user.c index fee2d2b..0f8070a 100644 --- a/examples/kernel_scout/user_mode/scout_user.c +++ b/examples/kernel_scout/user_mode/scout_user.c @@ -90,4 +90,4 @@ int main(int argc, char** argv) printf("press any key to continue...\n"); fgetc(stdin); return 0; -} \ No newline at end of file +} diff --git a/src/scout/arc/arm.c b/src/scout/arc/arm.c index 6ed062f..ef60004 100644 --- a/src/scout/arc/arm.c +++ b/src/scout/arc/arm.c @@ -33,4 +33,4 @@ void flush_cache(uint8_t * buffer, uint32_t size) #endif } -#endif /* SCOUT_ARCH_ARM */ \ No newline at end of file +#endif /* SCOUT_ARCH_ARM */ diff --git a/src/scout/arc/arm.h b/src/scout/arc/arm.h index 98ec5e3..8796779 100644 --- a/src/scout/arc/arm.h +++ b/src/scout/arc/arm.h @@ -21,4 +21,4 @@ void flush_cache(uint8_t * buffer, uint32_t size); #endif /* SCOUT_ARCH_ARM */ -#endif /* __SCOUT__ARC__ARM__H__ */ \ No newline at end of file +#endif /* __SCOUT__ARC__ARM__H__ */ diff --git a/src/scout/arc/intel.c b/src/scout/arc/intel.c index 67ece80..1c374e6 100644 --- a/src/scout/arc/intel.c +++ b/src/scout/arc/intel.c @@ -10,4 +10,4 @@ void flush_cache(uint8_t * buffer, uint32_t size) /* Intel has no caches that we need to flush :) */ } -#endif /* SCOUT_ARCH_INTEL */ \ No newline at end of file +#endif /* SCOUT_ARCH_INTEL */ diff --git a/src/scout/arc/intel.h b/src/scout/arc/intel.h index 446651a..ee7aea1 100644 --- a/src/scout/arc/intel.h +++ b/src/scout/arc/intel.h @@ -21,4 +21,4 @@ void flush_cache(uint8_t * buffer, uint32_t size); #endif /* SCOUT_ARCH_INTEL */ -#endif /* __SCOUT__ARC__INTEL__H__ */ \ No newline at end of file +#endif /* __SCOUT__ARC__INTEL__H__ */ diff --git a/src/scout/arc/mips.c b/src/scout/arc/mips.c index d6afab5..6ffbcbd 100644 --- a/src/scout/arc/mips.c +++ b/src/scout/arc/mips.c @@ -11,4 +11,4 @@ void flush_cache(uint8_t * buffer, uint32_t size) #endif } -#endif /* SCOUT_ARCH_MIPS */ \ No newline at end of file +#endif /* SCOUT_ARCH_MIPS */ diff --git a/src/scout/arc/mips.h b/src/scout/arc/mips.h index 9e22a35..e385119 100644 --- a/src/scout/arc/mips.h +++ b/src/scout/arc/mips.h @@ -21,4 +21,4 @@ void flush_cache(uint8_t * buffer, uint32_t size); #endif /* SCOUT_ARCH_MIPS */ -#endif /* __SCOUT__ARC__MIPS__H__ */ \ No newline at end of file +#endif /* __SCOUT__ARC__MIPS__H__ */ diff --git a/src/scout/architecture.h b/src/scout/architecture.h index 1f069c9..5bb79c6 100644 --- a/src/scout/architecture.h +++ b/src/scout/architecture.h @@ -130,4 +130,4 @@ typedef uint64_t addr_t; #define SCOUT_SLIM_SIZE #endif -#endif // __SCOUT__ARCHITECTURE__H__ \ No newline at end of file +#endif // __SCOUT__ARCHITECTURE__H__ diff --git a/src/scout/external_deps.h b/src/scout/external_deps.h index c49d854..0fc7ba0 100644 --- a/src/scout/external_deps.h +++ b/src/scout/external_deps.h @@ -108,4 +108,4 @@ int munmap(void * addr, size_t length); #endif /* SCOUT_ISOLATED_ENV */ -#endif // __SCOUT__EXTERNAL__DEPS__H__ \ No newline at end of file +#endif // __SCOUT__EXTERNAL__DEPS__H__ diff --git a/src/scout/loaders/loader.h b/src/scout/loaders/loader.h index fa65edf..60d922c 100644 --- a/src/scout/loaders/loader.h +++ b/src/scout/loaders/loader.h @@ -18,4 +18,4 @@ #endif /* SCOUT_LOADER */ -#endif /* __SCOUT__LOADER__H__ */ \ No newline at end of file +#endif /* __SCOUT__LOADER__H__ */ diff --git a/src/scout/loaders/tcp_client_loader.c b/src/scout/loaders/tcp_client_loader.c index f4c7b4b..b06570f 100644 --- a/src/scout/loaders/tcp_client_loader.c +++ b/src/scout/loaders/tcp_client_loader.c @@ -79,4 +79,4 @@ void main() } #endif /* SCOUT_RESTORE_FLOW */ return; -} \ No newline at end of file +} diff --git a/src/scout/loaders/tcp_server_loader.c b/src/scout/loaders/tcp_server_loader.c index 12dab7a..687662a 100644 --- a/src/scout/loaders/tcp_server_loader.c +++ b/src/scout/loaders/tcp_server_loader.c @@ -96,4 +96,4 @@ void main() } #endif /* SCOUT_RESTORE_FLOW */ return; -} \ No newline at end of file +} diff --git a/src/scout/pack.c b/src/scout/pack.c index 3b5e602..302e983 100644 --- a/src/scout/pack.c +++ b/src/scout/pack.c @@ -170,4 +170,4 @@ uint64_t ntohq(uint64_t value) #endif /* SCOUT_LITTLE_ENDIAN */ } -#endif /* SCOUT_ISOLATED_ENV */ \ No newline at end of file +#endif /* SCOUT_ISOLATED_ENV */ diff --git a/src/scout/pack.h b/src/scout/pack.h index 9643b2f..d27d139 100644 --- a/src/scout/pack.h +++ b/src/scout/pack.h @@ -191,4 +191,4 @@ uint64_t ntohq(uint64_t value); #endif /* SCOUT_ISOLATED_ENV */ -#endif // __SCOUT__PACK__H__ \ No newline at end of file +#endif // __SCOUT__PACK__H__ diff --git a/src/scout/pic/arm_pic_wrapper.c b/src/scout/pic/arm_pic_wrapper.c index c225777..a276756 100644 --- a/src/scout/pic/arm_pic_wrapper.c +++ b/src/scout/pic/arm_pic_wrapper.c @@ -68,4 +68,4 @@ void dummy_context() } #endif /* SCOUT_ARCH_ARM */ -#endif /* SCOUT_PIC_CODE */ \ No newline at end of file +#endif /* SCOUT_PIC_CODE */ diff --git a/src/scout/pic/intel_pic_wrapper.c b/src/scout/pic/intel_pic_wrapper.c index 3fd91ca..f98e759 100644 --- a/src/scout/pic/intel_pic_wrapper.c +++ b/src/scout/pic/intel_pic_wrapper.c @@ -73,4 +73,4 @@ void code_start() } #endif /* SCOUT_ARCH_INTEL */ -#endif /* SCOUT_PIC_CODE */ \ No newline at end of file +#endif /* SCOUT_PIC_CODE */ diff --git a/src/scout/pic/mips_pic_wrapper.c b/src/scout/pic/mips_pic_wrapper.c index 738d3b0..f1885b2 100644 --- a/src/scout/pic/mips_pic_wrapper.c +++ b/src/scout/pic/mips_pic_wrapper.c @@ -55,4 +55,4 @@ pic_context_t * get_context() } #endif /* SCOUT_ARCH_MIPS */ -#endif /* SCOUT_PIC_CODE */ \ No newline at end of file +#endif /* SCOUT_PIC_CODE */ diff --git a/src/scout/pic/pic_wrapper.h b/src/scout/pic/pic_wrapper.h index 1f37cb6..37523c6 100644 --- a/src/scout/pic/pic_wrapper.h +++ b/src/scout/pic/pic_wrapper.h @@ -81,4 +81,4 @@ void * get_live_address(const void * address); #endif /* SCOUT_PIC_CODE */ -#endif // __SCOUT__PIC__WRAPPER__H__ \ No newline at end of file +#endif // __SCOUT__PIC__WRAPPER__H__ diff --git a/src/scout/pic/scout_globals.c b/src/scout/pic/scout_globals.c index 821085f..adbc870 100644 --- a/src/scout/pic/scout_globals.c +++ b/src/scout/pic/scout_globals.c @@ -29,4 +29,4 @@ uint8_t * global_SendBuffer() #endif /* SCOUT_INSTRUCTIONS */ -#endif /* SCOUT_PIC_CODE */ \ No newline at end of file +#endif /* SCOUT_PIC_CODE */ diff --git a/src/scout/pic/scout_plt.c b/src/scout/pic/scout_plt.c index 5ece5be..bf1c4c8 100644 --- a/src/scout/pic/scout_plt.c +++ b/src/scout/pic/scout_plt.c @@ -83,4 +83,4 @@ int munmap(void * addr, size_t length) #endif /* SCOUT_MMAP */ -#endif /* SCOUT_PIC_CODE */ \ No newline at end of file +#endif /* SCOUT_PIC_CODE */ diff --git a/src/scout/pic/scout_plt.h b/src/scout/pic/scout_plt.h index fb584e2..93188f6 100644 --- a/src/scout/pic/scout_plt.h +++ b/src/scout/pic/scout_plt.h @@ -35,4 +35,4 @@ typedef struct __pic_got #endif /* SCOUT_PIC_CODE */ -#endif // __SCOUT__PIC__PLT__H__ \ No newline at end of file +#endif // __SCOUT__PIC__PLT__H__ diff --git a/src/scout/scout.h b/src/scout/scout.h index 6d1a839..574bd2a 100644 --- a/src/scout/scout.h +++ b/src/scout/scout.h @@ -26,4 +26,4 @@ #endif /* SCOUT_ISOLATED_ENV */ -#endif // __SCOUT__H__ \ No newline at end of file +#endif // __SCOUT__H__ diff --git a/src/scout/scout_api.c b/src/scout/scout_api.c index 004aee1..6b3dd1b 100644 --- a/src/scout/scout_api.c +++ b/src/scout/scout_api.c @@ -166,4 +166,4 @@ int32_t instruction_mem_write(void * ctx, uint8_t * instruction, uint32_t length return STATUS_OK; } -#endif /* SCOUT_INSTRUCTIONS */ \ No newline at end of file +#endif /* SCOUT_INSTRUCTIONS */ diff --git a/src/scout/scout_api.h b/src/scout/scout_api.h index f45b919..27d743e 100644 --- a/src/scout/scout_api.h +++ b/src/scout/scout_api.h @@ -228,4 +228,4 @@ int32_t instruction_mem_write(void * ctx, uint8_t * instruction, uint32_t length #endif /* SCOUT_INSTRUCTIONS */ -#endif // __SCOUT__API__H__ \ No newline at end of file +#endif // __SCOUT__API__H__ diff --git a/src/scout/tcp_server.c b/src/scout/tcp_server.c index d2b26ed..c9fa92e 100644 --- a/src/scout/tcp_server.c +++ b/src/scout/tcp_server.c @@ -268,4 +268,4 @@ int32_t start_server_loop(sock_fd serverSock) return ctx.status; } -#endif /* SCOUT_INSTRUCTIONS */ \ No newline at end of file +#endif /* SCOUT_INSTRUCTIONS */ diff --git a/src/scout/tcp_server.h b/src/scout/tcp_server.h index 1053896..3894a95 100644 --- a/src/scout/tcp_server.h +++ b/src/scout/tcp_server.h @@ -101,4 +101,4 @@ uint32_t full_net_recv(sock_fd sock, uint8_t * buffer, uint32_t length); */ uint32_t full_net_send(sock_fd sock, uint8_t * buffer, uint32_t length); -#endif // __SCOUT__TCP__SERVER__H__ \ No newline at end of file +#endif // __SCOUT__TCP__SERVER__H__ diff --git a/src/utils/compilation/arc_arm.py b/src/utils/compilation/arc_arm.py index 25c5945..a1348fa 100644 --- a/src/utils/compilation/arc_arm.py +++ b/src/utils/compilation/arc_arm.py @@ -1,56 +1,95 @@ from target_arc import targetArc class arcArm(targetArc): + """A class representing an Arm CPU architecture to which we will compile our binary. + + Attributes + ---------- + (all inherited from the base class) + + Notes + ----- + Can be extended by the Arm-Thumb architecture class. + """ + # Arm Toolchain arm_compiler_path = '/usr/bin/arm-none-eabi-gcc' arm_linker_path = '/usr/bin/arm-none-eabi-ld' arm_objcopy_path = '/usr/bin/arm-none-eabi-objcopy' arm_objcopy_flags = ('--section-alignment 4',) - + arm_pic_compile_flags = ('fno-jump-tables', 'mapcs-frame') def __init__(self, is_pic): + """Init the compilation configuration for the Arm architecture. + + Args: + is_pic (bool): True iff a position-independent compilation + """ super(arcArm, self).__init__(is_pic) # Arc specific PIC flags if is_pic: - self.compile_flags += arm_pic_compile_flags + self.compile_flags += self.arm_pic_compile_flags @staticmethod def name(): - """Get the architecture's name + """Get the architecture's name. Return Value: String name for the architecture """ return "Arm" - + # Overridden base function def setNotNative(self): - self.setToolchain(arm_compiler_path, arm_linker_path, arm_objcopy_path, arm_objcopy_flags) + """Mark the compilation as using a toolchain and not the native compiler.""" + self.setToolchain(self.arm_compiler_path, self.arm_linker_path, self.arm_objcopy_path, self.arm_objcopy_flags) # Overridden base function def setEndianness(self, is_little): + """Set the (little/big) endianness we are going to use. + + Args: + is_little (bool): True iff compiling a Little Endian binary + """ if is_little: self.compile_flags += ('mlittle-endian',) self.link_flags += ('EL',) else: self.compile_flags += ('mbig-endian',) self.link_flags += ('EB',) - + # Overridden base function def setBitness(self, is_32_bits): + """Set the (32/64) bitness we are going to use. + + Args: + is_32_bits (bool): True iff compiling a 32-bits binary + """ if not is_32_bits: raise NotImplementedError("Didn't yet implement the logic for 64 bits ARM") - + class arcArmThumb(arcArm): + """A class representing an Arm CPU architecture to which we will compile our Thumb binary. + + Attributes + ---------- + (all inherited from the base class) + """ + def __init__(self, is_pic): + """Init the compilation configuration for the Arm-Thumb architecture. + + Args: + is_pic (bool): True iff a position-independent compilation + """ super(arcArmThumb, self).__init__(is_pic) # Arc specific flags self.compile_flags += ('mthumb',) @staticmethod def name(): - """Get the architecture's name + """Get the architecture's name. Return Value: String name for the architecture @@ -59,5 +98,10 @@ def name(): # Overridden base function def setBitness(self, is_32_bits): + """Set the (32/64) bitness we are going to use. + + Args: + is_32_bits (bool): True iff compiling a 32-bits binary + """ if not is_32_bits: - raise Exception("Not sure if ARM-Thumb even supports 64 bits") \ No newline at end of file + raise Exception("Not sure if ARM-Thumb even supports 64 bits") diff --git a/src/utils/compilation/arc_intel.py b/src/utils/compilation/arc_intel.py index fff537f..1462094 100644 --- a/src/utils/compilation/arc_intel.py +++ b/src/utils/compilation/arc_intel.py @@ -1,26 +1,48 @@ from target_arc import targetArc class arcIntel(targetArc): + """A class representing an Intel CPU architecture to which we will compile our binary. + + Attributes + ---------- + (all inherited from the base class) + """ + def __init__(self, is_pic): + """Init the compilation configuration for Intel architecture. + + Args: + is_pic (bool): True iff a position-independent compilation + """ super(arcIntel, self).__init__(is_pic) - + @staticmethod def name(): - """Get the architecture's name + """Get the architecture's name. Return Value: String name for the architecture """ return "Intel" - + # Overridden base function def setEndianness(self, is_little): - if not is_32_bits: + """Set the (little/big) endianness we are going to use. + + Args: + is_little (bool): True iff compiling a Little Endian binary + """ + if not is_little: raise Exception("Intel doesn't support Big Endian :(") # Overridden base function def setBitness(self, is_32_bits): + """Set the (32/64) bitness we are going to use. + + Args: + is_32_bits (bool): True iff compiling a 32-bits binary + """ if not is_32_bits: return self.compile_flags += ('m32',) - self.link_flags += ('melf_i386',) \ No newline at end of file + self.link_flags += ('melf_i386',) diff --git a/src/utils/compilation/arc_mips.py b/src/utils/compilation/arc_mips.py index 088945c..351b9d5 100644 --- a/src/utils/compilation/arc_mips.py +++ b/src/utils/compilation/arc_mips.py @@ -1,23 +1,35 @@ from target_arc import targetArc class arcMips(targetArc): + """A class representing a Mips CPU architecture to which we will compile our binary. + + Attributes + ---------- + (all inherited from the base class) + """ + # Mips Toolchain mips_compiler_path = '/usr/bin/mips-linux-gnu-gcc' mips_linker_path = '/usr/bin/mips-linux-gnu-ld' mips_objcopy_path = '/usr/bin/mips-linux-gnu-objcopy' mips_objcopy_flags = ('--section-alignment 4',) - + mips_pic_compile_flags = ('fno-jump-tables', 'mno-shared', 'mplt') def __init__(self, is_pic): + """Init the compilation configuration for the Mips architecture. + + Args: + is_pic (bool): True iff a position-independent compilation + """ super(arcMips, self).__init__(is_pic) # Arc specific PIC flags if is_pic: - self.compile_flags += mips_pic_compile_flags - + self.compile_flags += self.mips_pic_compile_flags + @staticmethod def name(): - """Get the architecture's name + """Get the architecture's name. Return Value: String name for the architecture @@ -26,10 +38,16 @@ def name(): # Overridden base function def setNotNative(self): - self.setToolchain(mips_compiler_path, mips_linker_path, mips_objcopy_path, mips_objcopy_flags) - + """Mark the compilation as using a toolchain and not the native compiler.""" + self.setToolchain(self.mips_compiler_path, self.mips_linker_path, self.mips_objcopy_path, self.mips_objcopy_flags) + # Overridden base function def setEndianness(self, is_little): + """Set the (little/big) endianness we are going to use. + + Args: + is_little (bool): True iff compiling a Little Endian binary + """ if is_little: self.compile_flags += ('EL',) self.link_flags += ('EL',) @@ -39,5 +57,10 @@ def setEndianness(self, is_little): # Overridden base function def setBitness(self, is_32_bits): + """Set the (32/64) bitness we are going to use. + + Args: + is_32_bits (bool): True iff compiling a 32-bits binary + """ if not is_32_bits: - raise NotImplementedError("Didn't yet implement the logic for 64 bits Mips") \ No newline at end of file + raise NotImplementedError("Didn't yet implement the logic for 64 bits Mips") diff --git a/src/utils/compilation/scout_flags.py b/src/utils/compilation/scout_flags.py index 0a88193..5fa6c55 100644 --- a/src/utils/compilation/scout_flags.py +++ b/src/utils/compilation/scout_flags.py @@ -3,30 +3,30 @@ ############################# # flags files -FLAGS_FILE_NAME = 'flags.h' +FLAGS_FILE_NAME = 'flags.h' # configuration compile flags -flag_32_bit = 'SCOUT_BITS_32' -flag_64_bit = 'SCOUT_BITS_64' -flag_big_endian = 'SCOUT_BIG_ENDIAN' -flag_little_endian = 'SCOUT_LITTLE_ENDIAN' -flag_arc_intel = 'SCOUT_ARCH_INTEL' -flag_arc_arm = 'SCOUT_ARCH_ARM' -flag_arc_thumb = 'SCOUT_ARM_THUMB' -flag_arc_mips = 'SCOUT_ARCH_MIPS' -flag_mode_user = 'SCOUT_MODE_USER' -flag_mode_kernel = 'SCOUT_MODE_KERNEL' -flag_pic_code = 'SCOUT_PIC_CODE' -flag_host_glibc = 'SCOUT_HOST_GLIBC' -flag_host_uclibc = 'SCOUT_HOST_UCLIBC' -flag_instructions = 'SCOUT_INSTRUCTIONS' -flag_restore_flow = 'SCOUT_RESTORE_FLOW' -flag_dynamic_buffers= 'SCOUT_DYNAMIC_BUFFERS' -flag_proxy = 'SCOUT_PROXY' -flag_mmap = 'SCOUT_MMAP' -flag_load_thumb = 'SCOUT_LOADING_THUMB_CODE' -flag_loader = 'SCOUT_LOADER' -flag_loader_client = 'SCOUT_TCP_CLIENT' -flag_loader_server = 'SCOUT_TCP_SERVER' -flag_loader_transmit= 'SCOUT_TCP_SEND' -flag_native_compiler= 'SCOUT_NATIVE_COMPILATION' \ No newline at end of file +flag_32_bit = 'SCOUT_BITS_32' +flag_64_bit = 'SCOUT_BITS_64' +flag_big_endian = 'SCOUT_BIG_ENDIAN' +flag_little_endian = 'SCOUT_LITTLE_ENDIAN' +flag_arc_intel = 'SCOUT_ARCH_INTEL' +flag_arc_arm = 'SCOUT_ARCH_ARM' +flag_arc_thumb = 'SCOUT_ARM_THUMB' +flag_arc_mips = 'SCOUT_ARCH_MIPS' +flag_mode_user = 'SCOUT_MODE_USER' +flag_mode_kernel = 'SCOUT_MODE_KERNEL' +flag_pic_code = 'SCOUT_PIC_CODE' +flag_host_glibc = 'SCOUT_HOST_GLIBC' +flag_host_uclibc = 'SCOUT_HOST_UCLIBC' +flag_instructions = 'SCOUT_INSTRUCTIONS' +flag_restore_flow = 'SCOUT_RESTORE_FLOW' +flag_dynamic_buffers = 'SCOUT_DYNAMIC_BUFFERS' +flag_proxy = 'SCOUT_PROXY' +flag_mmap = 'SCOUT_MMAP' +flag_load_thumb = 'SCOUT_LOADING_THUMB_CODE' +flag_loader = 'SCOUT_LOADER' +flag_loader_client = 'SCOUT_TCP_CLIENT' +flag_loader_server = 'SCOUT_TCP_SERVER' +flag_loader_transmit = 'SCOUT_TCP_SEND' +flag_native_compiler = 'SCOUT_NATIVE_COMPILATION' diff --git a/src/utils/compilation/target_arc.py b/src/utils/compilation/target_arc.py index fd7f898..ce9a878 100644 --- a/src/utils/compilation/target_arc.py +++ b/src/utils/compilation/target_arc.py @@ -1,4 +1,20 @@ class targetArc: + """A class representing a target CPU architecture to which we will compile our binary. + + Attributes + ---------- + compiler_path (str): path to the used compiler + linker_path (str): path to the used linker + objcopy_path (str): path to the used objcopy + objcopy_flags (list): list of flags to be used by objcopy + compile_flags (list): list of compilation flags + link_flags (list): list of linking flags + + Notes + ----- + Serves as a base class that will be extended by specific architecture classes. + """ + native_compiler_path = 'gcc' native_linker_path = 'ld' native_objcopy_path = 'objcopy' @@ -8,34 +24,59 @@ class targetArc: base_executable_compile_flags = ('O2',) base_pic_compile_flags = ('Os', 'nostdlib', 'fno-toplevel-reorder') base_link_flags = () - + def __init__(self, is_pic): - self.compiler_path = native_compiler_path - self.linker_path = native_linker_path - self.objcopy_path = native_objcopy_path - self.objcopy_flags = list(native_objcopy_flags) - - self.compile_flags = list(base_compile_flags) - self.link_flags = list(base_link_flags) - - self.compile_flags += base_pic_compile_flags if is_pic else base_executable_compile_flags + """Init the base compilation configuration for the architecture. + + Args: + is_pic (bool): True iff a position-independent compilation + """ + self.compiler_path = self.native_compiler_path + self.linker_path = self.native_linker_path + self.objcopy_path = self.native_objcopy_path + self.objcopy_flags = list(self.native_objcopy_flags) + + self.compile_flags = list(self.base_compile_flags) + self.link_flags = list(self.base_link_flags) + + self.compile_flags += self.base_pic_compile_flags if is_pic else self.base_executable_compile_flags def setToolchain(self, compiler_path, linker_path, objcopy_path, objcopy_flags): + """Set the toolchain configurations for the given architecture. + + Args: + compiler_path (str): path to the target compiler + linker_path (str): path to the target linker + objcopy_path (str): path to the target objcopy + objcopy_flags (list): list of flags to be passed to objcopy + """ self.compiler_path = compiler_path self.linker_path = linker_path self.objcopy_path = objcopy_path self.objcopy_flags = [] + objcopy_flags - + def setNotNative(self): + """Mark the compilation as using a toolchain and not the native compiler.""" raise NotImplementedError("Subclasses should implement this!") - + def setEndianness(self, is_little): + """Set the (little/big) endianness we are going to use. + + Args: + is_little (bool): True iff compiling a Little Endian binary + """ raise NotImplementedError("Subclasses should implement this!") - + def setBitness(self, is_32_bits): + """Set the (32/64) bitness we are going to use. + + Args: + is_32_bits (bool): True iff compiling a 32-bits binary + """ raise NotImplementedError("Subclasses should implement this!") - + def prepareFlags(self): + """Prepare the compilation and linking flags to be passed on to the compiler.""" compile_flags = ' '.join(['-' + x for x in self.compile_flags]) link_flags = ' '.join(['-' + x for x in self.link_flags]) - return compile_flags, link_flags \ No newline at end of file + return compile_flags, link_flags diff --git a/src/utils/context_creator.py b/src/utils/context_creator.py index 8c222d4..57e9ac5 100644 --- a/src/utils/context_creator.py +++ b/src/utils/context_creator.py @@ -34,7 +34,7 @@ # * munmap def placeContext(got, globals, binary_file, logger): - """Embedds the PIC context into the compiled binary blob + """Embedds the PIC context into the compiled binary blob. Args: got (bytes): Content of the PIC GOT diff --git a/src/utils/scout_api.py b/src/utils/scout_api.py index dc652c9..d61aa34 100644 --- a/src/utils/scout_api.py +++ b/src/utils/scout_api.py @@ -11,22 +11,22 @@ ########################### error_codes = { # General errors - 0 : "STATUS_OK", - 1 : "STATUS_FAILURE", - 2 : "STATUS_INVALID_ARGS", - 3 : "STATUS_ALLOC_FAILED", - 4 : "STATUS_TCP_SOCK_FAILED", - 5 : "STATUS_TCP_BIND_FAILED", - 6 : "STATUS_TCP_LISTEN_FAILED", - 7 : "STATUS_TCP_ACCEPT_FAILED", - 8 : "STATUS_TCP_CONNECT_FAILED", - 9 : "STATUS_TCP_RECV_FAILED", - 10 : "STATUS_TCP_SEND_FAILED", + 0: "STATUS_OK", + 1: "STATUS_FAILURE", + 2: "STATUS_INVALID_ARGS", + 3: "STATUS_ALLOC_FAILED", + 4: "STATUS_TCP_SOCK_FAILED", + 5: "STATUS_TCP_BIND_FAILED", + 6: "STATUS_TCP_LISTEN_FAILED", + 7: "STATUS_TCP_ACCEPT_FAILED", + 8: "STATUS_TCP_CONNECT_FAILED", + 9: "STATUS_TCP_RECV_FAILED", + 10: "STATUS_TCP_SEND_FAILED", # Scout API - 20 : "STATUS_SMALL_HEADER", - 21 : "STATUS_ILLEGAL_LENGTH", - 22 : "STATUS_ILLEGAL_INSTR_ID" + 20: "STATUS_SMALL_HEADER", + 21: "STATUS_ILLEGAL_LENGTH", + 22: "STATUS_ILLEGAL_INSTR_ID" } ############################ @@ -51,19 +51,19 @@ ####################### def setBitness32(): - """Sets the module's bitness to match a 32 bit server""" + """Set the module's bitness to match a 32 bit server.""" global TARGET_BITNESS TARGET_BITNESS = 32 def setBitness64(): - """Sets the module's bitness to match a 64 bit server""" + """Set the module's bitness to match a 64 bit server.""" global TARGET_BITNESS TARGET_BITNESS = 64 def addErrorCodes(errors): - """Adds the given error codes to the supported dictionary + """Add the given error codes to the supported dictionary. Args: errors (dict): new supported error codes in the form: : @@ -78,47 +78,51 @@ def addErrorCodes(errors): ######################### def addHeader(opcode, raw_instr): - """Adds the protocol's header to the given instruction + """Add the protocol's header to the given instruction. Args: - opcode (numeric): instruction opcode ID + opcode (int): instruction opcode ID raw_instr (string): binary data of the wanted instruction + Return Value: string containing the complete serialized instruction """ - return struct.pack( "!HL", opcode, len( raw_instr )) + raw_instr + return struct.pack("!HL", opcode, len(raw_instr)) + raw_instr # basic instructions def instrNop(): - """Builds the NOP (Pong) instruction + """Build the NOP (Ping) instruction. Args: (none) + Return Value: string containing the serialized instruction """ - return addHeader( SCOUT_INST_NOP, b'' ) + return addHeader(SCOUT_INST_NOP, b'') def instrMemRead(addr, length): - """Builds the Read (Virtual) Memory instruction + """Build the Read (Virtual) Memory instruction. Args: - addr (numeric): (virtual) memory address - length (numeric): number of bytes to be read form the given address + addr (int): (virtual) memory address + length (int): number of bytes to be read form the given address + Return Value: string containing the serialized instruction """ - instr = struct.pack( "!QL" if TARGET_BITNESS == 64 else "!LL", addr, length ) - return addHeader( SCOUT_INST_MEM_READ, instr ) + instr = struct.pack("!QL" if TARGET_BITNESS == 64 else "!LL", addr, length) + return addHeader(SCOUT_INST_MEM_READ, instr) def instrMemWrite(addr, content): - """Builds the Write (Virtual) Memory instruction + """Build the Write (Virtual) Memory instruction. Args: - addr (numeric): (virtual) memory address + addr (int): (virtual) memory address content (string): binary data to be written to the given address + Return Value: string containing the serialized instruction """ - instr = struct.pack( "!Q" if TARGET_BITNESS == 64 else "!L", addr ) + content - return addHeader( SCOUT_INST_MEM_WRITE, instr ) \ No newline at end of file + instr = struct.pack("!Q" if TARGET_BITNESS == 64 else "!L", addr) + content + return addHeader(SCOUT_INST_MEM_WRITE, instr) diff --git a/src/utils/scout_compiler.py b/src/utils/scout_compiler.py index 6f8cdcb..1f19889 100644 --- a/src/utils/scout_compiler.py +++ b/src/utils/scout_compiler.py @@ -24,34 +24,60 @@ ARC_ARM_THUMB: arcArmThumb, ARC_MIPS: arcMips, } - + arc_flags = { ARC_INTEL: (flag_arc_intel,), ARC_ARM: (flag_arc_arm,), ARC_ARM_THUMB: (flag_arc_arm, flag_arc_thumb), ARC_MIPS: (flag_arc_mips,), } - + ################# ## Utilities ## ################# - + def systemLine(line, logger): - """Issues (and debug trace) a systen line + """Issue (and debug trace) a systen line. + + Args: + line (string): cmd line to be executed + logger (logger, elementals): logger to be used by the function (elementals) + """ + logger.debug(line) + os.system(line) - Args: - logger (logger, elementals): logger to be used by the function (elementals) - line (string): cmd line to be executed - """ - logger.debug(line) - os.system(line) - ############################### ## The full Scout Compiler ## ############################### class scoutCompiler: + """A class representing the Scout Compiler object, which manages the entire compilation logic. + + Attributes + ---------- + logger (logger): (elementals) logger + target_arc (targetArc): target architecture instance to hold CPU-specific configurations + project_folder (str): path to the user's working folder + scout_folder (str): path to Scout's base folder + config_flags (list): list of Scout configuration flags, accumulated along the process + is_32_bits (bool): True iff we are going to compile a 32-bits binary + is_little_endian (bool): True iff we are going to compile a Little Endian binary + is_pic (bool): True iff we are going to compile a PIC binary blob + full_got (bytes): blob containing the GOT function address table for a PIC compilation + global_vars (bytes): blob containing the global variables content for a PIC compilation + + Notes + ----- + This class serves as the main object to be used by the suer when compiling an executable or + a Position-Independent-Code (PIC) Scout binary. + """ + def __init__(self, logger): + """Construct the basic Scout compiler object. + + Args: + logger (logger): (elementals) logger + """ self.logger = logger self.target_arc = None self.project_folder = None @@ -62,9 +88,9 @@ def __init__(self, logger): self.is_pic = False self.full_got = b'' self.global_vars = b'' - + def setArc(self, arc, is_pic, is_32_bits=True, is_little_endian=True, is_native=False): - """Sets the target's architecture specifications + """Set the target's architecture specifications. Args: arc (string, enum): name of the target architecture (should be a key of arc_factory) @@ -80,11 +106,11 @@ def setArc(self, arc, is_pic, is_32_bits=True, is_little_endian=True, is_native= # Apply the chosen settings self.is_pic = is_pic self.target_arc = arc_factory[arc](is_pic) - if is native: + if is_native: target_arc.config_flags.append(flag_native_compiler) else: target_arc.setNotNative() - + # Configure the architecture target_arc.setEndianness(is_little_endian) target_arc.setBitness(is_32_bits) @@ -98,7 +124,7 @@ def setArc(self, arc, is_pic, is_32_bits=True, is_little_endian=True, is_native= self.config_flags.append(flag_pic_code) def setScoutMode(self, is_user): - """Sets the target's permission level + """Set the target's permission level. Args: is_user (bool): True iff the scout will run in user mode, otherwise it will assume kernel mode permissions @@ -106,7 +132,7 @@ def setScoutMode(self, is_user): self.config_flags.append(flag_mode_user if is_user else flag_mode_kernel) def setWorkingDirs(self, project_dir, scout_dir, include_dirs=[]): - """Sets the paths for the used directories + """Set the paths for the used directories. Args: project_dir (string): path to the project's directory @@ -123,32 +149,32 @@ def setWorkingDirs(self, project_dir, scout_dir, include_dirs=[]): main_folder = scout_dir + os.path.sep + ".." self.target_arc.compile_flags += ['I' + x for x in [project_folder, main_folder] + include_dirs] - + def addScoutFlags(self, flags): - """Adds the flags regarding the target's specifications + """Add the flags regarding the target's specifications. Args: flags (list): list of configuration flags (strings) """ self.config_flags += flags - + def addCompilationFlags(self, user_compile_flags=[], user_link_flags=[]): - """Add custom compilation / linking flags + """Add custom compilation / linking flags. Args: user_compile_flags (list, optional): list of compiler flags (without the '-' prefix) user_link_flags (list, optional) list of linker flags (without the '-' prefix) - """ + """ self.target_arc.compile_flags += user_compile_flags self.target_arc.link_flags += user_link_flags def verifyScoutFlags(self): - """Checks that all of the configuration flags are set correctly""" - if flag_mode_user is not in self.config_flags and flag_mode_kernel is not in self.config_files: + """Check that all of the configuration flags are set correctly.""" + if flag_mode_user not in self.config_flags and flag_mode_kernel not in self.config_files: self.logger.warning("Missing Scout flag - unknown permission mode. Defaulting to USER-MODE (low privileges)") def generateFlagsFile(self): - """Generates the architecture's "flags.h" file""" + """Generate the architecture's "flags.h" file.""" # Verify the flags verifyScoutFlags() @@ -176,7 +202,7 @@ def generateFlagsFile(self): fd.close() def populateGOT(self, scout_got, project_got, project_vars_size=0): - """Populates the PIC context with the GOT entries, and capacity for global variables. + """Populate the PIC context with the GOT entries, and capacity for global variables. Args: scout_got (list): list of (virtual) addresses according to Scout's GOT order @@ -215,7 +241,7 @@ def populateGOT(self, scout_got, project_got, project_vars_size=0): self.global_vars = b'\x00' * size_globals def compile(self, scout_files, project_files, elf_file): - """Compiles the "Scout" project, according to the PIC setup that was defined earlier. + """Compile the "Scout" project, according to the PIC setup that was defined earlier. Args: scout_files (list): list of file paths for scout's code (*.c) files @@ -305,4 +331,4 @@ def compile(self, scout_files, project_files, elf_file): placeContext(self.full_got, self.global_vars, binary_file, self.logger) self.logger.removeIndent() - return binary_file \ No newline at end of file + return binary_file diff --git a/src/utils/scout_network.py b/src/utils/scout_network.py index d74e0d2..4a4a1dd 100644 --- a/src/utils/scout_network.py +++ b/src/utils/scout_network.py @@ -6,7 +6,7 @@ SCOUT_HEADER_SIZE = struct.Struct(SCOUT_HEADER_FORMAT).size def sendInstr(sock, instr, logger): - """Sends an instruction to the (debuggee) server. + """Send an instruction to the (debuggee) server. Args: sock (socket): (TCP) socket to the server @@ -46,7 +46,7 @@ def sendInstr(sock, instr, logger): return data def remoteLoad(sock, full_scout): - """Sends TCP loader the loading instruction for the full scout. + """Send the TCP loader the loading instruction for the full scout. Args: sock (socket): (TCP) socket to the remote loader @@ -55,7 +55,7 @@ def remoteLoad(sock, full_scout): sock.send(struct.pack("!L", len(full_scout)) + full_scout) def remoteLoadServer(ip, full_scout, logger, port=LOADER_PORT): - """Connects to the remote TCP loader, and sends the full scout to be loaded. + """Connect to the remote TCP loader, and sends the full scout to be loaded. Args: ip (ip address): ip address of the remote scout loader @@ -71,7 +71,7 @@ def remoteLoadServer(ip, full_scout, logger, port=LOADER_PORT): sock.close() def remoteLoadClient(ip, full_scout, logger, port=LOADER_PORT): - """Creates a local TCP server for which the remote loader could connect, and sends it the full scout. + """Create a local TCP server for which the remote loader could connect, and sends it the full scout. Args: ip (ip address): ip address for our server @@ -88,4 +88,4 @@ def remoteLoadClient(ip, full_scout, logger, port=LOADER_PORT): logger.info(f"Accepted the remote loader from: {loader_addr[0]}") remoteLoad(loader_sock, full_scout) logger.info("Sent the loading instructions to the remote loader") - sock.close() \ No newline at end of file + sock.close() From d6beeddb816f5e2b1190f262544c1b897c210e04 Mon Sep 17 00:00:00 2001 From: chkp-eyalit Date: Sun, 2 May 2021 19:03:40 +0300 Subject: [PATCH 24/30] [testing] Both examples now compile and work Python package is now structured correctly, both examples are using the correct API, and work as expected. Kernel driver also includes a bypass to the mitigation in copy_to_user() using instrPhysRead() instead of a plain old instrMemRead(). --- .../manager/embedded_scout_api.py | 2 +- examples/embedded_scout/manager/manager.py | 8 +-- examples/embedded_scout/src/compile_scout.py | 8 ++- examples/embedded_scout/src/flags.h | 14 ++++ examples/kernel_scout/driver/Makefile | 3 +- .../driver/scout_kernel_instructions.c | 69 +++++++++++-------- .../driver/scout_kernel_instructions.h | 4 +- .../kernel_scout/manager/kernel_scout_api.py | 6 +- examples/kernel_scout/manager/manager.py | 24 ++++--- .../kernel_scout/user_mode/compile_scout.py | 13 ++-- examples/kernel_scout/user_mode/flags.h | 11 +-- setup.py | 7 +- src/scout/loaders/loader.h | 4 +- src/scout/loaders/tcp_client_loader.h | 2 +- src/scout/loaders/tcp_server_loader.h | 2 +- src/scout/tcp_server.c | 2 +- src/scout/tcp_server.h | 3 +- src/utils/__init__.py | 8 +-- src/utils/compilation/arc_arm.py | 2 +- src/utils/compilation/arc_intel.py | 2 +- src/utils/compilation/arc_mips.py | 2 +- src/utils/compilation/target_arc.py | 2 +- src/utils/scout_api.py | 4 ++ src/utils/scout_compiler.py | 29 ++++---- src/utils/scout_network.py | 2 +- 25 files changed, 138 insertions(+), 95 deletions(-) create mode 100644 examples/embedded_scout/src/flags.h diff --git a/examples/embedded_scout/manager/embedded_scout_api.py b/examples/embedded_scout/manager/embedded_scout_api.py index 86ded77..1fb13a5 100644 --- a/examples/embedded_scout/manager/embedded_scout_api.py +++ b/examples/embedded_scout/manager/embedded_scout_api.py @@ -1,4 +1,4 @@ -from scout.scout_api import * +from scout_debugger.scout_api import * ############################## ## Extended API Error Codes ## diff --git a/examples/embedded_scout/manager/manager.py b/examples/embedded_scout/manager/manager.py index b8ee9ae..ce6f577 100644 --- a/examples/embedded_scout/manager/manager.py +++ b/examples/embedded_scout/manager/manager.py @@ -1,8 +1,8 @@ -#!/usr/bin/python +#!/usr/bin/python3 -from embedded_scout_api import * -from scout.scout_network import * -from elementals import Prompter, hexDump +from embedded_scout_api import * +from scout_debugger.scout_network import * +from elementals import Prompter, hexDump import logging import struct diff --git a/examples/embedded_scout/src/compile_scout.py b/examples/embedded_scout/src/compile_scout.py index b7ca6e5..f82ce23 100644 --- a/examples/embedded_scout/src/compile_scout.py +++ b/examples/embedded_scout/src/compile_scout.py @@ -1,9 +1,10 @@ -#!/usr/bin/python +#!/usr/bin/python3 + import os import sys from elementals import Prompter -from scout.scout_compiler import * +from scout_debugger.scout_compiler import * ############################## ## Dynamic Configurations ## @@ -109,7 +110,8 @@ def compileScout(logger): # 2. Add additional flags: # * flag_instructions - Will use the TCP server for instructions # * flag_dynamic_buffers - Will use dynamic buffers (malloc) for the received instructions - compiler.addScoutFlags([flag_instructions, flag_dynamic_buffers]) + # * flag_mmap - mmap() will be available to the full scout + compiler.addScoutFlags([flag_instructions, flag_dynamic_buffers] + ([flag_mmap] if LOADER_USE_MMAP else [])) # 3. Add custom compilation flags (not needed) # compiler.addCompilationFlags(compile_flags=[], link_flags=[]) diff --git a/examples/embedded_scout/src/flags.h b/examples/embedded_scout/src/flags.h new file mode 100644 index 0000000..8e1b4cd --- /dev/null +++ b/examples/embedded_scout/src/flags.h @@ -0,0 +1,14 @@ +#ifndef __SCOUT__FLAGS__H__ +#define __SCOUT__FLAGS__H__ + +/* This file is AUTO-GENERATED, please do NOT edit it manually */ +#define SCOUT_BITS_32 +#define SCOUT_BIG_ENDIAN +#define SCOUT_ARCH_ARM +#define SCOUT_PIC_CODE +#define SCOUT_MODE_USER +#define SCOUT_INSTRUCTIONS +#define SCOUT_DYNAMIC_BUFFERS +#define SCOUT_MMAP + +#endif /* _SCOUT__FLAGS__H__ */ \ No newline at end of file diff --git a/examples/kernel_scout/driver/Makefile b/examples/kernel_scout/driver/Makefile index cb8a2c6..2646f9f 100644 --- a/examples/kernel_scout/driver/Makefile +++ b/examples/kernel_scout/driver/Makefile @@ -1,8 +1,9 @@ RM=rm SCOUT_SRC=../../../src/scout +SCOUT_INC=../../../src obj-m+=scout.o -EXTRA_CFLAGS := -I$(src) -I$(src)/../.. -Wno-incompatible-pointer-types +EXTRA_CFLAGS := -I$(src) -I$(src)/$(SCOUT_INC) -Wno-incompatible-pointer-types scout-objs := $(SCOUT_SRC)/pack.o $(SCOUT_SRC)/scout_api.o scout_driver.o scout_kernel_instructions.o # Build rules diff --git a/examples/kernel_scout/driver/scout_kernel_instructions.c b/examples/kernel_scout/driver/scout_kernel_instructions.c index f3a4737..f3f10a3 100644 --- a/examples/kernel_scout/driver/scout_kernel_instructions.c +++ b/examples/kernel_scout/driver/scout_kernel_instructions.c @@ -8,52 +8,65 @@ extern void add_input_randomness(unsigned int type, unsigned int code, unsigned void register_specific_instructions(void) { - register_instruction(KERNEL_INST_PHY_READ, INSTR_PHY_READ_MIN_SIZE, INSTR_PHY_READ_MAX_SIZE, INSTR_PHY_READ_HANDLER); - register_instruction(KERNEL_INST_PHY_WRITE, INSTR_PHY_WRITE_MIN_SIZE, INSTR_PHY_WRITE_MAX_SIZE, INSTR_PHY_WRITE_HANDLER); - register_instruction(KERNEL_INST_LEAK_ADDR, INSTR_LEAK_ADDR_MIN_SIZE, INSTR_LEAK_ADDR_MAX_SIZE, INSTR_LEAK_ADDR_HANDLER); + register_instruction(KERNEL_INST_PHY_READ, INSTR_PHY_READ_MIN_SIZE, INSTR_PHY_READ_MAX_SIZE, INSTR_PHY_READ_HANDLER); + register_instruction(KERNEL_INST_PHY_WRITE, INSTR_PHY_WRITE_MIN_SIZE, INSTR_PHY_WRITE_MAX_SIZE, INSTR_PHY_WRITE_HANDLER); + register_instruction(KERNEL_INST_LEAK_ADDR, INSTR_LEAK_ADDR_MIN_SIZE, INSTR_LEAK_ADDR_MAX_SIZE, INSTR_LEAK_ADDR_HANDLER); } int instruction_phy_read(void * c, uint8_t * instruction, uint32_t length) { - scout_kernel_ctx_t * ctx = (scout_kernel_ctx_t *)c; - addr_t src; - uint8_t * readHead = instruction; - - src = unpack_addr(&readHead); - length = unpack_uint32(&readHead); - - write_output(ctx, phys_to_virt(src), length); - - return STATUS_OK; + scout_kernel_ctx_t * ctx = (scout_kernel_ctx_t *)c; + addr_t src; + uint8_t * readHead = instruction; + /** + * In recent kernels there is a check on direct kernel<->user copy operations + * so we use an intermediate buffer to bypass them. + */ + uint8_t local_buffer[MAX_IO_REQUEST]; + + src = unpack_addr(&readHead); + length = unpack_uint32(&readHead); + + if(length > MAX_IO_REQUEST) + { + return STATUS_ILLEGAL_LENGTH; + } + memcpy(local_buffer, phys_to_virt(src), length); + + write_output(ctx, local_buffer, length); + + return STATUS_OK; } int instruction_phy_write(void * c, uint8_t * instruction, uint32_t length) { - addr_t dest; - uint8_t * readHead = instruction; + addr_t dest; + uint8_t * readHead = instruction; - (void)c; + (void)c; - dest = unpack_addr(&readHead); - length -= sizeof(addr_t); + dest = unpack_addr(&readHead); + length -= sizeof(addr_t); - memcpy(phys_to_virt(dest), readHead, length); + memcpy(phys_to_virt(dest), readHead, length); - return STATUS_OK; + return STATUS_OK; } int instruction_leak_addr(void * c, uint8_t * instruction, uint32_t length) { - scout_kernel_ctx_t * ctx = (scout_kernel_ctx_t *)c; - uint8_t * ptr = (uint8_t*)add_input_randomness; + scout_kernel_ctx_t * ctx = (scout_kernel_ctx_t *)c; + uint8_t * ptr = (uint8_t*)add_input_randomness; - (void)instruction; - (void)length; + (void)instruction; + (void)length; - /* Leaking the address of the pre-defined function: add_input_randomness */ - write_output(ctx, &ptr, sizeof(addr_t)); + /* Leaking the address of the pre-defined function: add_input_randomness */ + write_output(ctx, &ptr, sizeof(addr_t)); + ptr = (void *)virt_to_phys(add_input_randomness); + write_output(ctx, &ptr, sizeof(addr_t)); - printk(KERN_NOTICE "SCOUT-KERNEL: virt addres is 0x%p, phys is 0x%p\n", add_input_randomness, (void *)virt_to_phys(add_input_randomness)); + printk(KERN_NOTICE "SCOUT-KERNEL: virt addres is 0x%p, phys is 0x%p\n", add_input_randomness, (void *)virt_to_phys(add_input_randomness)); - return STATUS_OK; + return STATUS_OK; } diff --git a/examples/kernel_scout/driver/scout_kernel_instructions.h b/examples/kernel_scout/driver/scout_kernel_instructions.h index 2fe846d..38598be 100644 --- a/examples/kernel_scout/driver/scout_kernel_instructions.h +++ b/examples/kernel_scout/driver/scout_kernel_instructions.h @@ -74,13 +74,15 @@ int instruction_phy_write(void * ctx, uint8_t * instruction, uint32_t length); */ int instruction_leak_addr(void * ctx, uint8_t * instruction, uint32_t length); +#define MAX_IO_REQUEST 256 + /* The instruction records */ #define INSTR_PHY_READ_MIN_SIZE (sizeof(addr_t) + sizeof(uint32_t)) #define INSTR_PHY_READ_MAX_SIZE (sizeof(addr_t) + sizeof(uint32_t)) #define INSTR_PHY_READ_HANDLER instruction_phy_read #define INSTR_PHY_WRITE_MIN_SIZE (sizeof(addr_t)) -#define INSTR_PHY_WRITE_MAX_SIZE (sizeof(addr_t) + 256) +#define INSTR_PHY_WRITE_MAX_SIZE (sizeof(addr_t) + MAX_IO_REQUEST) #define INSTR_PHY_WRITE_HANDLER instruction_phy_write #define INSTR_LEAK_ADDR_MIN_SIZE 0 diff --git a/examples/kernel_scout/manager/kernel_scout_api.py b/examples/kernel_scout/manager/kernel_scout_api.py index 4815e54..f03b549 100644 --- a/examples/kernel_scout/manager/kernel_scout_api.py +++ b/examples/kernel_scout/manager/kernel_scout_api.py @@ -1,4 +1,4 @@ -from scout.scout_api import * +from scout_debugger.scout_api import * ############################## ## Extended API Error Codes ## @@ -33,7 +33,7 @@ def instrPhyRead(addr, length): Return Value: string containing the serialized instruction """ - instr = struct.pack("!QL" if TARGET_BITNESS == 64 else "!LL", addr, length) + instr = struct.pack("!LL" if isBitness32() else "!QL", addr, length) return addHeader(SCOUT_INST_PHY_READ, instr) def instrPhyWrite(addr, content): @@ -46,7 +46,7 @@ def instrPhyWrite(addr, content): Return Value: string containing the serialized instruction """ - instr = struct.pack("!Q" if TARGET_BITNESS == 64 else "!L", addr) + content + instr = struct.pack("!L" if isBitness32() else "!Q", addr) + content return addHeader(SCOUT_INST_PHY_READ, instr) def instrLeakAddr(): diff --git a/examples/kernel_scout/manager/manager.py b/examples/kernel_scout/manager/manager.py index 257afd7..55d6fad 100644 --- a/examples/kernel_scout/manager/manager.py +++ b/examples/kernel_scout/manager/manager.py @@ -1,8 +1,8 @@ -#!/usr/bin/python +#!/usr/bin/python3 -from kernel_scout_api import * -from scout.scout_network import * -from elementals import Prompter, hexDump +from kernel_scout_api import * +from scout_debugger.scout_network import * +from elementals import Prompter, hexDump import logging import struct @@ -18,15 +18,17 @@ def startManage(sock_fd, logger): logger.info('Sending the Leak instruction') data = sendInstr(sock_fd, instrLeakAddr(), logger) - leaked_addr = struct.unpack(' #include -typedef int sock_fd; #endif /* !SCOUT_ISOLATED_ENV */ +typedef int sock_fd; + /***************/ /** Structs **/ /***************/ diff --git a/src/utils/__init__.py b/src/utils/__init__.py index 51f6f60..6bbf34f 100644 --- a/src/utils/__init__.py +++ b/src/utils/__init__.py @@ -1,6 +1,6 @@ # Network API / Utils -import scout_api -import scout_network +from .scout_api import * +from .scout_network import sendInstr, remoteLoadServer, remoteLoadClient # Compilation Scripts -import context_creator -import scout_compiler \ No newline at end of file +from .scout_compiler import scoutCompiler, ARC_INTEL, ARC_ARM, ARC_ARM_THUMB, ARC_MIPS + diff --git a/src/utils/compilation/arc_arm.py b/src/utils/compilation/arc_arm.py index a1348fa..d13521b 100644 --- a/src/utils/compilation/arc_arm.py +++ b/src/utils/compilation/arc_arm.py @@ -1,4 +1,4 @@ -from target_arc import targetArc +from .target_arc import targetArc class arcArm(targetArc): """A class representing an Arm CPU architecture to which we will compile our binary. diff --git a/src/utils/compilation/arc_intel.py b/src/utils/compilation/arc_intel.py index 1462094..648d567 100644 --- a/src/utils/compilation/arc_intel.py +++ b/src/utils/compilation/arc_intel.py @@ -1,4 +1,4 @@ -from target_arc import targetArc +from .target_arc import targetArc class arcIntel(targetArc): """A class representing an Intel CPU architecture to which we will compile our binary. diff --git a/src/utils/compilation/arc_mips.py b/src/utils/compilation/arc_mips.py index 351b9d5..b52b4e3 100644 --- a/src/utils/compilation/arc_mips.py +++ b/src/utils/compilation/arc_mips.py @@ -1,4 +1,4 @@ -from target_arc import targetArc +from .target_arc import targetArc class arcMips(targetArc): """A class representing a Mips CPU architecture to which we will compile our binary. diff --git a/src/utils/compilation/target_arc.py b/src/utils/compilation/target_arc.py index ce9a878..ef55e4e 100644 --- a/src/utils/compilation/target_arc.py +++ b/src/utils/compilation/target_arc.py @@ -53,7 +53,7 @@ def setToolchain(self, compiler_path, linker_path, objcopy_path, objcopy_flags): self.compiler_path = compiler_path self.linker_path = linker_path self.objcopy_path = objcopy_path - self.objcopy_flags = [] + objcopy_flags + self.objcopy_flags = list(objcopy_flags) def setNotNative(self): """Mark the compilation as using a toolchain and not the native compiler.""" diff --git a/src/utils/scout_api.py b/src/utils/scout_api.py index d61aa34..ed0ba05 100644 --- a/src/utils/scout_api.py +++ b/src/utils/scout_api.py @@ -62,6 +62,10 @@ def setBitness64(): TARGET_BITNESS = 64 +def isBitness32(): + """Check if the given bitness configuration is for 32-bits.""" + return TARGET_BITNESS == 32 + def addErrorCodes(errors): """Add the given error codes to the supported dictionary. diff --git a/src/utils/scout_compiler.py b/src/utils/scout_compiler.py index 1f19889..5d3f7ae 100644 --- a/src/utils/scout_compiler.py +++ b/src/utils/scout_compiler.py @@ -107,19 +107,20 @@ def setArc(self, arc, is_pic, is_32_bits=True, is_little_endian=True, is_native= self.is_pic = is_pic self.target_arc = arc_factory[arc](is_pic) if is_native: - target_arc.config_flags.append(flag_native_compiler) + self.config_flags.append(flag_native_compiler) else: - target_arc.setNotNative() + self.target_arc.setNotNative() # Configure the architecture - target_arc.setEndianness(is_little_endian) - target_arc.setBitness(is_32_bits) + self.target_arc.setEndianness(is_little_endian) + self.target_arc.setBitness(is_32_bits) self.is_32_bits = is_32_bits self.is_little_endian = is_little_endian # Store the values for the configuration flags self.config_flags.append(flag_32_bit if is_32_bits else flag_64_bit) self.config_flags.append(flag_little_endian if is_little_endian else flag_big_endian) + self.config_flags += list(arc_flags[arc]) if self.is_pic: self.config_flags.append(flag_pic_code) @@ -148,7 +149,7 @@ def setWorkingDirs(self, project_dir, scout_dir, include_dirs=[]): else: main_folder = scout_dir + os.path.sep + ".." - self.target_arc.compile_flags += ['I' + x for x in [project_folder, main_folder] + include_dirs] + self.target_arc.compile_flags += ['I' + x for x in [self.project_folder, main_folder] + include_dirs] def addScoutFlags(self, flags): """Add the flags regarding the target's specifications. @@ -176,7 +177,7 @@ def verifyScoutFlags(self): def generateFlagsFile(self): """Generate the architecture's "flags.h" file.""" # Verify the flags - verifyScoutFlags() + self.verifyScoutFlags() # Verify we know where to store this file if self.project_folder is None: @@ -257,7 +258,7 @@ def compile(self, scout_files, project_files, elf_file): """ self.logger.addIndent() # 1. Auto-Generate the flags.h file - generateFlagsFile() + self.generateFlagsFile() # 2. Prepare the list of compilation files compilation_files = [os.path.join(self.scout_folder, f) for f in scout_files] + project_files @@ -271,11 +272,11 @@ def compile(self, scout_files, project_files, elf_file): if not self.is_pic: # 4. Re-organize the linker flags - fixed_link_flags = "".join("-Wl," + x for x in link_flags.split("-")[1:]) + fixed_link_flags = "".join("-Wl,-" + x for x in link_flags.split("-")[1:]) # 5. Compile together all of the file (and that's it) self.logger.info(f"Compiling the *.c files, linking them together and creating: {elf_file}") - systemLine(f"{target_arc.compiler_path} {compile_flags} {' '.join(compilation_files)} {fixed_link_flags} -o {elf_file}", self.logger) + systemLine(f"{self.target_arc.compiler_path} {compile_flags} {' '.join(compilation_files)} {fixed_link_flags} -o {elf_file}", self.logger) self.logger.removeIndent() return None @@ -290,7 +291,7 @@ def compile(self, scout_files, project_files, elf_file): s_files = [] for c_file in compilation_files: local_out_file = ".".join(c_file.split(".")[:-1]) + ".S" - systemLine(f"{target_arc.compiler_path} -S -c {compile_flags} {c_file} -o {local_out_file}", self.logger) + systemLine(f"{self.target_arc.compiler_path} -S -c {compile_flags} {c_file} -o {local_out_file}", self.logger) s_files.append(local_out_file) # 5. Work-around GCC's bugs @@ -312,20 +313,20 @@ def compile(self, scout_files, project_files, elf_file): o_files = [] for s_file in s_files: local_out_file = ".".join(s_file.split(".")[:-1]) + ".o" - systemLine(f"{target_arc.compiler_path} -c {compile_flags} {s_file} -o {local_out_file}", self.logger) + systemLine(f"{self.target_arc.compiler_path} -c {compile_flags} {s_file} -o {local_out_file}", self.logger) o_files.append(local_out_file) # 7. Link together all of the *.o files self.logger.info(f"Linking together all of the files, creating: {elf_file}") - systemLine(f"{target_arc.linker_path} {link_flags} {' '.join(o_files)} -o {elf_file}", self.logger) + systemLine(f"{self.target_arc.linker_path} {link_flags} {' '.join(o_files)} -o {elf_file}", self.logger) # 8. Objcopy the content to the actual wanted file - if elf_file.split('.')[0].lower() == "elf": + if elf_file.split('.')[-1].lower() == "elf": binary_file = '.'.join(elf_file.split('.')[:-1] + ['bin']) else: binary_file = elf_file + ".bin" self.logger.info(f"Extracting the final binary to: {binary_file}") - systemLine(f"{target_arc.objcopy_path} -O binary -j .text -j .rodata {' '.join(target_arc.objcopy_flags)} {elf_file} {binary_file}", self.logger) + systemLine(f"{self.target_arc.objcopy_path} -O binary -j .text -j .rodata {' '.join(self.target_arc.objcopy_flags)} {elf_file} {binary_file}", self.logger) # 9. Place the PIC context inside the file placeContext(self.full_got, self.global_vars, binary_file, self.logger) diff --git a/src/utils/scout_network.py b/src/utils/scout_network.py index 4a4a1dd..e068425 100644 --- a/src/utils/scout_network.py +++ b/src/utils/scout_network.py @@ -1,4 +1,4 @@ -from scout_api import * +from .scout_api import * import struct import socket From c195f9d0584661f1ce42dd08cf8384387afd7245 Mon Sep 17 00:00:00 2001 From: chkp-eyalit Date: Mon, 3 May 2021 10:11:56 +0300 Subject: [PATCH 25/30] [bugfix] PIC blob should start with _start Updated all architectures so that the compiler won't try to position "main" before "_start" (a problem we didn't have earlier when we used "scout_main"). Also had a check of the PIC compilations in all CPU configs, and some bug fixes in the context-related code. --- examples/embedded_scout/src/compile_scout.py | 2 +- src/scout/pic/arm_pic_wrapper.c | 2 + src/scout/pic/intel_pic_wrapper.c | 44 +++++++------------- src/utils/compilation/target_arc.py | 2 +- src/utils/scout_compiler.py | 26 +++++++++--- 5 files changed, 38 insertions(+), 38 deletions(-) diff --git a/examples/embedded_scout/src/compile_scout.py b/examples/embedded_scout/src/compile_scout.py index f82ce23..bd181ce 100644 --- a/examples/embedded_scout/src/compile_scout.py +++ b/examples/embedded_scout/src/compile_scout.py @@ -64,7 +64,7 @@ def setTargetFlags(logger): compiler = scoutCompiler(logger) # 1. Set the architecture - compiler.setArc(TARGET_ARCH, is_pic=True, is_32_bits=TARGET_BITNESS, is_little_endian=TARGET_ENDIANNESS) + compiler.setArc(TARGET_ARCH, is_pic=True, is_32_bits=TARGET_BITNESS, is_little_endian=TARGET_ENDIANNESS, is_native=TARGET_ARCH == ARC_INTEL) # 2. Set the permission mode (User & low CPU permissions, Kernel & High CPU permissions) compiler.setScoutMode(is_user=True) diff --git a/src/scout/pic/arm_pic_wrapper.c b/src/scout/pic/arm_pic_wrapper.c index a276756..9c16aca 100644 --- a/src/scout/pic/arm_pic_wrapper.c +++ b/src/scout/pic/arm_pic_wrapper.c @@ -22,6 +22,8 @@ #define STATIC_FUNC_ADDR (ELF_START + 0x10) #endif /* SCOUT_ARM_THUMB */ +asm(".section .text.startup,\"ax\",%progbits ;#Scout comment"); + void _start() { main(); diff --git a/src/scout/pic/intel_pic_wrapper.c b/src/scout/pic/intel_pic_wrapper.c index f98e759..3fad00c 100644 --- a/src/scout/pic/intel_pic_wrapper.c +++ b/src/scout/pic/intel_pic_wrapper.c @@ -24,46 +24,30 @@ addr_t get_pc() pic_context_t * get_context() { #ifdef SCOUT_BITS_32 - asm("push %ebx "); - asm("push %ecx "); - asm("lea CONTEXT_LABEL, %ebx "); - asm("call get_pc "); - asm("MEASURE_LABEL1: "); - asm("lea MEASURE_LABEL1, %ecx "); - asm("sub %ecx, %ebx "); - asm("add %ebx, %eax "); - asm("pop %ecx "); - asm("pop %ebx "); + asm("lea CONTEXT_LABEL, %eax "); + asm("call get_live_address "); #else /* SCOUT_BITS_64 */ - /* Function pointers are stored in a PIC fashion by default in 64 bits */ - asm("movq %0, %%rax " : : "r" ((addr_t)address)); + asm("lea CONTEXT_LABEL, %rdi "); + asm("call get_live_address "); #endif /* SCOUT_BITS_32 */ } void * get_live_address(const void * address) { #ifdef SCOUT_BITS_32 - asm("push %ebx "); - asm("push %ecx "); - asm("movl %0, %%ebx " : : "r" ((addr_t)address)); + asm("movl %0, %%edx " : : "r" ((addr_t)address)); asm("call get_pc "); - asm("MEASURE_LABEL2: "); - asm("lea MEASURE_LABEL2, %ecx "); - asm("sub %ecx, %ebx "); - asm("add %ebx, %eax "); - asm("pop %ecx "); - asm("pop %ebx "); + asm("MEASURE_LABEL1: "); + asm("lea MEASURE_LABEL1, %ecx "); + asm("sub %ecx, %edx "); + asm("add %edx, %eax "); #else /* SCOUT_BITS_64 */ - asm("push %rbx "); - asm("push %rcx "); - asm("movq %0, %%rbx " : : "r" ((addr_t)address)); + asm("movq %0, %%rdx " : : "r" ((addr_t)address)); asm("call get_pc "); - asm("MEASURE_LABEL2: "); - asm("lea MEASURE_LABEL2, %rcx "); - asm("sub %rcx, %rbx "); - asm("add %rbx, %rax "); - asm("pop %rcx "); - asm("pop %rbx "); + asm("MEASURE_LABEL1: "); + asm("lea MEASURE_LABEL1, %rcx "); + asm("sub %rcx, %rdx "); + asm("add %rdx, %rax "); #endif /* SCOUT_BITS_32 */ } diff --git a/src/utils/compilation/target_arc.py b/src/utils/compilation/target_arc.py index ef55e4e..db20c8a 100644 --- a/src/utils/compilation/target_arc.py +++ b/src/utils/compilation/target_arc.py @@ -20,7 +20,7 @@ class targetArc: native_objcopy_path = 'objcopy' native_objcopy_flags = () - base_compile_flags = ('fno-builtin', 'Wno-int-to-pointer-cast', 'Wno-pointer-to-int-cast') + base_compile_flags = ('fno-builtin', 'Wno-int-to-pointer-cast', 'Wno-pointer-to-int-cast', 'fno-pic') base_executable_compile_flags = ('O2',) base_pic_compile_flags = ('Os', 'nostdlib', 'fno-toplevel-reorder') base_link_flags = () diff --git a/src/utils/scout_compiler.py b/src/utils/scout_compiler.py index 5d3f7ae..363d86e 100644 --- a/src/utils/scout_compiler.py +++ b/src/utils/scout_compiler.py @@ -295,17 +295,31 @@ def compile(self, scout_files, project_files, elf_file): s_files.append(local_out_file) # 5. Work-around GCC's bugs + # We can afford these changes due to the following: + # a) We only perform them on PIC compilations + # b) PIC compilations don't contain string literals, so we won't conflict with them + # c) Our strings are very specific, so they (probably) won't conflict with something else self.logger.info("Fixing the *.S files to work around GCC's bugs") for s_file in s_files: fd = open(s_file, "r") - content = fd.read() + content_lines = fd.readlines() fd.close() - content = content.replace(".space #", ".space ").replace(".space $", ".space ") - # Mips: convert the calls to relative (PIC) - if self.target_arc.name() == ARC_MIPS: - content = content.replace("\tjal\t", "\tbal\t").replace("\tj\t", "\tb\t") + + new_content_lines = [] + for content in content_lines: + # Makes sure that only our special "_start" will be at the beginning of the compiled blob + # This is needed because gcc tends to place "Main" in .text.startup section, instead of our _start. + if ".section .text.startup" in content and "Scout" not in content: + continue + content = content.replace(".space #", ".space ").replace(".space $", ".space ") + # Mips: convert the calls to relative (PIC) + if self.target_arc.name() == ARC_MIPS: + content = content.replace("\tjal\t", "\tbal\t").replace("\tj\t", "\tb\t") + # save the modified line + new_content_lines.append(content) + fd = open(s_file, "w") - fd.write(content) + fd.writelines(new_content_lines) fd.close() # 6. Generate all of the *.o files From 4189853879f229ac9077f84b37d6d2fcb87dc08e Mon Sep 17 00:00:00 2001 From: chkp-eyalit Date: Mon, 3 May 2021 17:11:32 +0300 Subject: [PATCH 26/30] [bugfix] Support Scout in a mismatching Arm binary When compiling the GOT enable the project to increment the addressess on their side (thumb host), and also allow for a flag of "is_host_thumb" for us to do it on their behalf. This is so we would support a case in which Scout is Thumb but the host is Arm, or vice versa. --- src/utils/scout_compiler.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/utils/scout_compiler.py b/src/utils/scout_compiler.py index 363d86e..c267cbc 100644 --- a/src/utils/scout_compiler.py +++ b/src/utils/scout_compiler.py @@ -202,13 +202,14 @@ def generateFlagsFile(self): # can close the file fd.close() - def populateGOT(self, scout_got, project_got, project_vars_size=0): + def populateGOT(self, scout_got, project_got, project_vars_size=0, is_host_thumb=False): """Populate the PIC context with the GOT entries, and capacity for global variables. Args: scout_got (list): list of (virtual) addresses according to Scout's GOT order project_got (list): list of additional memory addresses for symbols used in the project's GOT projects_vars_size (int, optional): size (in bytes) of the project's global variables (0 by default) + is_host_thumb (bool, optional): True iff the host process is a Thumb binary (False by default) """ # Sanity Check #1 - PIC Compilation if not self.is_pic: @@ -222,8 +223,7 @@ def populateGOT(self, scout_got, project_got, project_vars_size=0): return format = ("<" if self.is_little_endian else ">") + ("L" if self.is_32_bits else "Q") - is_thumb = self.target_arc.name() == ARC_ARM_THUMB - self.full_got = b''.join([struct.pack(format, func + (1 if is_thumb else 0)) for func in scout_got + project_got]) + self.full_got = b''.join([struct.pack(format, func + (1 if is_host_thumb else 0)) for func in scout_got + project_got]) # Calculate the size for the global variables size_globals = project_vars_size From 3758c57aa235792c7cf44a7525d3500f89d4fce7 Mon Sep 17 00:00:00 2001 From: chkp-eyalit Date: Mon, 3 May 2021 18:59:28 +0300 Subject: [PATCH 27/30] [Refactor] Drastically shrink the size of PIC loaders Refactor the base PLT implemention on SLIM_SIZE and remove the htonq/ntohq on 32 bit slim binaries as it turns out that they are very wasty in size. --- src/scout/external_deps.h | 12 ++++++ src/scout/pack.c | 8 ++++ src/scout/pack.h | 8 ++++ src/scout/pic/scout_plt.c | 4 +- src/scout/pic/scout_plt.h | 86 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 116 insertions(+), 2 deletions(-) diff --git a/src/scout/external_deps.h b/src/scout/external_deps.h index 0fc7ba0..ddd89d4 100644 --- a/src/scout/external_deps.h +++ b/src/scout/external_deps.h @@ -14,11 +14,15 @@ typedef addr_t size_t; typedef size_t off_t; +#ifndef SCOUT_SLIM_SIZE + void * memcpy(void * dst, const void * src, size_t size); void * memset(void * dst, int value, size_t size); void * malloc(size_t size); void free(void * ptr); +#endif /* SCOUT_SLIM_SIZE */ + /***************************/ /** Socket Dependencies **/ /***************************/ @@ -67,6 +71,8 @@ struct sockaddr typedef int sock_fd; typedef size_t socklen_t; +#ifndef SCOUT_SLIM_SIZE + sock_fd socket(int domain, int type, int protocol); sock_fd bind(sock_fd socket, const struct sockaddr * address, socklen_t address_len); int listen(sock_fd sockfd, int backlog); @@ -76,6 +82,8 @@ int recv(sock_fd sockfd, void * buf, size_t len, int flags); int send(sock_fd sockfd, void * buf, size_t len, int flags); void close(sock_fd fd); +#endif /* SCOUT_SLIM_SIZE */ + /*************************/ /** MMap Dependencies **/ /*************************/ @@ -102,10 +110,14 @@ void close(sock_fd fd); #endif +#ifndef SCOUT_SLIM_SIZE + void * mmap(void * addr, size_t length, int prot, int flags, int fd, off_t offset); int mprotect(void * addr, size_t len, int prot); int munmap(void * addr, size_t length); +#endif /* SCOUT_SLIM_SIZE */ + #endif /* SCOUT_ISOLATED_ENV */ #endif // __SCOUT__EXTERNAL__DEPS__H__ diff --git a/src/scout/pack.c b/src/scout/pack.c index 302e983..70bd2ad 100644 --- a/src/scout/pack.c +++ b/src/scout/pack.c @@ -128,6 +128,8 @@ uint32_t htonl(uint32_t value) return value; } +#if defined(SCOUT_BITS_64) || !defined(SCOUT_SLIM_SIZE) + uint64_t htonq(uint64_t value) { #ifdef SCOUT_LITTLE_ENDIAN @@ -143,6 +145,8 @@ uint64_t htonq(uint64_t value) return value; } +#endif /* SCOUT_BITS_64 || !SCOUT_SLIM_SIZE */ + uint16_t ntohs(uint16_t value) { #ifdef SCOUT_LITTLE_ENDIAN @@ -161,6 +165,8 @@ uint32_t ntohl(uint32_t value) #endif /* SCOUT_LITTLE_ENDIAN */ } +#if defined(SCOUT_BITS_64) || !defined(SCOUT_SLIM_SIZE) + uint64_t ntohq(uint64_t value) { #ifdef SCOUT_LITTLE_ENDIAN @@ -170,4 +176,6 @@ uint64_t ntohq(uint64_t value) #endif /* SCOUT_LITTLE_ENDIAN */ } +#endif /* SCOUT_BITS_64 || !SCOUT_SLIM_SIZE */ + #endif /* SCOUT_ISOLATED_ENV */ diff --git a/src/scout/pack.h b/src/scout/pack.h index d27d139..94d7d89 100644 --- a/src/scout/pack.h +++ b/src/scout/pack.h @@ -145,6 +145,8 @@ uint16_t htons(uint16_t value); */ uint32_t htonl(uint32_t value); +#if defined(SCOUT_BITS_64) || !defined(SCOUT_SLIM_SIZE) + /** * Converts the given value from host order to network order * @@ -156,6 +158,8 @@ uint32_t htonl(uint32_t value); */ uint64_t htonq(uint64_t value); +#endif /* SCOUT_BITS_64 || !SCOUT_SLIM_SIZE */ + /** * Converts the given value from network order to host order * @@ -178,6 +182,8 @@ uint16_t ntohs(uint16_t value); */ uint32_t ntohl(uint32_t value); +#if defined(SCOUT_BITS_64) || !defined(SCOUT_SLIM_SIZE) + /** * Converts the given value from network order to host order * @@ -189,6 +195,8 @@ uint32_t ntohl(uint32_t value); */ uint64_t ntohq(uint64_t value); +#endif /* SCOUT_BITS_64 || !SCOUT_SLIM_SIZE */ + #endif /* SCOUT_ISOLATED_ENV */ #endif // __SCOUT__PACK__H__ diff --git a/src/scout/pic/scout_plt.c b/src/scout/pic/scout_plt.c index bf1c4c8..d7f3c20 100644 --- a/src/scout/pic/scout_plt.c +++ b/src/scout/pic/scout_plt.c @@ -1,6 +1,6 @@ #include "scout/pic/pic_wrapper.h" -#ifdef SCOUT_PIC_CODE +#if defined(SCOUT_PIC_CODE) && !defined(SCOUT_SLIM_SIZE) /* LibC */ void * memcpy(void * dst, const void * src, size_t size) @@ -83,4 +83,4 @@ int munmap(void * addr, size_t length) #endif /* SCOUT_MMAP */ -#endif /* SCOUT_PIC_CODE */ +#endif /* SCOUT_PIC_CODE && !SCOUT_SLIM_SIZE */ diff --git a/src/scout/pic/scout_plt.h b/src/scout/pic/scout_plt.h index 93188f6..668d5ef 100644 --- a/src/scout/pic/scout_plt.h +++ b/src/scout/pic/scout_plt.h @@ -33,6 +33,92 @@ typedef struct __pic_got #endif /* SCOUT_MMAP */ } pic_got_t; +/** + * If we are short in size (PIC loader), we will have special treatment for the default + * GOT/PLT of Scout itself (without the extensions). As we don't have strings in the code + * when it is under tight size constraints, this solution should be relatively robust. + * + * This way we would save the redundant assembly instructions of loading all arguments to + * registers, calling a PLT function, and then saving them all aside because we first need + * to fetch the context, and only then we need to use them for invoking the real function. + * + * Here is an example from the PLT record of accept in an ARM compilation: + * .text:00008284 EXPORT accept + * .text:00008284 accept + * .text:00008284 0D C0 A0 E1 MOV R12, SP + * .text:00008288 F0 D8 2D E9 PUSH {R4-R7,R11,R12,LR,PC} + * .text:0000828C 04 B0 4C E2 SUB R11, R12, #4 + * .text:00008290 00 40 A0 E1 MOV R4, R0 + * .text:00008294 01 50 A0 E1 MOV R5, R1 + * .text:00008298 02 60 A0 E1 MOV R6, R2 + * .text:0000829C 64 FF FF EB BL get_context + * .text:000082A0 06 20 A0 E1 MOV R2, R6 + * .text:000082A4 1C 30 90 E5 LDR R3, [R0,#0x1C] + * .text:000082A8 05 10 A0 E1 MOV R1, R5 + * .text:000082AC 04 00 A0 E1 MOV R0, R4 + * .text:000082B0 1C D0 4B E2 SUB SP, R11, #0x1C + * .text:000082B4 F0 68 9D E8 LDMFD SP, {R4-R7,R11,SP,LR} + * .text:000082B8 13 FF 2F E1 BX R3 + * .text:000082B8 ; End of function accept + * + * Our solution will use dedicated macros, that will fetch the context prior to invoking + * the function, thus saving these wasted instructions. + */ +#ifdef SCOUT_SLIM_SIZE + +/* LibC */ +#define memcpy(_D_, _S_, _L_) \ + (void * (*)(void *, const void *, size_t))get_context()->functions.scout.memcpy)(_D_, _S_, _L_) + +#define memset(_D_, _V_, _S_) \ + ((void * (*)(void *, int, size_t))get_context()->functions.scout.memset)(_D_, _V_, _S_) + +#define malloc(_S_) \ + ((void * (*)(size_t))get_context()->functions.scout.malloc)(_S_) + +#define free(_P_) \ + (((*)(void *))get_context()->functions.scout.free)(_P_) + +/* Sockets */ +#define socket(_D_, _T_, _P_) \ + ((sock_fd (*)(int, int, int))get_context()->functions.scout.socket)(_D_, _T_, _P_) + +#define bind(_S_, _A_, _L_) \ + ((sock_fd (*)(sock_fd, const struct sockaddr *, socklen_t))get_context()->functions.scout.bind)(_S_, _A_, _L_) + +#define listen(_S_, _B_) \ + ((int (*)(sock_fd, int))get_context()->functions.scout.listen)(_S_, _B_) + +#define accept(_S_, _A_, _L_) \ + ((sock_fd (*)(sock_fd, struct sockaddr *, socklen_t *))get_context()->functions.scout.accept)(_S_, _A_, _L_) + +#define connect(_S_, _A_, _L_) \ + ((int (*)(sock_fd, const struct sockaddr *, socklen_t))get_context()->functions.scout.connect)(_S_, _A_, _L_) + +#define recv(_S_, _B_, _L_, _F_) \ + ((int (*)(sock_fd, void *, size_t, int))get_context()->functions.scout.recv)(_S_, _B_, _L_, _F_) + +#define send(_S_, _B_, _L_, _F_) \ + ((int (*)(sock_fd, void *, size_t, int))get_context()->functions.scout.send)(_S_, _B_, _L_, _F_) + +#define close(_F_) \ + ((void (*)(sock_fd))get_context()->functions.scout.close)(_F_) + +#ifdef SCOUT_MMAP + +#define mmap(_A_, _L_, _P_, _F_, _FD_, _O_) \ + ((void * (*)(void *, size_t, int, int, int, off_t))get_context()->functions.scout.mmap)(_A_, _L_, _P_, _F_, _FD_, _O_) + +#define mprotect(_A_, _L_, _P_) \ + ((int (*)(void *, size_t, int))get_context()->functions.scout.mprotect)(_A_, _L_, _P_) + +#define munmap(_A_, _L_) \ + ((int (*)(void *, size_t))get_context()->functions.scout.munmap)(_A_, _L_) + +#endif /* SCOUT_MMAP */ + +#endif /* SCOUT_SLIM_SIZE */ + #endif /* SCOUT_PIC_CODE */ #endif // __SCOUT__PIC__PLT__H__ From 137fb7d72e758909c24716cf36d393af1b8be909 Mon Sep 17 00:00:00 2001 From: chkp-eyalit Date: Tue, 4 May 2021 08:08:37 +0300 Subject: [PATCH 28/30] [pip] Added pip package dirs to gitignore setup.py properly installs the python package from the vanilla repo, but it generates folder that shouldn't be on the repo itself. --- .gitignore | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 10da5a5..7a00f78 100644 --- a/.gitignore +++ b/.gitignore @@ -40,4 +40,9 @@ src/utils/*.pyc docs/_build/* docs/_build/*/* docs/_build/*/*/* -docs/_build/*/*/*/* \ No newline at end of file +docs/_build/*/*/*/* + +# Python package +build/ +dist/ +scout_debugger.* \ No newline at end of file From 4ae02b62d4871de86395514a34df7f0a8f49223a Mon Sep 17 00:00:00 2001 From: chkp-eyalit Date: Tue, 4 May 2021 08:56:33 +0300 Subject: [PATCH 29/30] [bugfix] Fix PIC context on x86 architectures Properly pass the argument using ths stack instead of by register. Also enhance the embedded_scout example and demonstrate how to use the scout loader through the scout_network api. --- .../manager/embedded_scout_api.py | 2 +- examples/embedded_scout/manager/manager.py | 34 +++++++++++++++---- .../embedded_scout/src/project_instructions.c | 2 +- src/scout/pic/intel_pic_wrapper.c | 2 ++ 4 files changed, 31 insertions(+), 9 deletions(-) diff --git a/examples/embedded_scout/manager/embedded_scout_api.py b/examples/embedded_scout/manager/embedded_scout_api.py index 1fb13a5..5346bde 100644 --- a/examples/embedded_scout/manager/embedded_scout_api.py +++ b/examples/embedded_scout/manager/embedded_scout_api.py @@ -42,4 +42,4 @@ def instrFree(address): Return Value: string containing the serialized instruction """ - return addHeader(EMBEDDED_INST_FREE, struct.pack("!L", address)) + return addHeader(EMBEDDED_INST_FREE, struct.pack("!L" if isBitness32() else "!Q", address)) diff --git a/examples/embedded_scout/manager/manager.py b/examples/embedded_scout/manager/manager.py index ce6f577..e5ad6c9 100644 --- a/examples/embedded_scout/manager/manager.py +++ b/examples/embedded_scout/manager/manager.py @@ -7,6 +7,7 @@ import logging import struct import socket +import time import sys ## @@ -18,21 +19,31 @@ def startManage(sock_fd, logger): logger.info('Allocating a remote memory buffer') data = sendInstr(sock_fd, instrAlloc(0x100), logger) - memory_addr = struct.unpack('!L', data)[0] - logger.info('The buffer was allocated at address: 0x%08x', memory_addr) + memory_addr = struct.unpack("') + print(f'Usage: {args[0]} [full_scout.bin]') print('Exiting') exit(1) @@ -41,17 +52,26 @@ def printUsage(args): ## def main(args): # Check the arguments - if len(args) != 1 + 1: - print(f'Wrong amount of arguments, got {len(args) - 1}, expected 1') + if len(args) not in [1 + 1, 1 + 2]: + print(f'Wrong amount of arguments, got {len(args) - 1}, expected 1/2') printUsage(args) # parse the args - server_ip = args[1] + server_ip = args[1] # open the log prompter = Prompter('Scout Manager', [('scout_log.txt', 'a', logging.DEBUG)]) + # Check if we need to load the full scout before connecting to it + if len(args) == 1 + 2: + scout_path = args[2] + full_scout = open(scout_path, "rb").read() + remoteLoadServer(server_ip, full_scout, prompter) + prompter.info("Waiting for Scout to fully load") + time.sleep(2) + # connect to the server + prompter.info("Connecting to the fully loaded scout") sock_fd = socket.create_connection((server_ip, SCOUT_PORT)) # configure the scout diff --git a/examples/embedded_scout/src/project_instructions.c b/examples/embedded_scout/src/project_instructions.c index f0b9cf8..f323260 100644 --- a/examples/embedded_scout/src/project_instructions.c +++ b/examples/embedded_scout/src/project_instructions.c @@ -32,7 +32,7 @@ int32_t instruction_free(void * ctx, uint8_t * instruction, uint32_t length) uint8_t * readHead = instruction; uint32_t addr; - addr = unpack_uint32( &readHead ); + addr = unpack_addr( &readHead ); /* Sanity check (example for a project-specific status code) */ if(addr == NULL) { diff --git a/src/scout/pic/intel_pic_wrapper.c b/src/scout/pic/intel_pic_wrapper.c index 3fad00c..425ed1a 100644 --- a/src/scout/pic/intel_pic_wrapper.c +++ b/src/scout/pic/intel_pic_wrapper.c @@ -25,7 +25,9 @@ pic_context_t * get_context() { #ifdef SCOUT_BITS_32 asm("lea CONTEXT_LABEL, %eax "); + asm("push %eax "); asm("call get_live_address "); + asm("pop %edx "); #else /* SCOUT_BITS_64 */ asm("lea CONTEXT_LABEL, %rdi "); asm("call get_live_address "); From aacd444769381d513951f2df656c5d83fdda2d08 Mon Sep 17 00:00:00 2001 From: chkp-eyalit Date: Tue, 4 May 2021 09:32:32 +0300 Subject: [PATCH 30/30] [docs] Refresh the docs and README.md Update the docs to reference the added config flags, compile instructions and python setup. --- README.md | 12 ++++++++---- docs/Adding Custom Instructions.md | 19 ++++++++++--------- docs/Compilation Modes.md | 15 ++++++++++----- docs/Default Instructions.md | 7 ++++--- docs/Default Loaders.md | 14 +++++++------- docs/PIC Compilation.md | 13 ++++++++----- docs/User Guide.md | 24 ++++++++++++++---------- 7 files changed, 61 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index b9f1bb3..8d1ac38 100644 --- a/README.md +++ b/README.md @@ -53,13 +53,17 @@ https://scout-debugger.readthedocs.io/ ## Folder Structure * **docs:** Documentation files that generated the read-the-docs that was linked above * **examples:** - * embedded_scout - Use case example for an "Embedded Mode" compilation - * kernel_scout - Use case example for a Linux "Kernel Mode" compilation + * **embedded_scout** - Use case example for an "Embedded Mode" compilation + * **kernel_scout** - Use case example for a Linux "Kernel Mode" compilation * **src** - * scout - Source code for the debugger (core of the server side) - * utils - Python compilation scripts and network API for the client/server + * **scout** - Source code for the debugger (core of the server side) + * **utils** - Python compilation scripts and network API for the client/server * **tests:** A simple exploit_me.c for checking PIC compiled binaries +## Installation +* Installing the python package: ```python3 setup.py install``` +* Dedicated compilers: A list of compilers per-architecture is found on ```compilers.txt``` + ## Credits This projects combines together design and compilation tricks that I learned from many fellow researchers during the years. diff --git a/docs/Adding Custom Instructions.md b/docs/Adding Custom Instructions.md index 7c63edf..0aa3393 100644 --- a/docs/Adding Custom Instructions.md +++ b/docs/Adding Custom Instructions.md @@ -4,9 +4,9 @@ Being an instruction-based debugger, Scout supports project extensions. Registration - C Code --------------------- -* Each of the instructions that are added by the project, should be registerred by calling ```register_instruction()```. -* The registration should take place inside the function ```register_specific_instructions()```. -* This design makes sure that when invoking ```register_all_instructions()```, all of the default instructions, and extension instruction, will be registerred correctly. +* Each of the instructions that are added by the project, should be registerred by calling ``register_instruction()``. +* The registration should take place inside the function ``register_specific_instructions()``. +* This design makes sure that when invoking ``register_all_instructions()``, all of the default instructions, and extension instruction, will be registerred correctly. Implementation - C Code ----------------------- @@ -15,15 +15,15 @@ In order to implement a new instruction, one should define each of the required * Instruction ID - must be unique, but not necessarily consecutive * Minimal Length - minimal amount of bytes needed for a valid instruction (robustness checks) * Maximal Length - maximal amount of bytes needed for a valid instruction (robustness checks) -* Instruction handler - a handler function with a fixed signature of: ```int32_t (*instrHandler)(void * ctx, uint8_t * instruction, uint32_t length)``` +* Instruction handler - a handler function with a fixed signature of: ``int32_t (*instrHandler)(void * ctx, uint8_t * instruction, uint32_t length)`` -**Note:** The instructions are stored in a global array with a **fixed** capacity. When adding new instructions, one should make sure to adjust this capacity accordingly. -The capacity is defined in ```scout_api.h``` and is set by default to ```#define SCOUT_MAX_INSTRS (10)```. +**Note:** The instructions are stored in a global array with a **fixed** capacity. When adding new instructions, one should make sure to adjust this capacity accordingly (both in the C and .py files). +The capacity is defined in ``scout_api.h`` and is set by default to ``#define SCOUT_MAX_INSTRS (10)``. Examples - C Code ----------------- -* Embedded mode (```embedded_scout```) - files ```project_instructions``` (*.c and *.h) -* Linux Kernel mode (```kernel_scout```) - files ```driver\scout_kernel_instructions``` (*.c and *.h) +* Embedded mode (``embedded_scout``) - files ``project_instructions`` (*.c and *.h) +* Linux Kernel mode (``kernel_scout``) - files ``driver\scout_kernel_instructions`` (*.c and *.h) Client Side - Python Code ------------------------- @@ -34,4 +34,5 @@ In the client side, adding a new instructions is even easier, and requires only Examples - Python Code ---------------------- -* Linux Kernel example (```manager```) - file ```kernel_scout_api.py``` \ No newline at end of file +* Embedded example (``manager``) - file ``embedded_scout_api.py`` +* Linux Kernel example (``manager``) - file ``kernel_scout_api.py`` diff --git a/docs/Compilation Modes.md b/docs/Compilation Modes.md index e2dc056..266cdc2 100644 --- a/docs/Compilation Modes.md +++ b/docs/Compilation Modes.md @@ -11,6 +11,9 @@ Scout is a configurable debugger, that could be deployed in several different en To decide what will be the suitable compilation mode / architecture flags, one should check the following parameters. Each of the defined parameters is a C MACRO (define) that controls the behavior (and compilation) of the resulting binary. +**Important Note:** +When using ``scoutCompiler``, it will automatically generate most of the needed flags by deducing the right values based on the architecture and configuration flags that are supplied to it. Please see the ``embedded_scout`` example for more info. + Target Endianness ----------------- * SCOUT_BIG_ENDIAN - Scout is executed on a Big Endian architecture @@ -37,7 +40,7 @@ Only one of above flags can be defined. If none are defined the base library will define "SCOUT_ARCH_INTEL" on it's own. **Additional Flags:** -* SCOUT_ARM_THUMB - Scout will be executed on an ARM cpu in Thumb mode. Can only be used together with the "SCOUT_ARCH_ARM" flag. +SCOUT_ARM_THUMB - Scout will be executed on an ARM cpu in Thumb mode. Can only be used together with the "SCOUT_ARCH_ARM" flag. The flags are needed only in PIC mode, in which we use inline assembly. @@ -51,6 +54,8 @@ If none are defined the base library will define "SCOUT_MODE_USER" on it's own. "SCOUT_MODE_KERNEL" will also be the right choice for an RTOS (Real-time OS) in which every task / our task has high privileges. The flag will lead to the definition of "SCOUT_HIGH_PRIVILEGES" by the compilation environment. +**Important Note:** As flushing the CPU cache usually requires high privileges, the per-architecture implementation will only be available if compiling using the "SCOUT_MODE_KERNEL" flag. + Position Independent Mode - SCOUT_PIC_CODE ------------------------------------------ Scout will be compiled for full Position Independent Code (PIC) mode. Any access to an external function / global variable will pass through a unique "Context" object. Read the section about "PIC Compilation" for more information. @@ -69,9 +74,9 @@ Loader Flags ------------ * SCOUT_LOADER - We are now compiling a loader (that might be using it's own pic plt / globals). * SCOUT_LOADING_THUMB_CODE - The loader will load a Scout that was compiled to be executed on an ARM cpu in Thumb mode. -* SCOUT_RESTORE_FLOW - The default loaders (```tcp_client_server.c```, ```tcp_loader_server.c```) will clean-up after themselves if the loaded scout will finish the endless loop. +* SCOUT_RESTORE_FLOW - The default loaders (``tcp_client_server.c``, ``tcp_loader_server.c``) will clean-up after themselves if the loaded scout will finish the endless loop. -If the loader will be compiled to be Position Independent (PIC), which is probably the most common use case, it will also define a new flag of "SCOUT_SLIM_SIZE", to help shrink the size of the binary (to serve as an effective shellcode. +If the loader will be compiled to be Position Independent (PIC), which is probably the most common use case, it will also define a new flag of "SCOUT_SLIM_SIZE", to help shrink the size of the binary (to serve as an effective shellcode). Under this definition the TCP server would expect the following flags (if needed): * SCOUT_TCP_CLIENT - There is a need to include the feature of a TCP client * SCOUT_TCP_SERVER - There is a need to include the feature of a TCP server @@ -80,6 +85,6 @@ Under this definition the TCP server would expect the following flags (if needed Additional Flags: ----------------- * SCOUT_INSTRUCTIONS - Scout is going to use the instructions api (using the TCP server for instance) -* SCOUT_DYNAMIC_BUFFERS - Scout will dynamically ```malloc()``` buffers to be used by the tcp server. Otherwise static buffers will be used. +* SCOUT_DYNAMIC_BUFFERS - Scout will dynamically ``malloc()`` buffers to be used by the tcp server. Otherwise static buffers will be used. * SCOUT_PROXY - Scout is going to act as a proxy (user scout passing instructions to a kernel driver for instance) -* SCOUT_MMAP - Should scout's loaders use ```mmap()``` and ```mprotect()``` when loading (if defined) or should they simply use ```malloc()``` (if undefined) +* SCOUT_MMAP - Should scout's loaders use ``mmap()`` and ``mprotect()`` when loading (if defined) or should they simply use ``malloc()`` (if undefined) diff --git a/docs/Default Instructions.md b/docs/Default Instructions.md index 577a35b..1549fa7 100644 --- a/docs/Default Instructions.md +++ b/docs/Default Instructions.md @@ -4,19 +4,20 @@ Scout is an instruction-based debugger, that commonly uses a TCP network session Default Instructions -------------------- -* **NOP** - Used as a Pong (or Keep-Alive) instruction to make sure the debugger is active and responds to commands +* **NOP** - Used as a Ping (or Keep-Alive) instruction to make sure the debugger is active and responds to commands * **Memory Read** - Reads (virtual) memory from the given address, and sends it back * **Memory Write** - Writes a given binary content to a (virtual) memory in the debuggee's address space -Each supported instruction must be pre-registered by the debugger before it enters his server loop, usually by calling ```register_all_instructions()```. +Each supported instruction must be pre-registered by the debugger before it enters his server loop, usually by calling ``register_all_instructions()``. Network API ----------- Each instruction is sent together with a network header that includes the following: + * Instruction ID - 2 Bytes * Length field - 4 Bytes The length field specifies the length, in bytes, of the serialized instruction. **Note:** All instructions should be serialized to NETWORK order. -See ```manager\scout_api.py``` for a python sample that prepares the instructions for network transmission. +See ``manager\scout_api.py`` for a python sample that prepares the instructions for network transmission. diff --git a/docs/Default Loaders.md b/docs/Default Loaders.md index 07498aa..5cdbd27 100644 --- a/docs/Default Loaders.md +++ b/docs/Default Loaders.md @@ -8,8 +8,8 @@ To overcome these limitations, the scout debugger comes with a list of supported The defualt loaders are: -1. ```tcp_client_loader.c``` - Connects to a predefined TCP server -2. ```tcp_server_loader.c``` - Waits for an incoming TCP client +1. ``tcp_client_loader.c`` - Connects to a predefined TCP server +2. ``tcp_server_loader.c`` - Waits for an incoming TCP client Both of the loaders use the same network protocol: @@ -18,13 +18,13 @@ Both of the loaders use the same network protocol: After a TCP connection was established, the loader will follow these steps: -1. The loader will receive the header and malloc() a memory buffer of appropriate size. +1. The loader will receive the header and ``malloc()``/``mmap()`` a memory buffer of appropriate size. 2. The data will be received and stored in this memory buffer. -3. The loader will flush the D-cache and I-cache of the buffer (only in architectures were this is needed) -4. The loader will mprotect() the memory to use the correct permissions (only in architectures were this is needed) +3. The loader will flush the D-cache and I-cache of the buffer (only in architectures were this is needed, and only if we have high enough CPU privileges for it) +4. The loader will ``mprotect()`` the memory to use the correct permissions (only in architectures were this is needed) 5. The loader will jump into the buffer's start (offset 0, as mentioned in the "PIC Compilation" section) -6. In the flow restore case, once the loaded executable finishes the loader will free the memory and close the used sockets. +6. In the flow restore case, once the loaded executable finishes, the loader will free the memory and close the used sockets. -The functions ```remoteLoadServer()``` and ```remoteLoadClient()``` in ```scout_network.py```, implement the required protocol for communicating with the loader, and loading up the full Scout. +The functions ``remoteLoadServer()`` and ``remoteLoadClient()`` in ``scout_network.py``, implement the required protocol for communicating with the loader, and loading up the full Scout. A working example is shown under the ``manager.py`` of the ``embedded_scout`` example. **Note:** In case there are any W^X style limitations in your environment, it is recommended to make sure that the allocated memory for the full debugger will have both Write and eXcutable permissions (should probably use the SCOUT_MMAP flag in this case). diff --git a/docs/PIC Compilation.md b/docs/PIC Compilation.md index 8af9e36..aecbdd4 100644 --- a/docs/PIC Compilation.md +++ b/docs/PIC Compilation.md @@ -6,13 +6,14 @@ Entry Point ----------- The entry point to our executable blob is at offset 0, meaning that we can literally jump into our buffer's start. -**IMPORATNT:** This can only be achieved if the ```*_pic_wrapper.c``` file will be linked as the FIRST file in the list of files. In case there are any errors it is always recommended to check if the compiled files were compiled in a different order. +**IMPORATNT:** This can only be achieved if the ``*_pic_wrapper.c`` file will be linked as the FIRST file in the list of files. In case there are any errors it is always recommended to check if the compiled files were compiled in a different order. -From the project's point of view, the main function is called ```main``` (as usual), since this is the function that will be executed by the start stub at offset 0. +From the project's point of view, the main function is called ``main`` (as usual), since this is the function that will be executed by the start stub at offset 0. The Context ----------- The PIC Context consists of 4 parts: + * Base scout "PLT" * Project "PLT" * Base scout "Globals" @@ -22,19 +23,21 @@ The code is compiled so that any call to an external function (library call) wil In a similar fashion, the code is compiled (and developed) so that any access to a global variable will pass through an indirection layer. This layer will locate the scout's context object, and will find the offset of the global variable inside the PIC context. +**Important Note:** There is an edge case in which Scout will be compiled as an Arm Thumb PIC blob, to be executed in the address space of a regular Arm process, or vice versa. In this case the user's compile script could either supply the GOT addresses with their actual (+0/+1) memory addresses, or could use the ``is_host_thumb`` flag of function ``populateGOT`` of the ``scoutCompiler`` to fix it automatically. + Locating the Context -------------------- -Our code can be compiled so that it will access the PIC context instead of being linked as an ordinary ELF. Now we only need to tell our code how to be able to locate the context's address in runtime, using a PIC way. The context itself will be embedded INSIDE the full executed binary blob, so that it will be stored in a known relative offset from our code. The final step of deriving the absolute address of the context will be solved using an assembly layer: ```*_pic_wrapper.c```. +Our code can be compiled so that it will access the PIC context instead of being linked as an ordinary ELF. Now we only need to tell our code how to be able to locate the context's address in runtime, using a PIC way. The context itself will be embedded INSIDE the full executed binary blob, so that it will be stored in a known relative offset from our code. The final step of deriving the absolute address of the context will be solved using an assembly layer: ``*_pic_wrapper.c``. **Important Note:** Locating the context is done in assembly, hence this is the only part that depends on the architecture on which we will be executed. Expanding the Context --------------------- -In order to be able to use additional symbols (functions) or globals (global variables), we need to add them to the respective ```project_plt.c``` and ```project_globals.c``` files, accordingly. Please make sure that the compilation script will be notified of these additions, so that the GOT will contain the needed addresses and the globals section will be of the correct size. +In order to be able to use additional symbols (functions) or globals (global variables), we need to add them to the respective ``project_plt.c`` and ``project_globals.c`` files, accordingly. Please make sure that the compilation script will be notified of these additions, so that the GOT will contain the needed addresses and the globals section will be of the correct size. Testing - exploit_me -------------------- -The ```exploit_me.c``` module in the testing folder lets you test your PIC scout (with / without a loader). As you can see in the "Known Gaps" section (point 2), it is recommended that the test will be done on a setup that contains RWX environments (Linux VMs without the NX bit exposed, for instance). +The ``exploit_me.c`` module in the testing folder lets you test your PIC scout (with / without a loader). As you can see in the "Known Gaps" section (point 2), it is recommended that the test will be done on a setup that contains RWX environments (Linux VMs without the NX bit exposed, for instance). Known Gaps ---------- diff --git a/docs/User Guide.md b/docs/User Guide.md index 0eed124..ed4c46d 100644 --- a/docs/User Guide.md +++ b/docs/User Guide.md @@ -9,18 +9,22 @@ The server is the debugger that is being sent / injected into the debugee, and t Folder Structure ---------------- -* docs - This documentation -* examples - * embedded_scout - Use case example for an "Embedded Mode" compilation - * kernel_scout - Use case example for a Linux "Kernel Mode" compilation -* src - * scout - Source code for the debugger (core of the server side) - * utils - Python compilation scripts and network API for the client/server -* tests - A simple exploit_me.c for checking PIC compiled binaries - ++ **docs** - This documentation ++ **examples** + - **embedded_scout** - Use case example for an "Embedded Mode" compilation + - **kernel_scout** - Use case example for a Linux "Kernel Mode" compilation ++ **src** + - **scout** - Source code for the debugger (core of the server side) + - **utils** - Python compilation scripts and network API for the client/server ++ **tests** - A simple exploit_me.c for checking PIC compiled binaries **Note:** More information on the different compilation modes can be found under the "Compilation Modes" section. +Installation +------------ +* Installing the python package: ``python3 setup.py install`` +* Dedicated compilers: A list of compilers per-architecture is found on ``compilers.txt`` + Beginner's Guide ---------------- When deploying Scout for a new research project, we recommend to pick the suitable use case out of the two examples. Both the "Embedded Mode" and the Linux "Kernel Mode" use case examples are supplied so that they will serve as templates for new projects. @@ -31,4 +35,4 @@ The project part of the server side consists of the following parts: * Project Instructions - When adding custom instructions * Loader PIC - globals / plt for the loader in an Embedded Mode * Project PIC - globals / plt for the project's extensions in an Embedded Mode -* Compilation Script - ```compile_scout.py``` with the compile instructions \ No newline at end of file +* Compilation Script - ``compile_scout.py`` with the compile instructions \ No newline at end of file