From 66a49c9d1aa374eb0056b861ad25d76e1e230ca5 Mon Sep 17 00:00:00 2001 From: ALittlePatate Date: Wed, 31 May 2023 08:48:15 +0200 Subject: [PATCH] add ret, call, stack v1 let's go ! --- README.md | 10 ++++---- examples/README.md | 2 +- examples/keylogger.pasm | 9 +++---- src/api.c | 13 +++++++++- src/api.h | 9 +++++++ src/instructions.c | 55 ++++++++++++++++++++++++++++++++++------- src/instructions.h | 9 ++++++- src/main.c | 26 ++++++++++++++++--- src/main.h | 6 ++++- src/parser.c | 2 +- 10 files changed, 113 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 322840f..d9d79e2 100644 --- a/README.md +++ b/README.md @@ -9,11 +9,11 @@ PASM is meant for being used in C2 agents as its interpreter is small. PASM is not a language that you daily use, it is not meant for big projects but rather for scripting using existing API (here the Windows API's but it can get extended). # Current state -At the moment i'm trying to get everything working before refactoring (there are bad practices and redundant code) and getting rid of the CRT, here is what is left to do : -- make control flow work (ret is gonna be a pain) (i need to fix the char_read counter, strlen doing its things ig) -- add the API -- think of a more clever way of going through the labels and later the API (currently done in get_instruction.c and instructions.c) -- make the stack work +PASM is in a working state, the [keylogger example](#code-examples) works like a charm. + +TODO : +- code refactor (still bad practices) +- get rid of the CRT (so we can get a smaller PE) - write the docs # Usage diff --git a/examples/README.md b/examples/README.md index 61f07b3..1e59cb4 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,2 +1,2 @@ # keylogger -This is a POC, i don't even know if it works as the interpreter and scripts are in very early stages \ No newline at end of file +Will output the pressed key. Works for keys from A-Z and 0-9. diff --git a/examples/keylogger.pasm b/examples/keylogger.pasm index e2911c4..09c6d8f 100644 --- a/examples/keylogger.pasm +++ b/examples/keylogger.pasm @@ -19,10 +19,10 @@ ; note about returns : you can directly call ret from a je/jne/ja/jna/jb/jnb with "jb return". ; so return cannot be used as a label. check: -cmp a1, 58 +cmp a1, 57 jb return ; if < -cmp a1, 64 +cmp a1, 63 ja return ; if > mov eax, 1 @@ -48,12 +48,11 @@ add a1, 1 ; i++ push a1 ; arg 1 (vKey) call GetAsyncKeyState -and eax, 32768 ; 0x8000 but i haven't implemented hex yet +and eax, 1 cmp eax, 0 je numbers ; if GetAsyncKeyState was false, jump to numbers mov a2, a1 ; necessary ? -push "%c" ; push format push a2 ; push char -call printf +call put jmp numbers \ No newline at end of file diff --git a/src/api.c b/src/api.c index bfa6e39..480c4bb 100644 --- a/src/api.c +++ b/src/api.c @@ -1 +1,12 @@ -#include "api.h" \ No newline at end of file +#include "api.h" +#include "main.h" + +#include + +void api_put() { + printf("%c\n", stack[top--]); +} + +void api_getasynckeystate() { + eax = GetAsyncKeyState(stack[top--]); +} \ No newline at end of file diff --git a/src/api.h b/src/api.h index 45dcbb0..88c196d 100644 --- a/src/api.h +++ b/src/api.h @@ -1,3 +1,12 @@ #pragma once +#include "instructions.h" +void api_put(); +void api_getasynckeystate(); +static const command_t api_map[] = { + {.command = "put", .fptr = api_put}, + {.command = "GetAsyncKeyState", .fptr = api_getasynckeystate}, + + {.command = NULL, .fptr = NULL} +}; diff --git a/src/instructions.c b/src/instructions.c index 509bca7..50e73d1 100644 --- a/src/instructions.c +++ b/src/instructions.c @@ -1,5 +1,6 @@ #include "instructions.h" #include "main.h" +#include "api.h" #include #include #include @@ -64,13 +65,13 @@ int get_value(char* arg) { return ret; } -const command_t *find_command(char *your_var) +const command_t *find_command(char *your_var, const command_t* func_map) { if (your_var == NULL) return NULL; - for (int index = 0; command_map[index].fptr != NULL; index += 1) { - if (strcmp(your_var, command_map[index].command) == 0) { - return &command_map[index]; + for (int index = 0; func_map[index].fptr != NULL; index += 1) { + if (strcmp(your_var, func_map[index].command) == 0) { + return &func_map[index]; } } return NULL; @@ -92,11 +93,30 @@ void cmp() { return; } +int line_should_ret = -1; +void ret() { + if (line_should_ret == -1) { + exit_code = 1; + return; + } + + + fseek(fptr, line_should_ret, SEEK_SET); +} + void jmp() { + if (strcmp(args->arg1, "return") == 0) { + ret(); + return; + } + + eax = 0; for (int i = 0; i < MAX_LABEL; i++) { if (labels[i] == NULL) break; if (strcmp(args->arg1, labels[i]) == 0) { + line_should_ret = (int)char_read; fseek(fptr, labels_lines[i], SEEK_SET); + (int)char_read = labels_lines[i]; return; } } @@ -153,20 +173,37 @@ void mov() { *get_reg(args->arg1) = get_value(args->arg2); } -void ret() { - -} - void call() { - + const command_t* com = find_command(args->arg1, api_map); + if (com != NULL) { + com->fptr(); + } + else { + last_jmp_code = 1; + } } void push() { + if (!((is_num(args->arg1) || (is_reg(args->arg1))))) { + last_check_args_code = ARG1_WRONG; + return; + } + if (top == STACK_SIZE) { //stack overflow + last_stack_code = OVERFLOW; + return; + } + + stack[++top] = get_value(args->arg1); } void pop() { + if (top == -1) { //stack underflow + last_stack_code = UNDERFLOW; + return; + } + --top; } void and() { diff --git a/src/instructions.h b/src/instructions.h index f84533e..ccb20fa 100644 --- a/src/instructions.h +++ b/src/instructions.h @@ -18,13 +18,20 @@ typedef enum check_args_codes { } check_args_codes ; extern check_args_codes last_check_args_code; +typedef enum stack_codes { + OVERFLOW, + UNDERFLOW, + STACK_OK +} stack_codes; +extern stack_codes last_stack_code; + //pasted from https://github.com/Sakutaroo/Templates/blob/main/C/FunctionPointer/function_pointer.h typedef struct command_s { char *command; void (*fptr)(); } command_t; -const command_t *find_command(char *your_var); +const command_t* find_command(char* your_var, const command_t* func_map); bool check_args(int num_in_first); diff --git a/src/main.c b/src/main.c index 4d08914..0345d10 100644 --- a/src/main.c +++ b/src/main.c @@ -10,15 +10,19 @@ void show_help() { } arguments* args = NULL; -int stack[9] = {0*9}; +int stack[STACK_SIZE] = {0*STACK_SIZE}; +int top = -1; int a1, a2, a3, a4, a5, a6, a7, a8, a9, eax = 0; char* labels[256] = {0*256}; int labels_lines[256] = {0*256}; int num_labels = 0; FILE* fptr = NULL; last_jmp_code = 0; +stack_codes last_stack_code = STACK_OK; cmp_return_codes last_cmp_code = CMP_EQUAL; last_check_args_code = OK; //init error code +size_t char_read = 0; +int exit_code = 0; int main(int argc, char** argv) { if (argc != 2) { printf("Bad arguments.\n"); @@ -41,10 +45,9 @@ int main(int argc, char** argv) { args = (arguments*)calloc(1, sizeof(arguments)); char line[256]; - int line_number = 1; - size_t char_read = 0; const command_t* com = NULL; int main_hit = 0; + int line_number = 1; while (fgets(line, sizeof(line), fptr)) { char_read += strlen(line) + 1; @@ -74,7 +77,7 @@ int main(int argc, char** argv) { continue; } - com = find_command(ins); + com = find_command(ins, command_map); if (com != NULL) { get_args(line, args_pos); } @@ -132,6 +135,21 @@ int main(int argc, char** argv) { return 1; } + if (last_stack_code != STACK_OK) { + printf("%s ^\n |\nstack %s on line %d", line, last_stack_code == OVERFLOW ? "overflow" : "underflow", line_number); + free(args->arg1); + free(args->arg2); + free(args); + return 1; + } + + if (exit_code) { + free(args->arg1); + free(args->arg2); + free(args); + return 0; + } + ++line_number; } diff --git a/src/main.h b/src/main.h index d05bfe0..0d54532 100644 --- a/src/main.h +++ b/src/main.h @@ -2,8 +2,10 @@ #include "instructions.h" #include #define MAX_LABEL 256 +#define STACK_SIZE 9 -extern int stack[9]; +extern int top; +extern int stack[STACK_SIZE]; extern int a1, a2, a3, a4, a5, a6, a7, a8, a9, eax; //registers extern char* labels[MAX_LABEL]; //max 256 labels extern int labels_lines[MAX_LABEL]; //line numbers for the labels @@ -11,6 +13,8 @@ extern int num_labels; //number of labels already in use extern cmp_return_codes last_cmp_code; extern int last_jmp_code; //easier when global extern FILE* fptr; //file pointer +extern int exit_code; +extern size_t char_read; typedef struct arguments{ char* arg1; diff --git a/src/parser.c b/src/parser.c index 7d5e0bd..28b94e9 100644 --- a/src/parser.c +++ b/src/parser.c @@ -48,7 +48,7 @@ void get_args(char* line, int args_start_pos) { int write_to_first = 1; //ugly hack but whatever int j = 0; - for (int i = args_start_pos; i < (int)strlen(line); i++) { + for (int i = args_start_pos; i < (int)strlen(line)+1; i++) { if (line[i] == '\n' || line[i] == '\0' || line[i] == ';') { second_arg[j] = '\0'; args->arg2 = (char*)calloc(1, strlen(second_arg) + 1);