Beispiel #1
0
/**
 * This is the part that launches the code in the Unicorn emulator.
 **/
int em_code(u8 *code, u32 bytelength, u32 startat,
            u8 *seed_res, uc_arch arch){

  // bit of lazy coding here: update a global arch var, so that
  // we can easily read the arch from the single step hook.
  // neither elegant nor dangerous. 
  if (global_arch != arch)
    global_arch = arch;

  /* The start address must be aligned to 4KB, or uc_mem_map will
   * throw a UC_ERR_ARG error. 
   */
  u32 round_start = startat & (u32) (~0xFFF);
  u32 offset = startat - round_start;
  int errcode = 0;
  int roundlength = roundup(bytelength);
  uc_engine *uc;
  uc_err err;
  uc_hook hook1;
  int sys_abi_len;
  uc_mode mode;
  
  int ret_inst;
  int *sys_abi_vec;

  /* if (DEBUG){ */
  /*   printf("IN EMULATOR\n"); */
  /*   fdump(stdout, code, bytelength); */
  /* } */
  
  switch (arch) {
  case UC_ARCH_X86 :
    sys_abi_vec = x86_64_syscall_abi; // careful
    sys_abi_len = x86_64_syscall_abi_len;
    mode = UC_MODE_64;
    ret_inst = UC_X86_INS_RET; 
    break;
  case UC_ARCH_ARM :
    if (DEBUG) printf("Emulating ARM architecture...\n");
    sys_abi_vec = arm_32_syscall_abi;
    sys_abi_len = arm_32_syscall_abi_len;
    mode = UC_MODE_ARM;
    break;
  default :
    fprintf(stderr,"Unknown architecture requested of em_code.\nExiting.\n");
    exit(EXIT_FAILURE);
  }
    
  union seedvals {
    u32 words[sys_abi_len]; // wrinkle here: the word size should be dynamic
    u8 bytes[sys_abi_len * sizeof(word)];
  } seedvals;

  /* fprintf(stderr, "bytelength = %d\nroundlength = %d\nsizeof(seedvals.bytes) = %d\nsizeof(seed_res) = %d\nsizeof(word) * sys_abi_len = %d\n",bytelength, roundlength, sizeof(seedvals.bytes), sizeof(seed_res), (sys_abi_len * sizeof(word))); */
  
  if (!memcpy(seedvals.bytes, seed_res,
              (sys_abi_len * sizeof(word)))){
    fprintf(stderr, "Error in memcpy, in em_code.\n");
  }
  
  /**
   * from the unicorn src: "This part of the API is less... clean...
   * because Unicorn supports arbitrary register types. So the least
   * intrusive solution is passing individual pointers. On the plus
   * side, you only need to make this pointer array once."
   */
  void *ptrs[sys_abi_len];
  int i;
  for (i = 0; i < sys_abi_len; i++) {
    ptrs[i] = &(seedvals.words[i]);
  }
  
  if ((err = uc_open(arch, mode, &uc))) {
    uc_perror("uc_open", err);
    return -1;
  }

  // seed the registers
  if ((err = uc_reg_write_batch(uc, sys_abi_vec, ptrs, sys_abi_len))){
    uc_perror("uc_reg_write_batch", err);
    return -1;
  }

  /* Add a single-stepping hook if debugging */
  if (DEBUG){
    if ((err = uc_hook_add(uc, &hook1, UC_HOOK_CODE, hook_step, NULL, 1, 0, 0))) {
      uc_perror("uc_hook_add", err);
      return 1;
    }
  }

  // don't leave 0x1000 a magic number
  if ((err = uc_mem_map(uc, round_start, 0x1000, UC_PROT_ALL))) {
    // does PROT_ALL mean 777? might want to set to XN for ROP...
    uc_perror("uc_mem_map", err);
    return -1;
  }

  if ((err = uc_mem_write(uc, startat, (void *) code,
                          bytelength-1))) {
    uc_perror("uc_mem_write", err);
    return -1;
  }
  // why does the unicorn example suggest sizeof(CODE) -1
  // where I have bytelength (sizeof(CODE))? probably because
  // it's implemented as a string, so it ends with a null byte
  if ((err = uc_emu_start(uc, startat,
                          startat + bytelength -1, 0, TTL))){
    if (DEBUG){
      uc_perror("uc_emu_start", err);
      if (err == UC_ERR_FETCH_UNMAPPED)
        ret_msg(uc, err, arch);
    }
    errcode = -2;
  }
  
  uc_reg_read_batch(uc, sys_abi_vec, ptrs, sys_abi_len);

  /** for testing  **/
  if (DEBUG) {
    printf("syscall vec: {");
    for (i = 0; i < sys_abi_len; i++) {
      if (i != 0) printf(", ");
      printf(WORDFMT, seedvals.words[i]);
    }
    printf("}\n");
  }
  /******************/
  memcpy(seed_res, seedvals.bytes,
         (sys_abi_len * sizeof(word)));  
  uc_close(uc);
  return errcode;
}
Beispiel #2
0
int main()
{
    int i;
    uc_hook sys_hook;
    uc_err err;
    uc_engine *uc;

    // set up register pointers
    for (i = 0; i < 7; i++) {
        ptrs[i] = &vals[i];
    }

    if ((err = uc_open(UC_ARCH_X86, UC_MODE_64, &uc))) {
        uc_perror("uc_open", err);
        return 1;
    }

    // reg_write_batch
    printf("reg_write_batch({200, 10, 11, 12, 13, 14, 15})\n");
    if ((err = uc_reg_write_batch(uc, syscall_abi, ptrs, 7))) {
        uc_perror("uc_reg_write_batch", err);
        return 1;
    }

    // reg_read_batch
    memset(vals, 0, sizeof(vals));
    if ((err = uc_reg_read_batch(uc, syscall_abi, ptrs, 7))) {
        uc_perror("uc_reg_read_batch", err);
        return 1;
    }

    printf("reg_read_batch = {");

    for (i = 0; i < 7; i++) {
        if (i != 0) printf(", ");
        printf("%llu", vals[i]);
    }

    printf("}\n");

    // syscall
    printf("\n");
    printf("running syscall shellcode\n");

    if ((err = uc_hook_add(uc, &sys_hook, UC_HOOK_INSN, hook_syscall, NULL, 1, 0, UC_X86_INS_SYSCALL))) {
        uc_perror("uc_hook_add", err);
        return 1;
    }

    if ((err = uc_mem_map(uc, BASE, 0x1000, UC_PROT_ALL))) {
        uc_perror("uc_mem_map", err);
        return 1;
    }

    if ((err = uc_mem_write(uc, BASE, CODE, sizeof(CODE) - 1))) {
        uc_perror("uc_mem_write", err);
        return 1;
    }

    if ((err = uc_emu_start(uc, BASE, BASE + sizeof(CODE) - 1, 0, 0))) {
        uc_perror("uc_emu_start", err);
        return 1;
    }

    return 0;
}