summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQuentin LADEVIE <qladevie@wanadev.fr>2024-09-03 11:15:10 +0200
committerQuentin LADEVIE <qladevie@wanadev.fr>2024-09-03 11:15:10 +0200
commite61b27e6c699ae175d7704ddaaee0d39b6d14382 (patch)
tree1b227cafa0f86681afddeb8e25d4d072318bb9fc
parent41d163a8a9be2f6d94e42157ad695fbe2cd000ae (diff)
Log dll name on loading
Print output debug string Refactored code Improved print Add a function to read memory from the deubgged process Fixed a read out of bounds
-rw-r--r--src/events.c121
-rw-r--r--src/main.c392
-rw-r--r--src/parser.c249
-rw-r--r--src/test.c2
-rw-r--r--src/utils.c54
5 files changed, 486 insertions, 332 deletions
diff --git a/src/events.c b/src/events.c
new file mode 100644
index 0000000..ea80e58
--- /dev/null
+++ b/src/events.c
@@ -0,0 +1,121 @@
+void handle_create_process() {
+ print("%s\n", "CreateProcessDebugEvent");
+}
+
+void handle_create_thread() {
+ print("%s\n", "CreateThreadDebugEvent");
+}
+
+void handle_exception() {
+ 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);
+ }
+}
+
+void handle_exit_process() {
+ print("%s\n", "ExitProcessDebugEvent");
+ TerminateProcess(NULL, 0U);
+}
+
+void handle_exit_thread() {
+ print("%s\n", "ExitThreadDebugEvent");
+}
+
+void handle_load_dll() {
+ LOAD_DLL_DEBUG_INFO dll_info = dbg_event.u.LoadDll;
+ const void* dll_name_addr = dll_info.lpImageName;
+ const void* dll_base_addr = dll_info.lpBaseOfDll;
+ if (dll_name_addr == NULL) {
+ print("%s\n", "Loading DLL : error read dll name");
+ return;
+ }
+
+ u8* addr = NULL;
+ if (!read_memory(dll_name_addr, (void*)&addr, 8U)) {
+ print("%s\n", "Loading DLL : error reading dll name");
+ return;
+ }
+
+ u8 dll_name[1024U] = { 0U };
+ if (!read_memory((const void*)addr, dll_name, sizeof(dll_name))) {
+ print("Cannot read dll name from proc memory\n");
+ }
+
+ if (dll_info.fUnicode) {
+ u8 dll_name_ansi[1024U] = { 0U };
+ WideCharToMultiByte(
+ CP_ACP,
+ 0,
+ (wchar_t*)dll_name,
+ -1,
+ (char*)dll_name_ansi,
+ sizeof(dll_name_ansi),
+ NULL,
+ NULL
+ );
+ StringCchCopyA((char*)dll_name, sizeof(dll_name), (const char*)dll_name_ansi);
+ }
+ print("%s%s\n", "Loading DLL : ", (char*)dll_name);
+
+ IMAGE_DOS_HEADER dos_header = { 0U };
+ if (!read_memory(dll_base_addr, (void*)&dos_header, sizeof(dos_header))) {
+ print("Cannot read DOS header for module %s at address %x\n", dll_name, dll_base_addr);
+ }
+
+ IMAGE_NT_HEADERS64 nt_header = { 0U };
+ if (!read_memory((const void*)((u64)dll_base_addr + dos_header.e_lfanew), (void*)&nt_header, sizeof(nt_header))) {
+ print("Cannot read NT header for module %s at address %x\n", dll_name, dll_base_addr);
+ }
+
+ IMAGE_DATA_DIRECTORY export_table = nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
+ IMAGE_EXPORT_DIRECTORY export_dir = { 0U };
+
+ if (!read_memory((const void*)((u64)dll_base_addr + (u64)export_table.VirtualAddress), (void*)&export_dir, export_table.Size)) {
+ print("Cannot read export table for module at address %x\n", dll_base_addr);
+ }
+}
+
+void handle_unload_dll() {
+ print("%s\n", "UnloadDLLDebugEvent");
+}
+
+void handle_output_debug_string() {
+ OUTPUT_DEBUG_STRING_INFO dbg_str_event = dbg_event.u.DebugString;
+ char* str_addr = dbg_str_event.lpDebugStringData;
+ size_t str_size = (size_t)dbg_str_event.nDebugStringLength;
+ // assert(str_size > 1024U);
+ u8 dbg_str[1024U] = { 0U };
+ if (read_memory(str_addr, dbg_str, str_size)) {
+ print("%s\n", "OutputDebugStringDebugEvent : error read debug string");
+ return;
+ }
+ if (dbg_str_event.fUnicode) {
+ u8 ansi_str[1024U] = { 0U };
+ WideCharToMultiByte(
+ CP_ACP,
+ 0,
+ (wchar_t*)dbg_str,
+ -1,
+ (char*)ansi_str,
+ sizeof(ansi_str),
+ NULL,
+ NULL
+ );
+ print("%s%s\n", "OutputDebugStringDebugEvent : ", ansi_str);
+ } else {
+ print("%s%s\n", "OutputDebugStringDebugEvent : ", dbg_str);
+ }
+}
+
+void handle_rip() {
+ print("%s\n", "RIPEvent");
+}
diff --git a/src/main.c b/src/main.c
index 83d4acd..94fdd37 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,4 +1,5 @@
#include <Windows.h>
+#include <intrin.h>
#include <strsafe.h>
#include "types.h"
@@ -6,288 +7,101 @@
#include "utils.c"
static HANDLE h_input = NULL;
+static HANDLE h_output = NULL;
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 DEBUG_EVENT dbg_event;
-static PROCESS_INFORMATION proc_info;
+static PROCESS_INFORMATION proc_info = { 0 };
-enum TOKEN_TYPE {
- // Commands
- TOKEN_CONTINUE,
- TOKEN_PRINT_REG,
- TOKEN_STEP_INTO,
- TOKEN_DUMP_MEMORY,
- TOKEN_QUIT,
-
- // Primaries
- TOKEN_DECIMAL_NUMBER,
- TOKEN_HEXADECIMAL_NUMBER,
-
- TOKEN_UNKNOWN,
+struct module {
+ u8 fix_compilation;
};
-struct token {
- enum TOKEN_TYPE type;
- const char* lexeme;
- u8 size;
-};
+static struct module mods[64U] = { 0U };
+static u64 mods_list = 0U;
-struct command {
- const char* start;
- u8 size;
-};
+u8 add_mod() {
+ u64 free_mods = ~mods_list;
+ assert(!free_mods);
+ u8 mod_index = (u8)(free_mods >> (_lzcnt_u64(free_mods) + 1U));
+ // struct module* mod = &mods[mod_index];
-struct ast_node {
- struct token* token;
- struct ast_node* left;
- struct ast_node* right;
-};
-static struct command commands[] = {
- { .start = "g", .size = 1 },
- { .start = "r", .size = 1 },
- { .start = "t", .size = 1 },
- { .start = "db", .size = 2 },
- { .start = "q", .size = 1 },
-};
-_Static_assert((sizeof(commands) / sizeof(commands[0])) == TOKEN_QUIT + 1, "Missing commands");
+ return mod_index;
+};
-u8 is_end(char c) {
- return c == '\0';
+void remove_mod(u8 mod_index) {
+ mods_list ^= (u64)(0x1 << (((i8)mod_index) - 1U));
}
-u8 is_alpha(char c) {
- return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
-}
+/* Read debugged process memory at address */
+u8 read_memory(const void* addr, void* buffer, size_t size) {
+ size_t b_read = 0U;
+ HRESULT hr = ReadProcessMemory(proc_info.hProcess, addr, buffer, size, &b_read);
-u8 is_decimal_digit(char c) {
- return '0' <= c && c <= '9';
+ return hr > 0 && b_read == size;
}
-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;
-
- while(*cur != '\0') {
- cur_token->type = TOKEN_UNKNOWN;
- if(*cur == '0' && cur[1] == 'x') {
- const char* start = cur;
- cur += 2;
+#include "parser.c"
+#include "events.c"
- 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++;
- while(is_alpha(*cur) && !is_end(*cur)) {
- cur++;
- }
+void dbg_loop() {
+ while(is_open) {
+ WaitForDebugEventEx(&dbg_event, INFINITE);
- cur_token->lexeme = start;
- cur_token->size = (u8)(cur - start);
+ continue_status = DBG_EXCEPTION_NOT_HANDLED;
- for(int i = 0; i < sizeof(commands) / sizeof(commands[0]); i++) {
- struct command cur_cmd = commands[i];
- if (CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, cur_cmd.start, cur_cmd.size, cur_token->lexeme, cur_token->size) == CSTR_EQUAL) {
- cur_token->type = i;
- cur_token++;
- break;
- }
- }
- } else {
- cur++;
+ switch (dbg_event.dwDebugEventCode) {
+ case CREATE_PROCESS_DEBUG_EVENT:
+ handle_create_process();
+ break;
+ case CREATE_THREAD_DEBUG_EVENT:
+ handle_create_thread();
+ break;
+ case EXCEPTION_DEBUG_EVENT:
+ handle_exception();
+ break;
+ case EXIT_PROCESS_DEBUG_EVENT:
+ handle_exit_process();
+ break;
+ case EXIT_THREAD_DEBUG_EVENT:
+ handle_exit_thread();
+ break;
+ case LOAD_DLL_DEBUG_EVENT:
+ handle_load_dll();
+ break;
+ case OUTPUT_DEBUG_STRING_EVENT:
+ handle_output_debug_string();
+ break;
+ case RIP_EVENT:
+ handle_rip();
+ break;
+ case UNLOAD_DLL_DEBUG_EVENT:
+ handle_unload_dll();
+ break;
}
- }
-}
-
-struct ast_node* parse_primary(struct token* tokens, struct ast_node* nodes) {
- struct ast_node* cur_node = &nodes[0];
- struct token* cur_token = &tokens[0];
- if (cur_token->type == TOKEN_HEXADECIMAL_NUMBER ||
- cur_token->type == TOKEN_DECIMAL_NUMBER) {
- cur_node->token = cur_token;
- cur_node->left = NULL;
- cur_node->right = NULL;
- return cur_node;
- } else {
- print("Expecting a primary token\n");
- return NULL;
- }
-}
-
-struct ast_node* parse_command(struct token* tokens, struct ast_node* nodes) {
- struct ast_node* cur_node = &nodes[0];
- struct token* cur_token = &tokens[0];
- switch(cur_token->type) {
- case TOKEN_CONTINUE:
- tokens++;
- print("TOKEN_CONTINUE\n");
- cur_node->token = cur_token;
- cur_node->left = NULL;
- cur_node->right = NULL;
- return cur_node;
- case TOKEN_PRINT_REG:
- tokens++;
- print("TOKEN_PRINT_REG\n");
- cur_node->token = cur_token;
- cur_node->left = NULL;
- cur_node->right = NULL;
- return cur_node;
- case TOKEN_STEP_INTO:
- tokens++;
- print("TOKEN_STEP_INTO\n");
- cur_node->token = cur_token;
- cur_node->left = NULL;
- cur_node->right = NULL;
- return cur_node;
- case TOKEN_DUMP_MEMORY:
- tokens++;
- print("TOKEN_DUMP_MEMORY\n");
- cur_node->token = cur_token;
- cur_node->left = NULL;
- cur_node->right = parse_primary(tokens, ++nodes);
- return cur_node;
- case TOKEN_QUIT:
- tokens++;
- print("TOKEN_QUIT\n");
- cur_node->token = cur_token;
- cur_node->left = NULL;
- cur_node->right = NULL;
- return cur_node;
- default:
- print("%s must be a command\n", cur_token->lexeme);
- return NULL;
- }
-}
-
-u64 eval_number(const struct ast_node* node) {
- if (node->token->type == TOKEN_DECIMAL_NUMBER ||
- node->token->type == TOKEN_HEXADECIMAL_NUMBER) {
- return atou64(node->token->lexeme, node->token->size);
- }
- return ~0U;
-}
-void run(struct ast_node* root) {
- struct ast_node cur_node = root[0];
- CONTEXT ctx = {
- .ContextFlags = CONTEXT_ALL,
- };
- HANDLE h_thread = OpenThread(
- THREAD_GET_CONTEXT | THREAD_SET_CONTEXT,
- FALSE,
- dbg_event.dwThreadId
- );
- GetThreadContext(h_thread, &ctx);
-
- if (cur_node.token->type == TOKEN_CONTINUE) {
- ContinueDebugEvent(
- dbg_event.dwProcessId,
- dbg_event.dwThreadId,
- continue_status
- );
- process_commands = FALSE;
- } else if (cur_node.token->type == TOKEN_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 (cur_node.token->type == TOKEN_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 (cur_node.token->type == TOKEN_QUIT) {
- is_open = FALSE;
- process_commands = FALSE;
- } else if (cur_node.token->type == TOKEN_DUMP_MEMORY) {
- u64 addr = eval_number(cur_node.right);
- u8 buf[16U] = { 0 };
- size_t b_read = 0U;
-
- HRESULT hr = ReadProcessMemory(
- proc_info.hProcess,
- (void*)addr,
- buf,
- sizeof(buf),
- &b_read
- );
+ while(process_commands) {
+ const char write_buffer[] = "> ";
+ DWORD c_written = 0U;
+ WriteConsole(h_output, write_buffer, sizeof(write_buffer), &c_written, NULL);
+ char input_buffer[64] = { 0 };
+ DWORD input_size = 0U;
+ ReadConsole(h_input, input_buffer, sizeof(input_buffer), &input_size, NULL);
- if (hr > 0) {
- print("%b %b %b %b %b %b %b %b %b %b %b %b %b %b %b %b\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]);
- } else {
- print("Unable to read memory at this address\n");
+ interpreter(input_buffer, input_size);
}
-
- } else {
- print("Command unknown\n");
- process_commands = TRUE;
- }
-
- CloseHandle(h_thread);
-}
-
-u8 interpreter(const char* str_cmd, size_t str_cmd_len) {
- struct token tokens[64U];
- struct ast_node nodes[64U];
-
- lexer(str_cmd, str_cmd_len, tokens);
-
- struct ast_node* root = parse_command(tokens, nodes);
-
- if(root == NULL) {
- print("Ill formed command\n");
- return FALSE;
}
-
- run(root);
- return TRUE;
}
int mainCRTStartup() {
- STARTUPINFOW startup_info = {
- .cb = sizeof(startup_info),
- };
+ STARTUPINFOW startup_info = { 0 };
+ startup_info.cb = sizeof(startup_info);
BOOL ret = CreateProcessW(
NULL,
@@ -307,6 +121,12 @@ int mainCRTStartup() {
return 0;
}
+ h_output = GetStdHandle(STD_OUTPUT_HANDLE);
+ if (h_output == NULL) {
+ TerminateProcess(proc_info.hProcess, 1U);
+ return 1U;
+ }
+
h_input = GetStdHandle(STD_INPUT_HANDLE);
if (h_input == NULL) {
TerminateProcess(proc_info.hProcess, 1U);
@@ -315,75 +135,7 @@ int mainCRTStartup() {
DWORD console_mode = ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
SetConsoleMode(h_input, console_mode);
- while(is_open) {
- 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;
- }
- case CREATE_THREAD_DEBUG_EVENT: {
- print("%s\n", "CreateThreadDebugEvent");
- break;
- }
- case EXCEPTION_DEBUG_EVENT: {
- 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: {
- print("%s\n", "ExitThreadDebugEvent");
- break;
- }
- case LOAD_DLL_DEBUG_EVENT: {
- // 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: {
- print("%s\n", "OutputDebugStringDebugEvent");
- break;
- }
- case RIP_EVENT: {
- print("%s\n", "RIPEvent");
- break;
- }
- case UNLOAD_DLL_DEBUG_EVENT: {
- print("%s\n", "UnloadDLLDebugEvent");
- break;
- }
- }
-
- 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);
-
- interpreter(input_buffer, input_size);
- }
- }
+ dbg_loop();
TerminateProcess(proc_info.hProcess, 0U);
return 0;
diff --git a/src/parser.c b/src/parser.c
new file mode 100644
index 0000000..c42c2cc
--- /dev/null
+++ b/src/parser.c
@@ -0,0 +1,249 @@
+enum TOKEN_TYPE {
+ // Commands
+ TOKEN_CONTINUE,
+ TOKEN_PRINT_REG,
+ TOKEN_STEP_INTO,
+ TOKEN_DUMP_MEMORY,
+ TOKEN_QUIT,
+
+ // Primaries
+ TOKEN_DECIMAL_NUMBER,
+ TOKEN_HEXADECIMAL_NUMBER,
+
+ TOKEN_UNKNOWN,
+};
+
+struct token {
+ enum TOKEN_TYPE type;
+ const char* lexeme;
+ u8 size;
+};
+
+struct command {
+ const char* start;
+ u8 size;
+};
+
+struct ast_node {
+ struct token* token;
+ struct ast_node* left;
+ struct ast_node* right;
+};
+
+static struct command commands[] = {
+ { .start = "g", .size = 1 },
+ { .start = "r", .size = 1 },
+ { .start = "t", .size = 1 },
+ { .start = "db", .size = 2 },
+ { .start = "q", .size = 1 },
+};
+
+_Static_assert((sizeof(commands) / sizeof(commands[0])) == TOKEN_QUIT + 1, "Missing commands");
+
+void lexer(const char* str_cmd, size_t str_cmd_len, struct token* tokens) {
+ const char* cur = str_cmd;
+ const char* end = str_cmd + str_cmd_len;
+ struct token* cur_token = tokens;
+ str_cmd_len = 0;
+
+ while(cur < end) {
+ cur_token->type = TOKEN_UNKNOWN;
+ if(*cur == '0' && cur[1] == 'x') {
+ const char* start = cur;
+ cur += 2;
+
+ while(is_hexadecimal_digit(*cur) && cur < end) {
+ 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) && cur < end) {
+ 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++;
+ while(is_alpha(*cur) && cur < end) {
+ cur++;
+ }
+
+ cur_token->lexeme = start;
+ cur_token->size = (u8)(cur - start);
+
+ for(int i = 0; i < sizeof(commands) / sizeof(commands[0]); i++) {
+ struct command cur_cmd = commands[i];
+ if (CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, cur_cmd.start, cur_cmd.size, cur_token->lexeme, cur_token->size) == CSTR_EQUAL) {
+ cur_token->type = i;
+ cur_token++;
+ break;
+ }
+ }
+ } else {
+ cur++;
+ }
+ }
+}
+
+struct ast_node* parse_primary(struct token* tokens, struct ast_node* nodes) {
+ struct ast_node* cur_node = &nodes[0];
+ struct token* cur_token = &tokens[0];
+ if (cur_token->type == TOKEN_HEXADECIMAL_NUMBER ||
+ cur_token->type == TOKEN_DECIMAL_NUMBER) {
+ cur_node->token = cur_token;
+ cur_node->left = NULL;
+ cur_node->right = NULL;
+ return cur_node;
+ } else {
+ print("Expecting a primary token\n");
+ return NULL;
+ }
+}
+
+struct ast_node* parse_command(struct token* tokens, struct ast_node* nodes) {
+ struct ast_node* cur_node = &nodes[0];
+ struct token* cur_token = &tokens[0];
+ switch(cur_token->type) {
+ case TOKEN_CONTINUE:
+ tokens++;
+ print("TOKEN_CONTINUE\n");
+ cur_node->token = cur_token;
+ cur_node->left = NULL;
+ cur_node->right = NULL;
+ return cur_node;
+ case TOKEN_PRINT_REG:
+ tokens++;
+ print("TOKEN_PRINT_REG\n");
+ cur_node->token = cur_token;
+ cur_node->left = NULL;
+ cur_node->right = NULL;
+ return cur_node;
+ case TOKEN_STEP_INTO:
+ tokens++;
+ print("TOKEN_STEP_INTO\n");
+ cur_node->token = cur_token;
+ cur_node->left = NULL;
+ cur_node->right = NULL;
+ return cur_node;
+ case TOKEN_DUMP_MEMORY:
+ tokens++;
+ print("TOKEN_DUMP_MEMORY\n");
+ cur_node->token = cur_token;
+ cur_node->left = NULL;
+ cur_node->right = parse_primary(tokens, ++nodes);
+ return cur_node;
+ case TOKEN_QUIT:
+ tokens++;
+ print("TOKEN_QUIT\n");
+ cur_node->token = cur_token;
+ cur_node->left = NULL;
+ cur_node->right = NULL;
+ return cur_node;
+ default:
+ print("%s must be a command\n", cur_token->lexeme);
+ return NULL;
+ }
+}
+
+u64 eval_number(const struct ast_node* node) {
+ if (node->token->type == TOKEN_DECIMAL_NUMBER ||
+ node->token->type == TOKEN_HEXADECIMAL_NUMBER) {
+ return atou64(node->token->lexeme, node->token->size);
+ }
+ return ~0U;
+}
+
+void run(struct ast_node* root) {
+ struct ast_node cur_node = root[0];
+ CONTEXT ctx = {
+ .ContextFlags = CONTEXT_ALL,
+ };
+ HANDLE h_thread = OpenThread(
+ THREAD_GET_CONTEXT | THREAD_SET_CONTEXT,
+ FALSE,
+ dbg_event.dwThreadId
+ );
+ GetThreadContext(h_thread, &ctx);
+
+ if (cur_node.token->type == TOKEN_CONTINUE) {
+ ContinueDebugEvent(
+ dbg_event.dwProcessId,
+ dbg_event.dwThreadId,
+ continue_status
+ );
+ process_commands = FALSE;
+ } else if (cur_node.token->type == TOKEN_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 (cur_node.token->type == TOKEN_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 (cur_node.token->type == TOKEN_QUIT) {
+ is_open = FALSE;
+ process_commands = FALSE;
+ } else if (cur_node.token->type == TOKEN_DUMP_MEMORY) {
+ u64 addr = eval_number(cur_node.right);
+ u8 buf[16U] = { 0 };
+
+ if(read_memory((const void*)addr, (void*)buf, sizeof(buf))) {
+ for (u32 index = 0U; index < sizeof(buf); index++) {
+ print("%b ", buf[index]);
+ }
+ print("\n");
+ } else {
+
+ print("Unable to read memory at this address, error %u\n", GetLastError());
+ }
+
+ } else {
+ print("Command unknown\n");
+ process_commands = TRUE;
+ }
+
+ CloseHandle(h_thread);
+}
+
+u8 interpreter(const char* str_cmd, size_t str_cmd_len) {
+ struct token tokens[64U];
+ struct ast_node nodes[64U];
+
+ lexer(str_cmd, str_cmd_len, tokens);
+
+ struct ast_node* root = parse_command(tokens, nodes);
+
+ if(root == NULL) {
+ print("Ill formed command\n");
+ return FALSE;
+ }
+
+ run(root);
+ return TRUE;
+}
diff --git a/src/test.c b/src/test.c
index cfd9e59..85c9136 100644
--- a/src/test.c
+++ b/src/test.c
@@ -1,7 +1,9 @@
+#include <Windows.h>
int mainCRTStartup() {
unsigned long long int i = 0;
while (1) {
+ OutputDebugStringA("Hello World !");
i++;
}
diff --git a/src/utils.c b/src/utils.c
index f7994f9..de719e9 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -1,3 +1,22 @@
+#if defined (_DEBUG)
+#define assert(x) if (!(x)) __debugbreak();
+#else
+#define assert(x) (x)
+#endif
+void print(const char* format, ...);
+
+u8 is_alpha(char c) {
+ return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
+}
+
+u8 is_decimal_digit(char c) {
+ return '0' <= c && c <= '9';
+}
+
+u8 is_hexadecimal_digit(char c) {
+ return ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F');
+}
+
void u64toa(u64 number, char* str, u32 base) {
static char codes[16U] = {
'0',
@@ -89,25 +108,36 @@ void print(const char* format, ...) {
char c = va_arg(args, char);
StringCchCatA(cur_char, 1U, &c);
cur_char += 1U;
+ } else if (*cur_fmt == 'x' && is_alpha(cur_fmt[1])) {
+ u32 base = 16U;
+ *cur_char = '0';
+ cur_char++;
+ *cur_char = 'x';
+ cur_char++;
+ cur_fmt++;
+
+ if(*cur_fmt == 'b') {
+ u8 number = va_arg(args, u8);
+ u64toa((u64)number, cur_char, base);
+ size_t length = 0U;
+ StringCchLengthA(formatted_str, sizeof(formatted_str), &length);
+ cur_char = formatted_str + length;
+ } else if(*cur_fmt == 'u') {
+ u64 number = va_arg(args, u64);
+ u64toa(number, cur_char, base);
+ size_t length = 0U;
+ StringCchLengthA(formatted_str, sizeof(formatted_str), &length);
+ cur_char = formatted_str + length;
+ }
} else if(*cur_fmt == 'b') {
u8 number = va_arg(args, u8);
- u64toa((u64)number, cur_char, 10);
+ u64toa((u64)number, cur_char, 10U);
size_t length = 0U;
StringCchLengthA(formatted_str, sizeof(formatted_str), &length);
cur_char = formatted_str + length;
} 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);
- *cur_char = '0';
- cur_char++;
- *cur_char = 'x';
- *cur_char++;
- u64toa(number, cur_char, 16);
+ u64toa(number, cur_char, 10U);
size_t length = 0U;
StringCchLengthA(formatted_str, sizeof(formatted_str), &length);
cur_char = formatted_str + length;