summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorladevieq <ladevie.quentin@gmail.com>2024-08-21 23:56:16 +0200
committerladevieq <ladevie.quentin@gmail.com>2024-08-21 23:56:16 +0200
commitd5ea670c6a047c1cd9c2d18e5f7877c5b791352a (patch)
tree2ecab30d4ec06777b73c63c7fc800575ce13bab0 /src
parentfa57140c3e3a56f23a37351a66d51f2cf3464561 (diff)
Split code in multiple files
Rework parser Add command to step in
Diffstat (limited to 'src')
-rw-r--r--src/main.c373
-rw-r--r--src/utils.c93
2 files changed, 400 insertions, 66 deletions
diff --git a/src/main.c b/src/main.c
index 3e9ee07..ff45864 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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));
+}