void CGIFImage:: readHeader(CFile *file, CGenImage *, CGIFImageHeader *header) { uchar byte1; uchar byte2; file->read((uchar *) header->signature, 3); file->read((uchar *) header->version , 3); file->read(&byte1, 1); file->read(&byte2, 1); header->width = (byte2 << 8) | byte1; file->read(&byte1, 1); file->read(&byte2, 1); header->height = (byte2 << 8) | byte1; file->read(&header->flags , 1); file->read(&header->background, 1); file->read(&header->aspect , 1); header->color_bits = (header->flags ) & 0x07; header->colors_sorted = (header->flags >> 3) & 0x01; header->max_color_bits = (header->flags >> 4) & 0x07; header->global_color_table = (header->flags >> 7) & 0x01; if (CGIFImage::getDebug()) { std::cerr << "Signature " << header->signature[0] << header->signature[1] << header->signature[2] << std::endl; std::cerr << "Version " << header->version[0] << header->version[1] << header->version[2] << std::endl; std::cerr << "Width " << header->width << std::endl; std::cerr << "Height " << header->height << std::endl; std::cerr << "Num Colors " << (1 << (header->color_bits + 1)) << std::endl; std::cerr << "Colors Sorted " << (int) header->colors_sorted << std::endl; std::cerr << "Max Colors " << 1 << (header->max_color_bits + 1) << std::endl; std::cerr << "Global Colors " << (int) header->global_color_table << std::endl; std::cerr << "Background " << (int) header->background << std::endl; std::cerr << "Aspect " << (int) header->aspect << std::endl; } if (strncmp(header->signature, "GIF", 3) != 0) CTHROW("Not a GIF File"); int type = 0; if (strncmp(header->version, "87a", 3) == 0) type = GIF87a; else if (strncmp(header->version, "89a", 3) == 0) type = GIF89a; if (type != GIF87a && type != GIF89a) CTHROW("Invalid GIF Version"); }
const PSViewName & PSViewDictionaryToken:: getName() { CTHROW("No name for token"); return psview_->getNameMgr()->getName(""); }
const PSViewName & PSViewBooleanToken:: getName() { CTHROW("No name for token"); return psview_->getNameMgr()->getName(""); }
CGIFAnim * CGIFImage:: createAnim(CFile *file, CGenImage *proto) { CGIFAnim *image_anim = new CGIFAnim; //------ file->rewind(); //------ CGIFImageData *gif_data = new CGIFImageData; gif_data->header = new CGIFImageHeader; gif_data->global_colors = NULL; gif_data->num_global_colors = 0; gif_data->local_colors = NULL; gif_data->num_local_colors = 0; //------ try { memset(&compress_data, 0, sizeof(CGIFImageCompressData)); CGenImage *image = NULL; readHeader(file, image, gif_data->header); //------ readGlobalColors(file, gif_data); //------ readAnimData(file, proto, image_anim, gif_data); } catch (...) { CTHROW("Failed to read GIF file"); } //------ if (gif_data != NULL) { delete gif_data->header; delete [] gif_data->global_colors; delete [] gif_data->local_colors; } delete gif_data; //------ return image_anim; }
bool CGIFImage:: readHeader(CFile *file, CGenImage *image) { file->rewind(); try { CGIFImageHeader header; readHeader(file, image, &header); //------ image->setType(CFILE_TYPE_IMAGE_GIF); image->setSize(header.width, header.height); } catch (...) { CTHROW("Failed to read GIF file"); return false; } return true; }
void CGIFImage:: readAnimData(CFile *file, CGenImage *proto, CGIFAnim *image_anim, CGIFImageData *gif_data) { int inum = 0; int delay = 0; bool transparent = false; uint transparent_color = 0; int dispose = 0; int user_input = 0; uint file_size = file->getSize(); while (true) { uchar id; try { if (! file->read(&id, 1)) break; } catch (...) { break; } if (id == IMAGE_ID) { ++inum; if (CGIFImage::getDebug()) std::cerr << "Image Id" << std::endl; CGIFImageImageHeader *image_header = new CGIFImageImageHeader; try { uchar byte1; uchar byte2; file->read(&byte1, 1); file->read(&byte2, 1); image_header->left = (byte2 << 8) | byte1; file->read(&byte1, 1); file->read(&byte2, 1); image_header->top = (byte2 << 8) | byte1; file->read(&byte1, 1); file->read(&byte2, 1); image_header->width = (byte2 << 8) | byte1; file->read(&byte1, 1); file->read(&byte2, 1); image_header->height = (byte2 << 8) | byte1; file->read(&image_header->flags, 1); image_header->local_color_table = (image_header->flags >> 7) & 0x01; image_header->interlaced = (image_header->flags >> 6) & 0x01; image_header->colors_sorted = (image_header->flags >> 5) & 0x01; image_header->color_bits = (image_header->flags ) & 0x07; if (CGIFImage::getDebug()) { std::cerr << "Left " << image_header->left << std::endl; std::cerr << "Top " << image_header->top << std::endl; std::cerr << "Width " << image_header->width << std::endl; std::cerr << "Height " << image_header->height << std::endl; std::cerr << "Local Colors " << image_header->local_color_table << std::endl; std::cerr << "Interlaced " << image_header->interlaced << std::endl; std::cerr << "Colors Sorted " << image_header->colors_sorted << std::endl; std::cerr << "Num Colors " << (1 << (image_header->color_bits + 1)) << std::endl; } if (image_header->local_color_table && image_header->color_bits > 0) { gif_data->num_local_colors = 1 << (image_header->color_bits + 1); gif_data->local_colors = new CGIFImageColorTable [gif_data->num_local_colors]; for (int i = 0; i < gif_data->num_local_colors; ++i) file->read((uchar *) &gif_data->local_colors[i], 3); if (CGIFImage::getDebug()) { for (int i = 0; i < gif_data->num_local_colors; ++i) std::cerr << gif_data->local_colors[i].r << " " << gif_data->local_colors[i].g << " " << gif_data->local_colors[i].b << std::endl; } } file->read(&compress_data.code_size, 1); compress_data.clear_code = 1 << compress_data.code_size; compress_data.eof_code = compress_data.clear_code + 1; compress_data.free_code = compress_data.clear_code + 2; ++compress_data.code_size; compress_data.init_code_size = compress_data.code_size; compress_data.max_code = 1 << compress_data.code_size; compress_data.code_mask = compress_data.max_code - 1; uint num_image_bytes = image_header->width*image_header->height; uchar *data = new uchar [file_size]; uchar size; file->read(&size, 1); uint num_bytes_read = 0; while (size > 0) { while (size--) { file->read(&data[num_bytes_read], 1); ++num_bytes_read; } file->read(&size, 1); } if (num_bytes_read < file_size) memset(&data[num_bytes_read], 0, file_size - num_bytes_read); //------ uchar *raw_data = new uchar [num_image_bytes]; decompressData(data, num_bytes_read, raw_data, num_image_bytes); delete [] data; if (image_header->interlaced) deInterlace(raw_data, image_header); //------ CGenImage *image = proto->dup(); image->setType(CFILE_TYPE_IMAGE_GIF); image->setColormap(true); image->setDataSize(image_header->width, image_header->height); int bottom = gif_data->header->height - image_header->height - image_header->top; int right = gif_data->header->width - image_header->width - image_header->left; //image->setBorder(image_header->left, bottom, right, image_header->top); if (bottom != 0 || right != 0) std::cerr << "Unhandled border" << std::endl; if (gif_data->num_local_colors > 0) { for (int i = 0; i < gif_data->num_local_colors; ++i) { CRGBA rgba; rgba.setRGBAI(gif_data->local_colors[i].r, gif_data->local_colors[i].g, gif_data->local_colors[i].b); image->addColor(rgba); } } else { for (int i = 0; i < gif_data->num_global_colors; ++i) { CRGBA rgba; rgba.setRGBAI(gif_data->global_colors[i].r, gif_data->global_colors[i].g, gif_data->global_colors[i].b); image->addColor(rgba); } //image->setBackground(image->getColor(gif_data->header->background)); } //------ if (transparent) image->setTransparentColor(transparent_color); //------ for (int y = 0, k = 0; y < image_header->height; ++y) for (int x = 0; x < image_header->width; ++x, ++k) image->setColorIndex(x, y, raw_data[k]); delete [] raw_data; //------ CGIFFrame *frame = new CGIFFrame(image); frame->setDelay(delay); frame->setDispose(dispose); frame->setUserInput(user_input); image_anim->add(frame); //------ delay = 0; transparent = false; transparent_color = 0; dispose = 0; user_input = 0; //------ delete image_header; image_header = NULL; } catch (...) { delete image_header; CTHROW("Failed to read GIF file"); } } else if (id == CONTROL_ID) {
static void inject_memory(void) { struct mem_region * stack_r = NULL; SYS_TRACE("nr_regions=%d\n", cf->nr_regions); /* for each mem region in ckpt file */ for (int i = 0; i < cf->nr_regions; i++) { struct mem_region * r = cf->regions[i]; SYS_TRACE("range %d: 0x%x--0x%x (0x%x:0x%x): %s\n", i, r->start, r->end, r->prot, r->offset, r->fn); /* find the region already mapped */ struct proc_entry e; bool_t res; uint32_t start, end; start = r->start; end = r->end; do { res = proc_find_in_range(&e, child_pid, start, end); if (res) { start = e.end; SYS_TRACE("\talready mapped in target: 0x%x--0x%x (0x%x:0x%x): %s\n", e.start, e.end, e.prot, e.offset, e.fn); /* check if 2 maps are same */ if ((e.start != r->start) || (e.end != r->end) || (e.prot != r->prot) || (strcmp(e.fn, r->fn) != 0)) { /* different */ /* special treat [heap] and [stack] */ if (strcmp(e.fn, "[heap]") == 0) { /* heap size is different */ /* that shouldn't happen, we restore heap address before * calling this function*/ THROW(EXCEPTION_FATAL, "heap address inconsistent"); } else if (strcmp(e.fn, "[stack]") == 0) { if (strcmp(r->fn, "[stack]") != 0) { /* that shouldn't happen... */ THROW(EXCEPTION_FATAL, "stack inconsistent"); } /* stack can auto expand */ } else if (strcmp(e.fn, "[vdso]") == 0) { THROW(EXCEPTION_FATAL, "vdso inconsistent"); } else { /* unmap the already mapped file */ /* first, check eip */ struct user_regs_struct regs = ptrace_peekuser(); if ((regs.eip >= e.start) && (regs.eip < e.end)) { /* target ckpt is special: it unmap itself... */ /* currently we don't support it */ THROW(EXCEPTION_FATAL, "eip (0x%x) inconsistent", (uint32_t)regs.eip); } /* now we can safely unmap that file or memregion */ int err; SYS_TRACE("\tunmap 0x%x--0x%x\n", e.start, e.end); err = ptrace_syscall(munmap, 2, e.start, e.end - e.start); if (err < 0) THROW(EXCEPTION_FATAL, "unmap memrigon 0x%x--0x%x failed: %d", e.start, e.end, err); } } } else { start = r->end; } } while (start < end); /* now the region has been cleaned up, there may be 2 situations: * 1. the desired region is empty; * 2. the desired region is mapped, but the same as ckpt. * here we use procutils to check it again. */ res = proc_find_in_range(&e, child_pid, r->start, r->end); if (res) { SYS_TRACE("\tdesired region is mapped\n"); if ((e.start != r->start) || (e.end != r->end) || (e.prot != r->prot) || (strcmp(e.fn, r->fn) != 0)) { /* if the lower end of stack inconsistent, don't care. * stack is auto expandable. */ /* NOT(e.fn same as r->fn and e.fn is "[stack]") */ if (!(!strcmp(e.fn, r->fn) && !strncmp(e.fn, "[stack]", 7))) { INJ_FATAL("this region is not cleaned up:\n"); INJ_FATAL("\tstart : 0x%x 0x%x\n", e.start, r->start); INJ_FATAL("\tend : 0x%x 0x%x\n", e.end, r->end); INJ_FATAL("\tprot : 0x%x 0x%x\n", e.prot, r->prot); INJ_FATAL("\tfn: : \"%s\" \"%s\"\n", e.fn, r->fn); THROW(EXCEPTION_FATAL, "Shouldn't happed...\n"); } } } else { SYS_TRACE("\tdesired region is unmapped\n"); /* from the ckpt, find the file and do the map */ uint32_t map_addr = r->start; uint32_t size = r->end - r->start; uint32_t prot = r->prot; uint32_t flags = MAP_FIXED | MAP_EXECUTABLE | MAP_PRIVATE; if ((r->fn_len <= 1) || (r->fn[0] == '\0')) { /* this is not a file map */ uint32_t ret_addr; flags |= MAP_ANONYMOUS; SYS_TRACE("\tdo the anonymouse map\n"); ret_addr = ptrace_syscall(mmap2, 6, map_addr, size, prot, flags, 0, 0); CTHROW(map_addr == ret_addr, "mmap2 failed, return 0x%x, not 0x%x", ret_addr, map_addr); } else { /* this is a file map */ uint32_t fn_pos; /* push the filename */ fn_pos = ptrace_push(r->fn, strlen(r->fn) + 1, TRUE); int fd = ptrace_syscall(open, 3, fn_pos, O_RDONLY, 0); CTHROW(fd >= 0, "open file %s failed: %d", r->fn, fd); SYS_TRACE("\tdo the map\n"); uint32_t off = r->offset; uint32_t ret_addr = ptrace_syscall(mmap2, 6, map_addr, size, prot, flags, fd, off >> PAGE_SHIFT); CTHROW(ret_addr == map_addr, "mmap2 file %s failed: return 0x%x", r->fn, ret_addr); ptrace_syscall(close, 1, fd); } } /* now the memory region has been built up, we then poke * memory into it */ /* don't update stack here. although in most case the stack * is the last region we meet, there are some special situations. * for example in compat memlayout. the stack may be polluted by * pervious ptrace_push operation. */ if (strcmp(r->fn, "[stack]") == 0) stack_r = r; else if (strcmp(r->fn, "[vdso]") != 0) /* chkp don't contain vdso */ ptrace_updmem(r->f_pos + cf->ckpt_img, r->start, r->end - r->start); } CTHROW(stack_r != NULL, "no \"[stack]\" found"); /* we poke stack at last */ ptrace_updmem(stack_r->f_pos + cf->ckpt_img, stack_r->start, stack_r->end - stack_r->start); }
static void gdbloader_main(const char * target_fn) { /* check: target_fn should be same as argv[0] */ if (strcmp(target_fn, cf->cmdline[0]) != 0) { SYS_FATAL("target should be %s, not %s\n", cf->cmdline[0], target_fn); THROW(EXCEPTION_FATAL, "cmdline error"); } /* execve child */ child_pid = ptrace_execve(target_fn, cf->cmdline, cf->environ); /* inject memory */ /* before we inject memory, we need to restore heap */ uint32_t heap_end; heap_end = ptrace_syscall(brk, 1, cf->state->brk); CTHROW(heap_end == cf->state->brk, "restore heap failed: %d", heap_end); SYS_TRACE("restore heap to 0x%x\n", heap_end); inject_memory(); /* then, we retrive the inject so file, enter from * __debug_entry. we need to push: * nothing. * process can retrive all from state vector. * and we cannot use stack now * */ /* NOTICE: the state_vector should be saved in the ckpt memory, * we needn't restore them in ptrace process. let the inject so * to do it. */ /* from the opts get the so-file bias */ uint32_t inj_bias = opts->inj_bias; /* use procutils to get the file */ struct proc_entry e; e.start = inj_bias; e.bits = PE_START; proc_fill_entry(&e, child_pid); SYS_TRACE("inject so is %s\n", e.fn); /* use elfutils to retrive the symbol */ void * img = load_file(e.fn); struct elf_handler * inj_so = elf_init(img, inj_bias); uintptr_t debug_entry = elf_get_symbol_address(inj_so, opts->entry); SYS_TRACE("symbol %s at 0x%x\n", opts->entry, debug_entry); /* inject the injector opts */ inject_injopts(inj_so); elf_cleanup(inj_so); free(img); /* we have to restore register here... */ SYS_FORCE("pid=%d\n", child_pid); SYS_FORCE("eip=0x%x\n", cf->state->regs.eip); ptrace_pokeuser(cf->state->regs); SYS_TRACE("eax=0x%x\n", cf->state->regs.eax); SYS_TRACE("ebx=0x%x\n", cf->state->regs.ebx); SYS_TRACE("ecx=0x%x\n", cf->state->regs.ecx); SYS_TRACE("edx=0x%x\n", cf->state->regs.edx); SYS_TRACE("esi=0x%x\n", cf->state->regs.esi); SYS_TRACE("edi=0x%x\n", cf->state->regs.edi); SYS_TRACE("ebp=0x%x\n", cf->state->regs.ebp); SYS_TRACE("esp=0x%x\n", cf->state->regs.esp); // SYS_TRACE("gs=0x%x\n", cf->state->regs.gs); // SYS_TRACE("es=0x%x\n", cf->state->regs.es); /* we push eip at the top of the new stack */ ptrace_push(&cf->state->regs.eip, sizeof(uint32_t), FALSE); /* fix libpthread problem: * * when gdb attaches to target, if it find libpthread, gdb * will try to use libthread_db to retrive thread-local info. * some data, like `errno', is TLS and need those info. * * When gdb does the work, it use ptrace to peek memory from target image. * so gdb will see the original thread info, the tid is different from * current pid, therefore gdb will think there are at least 2 threads and * then it will try to attach to the 'old' one and definitely fail. When this * failure occures, gdb print a warning message. * * We have 2 ways to solve this problem: * * 1. add a syscall into kernel's code, change its pid. it is simple. * 2. change the image when gdb attach. * * We choose the 2nd one because we prefer user space solution. * * */ uint32_t sym_stack_used = 0, sym_stack_user = 0; if (opts->fix_pthread_tid) { fix_libpthread(&sym_stack_used, &sym_stack_user); SYS_WARNING("sym_stack_used=0x%x, sym_stack_user=0x%x\n", sym_stack_used, sym_stack_user); } /* we push those 2 addresses onto the stack */ ptrace_push(&sym_stack_used, sizeof(uint32_t), FALSE); ptrace_push(&sym_stack_user, sizeof(uint32_t), FALSE); /* move eip and detach, let the target process to run */ ptrace_goto(debug_entry); /* detach in main */ return; }