From 5df51d811ba37f326ff3e7c2d444799b9646503a Mon Sep 17 00:00:00 2001 From: ALittlePatate Date: Mon, 19 Aug 2024 13:05:48 +0200 Subject: [PATCH] add: writing to arrays, hex in arrays fix: arguments parsing, show_error on windows --- examples/shellcode.pasm | 34 ++++++++++++++++++++++++++++++++++ msvc/interpreter.vcxproj.user | 4 ++-- src/api.c | 31 +++++++++++++++++++++++++++++++ src/api.h | 6 ++++++ src/debug.c | 2 +- src/file_utils.c | 2 +- src/instructions.c | 34 +++++++++++++++++----------------- src/interpreter_states.c | 21 ++++++++++++++++++++- src/interpreter_states.h | 1 + src/pasm.c | 7 ++++--- tests/interpreter.c | 8 ++++---- 11 files changed, 121 insertions(+), 29 deletions(-) create mode 100644 examples/shellcode.pasm diff --git a/examples/shellcode.pasm b/examples/shellcode.pasm new file mode 100644 index 0000000..a068c8d --- /dev/null +++ b/examples/shellcode.pasm @@ -0,0 +1,34 @@ +; Program that demonstrate the execution of a shellcode using pasm (using a Win32 calc.exe shellcode) + +set arr 0x31, 0xc9, 0xf7, 0xe1, 0x64, 0x8b, 0x41, 0x30, 0x8b, 0x40, 0x0c, 0x8b, 0x70, 0x14, 0xad, 0x96, 0xad, 0x8b, 0x58, 0x10, 0x8b, 0x53, 0x3c, 0x01, 0xda, 0x8b, 0x52, 0x78, 0x01, 0xda, 0x8b, 0x72, 0x20, 0x01, 0xde, 0x31, 0xc9, 0x41, 0xad, 0x01, 0xd8, 0x81, 0x38, 0x47, 0x65, 0x74, 0x50, 0x75, 0xf4, 0x81, 0x78, 0x0a, 0x72, 0x65, 0x73, 0x73, 0x75, 0xeb, 0x8b, 0x72, 0x24, 0x01, 0xde, 0x66, 0x8b, 0x0c, 0x4e, 0x49, 0x8b, 0x72, 0x1c, 0x01, 0xde, 0x8b, 0x14, 0x8e, 0x01, 0xda, 0x89, 0xd5, 0x31, 0xc9, 0x68, 0x73, 0x41, 0x61, 0x61, 0x66, 0x81, 0x6c, 0x24, 0x02, 0x61, 0x61, 0x68, 0x6f, 0x63, 0x65, 0x73, 0x68, 0x74, 0x65, 0x50, 0x72, 0x68, 0x43, 0x72, 0x65, 0x61, 0x54, 0x53, 0xff, 0xd2, 0x31, 0xc9, 0xb1, 0xff, 0x31, 0xff, 0x57, 0xe2, 0xfd, 0x68, 0x63, 0x61, 0x6c, 0x63, 0x89, 0xe1, 0x51, 0x51, 0x31, 0xd2, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x51, 0x52, 0xff, 0xd0, 0x83, 0xc4, 0x10, 0x68, 0x65, 0x73, 0x73, 0x61, 0x66, 0x83, 0x6c, 0x24, 0x03, 0x61, 0x68, 0x50, 0x72, 0x6f, 0x63, 0x68, 0x45, 0x78, 0x69, 0x74, 0x54, 0x53, 0xff, 0xd5, 0x31, 0xc9, 0x51, 0xff, 0xd0 + +main: +push 64 ; flprotect (PAGE_EXECUTE_READWRITE) +push 12288 ; alloctype (MEM_COMMIT | MEM_RESERVE) +push 176 ; size +push 0 ; address +call VirtualAlloc + +mov a4, eax ; copy of address +mov a1, eax ; address +mov a3, arr +mov a2, 0 ; count +memcpy: +cmp a2, 176 +jne 1 +jmp 6 ; jmp out of memcpy +mov *a1, *a3 +add a1, 1 +add a3, 8 +add a2, 1 +jmp memcpy + +push a4 +call CallRawAddress + +memcpy_end: +push 32768 ; free type (MEM_RELEASE) +push 0 ; size (all) +push a4 ; address +call VirtualFree +end \ No newline at end of file diff --git a/msvc/interpreter.vcxproj.user b/msvc/interpreter.vcxproj.user index f621c28..2c2cff5 100644 --- a/msvc/interpreter.vcxproj.user +++ b/msvc/interpreter.vcxproj.user @@ -1,7 +1,7 @@  - ../examples/array.pasm + ../examples/shellcode.pasm WindowsLocalDebugger @@ -9,7 +9,7 @@ WindowsLocalDebugger - ../examples/array.pasm + ../examples/ptr.pasm WindowsLocalDebugger diff --git a/src/api.c b/src/api.c index e449616..407e9ea 100644 --- a/src/api.c +++ b/src/api.c @@ -43,3 +43,34 @@ void api_getasynckeystate() { state->registers->eax = 1; #endif } + +void api_virtualalloc() { +#ifdef _WIN32 + long long address = state->STACK[state->STACK_IDX--]; + long long size = state->STACK[state->STACK_IDX--]; + long long alloctype = state->STACK[state->STACK_IDX--]; + long long flprotect = state->STACK[state->STACK_IDX--]; + state->registers->eax = (long long)VirtualAlloc((LPVOID)address, (SIZE_T)size, (DWORD)alloctype, (DWORD)flprotect); +#else + state->STACK_IDX -= 4; + state->registers->eax = 1; +#endif +} + +void api_virtualfree() { +#ifdef _WIN32 + long long address = state->STACK[state->STACK_IDX--]; + long long size = state->STACK[state->STACK_IDX--]; + long long freetype = state->STACK[state->STACK_IDX--]; + state->registers->eax = VirtualFree((LPVOID)address, (SIZE_T)size, (DWORD)freetype); +#else + state->STACK_IDX -= 3; + state->registers->eax = 1; +#endif +} + +void api_callrawaddr() { + long long address = state->STACK[state->STACK_IDX--]; + + ((void (*)())address)(); +} diff --git a/src/api.h b/src/api.h index 63967b8..89dc6f1 100644 --- a/src/api.h +++ b/src/api.h @@ -3,10 +3,16 @@ void api_put(); void api_getasynckeystate(); +void api_virtualalloc(); +void api_virtualfree(); +void api_callrawaddr(); static const command_t api_map[] = { {.command = "put", .fptr = api_put}, {.command = "GetAsyncKeyState", .fptr = api_getasynckeystate}, + {.command = "VirtualAlloc", .fptr = api_virtualalloc}, + {.command = "VirtualFree", .fptr = api_virtualfree}, + {.command = "CallRawAddress", .fptr = api_callrawaddr}, {.command = NULL, .fptr = NULL} }; diff --git a/src/debug.c b/src/debug.c index 2118c2a..df9c161 100644 --- a/src/debug.c +++ b/src/debug.c @@ -163,7 +163,7 @@ void debug_input(char *line) { printf("%s is not a valid label or line number in this context", &in[2]); break; case 'e': - state->should_exit = 1; + state->should_exit = 0; return; case 'h': default: diff --git a/src/file_utils.c b/src/file_utils.c index 369b304..30978b6 100644 --- a/src/file_utils.c +++ b/src/file_utils.c @@ -4,7 +4,7 @@ #include "interpreter_states.h" -#define MAX_LINE 1024 +#define MAX_LINE 2048 #ifdef _WIN32 extern int dprintf(int stream, const char *format, ...); diff --git a/src/instructions.c b/src/instructions.c index e673ca4..6987556 100644 --- a/src/instructions.c +++ b/src/instructions.c @@ -45,6 +45,8 @@ bool check_args(s_arguments *args, int num_in_first, int num_args) { } long long* get_reg(char* reg_char) { + int deref = reg_char[0] == '*'; + if (reg_char[0] == '&' || reg_char[0] == '*') ++reg_char; for (int i = 0; i < state->num_arrays; i++) @@ -52,25 +54,25 @@ long long* get_reg(char* reg_char) { return (long long *)&state->ARRAYS_VALUES[i]; switch (reg_char[1]) { case '1' : - return &state->registers->a1; + return deref ? (long long*)state->registers->a1 : &state->registers->a1; case '2' : - return &state->registers->a2; + return deref ? (long long*)state->registers->a2 : &state->registers->a2; case '3' : - return &state->registers->a3; + return deref ? (long long*)state->registers->a3 : &state->registers->a3; case '4' : - return &state->registers->a4; + return deref ? (long long*)state->registers->a4 : &state->registers->a4; case '5' : - return &state->registers->a5; + return deref ? (long long*)state->registers->a5 : &state->registers->a5; case '6' : - return &state->registers->a6; + return deref ? (long long*)state->registers->a6 : &state->registers->a6; case '7' : - return &state->registers->a7; + return deref ? (long long*)state->registers->a7 : &state->registers->a7; case '8' : - return &state->registers->a8; + return deref ? (long long*)state->registers->a8 : &state->registers->a8; case '9' : - return &state->registers->a9; + return deref ? (long long*)state->registers->a9 : &state->registers->a9; case 'a' : //eax - return &state->registers->eax; + return deref ? (long long*)state->registers->eax : &state->registers->eax; default : return NULL; //should never happen } @@ -83,11 +85,8 @@ long long get_value(char* arg) { if (arg[0] == '&') { ret = (long long)get_reg(arg); } - else if (arg[0] == '*') { - ret = *(long long *)(*get_reg(arg)); - } - else { - ret = *get_reg(arg); + else { + ret = *get_reg(arg); } } else { @@ -289,7 +288,8 @@ void push() { } } else { - value = (int)state->args->arg1[0]; + if (state->args->arg1[0] != '0') + value = (int)state->args->arg1[0]; } } @@ -327,5 +327,5 @@ void _xor() { } void end() { - state->should_exit = 1; + state->should_exit = 0; //could use EAX for return code but i don't think i care } diff --git a/src/interpreter_states.c b/src/interpreter_states.c index 4e01bd9..9620ecb 100644 --- a/src/interpreter_states.c +++ b/src/interpreter_states.c @@ -50,6 +50,7 @@ int init_state() { state->STACK_IDX = -1; state->last_stack_code = STACK_OK; state->last_check_args_code = OK; + state->should_exit = -1; return 0; } @@ -215,7 +216,12 @@ ARRAY_ERR add_array(char* line) { while (ptr != NULL && j < array_size) { if (ptr[0] == ' ') ++ptr; - arr[j++] = atoi(ptr); + if (strlen(ptr) > 2 && ptr[0] == '0' && ptr[1] == 'x') { + arr[j++] = strtol(ptr, NULL, 16); + } + else { + arr[j++] = atoi(ptr); + } ptr = strtok(NULL, ","); } state->ARRAYS_VALUES[state->num_arrays++] = arr; @@ -243,6 +249,19 @@ char *extract_arg(char *ptr, int a) { return arg; } +void sanitize_arguments() { //removes trailing spaces + if (state->args->arg1 == NULL) + return; + for (int i = 0; state->args->arg1[i] != '\0'; i++) + if (state->args->arg1[i] == ' ' || state->args->arg1[i] == '\t' || state->args->arg1[i] == '\n') + state->args->arg1[i] = '\0'; + if (state->args->arg2 == NULL) + return; + for (int i = 0; state->args->arg2[i] != '\0'; i++) + if (state->args->arg2[i] == ' ' || state->args->arg2[i] == '\t' || state->args->arg2[i] == '\n') + state->args->arg2[i] = '\0'; +} + int parse_arguments(char *line) { strcpy(state->args->arg1, ""); strcpy(state->args->arg2, ""); diff --git a/src/interpreter_states.h b/src/interpreter_states.h index 850d6a9..47fc149 100644 --- a/src/interpreter_states.h +++ b/src/interpreter_states.h @@ -78,4 +78,5 @@ void set_exit_state(int exit_state); int get_exit_state(); LABEL_ERR add_label(char *label, int line); ARRAY_ERR add_array(char *line); +void sanitize_arguments(); int parse_arguments(char *args); diff --git a/src/pasm.c b/src/pasm.c index a793453..24592be 100644 --- a/src/pasm.c +++ b/src/pasm.c @@ -36,7 +36,7 @@ int dprintf(int stream, const char * format, ...) { void show_error(size_t line, char *line_) { #ifdef _WIN32 - int wrote = dprintf(fstream, "%llu| ", line + 1); + int wrote = dprintf(fstream, "%ld| ", line + 1); #else int wrote = dprintf(fstream, "%ld| ", line + 1); #endif @@ -86,7 +86,7 @@ int check_errors(char *line) { /* _fstream: file descriptor for the output (can be a socket), default: stderr */ /* return value: nonzero if an error occurred */ int pasm_run_script(const char *filename, char **file, size_t lines, int _fstream) { - fstream = _fstream; + fstream = _fstream; if (filename && read_script(filename, &file, &lines) == 1) return 1; @@ -97,7 +97,7 @@ int pasm_run_script(const char *filename, char **file, size_t lines, int _fstrea } int found_main = 0; - for (state->curr_line = 0; state->curr_line < (int)lines && get_exit_state() == 0 ; ++state->curr_line) { + for (state->curr_line = 0; state->curr_line < (int)lines && get_exit_state() == -1 ; ++state->curr_line) { if (pasm_debug_mode && found_main) debug_input(file[state->curr_line]); #ifdef _WIN32 @@ -137,6 +137,7 @@ int pasm_run_script(const char *filename, char **file, size_t lines, int _fstrea continue; } parse_arguments(file[state->curr_line]); + sanitize_arguments(); if (found_main) com->fptr(); if (check_errors(file[state->curr_line])) { diff --git a/tests/interpreter.c b/tests/interpreter.c index 6b7c144..cafcd97 100644 --- a/tests/interpreter.c +++ b/tests/interpreter.c @@ -5,12 +5,12 @@ int main(int argc, char **argv) { if (argc > 3 || (argc == 2 && strcmp(argv[1], "-h") == 0) || (argc != 2 && argc != 3)) { - fprintf(stderr, "usage : %s filename [-d/--debug]\n", argv[0]); - return 1; + fprintf(stderr, "usage : %s filename [-d/--debug]\n", argv[0]); + return 1; } if (argc == 3 && (strcmp(argv[2], "-d") == 0 || strcmp(argv[2], "--debug") == 0)) { - pasm_debug_mode = 1; - printf("pasm: debug mode activated.\n"); + pasm_debug_mode = 1; + printf("pasm: debug mode activated.\n"); } return pasm_run_script(argv[1], 0, 0, 1); }