From 807ed29edfcda92f726096c2b7c8967fe7628a56 Mon Sep 17 00:00:00 2001 From: wuxuefei Date: Fri, 29 Dec 2023 16:47:30 +0800 Subject: [PATCH 1/3] added pe64(x64) support --- lib/atoi_itoa64.asm | 119 +++++++ src/ceed.h | 46 ++- src/ceed.y | 32 +- src/ceedcmpl.c | 166 ++++++---- src/ceedcmpl64.c | 463 ++++++++++++++++++++++++++ src/ceedelf.c | 2 +- src/ceedpe.c | 130 +++++--- src/ceedpe64.c | 791 ++++++++++++++++++++++++++++++++++++++++++++ src/ceedrtl.c | 21 +- src/main.c | 55 +++ src/makefile | 2 +- 11 files changed, 1659 insertions(+), 168 deletions(-) create mode 100644 lib/atoi_itoa64.asm create mode 100644 src/ceedcmpl64.c create mode 100644 src/ceedpe64.c create mode 100644 src/main.c diff --git a/lib/atoi_itoa64.asm b/lib/atoi_itoa64.asm new file mode 100644 index 0000000..a5968ba --- /dev/null +++ b/lib/atoi_itoa64.asm @@ -0,0 +1,119 @@ +BITS 64 +GLOBAL _start +SECTION .text +_start: +itoa: + + ; rax must contain the number that needs to be converted. + + ; rbx must point to a buffer that would store the converted string. + ; The buffer must have at least 12 bytes to contain maximum 4-byte number + ; including minus sign. + + push rbp + mov rbp, rsp + sub rsp, 8 ; Allocate 4 bytes for string length + + add rbx, 11 ; Mov to end of buffer + mov byte [rbx], 0 ; Put \0 or NULL at the end + mov rcx, 10 ; Divisor + mov dword [rbp - 8], 0 ; rbp-8 will contain string length + +.checknegative: + xor rdi, rdi + cmp rax, 0 + jge .divloop + neg rax + mov rdi, 1 + +.divloop: + xor rdx, rdx ; Zero out rdx (remainder is in rdx after idiv) + idiv rcx ; Divide rax by rcx + add rdx, 0x30 ; Add 0x30 to the remainder to get ASCII value + dec rbx ; Move the pointer backwards in the buffer + mov byte [rbx], dl ; Move the character into the buffer + inc dword [rbp - 8] ; Increase the length + + cmp rax, 0 ; Was the result zero? + jnz .divloop ; No it wasn't, keep looping + +.minussign: + cmp rdi, 1 + jne .done + + dec rbx + mov byte [rbx], 0x2d + inc dword [rbp - 8] ; Increase the length + +.done: + mov rcx, rbx ; rcx points to the beginning of the string + mov rdx, [rbp - 8] ; rbp-4 contains the length - move it into rdx + + mov rsp, rbp ; Clean up our stack + pop rbp + ret + + + +atoi: + + ; rbx must point to the input buffer that is NULL terminated. + + push rbp + mov rbp, rsp + sub rsp, 8 + +.init: + ; Initialize variables and registers + xor rdi, rdi ; Used as counter + mov rcx, 10 ; Used as multiplier + xor rax, rax ; Returns result + xor rdx, rdx ; Temporary + mov dword [rbp - 8], 0 ; Store result + +.checknegative: + xor rsi, rsi ; Used to represent negative numbers + mov dl, [rbx + rdi] ; Select the character + cmp dl, 0x2d ; Check if this is - sign + jne .multiplyLoop + mov rsi, 1 ; rsi = 1 represents negative numers + inc rdi ; mov buffer pointer + +.multiplyLoop: + mov rax, [rbp - 8] ; Get saved value + mul rcx ; Make this value 10x + jo .invalid ; Jump in case of overflow + mov dl, [rbx + rdi] ; Select the character + cmp dl, 0x30 ; Validate character between 0-9 + jl .invalid + cmp dl, 0x39 + jg .invalid + sub dl, 0x30 ; Subtract ASCII 48 to get its actual value + add rax, rdx ; Add new value and 10x old value + mov [rbp - 8], rax ; Save result + inc rdi ; Increase the counter + cmp byte [rbx + rdi], 0 ; Have we reached a null terminator? + je .finish ; If yes, we are done. + cmp byte [rbx + rdi], 0xa ; Have we reached a newline character? + je .finish ; If yes, we are done. + cmp byte [rbx + rdi], 0xd ; Did we reach a carriage return (in windows)? + je .finish ; If yes, we are done. + jmp .multiplyLoop ; Loop back + +.finish: + mov rax, [rbp - 8] ; Result in rax + +.minussign: + cmp rsi, 1 + jne .done + neg rax + jmp .done + +.invalid: + xor rax, rax + +.done: + mov rsp, rbp ; clean up our stack + pop rbp + ret + diff --git a/src/ceed.h b/src/ceed.h index af68b61..3fcf615 100644 --- a/src/ceed.h +++ b/src/ceed.h @@ -51,10 +51,14 @@ typedef struct _sym { extern int func[26]; -u32 emit_code(sym *p); +//u32 emit_code(sym *p); void emit8(u8 i); void emit16(u16 i); void emit32(u32 i); +void emit32at(u32 pos, u32 i); +void emit3(u8 a, u8 b, u8 c); +void emit64(u64 i); +void emit64at(u32 pos, u32 i); #define round_up(n, r) ((((n) + ((r)-1))/(r))*(r)) @@ -62,15 +66,19 @@ u32 add_str(pu8 str); void cmplr_init(); void elf_init(); void pe_init(); +void pe64_init(); +void cmplr64_init(); +void gen_exe(void); typedef void (*pfn_gen_exe_file)(pvoid ei); typedef pvoid (*pfn_set_exe_scn)(pvoid ei, pu8 scn_data, u32 scn_size); typedef pvoid (*pfn_get_va)(pvoid ei); typedef void (*pfn_emit_main_init)(); typedef void (*pfn_emit_main_exit)(); -typedef void (*pfn_emit_write)(u32 buf_addr, u32 buf_len); +typedef void (*pfn_emit_write)(u64 buf_addr, u32 buf_len); typedef void (*pfn_emit_write_reg_input)(); -typedef void (*pfn_emit_read)(u32 buf_addr, u32 buf_len); +typedef void (*pfn_emit_read)(u64 buf_addr, u32 buf_len); +typedef u32 (*pfn_emit_code)(sym* p); extern pvoid ei; extern pfn_gen_exe_file gen_exe_file; @@ -84,4 +92,36 @@ extern pfn_emit_main_exit emit_main_exit; extern pfn_emit_write emit_write; extern pfn_emit_write_reg_input emit_write_reg_input; extern pfn_emit_read emit_read; +extern pfn_emit_code emit_code; +extern u8 itoa_code[]; +extern u8 atoi_code[]; +extern u8 itoa_code64[]; +extern u8 atoi_code64[]; + +extern u32 code_pos; +extern pu8 code; +extern u32 rdata_pos; +extern pu8 rdata; + +#define CEED_MAX_CODE_SIZE 0x100000 // 1MB +#define CEED_MAX_RDATA_SIZE 0x100000 // 1MB + +#define CEED_OP_ADD 0 +#define CEED_OP_SUB 1 +#define CEED_OP_GT 0 +#define CEED_OP_EQ 1 + +#define CEED_TYPE_VAL 1 +#define CEED_TYPE_ADDR 2 + +// +// Reserve some temp space needed for itoa or atoi. +// +#define CEED_TEMP_ATOI_ITOA_BUF_ADDR 0x900 +// +// Need at least 13 bytes on windows to accomodate: -2,147,483,648 followed +// by CR-LF, which are appended on ReadConsole in Windows. We make length 16 +// bytes. +// +#define CEED_TEMP_ATOI_ITOA_BUF_LEN 0x10 \ No newline at end of file diff --git a/src/ceed.y b/src/ceed.y index 74adb89..06d3547 100644 --- a/src/ceed.y +++ b/src/ceed.y @@ -153,9 +153,11 @@ mk_stmt(int type, int sym_count, ...) va_list ap; sym *p; int i; - - if ((p = malloc(sizeof(sym) + (sym_count-1) * sizeof(sym *))) == NULL) + int plen = sizeof(sym) + (sym_count-1) * sizeof(sym *); + if ((p = malloc(plen)) == NULL){ yyerror("out of memory"); + exit(0); + } p->type = sym_typ_stmt; p->stmt.type = type; @@ -188,29 +190,3 @@ yyerror(char *s) fprintf(stdout, "Line: %d, Error: %s\n", yylineno, s); } -int -main(int argc, char *argv[]) -{ - func[0] = -1; - - if (argc == 1) { - elf_init(); - } else if (argc == 2 && (strcmp(argv[1], "-pe") == 0)) { - pe_init(); - } else { - printf("Invalid command line. Valid syntax is:\n"); - printf("For ELF output: ceed < input_file\n"); - printf("For PE output: ceed -pe < input_file\n"); - exit(-1); - } - - cmplr_init(); - - if (yyparse() == 0) { - gen_exe(); - return 0; - } else { - return -1; - } -} - diff --git a/src/ceedcmpl.c b/src/ceedcmpl.c index dc7781d..19117bd 100644 --- a/src/ceedcmpl.c +++ b/src/ceedcmpl.c @@ -8,18 +8,15 @@ license. See the LICENSE file for details. --*/ #include +#include #include #include "ceed.h" #include "ceed.tab.h" -#define CEED_MAX_CODE_SIZE 0x100000 // 1MB -#define CEED_MAX_RDATA_SIZE 0x100000 // 1MB -static u32 code_pos = 0; -static pu8 code; -static u32 rdata_pos = 0; +u32 code_pos = 0; +pu8 code; +u32 rdata_pos = 0; pu8 rdata; -extern u8 itoa_code[]; -extern u8 atoi_code[]; pvoid ei; pfn_gen_exe_file gen_exe_file; @@ -33,28 +30,9 @@ pfn_emit_main_exit emit_main_exit; pfn_emit_write emit_write; pfn_emit_write_reg_input emit_write_reg_input; pfn_emit_read emit_read; +pfn_emit_code emit_code; -#define CEED_OP_ADD 0 -#define CEED_OP_SUB 1 -#define CEED_OP_GT 0 -#define CEED_OP_EQ 1 - -#define CEED_TYPE_VAL 1 -#define CEED_TYPE_ADDR 2 - -// -// Reserve some temp space needed for itoa or atoi. -// -#define CEED_TEMP_ATOI_ITOA_BUF_ADDR 0x900 -// -// Need at least 13 bytes on windows to accomodate: -2,147,483,648 followed -// by CR-LF, which are appended on ReadConsole in Windows. We make length 16 -// bytes. -// -#define CEED_TEMP_ATOI_ITOA_BUF_LEN 0x10 - -void -chk_code_size(u32 size) +void chk_code_size(u32 size) { if ((size + code_pos) > CEED_MAX_CODE_SIZE) { printf("Error: Exceeded maximum CODE size of %d bytes.\n", @@ -63,20 +41,53 @@ chk_code_size(u32 size) } } -void -emit8(u8 i) +void emit1(u8 a) { chk_code_size(1); - memcpy(&code[code_pos], &i, 1); - code_pos++; + code[code_pos++] = a; } -void -emit16(u16 i) +void emit2(u8 a, u8 b) +{ + chk_code_size(2); + code[code_pos++] = a; + code[code_pos++] = b; +} + +void emit3(u8 a, u8 b, u8 c) +{ + chk_code_size(3); + code[code_pos++] = a; + code[code_pos++] = b; + code[code_pos++] = c; +} +void emit4(u8 a, u8 b, u8 c, u8 d) +{ + chk_code_size(4); + code[code_pos++] = a; + code[code_pos++] = b; + code[code_pos++] = c; + code[code_pos++] = d; +} +void emit(u8 bytes[], int n) +{ + chk_code_size(n); + for(int i=0;iident.index >= 0 && p->ident.index <= 25) { @@ -152,7 +173,7 @@ emit_var(sym *p) emit8(0x89); emit8(0xe9); - // sub ecx, x + // sub rcx, #imm8 48 83 e9 #imm8 emit8(0x83); emit8(0xe9); emit8((p->ident.index + 1) * 4); @@ -161,12 +182,12 @@ emit_var(sym *p) // mov ecx, data_section_va + offset emit8(0xb9); - emit32(get_data_va(ei) + ((p->ident.index - 26) * 4)); + emit32((u32)get_data_va(ei) + ((p->ident.index - 26) * 4)); } return CEED_TYPE_ADDR; } -u32 +static u32 emit_const(sym *p) { // Mov eax, imm32 @@ -175,7 +196,7 @@ emit_const(sym *p) return CEED_TYPE_VAL; } -void +static void emit_expr_val(sym *p) { if (emit_code(p) == CEED_TYPE_ADDR) { @@ -185,7 +206,7 @@ emit_expr_val(sym *p) } } -void +static void emit_if_else(sym *p) { int patchPos = 0, codePosTmp1 = 0, codePosTmp2 = 0; @@ -225,7 +246,7 @@ emit_if_else(sym *p) } } -void +static void emit_arith(sym *p, int sym_list) { emit_expr_val(p->stmt.sym_list[1]); @@ -249,7 +270,7 @@ emit_arith(sym *p, int sym_list) } } -void +static void emit_logical(sym *p, int sym_list) { emit_expr_val(p->stmt.sym_list[1]); @@ -289,10 +310,9 @@ emit_logical(sym *p, int sym_list) emit32(0x1); } -void +static void emit_set_var(sym *p) { - u8 tmp; u8 id = p->stmt.sym_list[0]->ident.index; // Get value of second operand in eax @@ -302,22 +322,22 @@ emit_set_var(sym *p) // Set Local or Global variable based on index. // if (id >= 0 && id <= 25) { - // mov [ebp + tmp], eax - tmp = (0 - ((id + 1) * 4)); + // mov [ebp + #imm8], eax + u8 off = (0 - ((id + 1) * 4)); emit8(0x89); emit8(0x45); - emit8(tmp); + emit8(off); } else if (id >= 26 && id <= 51) { // mov [data_section_va + offset], eax emit8(0xa3); - emit32(get_data_va(ei) + ((id - 26) * 4)); + emit32((u32)get_data_va(ei) + ((id - 26) * 4)); } else { printf("Error: Unexpected identifier: %d\n", id); exit(-1); } } -void +static void emit_func_def(sym *p) { u32 fn_id; @@ -347,30 +367,30 @@ emit_func_def(sym *p) } } -void +static void emit_func_call(sym *p) { int val = func[p->stmt.sym_list[0]->ident.index - 52]; // mov eax, emit8(0xb8); - emit32(val + get_code_va(ei)); + emit32(val + (u32)get_code_va(ei)); // call eax emit8(0xff); emit8(0xd0); } -void +static void emit_write_str(sym *p) { u32 str_len; str_len = strlen(rdata + p->con.value); - emit_write(get_rdata_va(ei) + p->con.value, str_len); + emit_write((u32)get_rdata_va(ei) + p->con.value, str_len); // printf("emit_write: %x, %d\n", get_rdata_va(ei) + p->con.value, str_len); } -void +static void emit_write_int() { // @@ -379,7 +399,7 @@ emit_write_int() // mov ebx, itoa_buf emit8(0xbb); - emit32(get_data_va(ei) + CEED_TEMP_ATOI_ITOA_BUF_ADDR); + emit32((u32)get_data_va(ei) + CEED_TEMP_ATOI_ITOA_BUF_ADDR); // mov ecx, (itoa) emit8(0xb9); @@ -397,33 +417,32 @@ emit_write_int() emit_write_reg_input(); } -void +static void emit_read_int() { // mov [addr], 0 - Zero first byte of buffer to ensure on error, we // don't convert the string to int with random values. emit16(0x05c6); - emit32(get_data_va(ei) + CEED_TEMP_ATOI_ITOA_BUF_ADDR); + emit32((u32)get_data_va(ei) + CEED_TEMP_ATOI_ITOA_BUF_ADDR); emit8(0x0); - emit_read(get_data_va(ei) + CEED_TEMP_ATOI_ITOA_BUF_ADDR, - CEED_TEMP_ATOI_ITOA_BUF_LEN); + emit_read((u32)get_data_va(ei) + CEED_TEMP_ATOI_ITOA_BUF_ADDR, CEED_TEMP_ATOI_ITOA_BUF_LEN); // mov ebx, buf_addr emit8(0xbb); - emit32(get_data_va(ei) + CEED_TEMP_ATOI_ITOA_BUF_ADDR); + emit32((u32)get_data_va(ei) + CEED_TEMP_ATOI_ITOA_BUF_ADDR); // mov ecx, (atoi) emit8(0xb9); - emit32(get_code_va(ei) + 0x80); + emit32((u32)get_code_va(ei) + 0x80); // call ecx emit8(0xff); emit8(0xd1); } -u32 -emit_code(sym *p) +static u32 +emit_code32(sym *p) { if (p == NULL) return 0; @@ -555,6 +574,7 @@ gen_exe() void cmplr_init() { + emit_code = emit_code32; code = malloc(CEED_MAX_CODE_SIZE); rdata = malloc(CEED_MAX_RDATA_SIZE); @@ -572,7 +592,7 @@ cmplr_init() rdata[0] = '\n'; rdata_pos = 2; - + // copy internal functions: itoa, atoi // TODO: HACK - Get actual size. memcpy(code, itoa_code, 0x80); code_pos += 0x80; diff --git a/src/ceedcmpl64.c b/src/ceedcmpl64.c new file mode 100644 index 0000000..f23f749 --- /dev/null +++ b/src/ceedcmpl64.c @@ -0,0 +1,463 @@ +/*++ + +Copyright (c) 2017, Pankaj Garg +All rights reserved. + +This software may be modified and distributed under the terms of the BSD +license. See the LICENSE file for details. + +--*/ +#include +#include +#include +#include "ceed.h" +#include "ceed.tab.h" + +static void +emit_prolog() +{ + // push rbp + emit8(0x55); + // mov rbp, rsp + emit3(0x48, 0x89, 0xe5); + // sub rsp, #imm32 48 81 ec d0 00 00 00 0xd0 (26 * 8) + emit3(0x48, 0x81, 0xec); + emit32(26 * 8); +} + +static void +emit_epilog_common() +{ + // mov rsp, rbp + emit3(0x48, 0x89, 0xec); + + // pop rbp + emit8(0x5d); + +} + +static void +emit_epilog() +{ + emit_epilog_common(); + + // ret + emit8(0xc3); +} + +static void +emit_epilog_final() +{ + emit_epilog_common(); + // + // For Windows, main can return by calling "ret" instruction.For Linux, + // main can only exit by invoking sys_exit syscall.Hence we call platform + // specific handler to generate exit code. + // + emit_main_exit(); +} + +static u32 +emit_var(sym *p) +{ + if (p->ident.index >= 0 && p->ident.index <= 25) { + // Local variable. + // mov rcx, rbp + emit3(0x48, 0x89, 0xe9); + + u32 imm = (p->ident.index + 1) * 8; + // sub rcx, #imm32 48 81 e9 #imm32 + emit3(0x48, 0x81, 0xe9); + emit32(imm); + } else if (p->ident.index >= 26 && p->ident.index <= 51) { + // Global variable. + // mov rcx, data_section_va + offset + emit2(0x48, 0xb9); + emit64((u64)get_data_va(ei) + ((p->ident.index - 26) * 8)); + } + return CEED_TYPE_ADDR; +} + +static u32 +emit_const(sym *p) +{ + // Mov rax, imm64 + emit2(0x48, 0xb8); + emit64(p->con.value); + return CEED_TYPE_VAL; +} + +static void +emit_expr_val(sym *p) +{ + if (emit_code(p) == CEED_TYPE_ADDR) { + // mov rax, [rcx] + emit3(0x48, 0x8b, 0x01); + } +} + +static void +emit_if_else(sym *p) +{ + int patchPos = 0, codePosTmp1 = 0, codePosTmp2 = 0; + int i = 0; + // + emit_code(p->stmt.sym_list[0]); + + // cmp rax, #imm32 48 3d 80 00 00 00 + // cmp rax, #imm8 48 83 f8 00 #imm8 -128 ~ 127 + emit4(0x48, 0x83, 0xf8, 0x00); + + // je or jz #offset32 + emit2(0x0f, 0x84); + patchPos = code_pos; // save current ip for reloc + emit32(0xdeadbeef); // emit tmp offset + codePosTmp1 = code_pos; + emit_code(p->stmt.sym_list[1]); + if (p->stmt.sym_count > 2) { + // Account for an extra jmp here that is needed to skip else block. + // Jmp instruction size is 5 so adding 5 to je; + i = code_pos - codePosTmp1 + 5; + emit32at(patchPos, i); + + // jmp + emit8(0xe9); + patchPos = code_pos; + emit32(0xdeadbeef); + codePosTmp1 = code_pos; + emit_code(p->stmt.sym_list[2]); + i = code_pos - codePosTmp1; + emit32at(patchPos, i); + } else { + i = code_pos - codePosTmp1; + emit32at(patchPos, i); + } +} + +static void +emit_arith(sym *p, int sym_list) +{ + emit_expr_val(p->stmt.sym_list[1]); + + // push rax + emit8(0x50); + + emit_expr_val(p->stmt.sym_list[0]); + + // pop rbx + emit8(0x5b); + + if (sym_list == CEED_OP_ADD) { + // add rax, rbx + emit8(0x48); + emit8(0x01); + emit8(0xd8); + } else { + // sub rax, rbx + emit8(0x48); + emit8(0x29); + emit8(0xd8); + } +} + +static void +emit_logical(sym *p, int sym_list) +{ + // + emit_expr_val(p->stmt.sym_list[1]); + // push rax + emit8(0x50); + // mov rax, [rcx] + emit_expr_val(p->stmt.sym_list[0]); + // pop ebx + emit8(0x5b); + // cmp rax, rbx + emit3(0x48, 0x39, 0xd8); + + if (sym_list == CEED_OP_GT) { + // jg 0x5 + emit8(0x7f); + emit8(0x05); // sizeof current instruction & next instruction + } else { + // je 0x5 + emit8(0x74); + emit8(0x05); + } + + // xor rax, rax + emit3(0x48, 0x31, 0xc0); + + // jmp 0x7 + emit8(0xeb); + emit8(0x07); // sizeof next instruction + + // mov rax, 1 + emit3(0x48, 0xc7, 0xc0); + emit32(0x01); +} + +static void +emit_set_var(sym *p) +{ + u8 id = p->stmt.sym_list[0]->ident.index; + + // Get value of second operand in eax + emit_expr_val(p->stmt.sym_list[1]); + + // + // Set Local or Global variable based on index. + // + if (id >= 0 && id <= 25) { + // mov [rbp + %imm32], rax + u32 off = (0 - ((id + 1) * 8)); + emit3(0x48, 0x89, 0x85); + emit32(off); + } else if (id >= 26 && id <= 51) { + // mov [data_section_va + offset], rax + // mov qword ptr[rip+#imm32], rax 48 89 05 59 30 00 00 + u64 off = (u64)get_data_va(ei) - (u64)get_code_va(ei) - code_pos - 7 + ((id - 26) * 8); + emit3(0x48, 0x89, 0x05); + emit32(off); + } else { + printf("Error: Unexpected identifier: %d\n", id); + exit(-1); + } +} + +static void +emit_func_def(sym *p) +{ + u32 fn_id; + + fn_id = p->stmt.sym_list[0]->ident.index - 52; + func[fn_id] = code_pos; + + emit_prolog(); + + if (fn_id == 0) { + // + // Emit any initialization code if needed. We use this to store + // handle to stdin and stdout on Windows. + // + emit_main_init(); + } + + // + // Generate actual function code. + // + emit_code(p->stmt.sym_list[1]); + + if (fn_id == 0) { + emit_epilog_final(); + } else { + emit_epilog(); + } +} + +static void +emit_func_call(sym *p) +{ + int val = func[p->stmt.sym_list[0]->ident.index - 52]; + + // mov rax, + emit8(0x48); + emit8(0xb8); + emit64(val + (u64)get_code_va(ei)); + + // call rax + emit8(0x48); + emit8(0xff); + emit8(0xd0); +} + +static void +emit_write_str(sym *p) +{ + u32 str_len; + str_len = strlen(rdata + p->con.value); + emit_write((u64)get_rdata_va(ei) + p->con.value, str_len); + // printf("emit_write: %x, %d\n", get_rdata_va(ei) + p->con.value, str_len); +} + +static void +emit_write_int() +{ + // + // At this point rax contains the number to be converted to string. + // + + // mov rbx, itoa_buf + emit8(0x48); + emit8(0xbb); + emit64((u64)get_data_va(ei) + CEED_TEMP_ATOI_ITOA_BUF_ADDR); + + // mov rcx, (itoa) + emit8(0x48); + emit8(0xb9); + emit64(get_code_va(ei)); + + // call rcx + emit8(0x48); + emit8(0xff); + emit8(0xd1); + + // + // This returns buffer in rcx and count in rdx, which is suitable for + // Linux syscall_write. + // + + emit_write_reg_input(); +} + +// call atoi +static void +emit_read_int() +{ + // mov [addr], 0 - Zero first byte of buffer to ensure on error, we + // don't convert the string to int with random values. + + //u64 off = (u64)get_data_va(ei) + CEED_TEMP_ATOI_ITOA_BUF_ADDR; + //emit2(0xc6, 0x05); + //emit64(off); + //emit8(0x0); + + emit_read((u64)get_data_va(ei) + CEED_TEMP_ATOI_ITOA_BUF_ADDR, CEED_TEMP_ATOI_ITOA_BUF_LEN); + //emit_write((u64)get_rdata_va(ei) + p->con.value, str_len); + + // mov rbx, buf_addr + emit2(0x48, 0xBB); + emit64((u64)get_data_va(ei) + CEED_TEMP_ATOI_ITOA_BUF_ADDR); + + // mov rcx, (atoi) + emit2(0x48, 0xB9); + emit64((u64)get_code_va(ei) + 0x80); + + // call rcx + emit2(0xff, 0xd1); +} + +static u32 +emit_code64(sym *p) +{ + if (p == NULL) + return 0; + + switch (p->type) { + case sym_typ_const: + return emit_const(p); + case sym_typ_ident: + return emit_var(p); + case sym_typ_stmt: + switch (p->stmt.type) { + case FN_DEF: + emit_func_def(p); + break; + case FN_CALL: + emit_func_call(p); + break; + case LOOP: + // This is left as an exercise for the reader. + printf("Error: Loop support is not implemented.\n"); + exit(-1); + case IF: + emit_if_else(p); + break; + case WRITE_STR: { + sym* s = p->stmt.sym_list[0]; + emit_write_str(s); + break; + } + case WRITE_INT: + emit_expr_val(p->stmt.sym_list[0]); + emit_write_int(); + break; + case WRITE_NEWLINE: + emit_write(get_rdata_va(ei), 1); + break; + case READ_INT: + emit_read_int(); + break; + case ';': + emit_code(p->stmt.sym_list[0]); + emit_code(p->stmt.sym_list[1]); + break; + case '=': + emit_set_var(p); + break; + case '+': + emit_arith(p, CEED_OP_ADD); + break; + case '-': + emit_arith(p, CEED_OP_SUB); + break; + case '>': + emit_logical(p, CEED_OP_GT); + break; + case EQ: + emit_logical(p, CEED_OP_EQ); + break; + } + } + + return 0; +} + + +//static u32 +//add_str(pu8 str) +//{ +// u32 str_len; +// u32 ret_pos; +// +// str_len = strlen(str); +// str[str_len - 1] = '\0'; // Remove terminating " +// if ((rdata_pos + str_len) > CEED_MAX_RDATA_SIZE) { +// printf("Error: Exceeded maximum RDATA size of %d bytes.\n", +// CEED_MAX_RDATA_SIZE); +// exit(-1); +// } +// strcpy(&rdata[rdata_pos], str); +// ret_pos = rdata_pos; +// rdata_pos += str_len; +// return ret_pos; +//} + +//static void +//gen_exe() +//{ +// set_exe_code_scn(ei, code, code_pos); +// set_exe_rdata_scn(ei, rdata, rdata_pos); +// gen_exe_file(ei); +//} + +void +cmplr64_init() +{ + emit_code = emit_code64; + code = malloc(CEED_MAX_CODE_SIZE); + rdata = malloc(CEED_MAX_RDATA_SIZE); + + if (code == NULL || rdata == NULL) { + printf("Insufficient memory.\n"); + exit(-1); + } + + memset(code, 0, CEED_MAX_CODE_SIZE); + memset(rdata, 0, CEED_MAX_RDATA_SIZE); + + // + // Create a new line string as it is needed to print new lines. + // + rdata[0] = '\n'; + rdata_pos = 2; + +#if 1 + // copy internal functions: itoa, atoi + // TODO: HACK - Get actual size. + memcpy(code, itoa_code64, 0x80); + code_pos += 0x80; + memcpy(&code[code_pos], atoi_code64, 0x80); + code_pos += 0x80; +#endif +} + diff --git a/src/ceedelf.c b/src/ceedelf.c index 07333ad..a66e717 100644 --- a/src/ceedelf.c +++ b/src/ceedelf.c @@ -240,7 +240,7 @@ elf_write_section_data(psection_info si, FILE *file) fwrite(si->scn_data, si->scn_file_size, 1, file); } -u8 data_buffer[4096]; +static u8 data_buffer[4096]; #define CEED_MAX_VARIABLES 26 void elf_gen_data_section(pexe_info ei) diff --git a/src/ceedpe.c b/src/ceedpe.c index 1dd20dc..7f0c1a3 100644 --- a/src/ceedpe.c +++ b/src/ceedpe.c @@ -127,11 +127,12 @@ typedef struct _IMAGE_IMPORT_DESCRIPTOR { } IMAGE_IMPORT_DESCRIPTOR; typedef IMAGE_IMPORT_DESCRIPTOR *PIMAGE_IMPORT_DESCRIPTOR; -unsigned char dos_hdr[128] = { +static unsigned char dos_hdr[128] = { +#define HDRL sizeof(dos_hdr) 0x4D, 0x5A, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, HDRL, 0x00, 0x00, 0x00, 0x0E, 0x1F, 0xBA, 0x0E, 0x00, 0xB4, 0x09, 0xCD, 0x21, 0xB8, 0x01, 0x4C, 0xCD, 0x21, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6F, 0x67, 0x72, 0x61, 0x6D, 0x20, 0x63, 0x61, 0x6E, 0x6E, 0x6F, 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6E, 0x20, 0x69, 0x6E, 0x20, 0x44, 0x4F, 0x53, 0x20, @@ -163,14 +164,21 @@ unsigned char dos_hdr[128] = { // purposes. // #define CEED_FILE_ALIGN 0x200 // 512B -#define CEED_SECTION_ALIGN 0x100000 // 16MB +#define CEED_SECTION_ALIGN 0x1000000 // 16MB #define CEED_IMAGE_BASE_VA 0x400000 +#define CEED_OLD +#ifdef CEED_OLD #define CEED_IMPORT_SECTION_RVA (CEED_SECTION_ALIGN * 1) #define CEED_DATA_SECTION_RVA (CEED_SECTION_ALIGN * 2) #define CEED_CODE_SECTION_RVA (CEED_SECTION_ALIGN * 3) #define CEED_RDATA_SECTION_RVA (CEED_SECTION_ALIGN * 4) - +#else +#define CEED_IMPORT_SECTION_RVA (CEED_SECTION_ALIGN * 3) +#define CEED_DATA_SECTION_RVA (CEED_SECTION_ALIGN * 2) +#define CEED_CODE_SECTION_RVA (CEED_SECTION_ALIGN * 1) +#define CEED_RDATA_SECTION_RVA (CEED_SECTION_ALIGN * 4) +#endif // // We use bottom 2K of DATA section for any system state outside of user's @@ -190,10 +198,10 @@ unsigned char dos_hdr[128] = { // functions imported from kernel32 after the exe and dlls are loaded by // windows loader. // -u32 k32_fn_array; -u32 fn_GetStdHandle; -u32 fn_ReadConsoleA; -u32 fn_WriteConsoleA; +static u32 k32_fn_array; +static u32 fn_GetStdHandle; +static u32 fn_ReadConsoleA; +static u32 fn_WriteConsoleA; typedef struct _section_info { @@ -219,7 +227,7 @@ typedef struct _exe_info } exe_info, *pexe_info; -psection_info +static psection_info pe_new_section(pexe_info ei, const char *name, u32 scn_va, u32 attr) { psection_info si = malloc(sizeof(section_info)); @@ -231,28 +239,41 @@ pe_new_section(pexe_info ei, const char *name, u32 scn_va, u32 attr) return si; } -pvoid +static pvoid pe_alloc_exe_info() { pexe_info ei = malloc(sizeof(exe_info)); memset(ei, 0, sizeof(exe_info)); +#ifdef CEED_OLD ei->import_scn = pe_new_section(ei, ".idata", CEED_IMPORT_SECTION_RVA, IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE); ei->data_scn = pe_new_section(ei, ".data", CEED_DATA_SECTION_RVA, - IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE); + IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE); ei->code_scn = pe_new_section(ei, ".text", CEED_CODE_SECTION_RVA, - IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ); + IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ); ei->rdata_scn = pe_new_section(ei, ".rdata", CEED_RDATA_SECTION_RVA, - IMAGE_SCN_MEM_READ); + IMAGE_SCN_MEM_READ); +#else + ei->code_scn = pe_new_section(ei, ".text", CEED_CODE_SECTION_RVA, + IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ); + + ei->data_scn = pe_new_section(ei, ".data", CEED_DATA_SECTION_RVA, + IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE); + ei->import_scn = pe_new_section(ei, ".idata", CEED_IMPORT_SECTION_RVA, + IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE); + + ei->rdata_scn = pe_new_section(ei, ".rdata", CEED_RDATA_SECTION_RVA, + IMAGE_SCN_MEM_READ); +#endif return ei; } -pvoid +static pvoid pe_set_scn(psection_info si, pu8 scn_data, u32 scn_size) { si->scn_data = scn_data; @@ -265,53 +286,53 @@ pe_set_scn(psection_info si, pu8 scn_data, u32 scn_size) return NULL; } -pvoid +static pvoid pe_set_exe_code_scn(pvoid einfo, pu8 scn_data, u32 scn_size) { pexe_info ei = einfo; return pe_set_scn(ei->code_scn, scn_data, scn_size); } -pvoid +static pvoid pe_set_exe_data_scn(pvoid einfo, pu8 scn_data, u32 scn_size) { pexe_info ei = einfo; return pe_set_scn(ei->data_scn, scn_data, scn_size); } -pvoid +static pvoid pe_set_exe_rdata_scn(pvoid einfo, pu8 scn_data, u32 scn_size) { pexe_info ei = einfo; return pe_set_scn(ei->rdata_scn, scn_data, scn_size); } -pvoid +static pvoid pe_set_exe_import_scn(pvoid einfo, pu8 scn_data, u32 scn_size) { pexe_info ei = einfo; return pe_set_scn(ei->import_scn, scn_data, scn_size); } -u32 +static u32 pe_get_code_va(pvoid einfo) { return CEED_IMAGE_BASE_VA + CEED_CODE_SECTION_RVA; } -u32 +static u32 pe_get_data_va(pvoid einfo) { return CEED_IMAGE_BASE_VA + CEED_DATA_SECTION_RVA; } -u32 +static u32 pe_get_rdata_va(pvoid einfo) { return CEED_IMAGE_BASE_VA + CEED_RDATA_SECTION_RVA; } -void +static void pe_write_fixed_hdrs(pexe_info ei, FILE *file) { u32 nt_sig = IMAGE_NT_SIGNATURE; @@ -331,7 +352,7 @@ pe_write_fixed_hdrs(pexe_info ei, FILE *file) } -void +static void pe_write_optional_hdr(pexe_info ei, FILE *file) { IMAGE_OPTIONAL_HEADER32 oh = { 0 }; @@ -345,7 +366,7 @@ pe_write_optional_hdr(pexe_info ei, FILE *file) oh.SizeOfUninitializedData = 0; oh.AddressOfEntryPoint = 0; // Fixed later. oh.BaseOfCode = 0; // Fixed later. - oh.ImageBase = 0x400000; + oh.ImageBase = CEED_IMAGE_BASE_VA; oh.SectionAlignment = CEED_SECTION_ALIGN; oh.FileAlignment = CEED_FILE_ALIGN; oh.MajorOperatingSystemVersion = 4; @@ -392,22 +413,22 @@ pe_write_optional_hdr(pexe_info ei, FILE *file) fwrite(&oh, sizeof(oh), 1, file); } -void +static void pe_write_section_hdr(psection_info si, FILE *file) { fwrite(&si->scn_hdr, sizeof(si->scn_hdr), 1, file); } -void +static void pe_write_section_data(psection_info si, u32 file_offset, FILE *file) { fseek(file, file_offset, SEEK_SET); fwrite(si->scn_data, si->scn_file_size, 1, file); } -u8 data_buffer[4096]; +static u8 data_buffer[4096]; #define CEED_MAX_VARIABLES 26 -void +static void pe_gen_data_section(pexe_info ei) { // @@ -420,8 +441,8 @@ pe_gen_data_section(pexe_info ei) #define MAX_FUNCTIONS_IMPORT_PER_DLL 8 #define c_assert(e) typedef char __c_assert__[(e)?1:-1] -u8 import_buffer[4096]; -void +static u8 import_buffer[4096]; +static void pe_gen_import_section(pexe_info ei) { pu8 import = import_buffer; @@ -429,10 +450,13 @@ pe_gen_import_section(pexe_info ei) IMAGE_THUNK_DATA32 *th; IMAGE_THUNK_DATA32 *oth; IMAGE_IMPORT_BY_NAME *iin; - const char *dll_names[] = { "kernel32.dll", "ntdll.dll" }; + const char *dll_names[] = { + "kernel32.dll", + "ntdll.dll" + }; const char *fn_names[][10] = { - { "WriteConsoleA", "ReadConsoleA", "GetStdHandle", 0 }, - { "NtReadFile", 0 }, + { "WriteConsoleA", "ReadConsoleA", "GetStdHandle", 0 }, + { "NtReadFile", 0 }, }; int dll_count = sizeof(dll_names) / sizeof(dll_names[0]); @@ -503,7 +527,7 @@ pe_gen_import_section(pexe_info ei) pe_set_exe_import_scn(ei, import, offset); } -void +static void pe_gen_exe_file(pvoid einfo) { pexe_info ei = einfo; @@ -549,7 +573,7 @@ pe_gen_exe_file(pvoid einfo) fclose(exe_file); } -void +static void pe_emit_indirect_call(u32 fn_addr) { // call [fn_addr] @@ -559,7 +583,7 @@ pe_emit_indirect_call(u32 fn_addr) } -void +static void pe_emit_get_std_handle(u8 handle_type, u32 save_location) { // push handle_type @@ -570,13 +594,13 @@ pe_emit_get_std_handle(u8 handle_type, u32 save_location) // mov [data_section_va + save_location], eax emit8(0xa3); - emit32(get_data_va(ei) + save_location); + emit32((u32)get_data_va(ei) + save_location); } #define STD_INPUT_HANDLE (-10) #define STD_OUTPUT_HANDLE (-11) -void +static void pe_emit_main_init() { // @@ -588,14 +612,14 @@ pe_emit_main_init() } -void +static void pe_emit_main_exit() { // ret emit8(0xc3); } -void +static void pe_emit_write(u32 buf_addr, u32 buf_len) { // @@ -607,7 +631,7 @@ pe_emit_write(u32 buf_addr, u32 buf_len) // push temp location (lpNumberOfCharsWritten) emit8(0x68); - emit32(get_data_va(ei) + CEED_TEMP_U32_1); + emit32((u32)get_data_va(ei) + CEED_TEMP_U32_1); // push buf_len (nNumberOfCharsToWrite) emit8(0x68); @@ -619,14 +643,14 @@ pe_emit_write(u32 buf_addr, u32 buf_len) // push stdout handle from saved location emit16(0x35ff); - emit32(get_data_va(ei) + CEED_STDOUT_HANDLE_RVA); + emit32((u32)get_data_va(ei) + CEED_STDOUT_HANDLE_RVA); // call [fn_addr] emit16(0x15ff); emit32(fn_WriteConsoleA); } -void +static void pe_emit_write_reg_input() { // @@ -638,7 +662,7 @@ pe_emit_write_reg_input() // push temp location (lpNumberOfCharsWritten) emit8(0x68); - emit32(get_data_va(ei) + CEED_TEMP_U32_1); + emit32((u32)get_data_va(ei) + CEED_TEMP_U32_1); // push edx (edx represents buffer length) emit8(0x52); @@ -648,26 +672,24 @@ pe_emit_write_reg_input() // push stdout handle from saved location emit16(0x35ff); - emit32(get_data_va(ei) + CEED_STDOUT_HANDLE_RVA); + emit32((u32)get_data_va(ei) + CEED_STDOUT_HANDLE_RVA); // call [fn_addr] emit16(0x15ff); emit32(fn_WriteConsoleA); } -void -pe_emit_read(u32 buf_addr, u32 buf_len) -{ - // - // Uses ReadConsole win32 API. - // - +// +// Uses ReadConsole win32 API. +// +static void +pe_emit_read(u32 buf_addr, u32 buf_len){ // push 0 (pInputControl -> NULL) emit16(0x006a); // push temp location (lpNumberOfCharsRead) emit8(0x68); - emit32(get_data_va(ei) + CEED_TEMP_U32_1); + emit32((u32)get_data_va(ei) + CEED_TEMP_U32_1); // push buf_len (nNumberOfCharsToRead) emit8(0x68); @@ -679,7 +701,7 @@ pe_emit_read(u32 buf_addr, u32 buf_len) // push stdin handle from saved location emit16(0x35ff); - emit32(get_data_va(ei) + CEED_STDIN_HANDLE_RVA); + emit32((u32)get_data_va(ei) + CEED_STDIN_HANDLE_RVA); // call [fn_addr] emit16(0x15ff); diff --git a/src/ceedpe64.c b/src/ceedpe64.c new file mode 100644 index 0000000..2e6d29f --- /dev/null +++ b/src/ceedpe64.c @@ -0,0 +1,791 @@ +/*++ + +Copyright (c) 2017, Pankaj Garg +All rights reserved. + +This software may be modified and distributed under the terms of the BSD +license. See the LICENSE file for details. + +--*/ +#include +#include +#include +#include +#include + +#include "ceed.h" + +// +// Standard ELF definitions. +// + +#define IMAGE_NT_SIGNATURE 0x00004550 +#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b +#define IMAGE_FILE_MACHINE_I386 0x014c +#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b +#define IMAGE_FILE_MACHINE_X64 0x8664 +#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 +#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 //console +// Directory Entries +#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory +#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory +#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory +#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory +#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory +#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table +#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory +// IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 // (X86 usage) +#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 // Architecture Specific Data +#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // RVA of GP +#define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory +#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory +#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 // Bound Import Directory in headers +#define IMAGE_DIRECTORY_ENTRY_IAT 12 // Import Address Table +#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 // Delay Load Import Descriptors +#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 // COM Runtime descriptor +// +#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 // Relocation info stripped from file. +#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 // File is executable (i.e. no unresolved external references). +#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 // Line nunbers stripped from file. +#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 // Local symbols stripped from file. +#define IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010 // Aggressively trim working set +#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 // App can handle >2gb addresses +#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 // Bytes of machine word are reversed. +#define IMAGE_FILE_32BIT_MACHINE 0x0100 // 32 bit word machine. +#define IMAGE_FILE_DEBUG_STRIPPED 0x0200 // Debugging info stripped from file in .DBG file +#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 // If Image is on removable media, copy and run from the swap file. +#define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 // If Image is on Net, copy and run from the swap file. +#define IMAGE_FILE_SYSTEM 0x1000 // System File. +#define IMAGE_FILE_DLL 0x2000 // File is a DLL. +#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 // File should only be run on a UP machine +#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 // Bytes of machine word are reversed. + +#define IMAGE_SCN_CNT_CODE 0x00000020 // Section contains code. +#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 // Section contains initialized data. +#define IMAGE_SCN_MEM_EXECUTE 0x20000000 +#define IMAGE_SCN_MEM_READ 0x40000000 +#define IMAGE_SCN_MEM_WRITE 0x80000000 +#define IMAGE_SIZEOF_SHORT_NAME 8 + +#pragma pack (push, 1) + +typedef struct _IMAGE_FILE_HEADER { + u16 Machine; + u16 NumberOfSections; + u32 TimeDateStamp; + u32 PointerToSymbolTable; + u32 NumberOfSymbols; + u16 SizeOfOptionalHeader; + u16 Characteristics; +} IMAGE_FILE_HEADER, * PIMAGE_FILE_HEADER; + +typedef struct _IMAGE_DATA_DIRECTORY { + u32 VirtualAddress; + u32 Size; +} IMAGE_DATA_DIRECTORY, * PIMAGE_DATA_DIRECTORY; + +typedef struct _IMAGE_OPTIONAL_HEADER { + u16 Magic; + u8 MajorLinkerVersion; + u8 MinorLinkerVersion; + u32 SizeOfCode; + u32 SizeOfInitializedData; + u32 SizeOfUninitializedData; + u32 AddressOfEntryPoint; + u32 BaseOfCode; + u64 ImageBase; + + u32 SectionAlignment; + u32 FileAlignment; + u16 MajorOperatingSystemVersion; + u16 MinorOperatingSystemVersion; + u16 MajorImageVersion; + u16 MinorImageVersion; + u16 MajorSubsystemVersion; + u16 MinorSubsystemVersion; + u32 Win32VersionValue; + u32 SizeOfImage; + u32 SizeOfHeaders; + u32 CheckSum; + u16 Subsystem; + u16 DllCharacteristics; + u64 SizeOfStackReserve; + u64 SizeOfStackCommit; + u64 SizeOfHeapReserve; + u64 SizeOfHeapCommit; + u32 LoaderFlags; + u32 NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; + //} IMAGE_OPTIONAL_HEADER32, * PIMAGE_OPTIONAL_HEADER32; +} IMAGE_OPTIONAL_HEADER64, * PIMAGE_OPTIONAL_HEADER64; + +typedef struct _IMAGE_SECTION_HEADER { + s8 Name[IMAGE_SIZEOF_SHORT_NAME]; + union { + u32 PhysicalAddress; + u32 VirtualSize; + } Misc; + u32 VirtualAddress; + u32 SizeOfRawData; + u32 PointerToRawData; + u32 PointerToRelocations; + u32 PointerToLinenumbers; + u16 NumberOfRelocations; + u16 NumberOfLinenumbers; + u32 Characteristics; +} IMAGE_SECTION_HEADER, * PIMAGE_SECTION_HEADER; + +typedef struct _IMAGE_IMPORT_BY_NAME { + u16 Hint; + s8 Name[1]; +} IMAGE_IMPORT_BY_NAME, * PIMAGE_IMPORT_BY_NAME; + +typedef struct _IMAGE_THUNK_DATA64 { + union { + u64 ForwarderString; + u64 Function; + u64 Ordinal; + u64 AddressOfData; + }; +} IMAGE_THUNK_DATA64; +typedef IMAGE_THUNK_DATA64* PIMAGE_THUNK_DATA64; + +typedef struct _IMAGE_IMPORT_DESCRIPTOR { + union { + u32 Characteristics; + u32 OriginalFirstThunk; + }; + u32 TimeDateStamp; + u32 ForwarderChain; + u32 Name; + u32 FirstThunk; +} IMAGE_IMPORT_DESCRIPTOR; +typedef IMAGE_IMPORT_DESCRIPTOR *PIMAGE_IMPORT_DESCRIPTOR; + +static unsigned char dos_hdr[128] = { +#define HDRL sizeof(dos_hdr) + 0x4D, 0x5A, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, + 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, HDRL, 0x00, 0x00, 0x00, + 0x0E, 0x1F, 0xBA, 0x0E, 0x00, 0xB4, 0x09, 0xCD, 0x21, 0xB8, 0x01, 0x4C, 0xCD, 0x21, 0x54, 0x68, + 0x69, 0x73, 0x20, 0x70, 0x72, 0x6F, 0x67, 0x72, 0x61, 0x6D, 0x20, 0x63, 0x61, 0x6E, 0x6E, 0x6F, + 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6E, 0x20, 0x69, 0x6E, 0x20, 0x44, 0x4F, 0x53, 0x20, + 0x6D, 0x6F, 0x64, 0x65, 0x2E, 0x0D, 0x0D, 0x0A, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +#pragma pack(pop) + +// +// ceed specific definitions and code. +// + +// +// We are using hardcoded section offset. The reason for this is simplicity. +// +// A code that is accessing a gloal variable or constant needs to know its +// virtual address. Typically this requires two passes: +// +// First pass to generate code (as code generation is needed to calculate +// section size, which is then used to calculate offset for each section and +// using section offset, VA of global variables and constants is calculated. +// +// Second pass to patch the code that was generated without actually knowing +// the offsets. +// +// By assuming fixed offsets, we know VA of each section ahead of time and +// generate code in one pass without need for patching later. This makes code +// simpler. One limitation of this scheme is that each section is limited to +// 16MB, which is acceptable for this compiler as it is only for educational +// purposes. +// +#define CEED_FILE_ALIGN 0x200 // 512B +#define CEED_SECTION_ALIGN 0x1000000 // 16MB + +#define CEED_IMAGE_BASE_VA 0x140000000 +#define CEED_OLD +#ifdef CEED_OLD +#define CEED_IMPORT_SECTION_RVA (CEED_SECTION_ALIGN * 1) +#define CEED_DATA_SECTION_RVA (CEED_SECTION_ALIGN * 2) +#define CEED_CODE_SECTION_RVA (CEED_SECTION_ALIGN * 3) +#define CEED_RDATA_SECTION_RVA (CEED_SECTION_ALIGN * 4) +#else +#define CEED_IMPORT_SECTION_RVA (CEED_SECTION_ALIGN * 3) +#define CEED_DATA_SECTION_RVA (CEED_SECTION_ALIGN * 2) +#define CEED_CODE_SECTION_RVA (CEED_SECTION_ALIGN * 1) +#define CEED_RDATA_SECTION_RVA (CEED_SECTION_ALIGN * 4) +#endif + +// +// We use bottom 2K of DATA section for any system state outside of user's +// code. For example, to support read/write from console, we store handle to +// stdin and stdout during initialization instead of only each read/write call. +// +#define CEED_STDIN_HANDLE_RVA 0x800 +#define CEED_STDOUT_HANDLE_RVA 0x808 + +// +// Reserve some temp space needs to invoke certain windows API. +// +#define CEED_TEMP_U64_1 0xf00 + +// +// Stores offset of k32 functions & array. This array would contain address of +// functions imported from kernel32 after the exe and dlls are loaded by +// windows loader. +// +static u64 k32_fn_array; +static u64 fn_GetStdHandle; +static u64 fn_ReadConsoleA; +static u64 fn_WriteConsoleA; + +typedef struct _section_info +{ + IMAGE_SECTION_HEADER scn_hdr; + pu8 scn_data; + u32 scn_size; + u32 scn_file_size; + u32 scn_file_offset; + u32 scn_virtual_size; +} section_info, * psection_info; + +typedef struct _exe_info +{ + psection_info import_scn; + psection_info data_scn; + psection_info code_scn; + psection_info rdata_scn; + + IMAGE_FILE_HEADER fh; + IMAGE_OPTIONAL_HEADER64 oh; + u32 scn_count; + psection_info scn_list[8]; +} exe_info, * pexe_info; + + +static psection_info +pe64_new_section(pexe_info ei, const char* name, u32 scn_va, u32 attr) +{ + psection_info si = malloc(sizeof(section_info)); + memset(si, 0, sizeof(section_info)); + strcpy(si->scn_hdr.Name, name); + si->scn_hdr.Characteristics = attr; + si->scn_hdr.VirtualAddress = scn_va; + ei->scn_list[ei->scn_count++] = si; + return si; +} + +static pvoid +pe64_alloc_exe_info() +{ + pexe_info ei = malloc(sizeof(exe_info)); + memset(ei, 0, sizeof(exe_info)); +#ifdef CEED_OLD + ei->import_scn = pe64_new_section(ei, ".idata", CEED_IMPORT_SECTION_RVA, + IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE); + + ei->data_scn = pe64_new_section(ei, ".data", CEED_DATA_SECTION_RVA, + IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE); + + ei->code_scn = pe64_new_section(ei, ".text", CEED_CODE_SECTION_RVA, + IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ); + + ei->rdata_scn = pe64_new_section(ei, ".rdata", CEED_RDATA_SECTION_RVA, + IMAGE_SCN_MEM_READ); +#else + ei->code_scn = pe64_new_section(ei, ".text", CEED_CODE_SECTION_RVA, + IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ); + + ei->data_scn = pe64_new_section(ei, ".data", CEED_DATA_SECTION_RVA, + IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE); + + ei->import_scn = pe64_new_section(ei, ".idata", CEED_IMPORT_SECTION_RVA, + IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE); + + ei->rdata_scn = pe64_new_section(ei, ".rdata", CEED_RDATA_SECTION_RVA, + IMAGE_SCN_MEM_READ); +#endif + return ei; +} + +static pvoid +pe64_set_scn(psection_info si, pu8 scn_data, u32 scn_size) +{ + if (si) { + si->scn_data = scn_data; + si->scn_size = scn_size; + si->scn_virtual_size = scn_size; + si->scn_file_size = round_up(scn_size, CEED_FILE_ALIGN); + + si->scn_hdr.Misc.VirtualSize = si->scn_virtual_size; + si->scn_hdr.SizeOfRawData = si->scn_file_size; + } + return NULL; +} + +static pvoid +pe64_set_exe_code_scn(pvoid einfo, pu8 scn_data, u32 scn_size) +{ + pexe_info ei = einfo; + return pe64_set_scn(ei->code_scn, scn_data, scn_size); +} + +static pvoid +pe64_set_exe_data_scn(pvoid einfo, pu8 scn_data, u32 scn_size) +{ + pexe_info ei = einfo; + return pe64_set_scn(ei->data_scn, scn_data, scn_size); +} + +static pvoid +pe64_set_exe_rdata_scn(pvoid einfo, pu8 scn_data, u32 scn_size) +{ + pexe_info ei = einfo; + return pe64_set_scn(ei->rdata_scn, scn_data, scn_size); +} + +static pvoid +pe64_set_exe_import_scn(pvoid einfo, pu8 scn_data, u32 scn_size) +{ + pexe_info ei = einfo; + return pe64_set_scn(ei->import_scn, scn_data, scn_size); +} + +static u64 +pe64_get_code_va(pvoid einfo) +{ + return CEED_IMAGE_BASE_VA + CEED_CODE_SECTION_RVA; +} + +static u64 +pe64_get_data_va(pvoid einfo) +{ + return CEED_IMAGE_BASE_VA + CEED_DATA_SECTION_RVA; +} + +static u64 +pe64_get_rdata_va(pvoid einfo) +{ + return CEED_IMAGE_BASE_VA + CEED_RDATA_SECTION_RVA; +} + +static void +pe64_write_fixed_hdrs(pexe_info ei, FILE* file) +{ + u32 nt_sig = IMAGE_NT_SIGNATURE; + IMAGE_FILE_HEADER fh = { 0 }; + + fh.Machine = IMAGE_FILE_MACHINE_X64; + fh.NumberOfSections = ei->scn_count; + fh.TimeDateStamp = 0; + fh.PointerToSymbolTable = 0; + fh.NumberOfSymbols = 0; + fh.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER64); + fh.Characteristics = (IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_LARGE_ADDRESS_AWARE | IMAGE_FILE_RELOCS_STRIPPED); + + fwrite(dos_hdr, sizeof(dos_hdr), 1, file); + fwrite(&nt_sig, sizeof(nt_sig), 1, file); + fwrite(&fh, sizeof(fh), 1, file); +} + + +static void +pe64_write_optional_hdr(pexe_info ei, FILE* file) +{ + IMAGE_OPTIONAL_HEADER64 oh = { 0 }; + u32 hdr_size; + + oh.Magic = IMAGE_NT_OPTIONAL_HDR64_MAGIC; + oh.MajorLinkerVersion = 0; + oh.MinorLinkerVersion = 1; + oh.SizeOfCode = 8; + oh.SizeOfInitializedData = 0; + oh.SizeOfUninitializedData = 0; + oh.AddressOfEntryPoint = 0; // Fixed later. + oh.BaseOfCode = 0; // Fixed later. + oh.ImageBase = CEED_IMAGE_BASE_VA; + oh.SectionAlignment = CEED_SECTION_ALIGN; + oh.FileAlignment = CEED_FILE_ALIGN; + oh.MajorOperatingSystemVersion = 4; + oh.MinorOperatingSystemVersion = 0; + oh.MajorImageVersion = 0; + oh.MinorImageVersion = 0; + oh.MajorSubsystemVersion = 4; + oh.MinorSubsystemVersion = 0; + oh.Win32VersionValue = 0; + oh.SizeOfImage = 0; // Fixed later. + oh.SizeOfHeaders = 0; // Fixed later. + oh.CheckSum = 0; + oh.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI; + oh.DllCharacteristics = 0; + oh.SizeOfStackReserve = 0x100000; + oh.SizeOfStackCommit = 0x1000; + oh.SizeOfHeapReserve = 0x100000; + oh.SizeOfHeapCommit = 0x1000; + oh.LoaderFlags = 0; + oh.NumberOfRvaAndSizes = 16; + // Leave all DataDirectory as 0. + + if (ei->import_scn) { + oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = CEED_IMPORT_SECTION_RVA; + oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = ei->import_scn->scn_file_size; + oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = CEED_IMPORT_SECTION_RVA; + oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = ei->import_scn->scn_file_size; + } + + oh.AddressOfEntryPoint = CEED_CODE_SECTION_RVA + func[0]; + oh.BaseOfCode = CEED_CODE_SECTION_RVA; + + // + // This needs to be calculated to be the actual size in memory of the + // image. So all section's virtual size. + // + hdr_size = sizeof(dos_hdr) + sizeof(u32) + sizeof(IMAGE_FILE_HEADER) + + sizeof(IMAGE_OPTIONAL_HEADER64) + + (sizeof(IMAGE_SECTION_HEADER) * ei->scn_count); + oh.SizeOfImage = round_up(hdr_size, CEED_SECTION_ALIGN); + for (int i = 0; i < ei->scn_count; i++) + { + oh.SizeOfImage += round_up(ei->scn_list[i]->scn_virtual_size, + CEED_SECTION_ALIGN); + } + oh.SizeOfHeaders = hdr_size; + + fwrite(&oh, sizeof(oh), 1, file); +} + +static void +pe64_write_section_hdr(psection_info si, FILE* file) +{ + fwrite(&si->scn_hdr, sizeof(si->scn_hdr), 1, file); +} + +static void +pe64_write_section_data(psection_info si, u32 file_offset, FILE* file) +{ + fseek(file, file_offset, SEEK_SET); + fwrite(si->scn_data, si->scn_file_size, 1, file); +} + +static u8 data_buffer[4096]; +#define CEED_MAX_VARIABLES 26 +static void +pe64_gen_data_section(pexe_info ei) +{ + // + // Only 26 global variables of 4-byte int size are supported. + // + pe64_set_exe_data_scn(ei, data_buffer, (CEED_MAX_VARIABLES * 4)); +} + + +#define MAX_FUNCTIONS_IMPORT_PER_DLL 8 +#define c_assert(e) typedef char __c_assert__[(e)?1:-1] + +static u8 import_buffer[4096]; +static void +pe64_gen_import_section(pexe_info ei) +{ + pu8 import = import_buffer; + IMAGE_IMPORT_DESCRIPTOR* iid; + IMAGE_THUNK_DATA64* th; + IMAGE_THUNK_DATA64* oth; + IMAGE_IMPORT_BY_NAME* iin; + const char* dll_names[] = { + "kernel32.dll", + "ntdll.dll" + }; + const char* fn_names[][10] = { + { "WriteConsoleA", "ReadConsoleA", "GetStdHandle", 0 }, + { "NtReadFile", 0 }, + }; + + int dll_count = sizeof(dll_names) / sizeof(dll_names[0]); + + c_assert((sizeof(dll_names) / sizeof(dll_names[0])) == + (sizeof(fn_names) / sizeof(fn_names[0]))); + + // + // Add +1 in dll_count to add a NULL entry as dll import array is NULL + // terminated. + // + u32 offset = (dll_count + 1) * sizeof(IMAGE_IMPORT_DESCRIPTOR); + + iid = (IMAGE_IMPORT_DESCRIPTOR*)import; + + for (int i = 0; i < dll_count; i++) { + u32 thunk_count = 0; + pu8 name = import + offset; + u32 th_size; + + iid[i].Name = offset + CEED_IMPORT_SECTION_RVA; + strcpy(name, dll_names[i]); + offset += strlen(name) + 1; + + for (int j = 0; j < MAX_FUNCTIONS_IMPORT_PER_DLL; j++) { + if (fn_names[i][j] == NULL) { + break; + } + thunk_count++; + } + + // + // Add +1 in thunk_count to add a NULL entry as thunk array is NULL + // terminated. + // + th_size = (thunk_count + 1) * sizeof(IMAGE_THUNK_DATA64); + iid[i].OriginalFirstThunk = offset + CEED_IMPORT_SECTION_RVA; + iid[i].FirstThunk = offset + th_size + CEED_IMPORT_SECTION_RVA; + if (strcmp(dll_names[i], "kernel32.dll") == 0) { + k32_fn_array = iid[i].FirstThunk + CEED_IMAGE_BASE_VA; + } + oth = (IMAGE_THUNK_DATA64*)(import + offset); + th = (IMAGE_THUNK_DATA64*)(import + offset + th_size); + offset += (2 * th_size); + + for (int j = 0; j < MAX_FUNCTIONS_IMPORT_PER_DLL; j++) { + if (fn_names[i][j] == NULL) { + break; + } + + if (strcmp(fn_names[i][j], "GetStdHandle") == 0) { + fn_GetStdHandle = k32_fn_array + (sizeof(u64) * j); + } + else if (strcmp(fn_names[i][j], "ReadConsoleA") == 0) { + fn_ReadConsoleA = k32_fn_array + (sizeof(u64) * j); + } + else if (strcmp(fn_names[i][j], "WriteConsoleA") == 0) { + fn_WriteConsoleA = k32_fn_array + (sizeof(u64) * j); + } + + oth[j].AddressOfData = offset + CEED_IMPORT_SECTION_RVA; + th[j].AddressOfData = oth[j].AddressOfData; + + iin = (pvoid)(import + offset); + strcpy((char*)iin->Name, fn_names[i][j]); + u32 off = offsetof(IMAGE_IMPORT_BY_NAME, Name); + offset += (off + strlen(iin->Name) + 1); + } + } + pe64_set_exe_import_scn(ei, import, offset); +} + +static void +pe64_gen_exe_file(pvoid einfo) +{ + pexe_info ei = einfo; + FILE* exe_file; + u32 hdr_size; + u32 file_offset; + + if (func[0] == -1) + { + printf("Entry point function '_a' not found.\n"); + exit(-1); + } + + exe_file = fopen("a.exe", "wb+"); + if (exe_file == NULL) + { + printf("Failed to create output file (a.exe).\n"); + exit(errno); + } + + pe64_gen_data_section(ei); + pe64_write_fixed_hdrs(ei, exe_file); + pe64_write_optional_hdr(ei, exe_file); + hdr_size = sizeof(dos_hdr) + sizeof(u32) + sizeof(IMAGE_FILE_HEADER) + + sizeof(IMAGE_OPTIONAL_HEADER64) + + (sizeof(IMAGE_SECTION_HEADER) * ei->scn_count); + file_offset = round_up(hdr_size, CEED_FILE_ALIGN); + for (int i = 0; i < ei->scn_count; i++) + { + psection_info si = ei->scn_list[i]; + si->scn_hdr.PointerToRawData = file_offset; + pe64_write_section_hdr(si, exe_file); + file_offset += si->scn_file_size; + } + file_offset = round_up(hdr_size, CEED_FILE_ALIGN); + for (int i = 0; i < ei->scn_count; i++) + { + psection_info si = ei->scn_list[i]; + pe64_write_section_data(si, file_offset, exe_file); + file_offset += si->scn_file_size; + } + + fclose(exe_file); +} + +static void +pe64_emit_indirect_call(u64 fn_addr) +{ + // call qword ptr[fn_addr] # 0xff 0x15 u32_offset + fn_addr = fn_addr - CEED_IMAGE_BASE_VA - CEED_CODE_SECTION_RVA - code_pos - 6; //get_code_va() + emit8(0xff); + emit8(0x15); + emit32(fn_addr); +} + + +static void +pe64_emit_get_std_handle(u32 handle_type, u64 save_location) +{ + //mov ecx, handle_type + emit8(0xB9); + emit32(handle_type); + + pe64_emit_indirect_call(fn_GetStdHandle); + + // mov [data_section_va + save_location], rax + // mov [rip + save_location], rax 48 89 05 00 00 00 00 mov QWORD PTR [rip+0x0],rax + u32 off = (u64)get_data_va(ei) - (u64)get_code_va(ei) - code_pos - 7 + save_location; + + emit3(0x48, 0x89, 0x05); + emit32((u32)off); +} + +#define STD_INPUT_HANDLE (-10) +#define STD_OUTPUT_HANDLE (-11) + +static void +pe64_emit_main_init() +{ + // + // We use this to invoke some code from main that stores handles to stdin + // and stdout in global variable. + // + pe64_emit_get_std_handle(STD_INPUT_HANDLE, CEED_STDIN_HANDLE_RVA); + pe64_emit_get_std_handle(STD_OUTPUT_HANDLE, CEED_STDOUT_HANDLE_RVA); + +} + +static void +pe64_emit_main_exit() +{ + // ret + emit8(0xc3); +} + +// +// Uses WriteConsole win32 API. +// +static void pe64_emit_write(u64 buf_addr, u32 buf_len) { + // mov qword ptr [rsp+20 h], 0 (pInputControl -> NULL) + emit4(0x48, 0xc7, 0x44, 0x24); + emit8(0x20); // sizeof(arg1 + arg2 + arg3 + arg4) + emit32(0x0); + // xor r9d, r9d (lpNumberOfCharsWritten) + emit3(0x45, 0x33, 0xc9); + + // mov r8d, buf_len // buf_len (nNumberOfCharsToRead) + emit2(0x41, 0xb8); + emit32(buf_len); + + // mov rdx, qword ptr[140003000 h] //48 8B 15 D5 1F 00 00 fetch *((char**)0x140003000) + // mov rdx, offset aHelloWorld //48 BA 00 30 00 40 01 00 00 00 buf_addr (lpBuffer) + // mov rdx, buf_addr + emit2(0x48, 0xba); + emit64(buf_addr); + + // rcx = stdout handle + // lea rcx,[140002018 h] //48 8D 0D 05 10 00 00 rcx = 0x140002018 + // mov rcx,[140002018 h] //48 8B 0D 05 10 00 00 rcx = [0x140002018] + u32 off = (u64)get_data_va(ei) - (u64)get_code_va(ei) - code_pos - 7 + CEED_STDOUT_HANDLE_RVA; + emit3(0x48, 0x8b, 0x0d); + emit32(off); + + // call [fn_addr] + pe64_emit_indirect_call(fn_WriteConsoleA); +} + +// +// Uses WriteConsole win32 API. +// rcx = buf, rdx = buf_len +// +static void +pe64_emit_write_reg_input() +{ + // mov qword ptr [rsp+20 h], 0 (pInputControl -> NULL) + emit4(0x48, 0xc7, 0x44, 0x24); + emit8(0x20); // sizeof(arg1 + arg2 + arg3 + arg4) + emit32(0x0); + + // xor r9d, r9d (lpNumberOfCharsWritten) + emit3(0x45, 0x33, 0xc9); + + // mov r8d, rdx // buf_len (nNumberOfCharsToRead) + emit3(0x49, 0x89, 0xd0); + + //48 89 ca mov rdx, rcx + emit3(0x48, 0x89, 0xca); + + // rcx = stdout handle + // lea rcx,[140002018 h] //48 8D 0D 05 10 00 00 rcx = 0x140002018 + u32 off = (u64)get_data_va(ei) - (u64)get_code_va(ei) - code_pos - 7 + CEED_STDOUT_HANDLE_RVA; + emit3(0x48, 0x8b, 0x0d); + emit32(off); + + // call [fn_addr] + pe64_emit_indirect_call(fn_WriteConsoleA); +} + +// +// Uses ReadConsole win32 API. +// +static void pe64_emit_read(u64 buf_addr, u32 buf_len){ + // mov qword ptr [rsp+20 h], 0 (pInputControl -> NULL) + emit4(0x48, 0xc7, 0x44, 0x24); + emit8(0x20); // sizeof(arg1 + arg2 + arg3 + arg4) + emit32(0x0); + // xor r9d, r9d (lpNumberOfCharsRead) + //emit3(0x45, 0x33, 0xc9); + u32 off = (u64)get_data_va(ei) - (u64)get_code_va(ei) - code_pos - 7 + CEED_TEMP_U64_1; + emit3(0x4C, 0x8D, 0x0D); // 4C 8D 0D C7 30 00 00 lea r9,[dwRead (01400041B0h)] + emit32(off); + + // mov r8d, buf_len // buf_len (nNumberOfCharsToRead) + emit2(0x41, 0xb8); + emit32(buf_len); + + // mov rdx, qword ptr[140003000 h] //48 8B 15 D5 1F 00 00 fetch *((char**)0x140003000) + // mov rdx, offset aHelloWorld //48 BA 00 30 00 40 01 00 00 00 buf_addr (lpBuffer) + // lea rdx, [140003000 h] //48 8D 14 25 00 10 00 00 rdx = 0x140003000 + // emit4(0x48, 0xba, 0x14, 0x25); + // emit64(buf_addr + CEED_IMAGE_BASE_VA); + // mov rdx, buf_addr + emit2(0x48, 0xba); + emit64(buf_addr); + + // rcx = stdin handle + // lea rcx,[140002018 h] //48 8D 0D 05 10 00 00 rcx = 0x140002018 + // mov rcx,[140002018 h] //48 8B 0D 05 10 00 00 rcx = [0x140002018] + off = (u64)get_data_va(ei) - (u64)get_code_va(ei) - code_pos - 7 + CEED_STDIN_HANDLE_RVA; + emit3(0x48, 0x8b, 0x0d); + emit32(off); + + // call [fn_addr] + pe64_emit_indirect_call(fn_ReadConsoleA); +} + + +void +pe64_init() +{ + ei = pe64_alloc_exe_info(); + // + // We generate import section ahead of time, as the offsets in IAT (import + // address table) are needed in code generation for console I/O. + // + pe64_gen_import_section(ei); + gen_exe_file = pe64_gen_exe_file; + set_exe_code_scn = pe64_set_exe_code_scn; + set_exe_rdata_scn = pe64_set_exe_rdata_scn; + get_code_va = pe64_get_code_va; + get_data_va = pe64_get_data_va; + get_rdata_va = pe64_get_rdata_va; + emit_main_exit = pe64_emit_main_exit; + emit_main_init = pe64_emit_main_init; + emit_write = pe64_emit_write; + emit_write_reg_input = pe64_emit_write_reg_input; + emit_read = pe64_emit_read; +} + diff --git a/src/ceedrtl.c b/src/ceedrtl.c index 35f9437..8feef82 100644 --- a/src/ceedrtl.c +++ b/src/ceedrtl.c @@ -9,13 +9,18 @@ license. See the LICENSE file for details. --*/ #include "ceed.h" -u8 itoa_code[0x80] = - { - 0x55, 0x89, 0xE5, 0x83, 0xEC, 0x04, 0x83, 0xC3, 0x0B, 0xC6, 0x03, 0x00, 0xB9, 0x0A, 0x00, 0x00, 0x00, 0xC7, 0x45, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x31, 0xFF, 0x83, 0xF8, 0x00, 0x7D, 0x07, 0xF7, 0xD8, 0xBF, 0x01, 0x00, 0x00, 0x00, 0x31, 0xD2, 0xF7, 0xF9, 0x83, 0xC2, 0x30, 0x4B, 0x88, 0x13, 0xFF, 0x45, 0xFC, 0x83, 0xF8, 0x00, 0x75, 0xEE, 0x83, 0xFF, 0x01, 0x75, 0x07, 0x4B, 0xC6, 0x03, 0x2D, 0xFF, 0x45, 0xFC, 0x89, 0xD9, 0x8B, 0x55, 0xFC, 0x89, 0xEC, 0x5D, 0xC3 - }; +u8 itoa_code[0x80] = { + 0x55, 0x89, 0xE5, 0x83, 0xEC, 0x04, 0x83, 0xC3, 0x0B, 0xC6, 0x03, 0x00, 0xB9, 0x0A, 0x00, 0x00, 0x00, 0xC7, 0x45, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x31, 0xFF, 0x83, 0xF8, 0x00, 0x7D, 0x07, 0xF7, 0xD8, 0xBF, 0x01, 0x00, 0x00, 0x00, 0x31, 0xD2, 0xF7, 0xF9, 0x83, 0xC2, 0x30, 0x4B, 0x88, 0x13, 0xFF, 0x45, 0xFC, 0x83, 0xF8, 0x00, 0x75, 0xEE, 0x83, 0xFF, 0x01, 0x75, 0x07, 0x4B, 0xC6, 0x03, 0x2D, 0xFF, 0x45, 0xFC, 0x89, 0xD9, 0x8B, 0x55, 0xFC, 0x89, 0xEC, 0x5D, 0xC3 +}; -u8 atoi_code[0x80] = - { - 0x55, 0x89, 0xE5, 0x83, 0xEC, 0x04, 0x31, 0xFF, 0xB9, 0x0A, 0x00, 0x00, 0x00, 0x31, 0xC0, 0x31, 0xD2, 0xC7, 0x45, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x31, 0xF6, 0x8A, 0x14, 0x3B, 0x80, 0xFA, 0x2D, 0x75, 0x06, 0xBE, 0x01, 0x00, 0x00, 0x00, 0x47, 0x8B, 0x45, 0xFC, 0xF7, 0xE1, 0x70, 0x36, 0x8A, 0x14, 0x3B, 0x80, 0xFA, 0x30, 0x7C, 0x2E, 0x80, 0xFA, 0x39, 0x7F, 0x29, 0x80, 0xEA, 0x30, 0x01, 0xD0, 0x89, 0x45, 0xFC, 0x47, 0x80, 0x3C, 0x3B, 0x00, 0x74, 0x0E, 0x80, 0x3C, 0x3B, 0x0A, 0x74, 0x08, 0x80, 0x3C, 0x3B, 0x0D, 0x74, 0x02, 0xEB, 0xCF, 0x8B, 0x45, 0xFC, 0x83, 0xFE, 0x01, 0x75, 0x06, 0xF7, 0xD8, 0xEB, 0x02, 0x31, 0xC0, 0x89, 0xEC, 0x5D, 0xC3 - }; +u8 atoi_code[0x80] = { + 0x55, 0x89, 0xE5, 0x83, 0xEC, 0x04, 0x31, 0xFF, 0xB9, 0x0A, 0x00, 0x00, 0x00, 0x31, 0xC0, 0x31, 0xD2, 0xC7, 0x45, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x31, 0xF6, 0x8A, 0x14, 0x3B, 0x80, 0xFA, 0x2D, 0x75, 0x06, 0xBE, 0x01, 0x00, 0x00, 0x00, 0x47, 0x8B, 0x45, 0xFC, 0xF7, 0xE1, 0x70, 0x36, 0x8A, 0x14, 0x3B, 0x80, 0xFA, 0x30, 0x7C, 0x2E, 0x80, 0xFA, 0x39, 0x7F, 0x29, 0x80, 0xEA, 0x30, 0x01, 0xD0, 0x89, 0x45, 0xFC, 0x47, 0x80, 0x3C, 0x3B, 0x00, 0x74, 0x0E, 0x80, 0x3C, 0x3B, 0x0A, 0x74, 0x08, 0x80, 0x3C, 0x3B, 0x0D, 0x74, 0x02, 0xEB, 0xCF, 0x8B, 0x45, 0xFC, 0x83, 0xFE, 0x01, 0x75, 0x06, 0xF7, 0xD8, 0xEB, 0x02, 0x31, 0xC0, 0x89, 0xEC, 0x5D, 0xC3 +}; +u8 itoa_code64[0x80] = { + 0x55, 0x48, 0x89, 0xe5, 0x48, 0x83, 0xec, 0x08, 0x48, 0x83, 0xc3, 0x0b, 0xc6, 0x03, 0x00, 0xb9, 0x0a, 0x00, 0x00, 0x00, 0xc7, 0x45, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x48, 0x31, 0xff, 0x48, 0x83, 0xf8, 0x00, 0x7d, 0x08, 0x48, 0xf7, 0xd8, 0xbf, 0x01, 0x00, 0x00, 0x00, 0x48, 0x31, 0xd2, 0x48, 0xf7, 0xf9, 0x48, 0x83, 0xc2, 0x30, 0x48, 0xff, 0xcb, 0x88, 0x13, 0xff, 0x45, 0xf8, 0x48, 0x83, 0xf8, 0x00, 0x75, 0xe8, 0x48, 0x83, 0xff, 0x01, 0x75, 0x09, 0x48, 0xff, 0xcb, 0xc6, 0x03, 0x2d, 0xff, 0x45, 0xf8, 0x48, 0x89, 0xd9, 0x48, 0x8b, 0x55, 0xf8, 0x48, 0x89, 0xec, 0x5d, 0xc3 +}; + +u8 atoi_code64[0x80] = { + 0x55, 0x48, 0x89, 0xe5, 0x48, 0x83, 0xec, 0x08, 0x48, 0x31, 0xff, 0xb9, 0x0a, 0x00, 0x00, 0x00, 0x48, 0x31, 0xc0, 0x48, 0x31, 0xd2, 0xc7, 0x45, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x48, 0x31, 0xf6, 0x8a, 0x14, 0x3b, 0x80, 0xfa, 0x2d, 0x75, 0x08, 0xbe, 0x01, 0x00, 0x00, 0x00, 0x48, 0xff, 0xc7, 0x48, 0x8b, 0x45, 0xf8, 0x48, 0xf7, 0xe1, 0x70, 0x3d, 0x8a, 0x14, 0x3b, 0x80, 0xfa, 0x30, 0x7c, 0x35, 0x80, 0xfa, 0x39, 0x7f, 0x30, 0x80, 0xea, 0x30, 0x48, 0x01, 0xd0, 0x48, 0x89, 0x45, 0xf8, 0x48, 0xff, 0xc7, 0x80, 0x3c, 0x3b, 0x00, 0x74, 0x0e, 0x80, 0x3c, 0x3b, 0x0a, 0x74, 0x08, 0x80, 0x3c, 0x3b, 0x0d, 0x74, 0x02, 0xeb, 0xc9, 0x48, 0x8b, 0x45, 0xf8, 0x48, 0x83, 0xfe, 0x01, 0x75, 0x08, 0x48, 0xf7, 0xd8, 0xeb, 0x03, 0x48, 0x31, 0xc0, 0x48, 0x89, 0xec, 0x5d, 0xc3 +}; diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..83efb21 --- /dev/null +++ b/src/main.c @@ -0,0 +1,55 @@ +#include +#include +#include +#include + +#include "ceed.h" + +extern FILE* yyin; +int yyparse(void); + +void usage() { + printf( "Usage: ceed