diff options
| author | ladevieq <ladevie.quentin@gmail.com> | 2024-08-21 23:56:16 +0200 |
|---|---|---|
| committer | ladevieq <ladevie.quentin@gmail.com> | 2024-08-21 23:56:16 +0200 |
| commit | d5ea670c6a047c1cd9c2d18e5f7877c5b791352a (patch) | |
| tree | 2ecab30d4ec06777b73c63c7fc800575ce13bab0 /src | |
| parent | fa57140c3e3a56f23a37351a66d51f2cf3464561 (diff) | |
Split code in multiple files
Rework parser
Add command to step in
Diffstat (limited to 'src')
| -rw-r--r-- | src/main.c | 373 | ||||
| -rw-r--r-- | src/utils.c | 93 |
2 files changed, 400 insertions, 66 deletions
@@ -1,89 +1,310 @@ #include <Windows.h> -#include <strsafe.h> -#include <stdint.h> #include <winbase.h> +#include <strsafe.h> +#include <winuser.h> -typedef uint8_t u8; -typedef uint16_t u16; -typedef uint32_t u32; -typedef uint64_t u64; - -typedef int8_t i8; -typedef int16_t i16; -typedef int32_t i32; -typedef int64_t i64; +#include "types.h" +#include "utils.c" +static u8 is_open = TRUE; +static u8 process_commands = TRUE; +static u8 expect_single_step = FALSE; +static DWORD continue_status = DBG_EXCEPTION_NOT_HANDLED; +static HANDLE h_input = NULL; enum CMD_TYPE { CMD_CONTINUE, - CMD_MAX, + CMD_PRINT_REG, + CMD_STEP_INTO, + CMD_QUIT, + CMD_DUMP_MEMORY, + CMD_UNKNOWN, +}; + +enum TOKEN_TYPE { + TOKEN_CONTINUE, + TOKEN_PRINT_REG, + TOKEN_STEP_INTO, + TOKEN_DUMP_MEMORY, + TOKEN_QUIT, + + TOKEN_DECIMAL_NUMBER, + TOKEN_HEXADECIMAL_NUMBER, + + TOKEN_UNKNOWN, }; struct token { - const char* start; + enum TOKEN_TYPE type; + const char* lexeme; u8 size; }; struct command { - enum CMD_TYPE cmd_type; + enum CMD_TYPE type; + struct token name; + struct token args[2]; }; -void tokenize(const char* cmd, struct token* tokens) { - const char* start = cmd; - const char* cur = cmd; - struct token* cur_token = tokens[0]; - while(*cur != '\0') { - - } +static char* commands[] = { + "g", + "r", + "t", + "db", + "q", +}; + +struct cmd { + const char* start; + u8 size; +}; + +static struct cmd cmds[] = { + { .start = "g", .size = 1 }, + { .start = "r", .size = 1 }, + { .start = "t", .size = 1 }, + { .start = "q", .size = 1 }, + { .start = "db", .size = 2 }, +}; + +struct ast_node { + struct token token; + u8 left; +}; + +_Static_assert((sizeof(commands) / sizeof(commands[0])) == CMD_UNKNOWN, "Missing commands"); + +u8 is_end(char c) { + return c == '\0'; } -enum CMD_TYPE command_parser(const char* cmd) { - struct token* tokens = (struct token*)VirtualAlloc(NULL, sizeof(struct token) * 32, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); - tokenize(cmd, tokens); +u8 is_alpha(char c) { + return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); +} - return CMD_MAX; +u8 is_decimal_digit(char c) { + return '0' <= c && c <= '9'; } -void print(const char* format, ...) { - va_list args; - va_start(args, format); - const uint32_t max_size = 4096U; - STRSAFE_LPSTR formatted_str = (char*)VirtualAlloc(NULL, max_size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); - STRSAFE_LPSTR cur_char = formatted_str; +u8 is_hexadecimal_digit(char c) { + return ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F'); +} + +void lexer(const char* str_cmd, size_t str_cmd_len, struct token* tokens) { + const char* cur = str_cmd; + struct token* cur_token = tokens; + str_cmd_len = 0; - const char* cur = format; while(*cur != '\0') { - if(*cur == '%') { + cur_token->type = TOKEN_UNKNOWN; + if(*cur == '0' && cur[1] == 'x') { + const char* start = cur; + cur += 2; + + while(is_hexadecimal_digit(*cur) && !is_end(*cur)) { + cur++; + } + + cur_token->lexeme = start; + cur_token->type = TOKEN_HEXADECIMAL_NUMBER; + cur_token->size = (u8)(cur - start); + cur_token++; + } else if(is_decimal_digit(*cur)) { + const char* start = cur; + cur++; + + while(is_decimal_digit(*cur) && !is_end(*cur)) { + cur++; + } + + cur_token->lexeme = start; + cur_token->type = TOKEN_DECIMAL_NUMBER; + cur_token->size = (u8)(cur - start); + cur_token++; + } else if(is_alpha(*cur)) { + const char* start = cur; cur++; - if (*cur == 's') { - const char* str = va_arg(args, const char*); - size_t length; - StringCchLength(str, max_size, &length); - StringCchCatA(cur_char, length + 1U, str); - cur_char += length; - } else if (*cur == 'c') { - char c = va_arg(args, char); - StringCchCatA(cur_char, 1U, &c); - cur_char += 1U; + while(is_alpha(*cur) && !is_end(*cur)) { + cur++; + } + + cur_token->lexeme = start; + cur_token->size = (u8)(cur - start); + + for(int i = 0; i < sizeof(cmds) / sizeof(cmds[0]); i++) { + const char* cur_cmd = cmds[i].start; + if (CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, cur_cmd, cmds[i].size, cur_token->lexeme, cur_token->size) == CSTR_EQUAL) { + cur_token->type = i; + cur_token++; + break; + } } } else { - *cur_char = *cur; - cur_char++; + cur++; } - cur++; } +} - va_end(args); +void parse_command(struct token* tokens, struct ast_node* nodes) +{ + if (tokens[0].type <= TOKEN_DECIMAL_NUMBER) { + nodes[0].token = tokens[0]; + } else { + print("%s must be a command\n", tokens[0].lexeme); + } +} - HANDLE standard_err = GetStdHandle(STD_ERROR_HANDLE); - SUCCEEDED(WriteFile(standard_err, formatted_str, 30, NULL, NULL)); +void parser(struct token* tokens, struct ast_node* nodes) { + if (tokens[0].type <= TOKEN_DECIMAL_NUMBER) { + nodes[0].token = tokens[0]; + } +} - VirtualFree((void*)formatted_str, 0U, MEM_RELEASE); +void tokenize(const char* str_cmd, size_t str_cmd_len, struct command* cmd) { + const char* cur = str_cmd; + str_cmd_len = 0; + + cmd->type = CMD_UNKNOWN; + cmd->name.lexeme = NULL; + cmd->name.size = 0; + + for(int i = 0; i < sizeof(commands) / sizeof(commands[0]); i++) { + char* cur_cmd = commands[i]; + size_t cur_cmd_len = 0U; + StringCchLengthA(cur_cmd, 16U, &cur_cmd_len); + if (CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, cur_cmd,(int)cur_cmd_len, str_cmd, (int)cur_cmd_len) == CSTR_EQUAL) { + cmd->name.lexeme = cur; + cmd->name.size = (u8)cur_cmd_len; + cmd->type = i; + cur += cur_cmd_len; + break; + } + } + + if (cmd->type < CMD_DUMP_MEMORY) { + return; + } + + struct token* cur_args = cmd->args; + while(*cur != '\0' && *cur != '\r' && *cur != '\n' + || cur_args - cmd->args >= sizeof(cmd->args) / sizeof(cmd->args[0])) { + if (*cur != ' ') { + cur_args->lexeme = cur; + cur++; + while (*cur != ' ' && *cur != '\r') { + cur++; + } + cur_args->size = (u8)(cur - cur_args->lexeme); + cur_args++; + } + else { + cur++; + } + } +} + +void dump_cmd(struct command* cmd) { + switch(cmd->type) { + case CMD_CONTINUE: { + print("%s\n", "continue"); + break; + } + case CMD_UNKNOWN: + print("%s\n", "unknown command encountered"); + break; + default: + break; + } +} + +struct command command_parser(const char* str_cmd, size_t str_cmd_len) { + struct command cmd; + cmd.type = 0; + struct token tokens[64U]; + + lexer(str_cmd, str_cmd_len, tokens); + + u32 index = 0; + while(tokens[index].type != TOKEN_UNKNOWN) { + if(tokens[index].type == TOKEN_DECIMAL_NUMBER) { + print("Decimal umber\n"); + } else if(tokens[index].type == TOKEN_HEXADECIMAL_NUMBER) { + print("Hexadecimal number\n"); + } else if(tokens[index].type == TOKEN_CONTINUE) { + print("Continue\n"); + } else if(tokens[index].type == TOKEN_PRINT_REG) { + print("Print reg\n"); + } else if(tokens[index].type == TOKEN_STEP_INTO) { + print("Print step into\n"); + } else if(tokens[index].type == TOKEN_QUIT) { + print("Print quit\n"); + } else if(tokens[index].type == TOKEN_DUMP_MEMORY) { + print("Print dump memory\n"); + } + index++; + } + + // tokenize(str_cmd, str_cmd_len, &cmd); + // dump_cmd(&cmd); + + return cmd; +} + +void interp_command(struct command* cmd, LPDEBUG_EVENT dbg_event) { + CONTEXT ctx = { + .ContextFlags = CONTEXT_ALL, + }; + HANDLE h_thread = OpenThread( + THREAD_GET_CONTEXT | THREAD_SET_CONTEXT, + FALSE, + dbg_event->dwThreadId + ); + GetThreadContext(h_thread, &ctx); + + if (cmd->type == CMD_CONTINUE) { + ContinueDebugEvent( + dbg_event->dwProcessId, + dbg_event->dwThreadId, + continue_status + ); + process_commands = FALSE; + } else if (cmd->type == CMD_PRINT_REG) { + print("RIP : %x\n", ctx.Rip); + print("RAX : %x\n", ctx.Rax); + print("RCX : %x\n", ctx.Rcx); + print("RDX : %x\n", ctx.Rdx); + print("RBX : %x\n", ctx.Rbx); + print("RSP : %x\n", ctx.Rsp); + print("RBP : %x\n", ctx.Rbp); + print("RSI : %x\n", ctx.Rsi); + print("RDI : %x\n", ctx.Rdi); + process_commands = TRUE; + } else if (cmd->type == CMD_STEP_INTO) { + ctx.EFlags |= 0x100; // TRAP_FLAG + if(SetThreadContext(h_thread, &ctx) == 0) { + __debugbreak(); + } + ContinueDebugEvent( + dbg_event->dwProcessId, + dbg_event->dwThreadId, + continue_status + ); + expect_single_step = TRUE; + process_commands = FALSE; + } else if (cmd->type == CMD_QUIT) { + is_open = FALSE; + process_commands = FALSE; + } else if (cmd->type == CMD_DUMP_MEMORY) { + // ReadProcessMemory(dbg_event.) + } else { + print("Command unknown\n"); + process_commands = TRUE; + } + + CloseHandle(h_thread); } int mainCRTStartup() { - u8 is_open = TRUE; - char input_buffer[16]; STARTUPINFOW startup_info = { .cb = sizeof(startup_info), @@ -108,18 +329,23 @@ int mainCRTStartup() { return 0; } - HANDLE h_input = GetStdHandle(STD_INPUT_HANDLE); + h_input = GetStdHandle(STD_INPUT_HANDLE); + if (h_input == NULL) { + TerminateProcess(proc_info.hProcess, 1U); + return 1U; + } DWORD console_mode = ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT; SetConsoleMode(h_input, console_mode); while(is_open) { - DWORD input_size = 0U; - DEBUG_EVENT dbg_event; WaitForDebugEventEx(&dbg_event, INFINITE); + continue_status = DBG_EXCEPTION_NOT_HANDLED; + switch (dbg_event.dwDebugEventCode) { case CREATE_PROCESS_DEBUG_EVENT: { + OpenThread(THREAD_GET_CONTEXT | THREAD_SET_CONTEXT, FALSE, dbg_event.dwThreadId); print("%s\n", "CreateProcessDebugEvent"); break; } @@ -128,11 +354,25 @@ int mainCRTStartup() { break; } case EXCEPTION_DEBUG_EVENT: { - print("%s\n", "ExceptionDebugEvent"); + print("%s : ", "ExceptionDebugEvent"); + + if (dbg_event.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_SINGLE_STEP && expect_single_step) { + print("%s\n", "Single Step"); + continue_status = DBG_CONTINUE; + expect_single_step = FALSE; + } else if (dbg_event.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT) { + print("%s\n", "Breakpoint"); + continue_status = DBG_CONTINUE; + } else { + print("%u\n", dbg_event.u.Exception.ExceptionRecord.ExceptionCode); + } + break; } case EXIT_PROCESS_DEBUG_EVENT: { print("%s\n", "ExitProcessDebugEvent"); + TerminateProcess(NULL, 0U); + return 0; break; } case EXIT_THREAD_DEBUG_EVENT: { @@ -140,7 +380,8 @@ int mainCRTStartup() { break; } case LOAD_DLL_DEBUG_EVENT: { - print("%s%s\n", "Loading DLL : ", (char*)dbg_event.u.LoadDll.lpImageName); + // print("%s%s\n", "Loading DLL : ", (char*)dbg_event.u.LoadDll.lpImageName); + print("%s%s\n", "Loading DLL : ", NULL); break; } case OUTPUT_DEBUG_STRING_EVENT: { @@ -157,18 +398,18 @@ int mainCRTStartup() { } } - ReadConsole(h_input, input_buffer, sizeof(input_buffer), &input_size, NULL); - // print("%s%s", "ReadConsole :", input_buffer); + process_commands = TRUE; + while(process_commands) { + char input_buffer[16]; + DWORD input_size = 0U; + ReadConsole(h_input, input_buffer, sizeof(input_buffer), &input_size, NULL); - command_parser(input_buffer); - if (input_buffer[0] == 'g') { - ContinueDebugEvent( - dbg_event.dwProcessId, - dbg_event.dwThreadId, - DBG_EXCEPTION_NOT_HANDLED - ); + struct command cmd = command_parser(input_buffer, input_size); + cmd.type = 0; + // interp_command(&cmd, &dbg_event); } } + TerminateProcess(proc_info.hProcess, 0U); return 0; } diff --git a/src/utils.c b/src/utils.c new file mode 100644 index 0000000..71377bc --- /dev/null +++ b/src/utils.c @@ -0,0 +1,93 @@ +#include <strsafe.h> +#include <Windows.h> + +#include "types.h" + +void u64toa(u64 number, char* str, u32 base) { + static char codes[16U] = { + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + 'A', + 'B', + 'C', + 'D', + 'E', + 'F', + }; + u32 remainder = 0U; + u32 size = 0U; + + if (number == 0) { + str[0U] = codes[0U]; + return; + } + + for(; number != 0U; size++) { + remainder = number % base; + number /= base; + str[size] = codes[remainder]; + } + + for(u32 i = 0; i < size / 2U; i++) { + char c = str[i]; + str[i] = str[size - i - 1]; + str[size - i - 1] = c; + } +} + +void print(const char* format, ...) { + va_list args; + va_start(args, format); + char formatted_str[4096U] = {}; + STRSAFE_LPSTR cur_char = formatted_str; + + const char* cur_fmt = format; + while(*cur_fmt != '\0') { + if(*cur_fmt == '%') { + cur_fmt++; + if (*cur_fmt == 's') { + const char* str = va_arg(args, const char*); + if(str != NULL) { + size_t length = 0U; + StringCchLengthA(str, sizeof(formatted_str), &length); + StringCchCatA(cur_char, length + 1U, str); + cur_char += length; + } + } else if(*cur_fmt == 'c') { + char c = va_arg(args, char); + StringCchCatA(cur_char, 1U, &c); + cur_char += 1U; + } else if(*cur_fmt == 'u') { + u64 number = va_arg(args, u64); + u64toa(number, cur_char, 10); + size_t length = 0U; + StringCchLengthA(formatted_str, sizeof(formatted_str), &length); + cur_char = formatted_str + length; + } else if(*cur_fmt == 'x') { + u64 number = va_arg(args, u64); + u64toa(number, cur_char, 16); + size_t length = 0U; + StringCchLengthA(formatted_str, sizeof(formatted_str), &length); + cur_char = formatted_str + length; + } + } else { + *cur_char = *cur_fmt; + cur_char++; + } + cur_fmt++; + } + va_end(args); + + HANDLE standard_err = GetStdHandle(STD_ERROR_HANDLE); + size_t length = 0U; + StringCchLengthA(formatted_str, sizeof(formatted_str), &length); + SUCCEEDED(WriteFile(standard_err, formatted_str, (DWORD)length, NULL, NULL)); +} |
