diff --git a/.gitignore b/.gitignore index f3265eb..fd55dfd 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,6 @@ rsa/rsa *.a woody_woodpacker woody +asm +payload +print diff --git a/Makefile b/Makefile index 1cd28f8..c441a74 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,8 @@ SRCS_PATH = srcs/ SRCS = $(SRCS_PATH)main.c \ $(SRCS_PATH)utils.c \ - $(SRCS_PATH)woody.c + $(SRCS_PATH)woody.c \ + $(SRCS_PATH)encrypt.c OBJS = ${SRCS:.c=.o} @@ -37,4 +38,4 @@ fclean: re: fclean make all -.PHONY : all clean fclean re +.PHONY : all clean fclean re \ No newline at end of file diff --git a/README b/README new file mode 100644 index 0000000..c5565b7 --- /dev/null +++ b/README @@ -0,0 +1,5 @@ +Transform payload code in hexa : + nasm -f elf64 -o print.o print.s && ld -o print print.o && nasm -f bin -o payload print.s && hexdump -v -e '"\\\x\" 1/1 "%02x"' payload + +To get it in the clipboad directly append : + | xclip -sel clip to directly \ No newline at end of file diff --git a/ft_printf/libft/Makefile b/ft_printf/libft/Makefile index 0ff9c4e..9bfb217 100644 --- a/ft_printf/libft/Makefile +++ b/ft_printf/libft/Makefile @@ -41,6 +41,7 @@ SRCS = $(SRCS_PATH)ft_atoi.c \ $(SRCS_PATH)ft_bzero.c \ $(SRCS_PATH)ft_strdup.c \ $(SRCS_PATH)ft_strnstr.c \ + $(SRCS_PATH)ft_strnstr_nullterminated.c \ $(SRCS_PATH)ft_calloc.c \ $(SRCS_PATH)ft_substr.c \ $(SRCS_PATH)ft_strjoin.c \ diff --git a/ft_printf/libft/ft_lstdelone.c b/ft_printf/libft/ft_lstdelone.c index 5f21f42..1d01c83 100644 --- a/ft_printf/libft/ft_lstdelone.c +++ b/ft_printf/libft/ft_lstdelone.c @@ -18,7 +18,8 @@ void ft_lstdelone(t_list *lst, void (*del)(void *)) return ; if (del) { - free(lst); del(lst->content); + free(lst); } } + diff --git a/ft_printf/libft/ft_strnstr_nullterminated.c b/ft_printf/libft/ft_strnstr_nullterminated.c new file mode 100644 index 0000000..3f13db2 --- /dev/null +++ b/ft_printf/libft/ft_strnstr_nullterminated.c @@ -0,0 +1,17 @@ +#include "libft.h" + +char *ft_strnstr_nullterminated(const char *big, const char *little, size_t len) +{ + size_t len_l; + + if (*little == 0) + return ((char *)big); + len_l = ft_strlen(little); + while (len-- >= len_l) + { + if (*big == *little && ft_strncmp(big, little, len_l) == 0) + return ((char *)big); + big++; + } + return (NULL); +} \ No newline at end of file diff --git a/ft_printf/libft/libft.h b/ft_printf/libft/libft.h index 93441d3..fd6ed1d 100644 --- a/ft_printf/libft/libft.h +++ b/ft_printf/libft/libft.h @@ -37,6 +37,7 @@ int ft_strncmp(const char *s1, const char *s2, size_t n); size_t ft_strlcpy(char *dst, const char *src, size_t size); size_t ft_strlcat(char *dst, const char *src, size_t size); char *ft_strnstr(const char *big, const char *little, size_t len); +char *ft_strnstr_nullterminated(const char *big, const char *little, size_t len); int ft_atoi(const char *nptr); char *ft_substr(char const *s, unsigned int start, size_t len); char *ft_strjoin(char const *s1, char const *s2); @@ -55,6 +56,7 @@ void *ft_calloc(size_t nmemb, size_t size); char *ft_convert_base(char *nbr, char *base_from, char *base_to); char *ft_u_convert(char *nbr, char *base_from, char *base_to); void ft_rev_int_tab(char *tab, int size); + typedef struct s_list { void *content; diff --git a/gen_payload.sh b/gen_payload.sh new file mode 100755 index 0000000..2c99491 --- /dev/null +++ b/gen_payload.sh @@ -0,0 +1 @@ +nasm -f elf64 -o print.o print.s && ld -o print print.o && nasm -f bin -o payload print.s && hexdump -v -e '"\\\x\" 1/1 "%02x"' payload diff --git a/includes/woody.h b/includes/woody.h index c86a04a..6183a7b 100644 --- a/includes/woody.h +++ b/includes/woody.h @@ -1,7 +1,8 @@ #ifndef WOODY_H -# define WOODY_H +#define WOODY_H #include "../ft_printf/includes/ft_printf.h" +#include #include #include #include @@ -11,21 +12,43 @@ #include #include #include +#include -typedef struct efl_content + +#define JUMP "\xe9" +#define WOODY "..WOODY.." +#define TEXT_OFFSET "\xba\xba\xba\xba\xba\xba\xba\xba" +#define SECTION_SIZE "\xca\xca\xca\xca\xca\xca\xca\xca" + +typedef struct payload +{ + char *payload; + size_t len; +} t_payload; + +typedef struct elf_content { long unsigned int file_size; - char *file_path; - char *file; - char *extra_data; -} t_efl_content; - + char *file_path; + char *file; + Elf64_Ehdr *Ehdr; + Elf64_Phdr *Phdr; + Elf64_Shdr *Shdr; + Elf64_Shdr *text_section; + char *extra_data; +} t_elf_content; // utils.c -void *secure_access(char *file, unsigned long file_size, unsigned long offset_to_data, unsigned long supposed_data_size); -int ft_put_error(char *str); +void *fetch(char *file, unsigned long file_size, unsigned long offset_to_data, unsigned long supposed_data_size); +int ft_put_error(char *str); +char *get_string(char *str, char *end_file); +int get_symbols_count(int sh_size, int sh_entsize); // woody.c -int woody(t_efl_content *file_content); +int prepare_injection(t_elf_content *woody); + +// encrypt.c +void encrypt(char *file, unsigned long int offset, unsigned long int size); + +#endif -#endif \ No newline at end of file diff --git a/print.s b/print.s new file mode 100644 index 0000000..5c2c123 --- /dev/null +++ b/print.s @@ -0,0 +1,37 @@ +bits 64 +global _start + +_start: + push rax + push rdi + push rsi + push rdx + + mov rdi, 1 + lea rsi, [rel msg] + mov rax, rsi + sub rax, qword [rel text_section] ;text_section address + mov r8, qword [rel section_sisze] ;text_section size + mov r9, 0 ;increment register + xor r10, r10 + ; encrypt: + ; cmp r8, r9 + ; je end_encrypt + ; mov r10b, byte[rax + r9] + ; inc r10b ;rot + 1 + ; mov byte[rax + r9], r10b + ; inc r9 + ; jmp encrypt + ; end_encrypt: + mov rdx, 14 + mov rax, 1 + syscall + pop rdx + pop rsi + pop rdi + pop rax + + jmp 0x00000000 ;for now it needs to be the first jmp + msg db "....WOODY....",10 + text_section dq 0xbabababababababa + section_sisze dq 0xcacacacacacacaca diff --git a/srcs/encrypt.c b/srcs/encrypt.c new file mode 100644 index 0000000..f7866d7 --- /dev/null +++ b/srcs/encrypt.c @@ -0,0 +1,11 @@ +#include "../includes/woody.h" + +void encrypt(char *file, unsigned long int offset, unsigned long int size) +{ + size_t i = 0; + while (i < size) + { + file[offset + i] = file[offset + i] - 1; + ++i; + } +} \ No newline at end of file diff --git a/srcs/main.c b/srcs/main.c index a5d84b1..807f492 100644 --- a/srcs/main.c +++ b/srcs/main.c @@ -1,29 +1,29 @@ #include "../includes/woody.h" -int get_elf_file(t_efl_content *file_content) +int get_elf_file(t_elf_content *woody) { int fd; off_t off; - fd = open(file_content->file_path, O_RDONLY); + fd = open(woody->file_path, O_RDONLY); if (fd < 0) { - ft_printf("Error: Failed to open \'%s\'\n", file_content->file_path); + ft_printf("Error: Failed to open \'%s\'\n", woody->file_path); return EXIT_FAILURE; } off = lseek(fd, 0, SEEK_END); if (off == -1) { close(fd); - ft_printf("Error: Failed to read file offset \'%s\'\n", file_content->file_path); + ft_printf("Error: Failed to read file offset \'%s\'\n", woody->file_path); return EXIT_FAILURE; } - file_content->file_size = off; - file_content->file = mmap(NULL, file_content->file_size, PROT_READ, MAP_PRIVATE, fd, 0); - if (file_content->file == MAP_FAILED) + woody->file_size = off; + woody->file = mmap(NULL, woody->file_size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, 0); + if (woody->file == MAP_FAILED) { close(fd); - ft_printf("Error: Failed to map file \'%s\'\n", file_content->file_path); + ft_printf("Error: Failed to map file \'%s\'\n", woody->file_path); return EXIT_FAILURE; } close(fd); @@ -32,15 +32,15 @@ int get_elf_file(t_efl_content *file_content) int main(int ac, char **av) { - t_efl_content file_content; + t_elf_content woody; if (ac != 2) { return ft_put_error("Woody_woodpacker take 1 argument\n"); } - file_content.file_path = av[1]; - int ret = get_elf_file(&file_content); + woody.file_path = av[1]; + int ret = get_elf_file(&woody); if (ret == EXIT_FAILURE) return ret; - - return woody(&file_content); -} \ No newline at end of file + return prepare_injection(&woody); +} + diff --git a/srcs/utils.c b/srcs/utils.c index 81a6e3c..1857a26 100644 --- a/srcs/utils.c +++ b/srcs/utils.c @@ -1,12 +1,32 @@ #include "../includes/woody.h" -void *secure_access(char *file, unsigned long file_size, unsigned long offset_to_data, unsigned long supposed_data_size) +void *fetch(char *file, unsigned long file_size, unsigned long offset_to_data, unsigned long supposed_data_size) { if (file_size > offset_to_data && file_size >= (offset_to_data + supposed_data_size)) return (file + offset_to_data); return NULL; } +int get_symbols_count(int sh_size, int sh_entsize) +{ + if (sh_size <= 0 || sh_entsize <= 0) + return 0; + return (sh_size / sh_entsize); +} + +char *get_string(char *str, char *end_file) +{ + char *search_end = str; + while (search_end < end_file) + { + if (*search_end == 0) + return str; + ++search_end; + + } + return NULL; +} + int ft_put_error(char *str) { ft_putstr_fd("Error: ", STDERR_FILENO); diff --git a/srcs/woody.c b/srcs/woody.c index 7435bc1..3344599 100644 --- a/srcs/woody.c +++ b/srcs/woody.c @@ -5,17 +5,7 @@ int elf_magic_numbers(char *str) return (!ft_strncmp(str, ELFMAG, SELFMAG)); } -void encrypt_zone(char *file, unsigned long int offset, unsigned long int size) -{ - size_t i = 0; - while (i < size) - { - file[offset + i] = 0; - ++i; - } -} - -int save_elf(char *path, char *file, unsigned long int size) +int save_elf(char *path, char *file, unsigned long int size) { int fd = open(path, O_CREAT | O_WRONLY | O_TRUNC, 0755); if (fd == -1) { @@ -36,49 +26,204 @@ int save_elf(char *path, char *file, unsigned long int size) return EXIT_SUCCESS; } -int woody(t_efl_content *file_content) +int get_load_segment(t_elf_content *woody, int start, bool executable) { - Elf64_Ehdr *Ehdr = (Elf64_Ehdr *)secure_access(file_content->file, file_content->file_size, 0, sizeof(Elf64_Ehdr)); - - if (!Ehdr || !elf_magic_numbers(file_content->file) || Ehdr->e_ident[EI_CLASS] != 2) + for (int i = start; i < woody->Ehdr->e_phnum; i++) { - ft_printf("Error: \'%s\' is not a valid 64-bit ELF file\n", file_content->file_path); + if (woody->Phdr[i].p_type == PT_LOAD) + { + if (executable) + { + if (woody->Phdr[i].p_flags & PF_X) + return i; + } + else + return i; + } + } + return -1; +} + +void offset_sections(t_elf_content *woody, unsigned int from, unsigned int offset_ammount) +{ + for (int i = 0; i < woody->Ehdr->e_phnum; i++) + { + if (woody->Phdr[i].p_offset > from) + woody->Phdr[i].p_offset += offset_ammount; + } + for (int i = 0; i < woody->Ehdr->e_shnum; i++) + { + if (woody->Shdr[i].sh_offset > from) + woody->Shdr[i].sh_offset += offset_ammount; + } +} + +size_t create_codecave(t_elf_content *woody, Elf64_Phdr *load_segment, t_payload *payload) +{ + const unsigned int page_size = 4096; // getpagesize(); not authorized + unsigned int padding_size = ((payload->len / page_size) + 1) * page_size; + unsigned int codecave_start = load_segment->p_offset + load_segment->p_filesz; + offset_sections(woody, codecave_start, padding_size); + char *new_woody = malloc(woody->file_size + padding_size); + if (!new_woody) + return 0; + ft_memcpy(new_woody, woody->file, codecave_start); + ft_bzero(new_woody + codecave_start, padding_size); + ft_memcpy(new_woody + codecave_start + padding_size, woody->file + codecave_start, woody->file_size - codecave_start); + munmap(woody->file, woody->file_size); + woody->file = new_woody; + woody->file_size += padding_size; + woody->Ehdr = (Elf64_Ehdr *)new_woody; + woody->Phdr = (Elf64_Phdr *)fetch(woody->file, woody->file_size, woody->Ehdr->e_phoff, sizeof(Elf64_Phdr)); + woody->Shdr = (Elf64_Shdr *)fetch(woody->file, woody->file_size, woody->Ehdr->e_shoff, sizeof(Elf64_Shdr)); + return codecave_start; +} + +t_payload *get_payload() +{ + t_payload *payload = malloc(sizeof(t_payload)); + if (!payload) + return NULL; + char buffer[1024]; + int fd = open("payload", O_RDONLY); + if (fd == -1) { + perror("error opening payload"); + free(payload); + exit(1); + } + payload->len = read(fd, buffer, 1024); + payload->payload = malloc(sizeof(char) * payload->len); + ft_memcpy(payload->payload, buffer, payload->len); + return payload; +} + +int insert_payload(t_elf_content *woody, t_payload *payload, size_t payload_position) +{ + char *ptr_jmp = ft_strnstr_nullterminated(payload->payload, JUMP, payload->len); + char *ptr_woody = ft_strnstr_nullterminated(payload->payload, WOODY, payload->len); + char *ptr_text_section = ft_strnstr_nullterminated(payload->payload, TEXT_OFFSET, payload->len); + char *ptr_section_size = ft_strnstr_nullterminated(payload->payload, SECTION_SIZE, payload->len); + if (ptr_jmp && ptr_woody && ptr_text_section && ptr_section_size) + { + int32_t woody_index = ptr_woody - payload->payload; + + int32_t jmp_index = ptr_jmp - payload->payload; + int32_t jump_value = ((payload_position + jmp_index + 5) - woody->Ehdr->e_entry) * -1; // 5 = JUMP SIZE (OPCODE + 4 bytes operand) + ft_memcpy(&payload->payload[jmp_index + 1], &jump_value, sizeof(jump_value)); + + int64_t text_index = ptr_text_section - payload->payload; + int64_t text_value = payload_position - woody->Ehdr->e_entry + woody_index; + ft_memcpy(&payload->payload[text_index], &text_value, sizeof(text_value)); + + int64_t section_index = ptr_section_size - payload->payload; + int64_t section_value = woody->text_section->sh_size; + ft_memcpy(&payload->payload[section_index], §ion_value, sizeof(section_value)); + + ft_memcpy(woody->file + payload_position, payload->payload, payload->len); + + printf("jmp_index : %d (%x)\n", jmp_index, jmp_index); + printf("woody index :%d (%x)\n", woody_index, woody_index); + printf("jmp_index++ : %ld (%lx)\n", jmp_index + sizeof(JUMP) + sizeof(jump_value), jmp_index + sizeof(JUMP) + sizeof(jump_value) - 1); + printf("text_value : %ld (%lx)\n", text_value, text_value); + printf("Old entry : %ld (%lx)\n", woody->Ehdr->e_entry, woody->Ehdr->e_entry); + printf("Code cave start = %ld (%lx)\n", payload_position, payload_position); + printf("Payload size = %ld (%lx)\n", payload->len, payload->len); + printf("Backward offset = %d (%x)(%x)\n", jump_value, jump_value, -jump_value); + return EXIT_SUCCESS; + } + return EXIT_FAILURE; +} + +void inject(t_elf_content *woody) +{ + t_payload *payload = get_payload(); + int i = get_load_segment(woody, 0, true); + int j = get_load_segment(woody, i + 1, false); + + size_t code_cave_size = woody->Phdr[j].p_offset - (woody->Phdr[i].p_offset + woody->Phdr[i].p_filesz); + size_t payload_position; + printf("load position = : %ld (%lx)\n", woody->Phdr[i].p_offset, woody->Phdr[i].p_offset); + printf("load size = : %ld (%lx)\n", woody->Phdr[i].p_filesz, woody->Phdr[i].p_filesz); + if (code_cave_size > payload->len) // inverse here to test the other technique + { + payload_position = woody->Phdr[i].p_offset + woody->Phdr[i].p_memsz; + printf("Code_cave_size = %ld (%lx)\n", code_cave_size, code_cave_size); + } + else + { + payload_position = create_codecave(woody, &woody->Phdr[i], payload); + } + insert_payload(woody, payload, payload_position); + + woody->Ehdr->e_entry = payload_position; + woody->Phdr[i].p_filesz += payload->len; + woody->Phdr[i].p_memsz += payload->len; + woody->Phdr[i].p_flags = PF_X | PF_W | PF_R; + woody->text_section->sh_size += payload->len; + printf("New entry = %ld (%lx)\n", woody->Ehdr->e_entry, woody->Ehdr->e_entry); +} + +int is_special_section_indice(uint16_t section_index) { + return (section_index == SHN_LOPROC || section_index == SHN_BEFORE || + section_index == SHN_AFTER || section_index == SHN_HIPROC || + section_index == SHN_LOOS || section_index == SHN_HIOS || + section_index == SHN_ABS || section_index == SHN_COMMON || + section_index == SHN_XINDEX || section_index == SHN_HIRESERVE); +} + +int get_elf_sections(t_elf_content *woody) +{ + woody->Ehdr = (Elf64_Ehdr *)fetch(woody->file, woody->file_size, 0, sizeof(Elf64_Ehdr)); + if (!woody->Ehdr || !elf_magic_numbers(woody->file) || woody->Ehdr->e_ident[EI_CLASS] != ELFCLASS64) + { + ft_printf("Error: \'%s\' is not a valid 64-bit ELF file\n", woody->file_path); return EXIT_FAILURE; } + woody->Phdr = (Elf64_Phdr *)fetch(woody->file, woody->file_size, woody->Ehdr->e_phoff, sizeof(Elf64_Phdr)); - Elf64_Shdr *Shdr = (Elf64_Shdr *)secure_access(file_content->file, file_content->file_size, Ehdr->e_shoff, sizeof(Elf64_Shdr)); - if (Shdr == NULL || !secure_access(file_content->file, file_content->file_size, Ehdr->e_shoff, Ehdr->e_shnum * sizeof(Elf64_Shdr))) + woody->Shdr = (Elf64_Shdr *)fetch(woody->file, woody->file_size, woody->Ehdr->e_shoff, sizeof(Elf64_Shdr)); + if (!woody->Shdr|| !fetch(woody->file, woody->file_size, woody->Ehdr->e_shoff, woody->Ehdr->e_shnum * sizeof(Elf64_Shdr))) + return EXIT_FAILURE; + + if (!fetch(woody->file, woody->file_size, woody->Ehdr->e_shoff + (woody->Ehdr->e_shstrndx * sizeof(Elf64_Shdr)), sizeof(Elf64_Shdr))) { - return ft_put_error("Corrupted file"); + return EXIT_FAILURE; } - if (file_content->file_size > Ehdr->e_shoff + Ehdr->e_shnum * sizeof(Elf64_Shdr)) + char *Sshstrtab = (char *)fetch(woody->file, woody->file_size, woody->Shdr[woody->Ehdr->e_shstrndx].sh_offset, 0); + if (Sshstrtab == NULL) { - printf("extra_data !\n"); // save it in file_content->extra_data and append it to the end of the woody file ? Could be dangerous + return EXIT_FAILURE; + } + for (int j = 0; j < woody->Ehdr->e_shnum;j++) + { + if (woody->Shdr[j].sh_name > woody->Shdr[woody->Ehdr->e_shstrndx].sh_size) return EXIT_FAILURE; + if (woody->Shdr[j].sh_type == SHT_PROGBITS && woody->Shdr[j].sh_flags & SHF_EXECINSTR && + woody->Shdr[j].sh_flags & SHF_ALLOC && + Sshstrtab + woody->Shdr[j].sh_name < (char *)woody->file + woody->file_size && + !ft_strncmp(".text\0", Sshstrtab + woody->Shdr[j].sh_name, 6)) + { + woody->text_section = &woody->Shdr[j]; + break; + } } - Elf64_Shdr *symbols_table = NULL; - for (int i = 0; i < Ehdr->e_shnum; i++) { - if (Shdr[i].sh_type == SHT_SYMTAB) { - symbols_table = secure_access(file_content->file, file_content->file_size, Ehdr->e_shoff + (i * sizeof(Elf64_Shdr)), sizeof(Elf64_Shdr)); - } - } - if (symbols_table == NULL) - return ft_put_error("Corrupted file"); + return EXIT_SUCCESS; +} - Elf64_Shdr *strtab_header = (Elf64_Shdr *)secure_access(file_content->file, file_content->file_size, Ehdr->e_shoff + (symbols_table->sh_link * Ehdr->e_shentsize), sizeof(Elf64_Shdr)); - if (!strtab_header) - return ft_put_error("Corrupted file"); +int prepare_injection(t_elf_content *woody) +{ + int elf_statut = get_elf_sections(woody); + if (elf_statut) + return elf_statut; + inject(woody); + // encrypt(woody->file, woody->text_section->sh_offset, woody->text_section->sh_size); + char *woody_file; + if (!(woody_file = malloc(woody->file_size))) + return ft_put_error("Allocation error"); + ft_memcpy(woody_file, woody->file, woody->file_size); + munmap(woody_file, woody->file_size); + save_elf("woody", woody_file, woody->file_size); + free(woody_file); + return EXIT_SUCCESS; +} - - if (strtab_header->sh_offset + strtab_header->sh_size > file_content->file_size) - { - return ft_put_error("Encrypt after the end of the file"); - } - - char *woody = malloc(file_content->file_size); - ft_memcpy(woody, file_content->file, file_content->file_size); - - encrypt_zone(woody, strtab_header->sh_offset , strtab_header->sh_size); - - return save_elf("woody", woody, file_content->file_size); -} \ No newline at end of file