feat: xor payload

This commit is contained in:
gbrochar 2024-09-03 22:14:18 +02:00
parent 7d93440bd1
commit 77b90650b1
3 changed files with 171 additions and 18 deletions

76
assets/xor.s Normal file
View File

@ -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

View File

@ -10,11 +10,26 @@
# define RET_ERR 1 # define RET_ERR 1
# define RET_OK 0 # define RET_OK 0
# define PL_XOR 0
# define PL_RSA 1
# define PL_DEBUG 2
typedef struct s_map { typedef struct s_map {
void *data; void *data;
off_t size; off_t size;
} t_map; } 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); int woody_woodpacker(char *path);

View File

@ -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.data = fetch(file, longest_i + offset, longest);
code_cave.size = longest; code_cave.size = longest;
if (!code_cave.data) { if (!code_cave.data) {
printf("unreachable !!!\n"); ft_printf("unreachable !!!\n");
} }
return code_cave; 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) { int pack_elf64(t_map file) {
Elf64_Ehdr *elf_header = (Elf64_Ehdr *)fetch(file, 0, sizeof(Elf64_Ehdr)); Elf64_Ehdr *elf_header = (Elf64_Ehdr *)fetch(file, 0, sizeof(Elf64_Ehdr));
if (!elf_header) { if (!elf_header) {
@ -123,35 +187,33 @@ int pack_elf64(t_map file) {
t_map code_cave = get_code_cave(file, *load_segment); t_map code_cave = get_code_cave(file, *load_segment);
size_t payload_len = 55; t_payload64 payload = get_xor_payload64();
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;
// This should fallback to compression algorithm, or smaller payload (eg rsa->xor) // 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); printf("code cave size: %ld (0x%lx) bytes\n", code_cave.size, code_cave.size);
return wdy_error("payload length exceed code cave size"); return wdy_error("payload length exceed code cave size");
} }
// e_entry because relative to this (where we gonna go) // e_entry because relative to this (where we gonna go)
// code cave start because thats the start of the code // code cave start because thats the start of the code
// jump_i because thats the index of jump from code cave start // jump_offset is the index of jump from code cave start
// 5 because jump_i is 5 bytes long operation (1 byte opcode + 4 byte operand) // 4 because jump has a 4 byte operand)
int jump_value = elf_header->e_entry - (code_cave.data - file.data) - jump_i - 5; 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; elf_header->e_entry = code_cave.data - file.data;
//load_segment->p_filesz += payload_len; load_segment->p_filesz += payload.len;
load_segment->p_memsz += payload_len; load_segment->p_memsz += payload.len;
load_segment->p_flags |= PF_W | PF_R; 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); int fd = open("woody", O_WRONLY | O_CREAT, 0755);
if (fd == -1) { if (fd == -1) {