From 6fc4a74020a9b8ca46f663d057cfeabd93f0c7e7 Mon Sep 17 00:00:00 2001 From: Stefano Moioli Date: Sat, 6 Apr 2024 04:49:33 +0200 Subject: [PATCH] add additional secret data functions and sample utilization code --- xzre.S | 41 +++++++++++++++++++++++++++++++++++++++++ xzre.c | 33 +++++++++++++++++++++++++++++++++ xzre.h | 17 +++++++++++++++-- xzre.lds | 15 ++++++++++++++- 4 files changed, 103 insertions(+), 3 deletions(-) diff --git a/xzre.S b/xzre.S index 292c044..75e6277 100644 --- a/xzre.S +++ b/xzre.S @@ -8,6 +8,47 @@ .globl dasm_sample .globl dasm_sample_end .globl dasm_sample_dummy_location +.globl secret_data_append_trampoline + +/** + * This function sets up a dummy code block + * that will pass the backdoor validation rules, so that + * data shifting is always permitted + */ +secret_data_append_trampoline: + endbr64 + push rbp + mov rbp, rsp + + // shift register (edx) from caller (arg1) + mov edx, edi + // num of instructions (ecx) from caller (arg2) + mov ecx, esi + + // code start (dummy code block) + lea rdi, [rip + 3f] + // code end (dummy code block) + lea rsi, [rip + 4f] + // don't look for a CALL instruction + xor r8d, r8d + call secret_data_append_from_function + // skip the dummy code block + jmp 4f + /** + * dummy code block to make the validator happy + * the number of instructions dictates the maximum number of bitshifts + */ +3: + // list of allowed instructions: ADD, SUB, OR, AND, CMP + // NOTE: MOV instructions are counted, but don't cause any shift + // list of allowed registers: AX, EAX, RAX, BX, EBX, RBX, CX, ECX, RCX, ECX, RCX + add cx, cx; sub cx, cx; or cx, cx; and cx, cx; cmp cx, cx + add cx, cx; sub cx, cx; or cx, cx; and cx, cx; cmp cx, cx + add cx, cx; sub cx, cx; or cx, cx; and cx, cx; cmp cx, cx + add cx, cx; sub cx, cx; or cx, cx; and cx, cx; cmp cx, cx +4: + pop rbp + ret dasm_sample: endbr64 diff --git a/xzre.c b/xzre.c index ca22bdd..e1d3864 100644 --- a/xzre.c +++ b/xzre.c @@ -9,6 +9,36 @@ extern void dasm_sample(void); extern void dasm_sample_end(); extern void dasm_sample_dummy_location(); +extern BOOL secret_data_append_trampoline(secret_data_shift_cursor shift_cursor, unsigned shift_count); + +extern char __executable_start; +extern char __etext; + +static global_context_t my_global_ctx = { 0 }; + +void xzre_secret_data_init(){ + global_ctx = &my_global_ctx; + memset(global_ctx, 0x00, sizeof(*global_ctx)); + global_ctx->code_range_start = (u64)&__executable_start; + global_ctx->code_range_end = (u64)&__etext; +} + +void xzre_secret_data_test(){ + // disable x86_dasm shift slot + my_global_ctx.shift_operations[2] = 1; + + secret_data_shift_cursor cursor = { + .byte_index = 16, + .bit_index = 0 + }; + + if(secret_data_append_trampoline(cursor, 1)){ + puts("secret data push OK!"); + hexdump(my_global_ctx.secret_data, sizeof(my_global_ctx.secret_data)); + } else { + puts("secret data push FAIL!"); + } +} int main(int argc, char *argv[]){ puts("xzre 0.1 by Smx :)"); @@ -47,5 +77,8 @@ int main(int argc, char *argv[]){ fake_allocator->free, fake_allocator->opaque ); + + xzre_secret_data_init(); + xzre_secret_data_test(); return 0; } \ No newline at end of file diff --git a/xzre.h b/xzre.h index 6d16988..d71f4b3 100644 --- a/xzre.h +++ b/xzre.h @@ -828,6 +828,14 @@ extern char *elf_find_string( */ extern lzma_allocator *get_lzma_allocator(); +extern BOOL secret_data_append_from_instruction(dasm_ctx_t *dctx, secret_data_shift_cursor *cursor); + +extern BOOL secret_data_append_from_function( + void *function_start, + void *code_end, + secret_data_shift_cursor shift_cursor, + unsigned shift_count, unsigned operation_index); + /** * @brief Calls @ref secret_data_append_singleton, if @p flags are non-zero * @@ -856,7 +864,9 @@ extern BOOL secret_data_append_if_flags( * and making sure that the code lies between a pre-defined code range (set in @ref backdoor_setup from @ref elf_get_code_segment) * - search for @p shift_count number of "reg2reg" instructions (explained below) * - for each instruction, shift a '1' in the data register, and increment the shift cursor to the next bit index - * if, at any given point, a non reg2reg instruction is encountered, the whole loop will stop and FALSE will be returned. + * if, at any given point, a non reg2reg instruction is encountered, the whole loop will stop. + * the function will return TRUE if the number of shifts executed == number of wanted shifts + * NOTE: MOV instructions are counted, but don't cause any shift (they are skipped). * * a reg2reg instruction is an x64 instruction with one of the following characteristics: * - primary opcode of 0x89 (MOV) or 0x3B (CMP) @@ -881,7 +891,8 @@ extern BOOL secret_data_append_if_flags( * @param shift_count number of shift instructions to perform, * represented by the number of"reg2reg" instructions expected in the function pointed to by @p code * @param operation_index index/id of shit shift operation - * @return BOOL TRUE if validation was successful and data was added, FALSE otherwise + * @return BOOL TRUE if the number of requested shifts were all executed. + * FALSE if some shift wasn't executed due to code validation failure. */ extern BOOL secret_data_append_singleton( u8 *call_site, u8 *code, @@ -927,5 +938,7 @@ extern BOOL resolve_libc_imports( libc_imports_t *imports ); +extern global_context_t *global_ctx; + #include "util.h" #endif \ No newline at end of file diff --git a/xzre.lds b/xzre.lds index de0892c..1ec1343 100644 --- a/xzre.lds +++ b/xzre.lds @@ -1,5 +1,5 @@ SECTIONS { - .lzma : { + .lzma_text : { "x86_dasm" = .; *(.text.x86_codd); @@ -57,6 +57,12 @@ SECTIONS { "elf_find_string" = "."; *(.text.lzip_decoda); + "secret_data_append_from_instruction" = "."; + *(.text.lzma_lzma_encoder_inia); + + "secret_data_append_from_function" = "."; + *(.text.lzma_memlimit_gea); + "secret_data_append_if_flags" = "."; *(.text.lzma_check_inia); @@ -73,3 +79,10 @@ SECTIONS { *(.text.lzma_index_buffer_encoda); } } INSERT AFTER .text; + +SECTIONS { + .lzma_bss : { + "global_ctx" = "."; + *(.bss.lzma12_codez); + } +} INSERT AFTER .bss;