diff --git a/assets/xor.s b/assets/xor.s new file mode 100644 index 0000000..daea697 --- /dev/null +++ b/assets/xor.s @@ -0,0 +1,76 @@ +bits 64 +global _start + +_start: + push rbp + push rsp + push rbx + push r13 + push rax + push rcx + push rdx + push rsi + push rdi + push r8 + push r9 + + mov rdi, 1 + lea rsi, [rel msg] + mov rbx, rsi + ;mov rbx, qword [rel text_section] + sub rbx, qword [rel text_section] ;text_section address because of this and that + mov r8, qword [rel section_size] ;text_section size + mov r9, 0 ;increment register + xor r13, r13 + mov r13, qword [rel private_key] + + decrypt_whole_blocks: + ; check left to decrypt < block_size + mov rcx, r8 + sub rcx, r9 + cmp rcx, 8 + jle decrypt_last_block + ; xor section with private_key + mov rdx, rbx + add rdx, r9 + xor [rdx], r13 + ; increase section address + ; increase counter + add r9, 8 + jmp decrypt_whole_blocks + + decrypt_last_block: + mov rdx, 8 + sub rdx, rcx + mov rcx, rdx + mov rax, 8 + mul cl + mov rcx, rax + shl r13, cl + shr r13, cl + mov rdx, rbx + add rdx, r9 + xor [rdx], r13 + + end_decrypt: + mov rdx, 14 + mov rax, 1 + syscall + + pop r9 + pop r8 + pop rdi + pop rsi + pop rdx + pop rcx + pop rax + pop r13 + pop rbx + pop rsp + pop rbp + + jmp 0xdadadada ; this needs to be just before that + msg db "....WOODY....",10 ; that needs to be just after this + text_section dq 0xbabababababababa + section_size dq 0xcacacacacacacaca + private_key dq 0xabcdefabcdefabcd diff --git a/inc/woody.h b/inc/woody.h index cdc5919..4ac7983 100644 --- a/inc/woody.h +++ b/inc/woody.h @@ -10,11 +10,26 @@ # define RET_ERR 1 # define RET_OK 0 +# define PL_XOR 0 +# define PL_RSA 1 +# define PL_DEBUG 2 + typedef struct s_map { void *data; off_t size; } t_map; +typedef struct s_payload64 { + int (*encrypt)(t_map, Elf64_Phdr); + size_t jump_offset; + size_t woody_offset; + size_t load_ptr_offset; + size_t load_size_offset; + size_t private_key_offset; + size_t len; + unsigned char *data; +} t_payload64; + int woody_woodpacker(char *path); diff --git a/src/woody_woodpacker.c b/src/woody_woodpacker.c index 7de7058..d9f7dda 100644 --- a/src/woody_woodpacker.c +++ b/src/woody_woodpacker.c @@ -86,11 +86,75 @@ t_map get_code_cave(t_map file, Elf64_Phdr load_segment) { code_cave.data = fetch(file, longest_i + offset, longest); code_cave.size = longest; if (!code_cave.data) { - printf("unreachable !!!\n"); + ft_printf("unreachable !!!\n"); } return code_cave; } +int encrypt_default( + __attribute__((unused)) t_map file, + __attribute__((unused)) Elf64_Phdr load_segment) { + return RET_OK; +} + +int encrypt_xor(t_map file, Elf64_Phdr load_segment) { + uint64_t key = 0xabcdefabcdefabcd; + printf("xor begin\n"); + size_t i = 0; + while (i < load_segment.p_filesz >> 3) { + ((uint64_t *)file.data)[i + (load_segment.p_offset >> 3)] ^= key; + i++; + } + key <<= (8 - (load_segment.p_filesz % 8)) * 8; + key >>= (8 - (load_segment.p_filesz % 8)) * 8; + ((uint64_t *)file.data)[i + (load_segment.p_offset >> 3)] ^= key; + // TODO end encrypt and fix asm + printf("xor ok\n"); + return RET_OK; +} + +t_payload64 get_xor_payload64(void) { + t_payload64 payload; + + payload.len = 191; + payload.jump_offset = 149; + payload.load_ptr_offset = 167; + payload.load_size_offset = 175; + payload.encrypt = &encrypt_xor; + payload.data = malloc(payload.len * sizeof(unsigned char)); + ft_memcpy(payload.data, + "\x55\x54\x53\x41\x55\x50\x51\x52\x56\x57\x41\x50\x41\x51\xbf\x01" + "\x00\x00\x00\x48\x8d\x35\x7f\x00\x00\x00\x48\x89\xf3\x48\x2b\x1d" + "\x83\x00\x00\x00\x4c\x8b\x05\x84\x00\x00\x00\x41\xb9\x00\x00\x00" + "\x00\x4d\x31\xed\x4c\x8b\x2d\x7c\x00\x00\x00\x4c\x89\xc1\x4c\x29" + "\xc9\x48\x83\xf9\x08\x7e\x0f\x48\x89\xda\x4c\x01\xca\x4c\x31\x2a" + "\x49\x83\xc1\x08\xeb\xe5\xba\x08\x00\x00\x00\x48\x29\xca\x48\x89" + "\xd1\xb8\x08\x00\x00\x00\xf6\xe1\x48\x89\xc1\x49\xd3\xe5\x49\xd3" + "\xed\x48\x89\xda\x4c\x01\xca\x4c\x31\x2a\xba\x0e\x00\x00\x00\xb8" + "\x01\x00\x00\x00\x0f\x05\x41\x59\x41\x58\x5f\x5e\x5a\x59\x58\x41" + "\x5d\x5b\x5c\x5d\xe9\x41\xda\xda\xda\x2e\x2e\x2e\x2e\x57\x4f\x4f" + "\x44\x59\x2e\x2e\x2e\x2e\x0a\xba\xba\xba\xba\xba\xba\xba\xba\xca" + "\xca\xca\xca\xca\xca\xca\xca\xcd\xab\xef\xcd\xab\xef\xcd\xab", + payload.len); + return payload; +} + +t_payload64 get_debug_payload64(void) { + t_payload64 payload; + + payload.len = 55; + payload.jump_offset = 37; + payload.encrypt = &encrypt_default; + payload.data = malloc(payload.len * sizeof(unsigned char)); + ft_memcpy(payload.data, + "\x55\x54\x50\x52\x56\x57\xbf\x01\x00\x00\x00\x48\x8d\x35\x17\x00" + "\x00\x00\xba\x0e\x00\x00\x00\xb8\x01\x00\x00\x00\x0f\x05\x5f\x5e" + "\x5a\x58\x5c\x5d\xe9\xb1\xda\xda\xda\x2e\x2e\x2e\x2e\x57\x4f\x4f" + "\x44\x59\x2e\x2e\x2e\x2e\x0a", + payload.len); + return payload; +} + int pack_elf64(t_map file) { Elf64_Ehdr *elf_header = (Elf64_Ehdr *)fetch(file, 0, sizeof(Elf64_Ehdr)); if (!elf_header) { @@ -123,35 +187,33 @@ int pack_elf64(t_map file) { t_map code_cave = get_code_cave(file, *load_segment); - size_t payload_len = 55; - unsigned char *payload = malloc(payload_len * sizeof(unsigned char)); - ft_memcpy(payload, "\x55\x54\x50\x52\x56\x57\xbf\x01\x00\x00\x00\x48\x8d\x35\x17\x00\x00\x00\xba\x0e\x00\x00\x00\xb8\x01\x00\x00\x00\x0f\x05\x5f\x5e\x5a\x58\x5c\x5d\xe9\xb1\xda\xda\xda\x2e\x2e\x2e\x2e\x57\x4f\x4f\x44\x59\x2e\x2e\x2e\x2e\x0a", payload_len); - // todo measure this, probably wc/4 in shell script output + hardcoded - // 55 bytes ^^^ - - // same, probably will hardcode it in functions like "get_debug_payload_info" - // or "get_rsa_payload_info" etc etc... - size_t jump_i = 36; + t_payload64 payload = get_xor_payload64(); // This should fallback to compression algorithm, or smaller payload (eg rsa->xor) - if (payload_len > (size_t)code_cave.size) { + if (payload.len > (size_t)code_cave.size) { printf("code cave size: %ld (0x%lx) bytes\n", code_cave.size, code_cave.size); return wdy_error("payload length exceed code cave size"); } // e_entry because relative to this (where we gonna go) // code cave start because thats the start of the code - // jump_i because thats the index of jump from code cave start - // 5 because jump_i is 5 bytes long operation (1 byte opcode + 4 byte operand) - int jump_value = elf_header->e_entry - (code_cave.data - file.data) - jump_i - 5; + // jump_offset is the index of jump from code cave start + // 4 because jump has a 4 byte operand) + size_t code_cave_start = code_cave.data - file.data; + int jump_value = elf_header->e_entry - code_cave_start - payload.jump_offset - 4; - ft_memcpy(payload + jump_i + 1, &jump_value, 4); + ft_memcpy(payload.data + payload.jump_offset, &jump_value, sizeof(jump_value)); + uint64_t load_ptr_value = code_cave_start - load_segment->p_offset + payload.jump_offset + 4; + ft_memcpy(payload.data + payload.load_ptr_offset, &load_ptr_value, sizeof(load_ptr_value)); + + ft_memcpy(payload.data + payload.load_size_offset, &load_segment->p_memsz, sizeof(load_segment->p_memsz)); + payload.encrypt(file, *load_segment); elf_header->e_entry = code_cave.data - file.data; - //load_segment->p_filesz += payload_len; - load_segment->p_memsz += payload_len; + load_segment->p_filesz += payload.len; + load_segment->p_memsz += payload.len; load_segment->p_flags |= PF_W | PF_R; - ft_memcpy(code_cave.data, payload, payload_len); + ft_memcpy(code_cave.data, payload.data, payload.len); int fd = open("woody", O_WRONLY | O_CREAT, 0755); if (fd == -1) {