美文网首页
unicorn 使用介绍

unicorn 使用介绍

作者: android小奉先 | 来源:发表于2024-03-02 20:43 被阅读0次

    本篇介绍

    unicorn是一个轻量级,多平台,多架构的CPU模拟器框架。使用Unicorn可以模拟执行执行,并且也支持指令级别的hook。本篇看下unicorn的用法。

    模拟指令介绍

    代码如下:

    #include <iostream>
    
    #include <unicorn/unicorn.h>
    
    // code to be emulated
    #define X86_CODE32 "\x41\x4a" // INC ecx; DEC edx
    
    // memory address where emulation starts
    #define ADDRESS 0x1000000
    
    int main(int argc, char **argv, char **envp)
    {
      uc_engine *uc;
      uc_err err;
      int r_ecx = 0x1234;     // ECX register
      int r_edx = 0x7890;     // EDX register
    
      std::cout<<"Emulate i386 code"<<std::endl;
    
      // Initialize emulator in X86-32bit mode
      err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc);
      if (err != UC_ERR_OK) {
        std::cout<<"Failed on uc_open() with error returned:"<<err<<std::endl;
        return -1;
      }
    
      // map 2MB memory for this emulation
      uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
    
      // write machine code to be emulated to memory
      if (uc_mem_write(uc, ADDRESS, X86_CODE32, sizeof(X86_CODE32) - 1)) {
        std::cout<<"Failed to write emulation code to memory, quit!"<<err<<std::endl;
        return -1;
      }
      
      std::cout<<"Before Emulation done"<<std::endl;
      std::cout<<">>> ECX = "<<std::hex << r_ecx << std::endl;
      std::cout<<">>> EDX = "<<std::hex<< r_edx<< std::endl;
    
      // initialize machine registers
      uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx);
      uc_reg_write(uc, UC_X86_REG_EDX, &r_edx);
    
      // emulate code in infinite time & unlimited instructions
      err=uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32) - 1, 0, 0);
      if (err) {
        std::cout<<"Failed on uc_emu_start() with error returned"<< err << uc_strerror(err) << std::endl;
      }
    
      // now print out some registers
      std::cout<<"Emulation done. Below is the CPU context"<<std::endl;
    
      uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx);
      uc_reg_read(uc, UC_X86_REG_EDX, &r_edx);
      std::cout<<">>> ECX = "<<std::hex << r_ecx << std::endl;
      std::cout<<">>> EDX = "<<std::hex<< r_edx<< std::endl;
    
      uc_close(uc);
    
      return 0;
    }
    

    执行结果如下:

    Emulate i386 code
    Before Emulation done
    >>> ECX = 1234
    >>> EDX = 7890
    Emulation done. Below is the CPU context
    >>> ECX = 1235
    >>> EDX = 788f
    

    从上面的例子总结如下:

    uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **uc);
    

    负责创建新的 Unicorn实例。

    uc_err uc_mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms);
    

    为模拟映射一块内存,地址首地址和长度都需要是0x1000的整倍数,在模拟过程中,左右的CPU操作都只能访问此内存。

    uc_err uc_mem_write(uc_engine *uc, uint64_t address, const void *bytes, size_t
    size);
    

    在内存中写入一段字节码。

    uc_err uc_reg_write(uc_engine *uc, int regid, const void *value);
    

    将值写入寄存器。

    uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until, uint64_t
    timeout, size_t count);
    

    在指定的时间内模拟机器码。

    uc_err uc_reg_read(uc_engine *uc, int regid, void *value);
    

    读取寄存器的值。

    hook指令介绍

    unicorn也支持多种类型的hook,类型如下:

    typedef enum uc_hook_type {
        // Hook all interrupt/syscall events
        UC_HOOK_INTR = 1 << 0,
        // Hook a particular instruction - only a very small subset of instructions
        // supported here
        UC_HOOK_INSN = 1 << 1,
        // Hook a range of code
        UC_HOOK_CODE = 1 << 2,
        // Hook basic blocks
        UC_HOOK_BLOCK = 1 << 3,
        // Hook for memory read on unmapped memory
        UC_HOOK_MEM_READ_UNMAPPED = 1 << 4,
        // Hook for invalid memory write events
        UC_HOOK_MEM_WRITE_UNMAPPED = 1 << 5,
        // Hook for invalid memory fetch for execution events
        UC_HOOK_MEM_FETCH_UNMAPPED = 1 << 6,
        // Hook for memory read on read-protected memory
        UC_HOOK_MEM_READ_PROT = 1 << 7,
        // Hook for memory write on write-protected memory
        UC_HOOK_MEM_WRITE_PROT = 1 << 8,
        // Hook for memory fetch on non-executable memory
        UC_HOOK_MEM_FETCH_PROT = 1 << 9,
        // Hook memory read events.
        UC_HOOK_MEM_READ = 1 << 10,
        // Hook memory write events.
        UC_HOOK_MEM_WRITE = 1 << 11,
        // Hook memory fetch for execution events
        UC_HOOK_MEM_FETCH = 1 << 12,
        // Hook memory read events, but only successful access.
        // The callback will be triggered after successful read.
        UC_HOOK_MEM_READ_AFTER = 1 << 13,
        // Hook invalid instructions exceptions.
        UC_HOOK_INSN_INVALID = 1 << 14,
        // Hook on new edge generation. Could be useful in program analysis.
        //
        // NOTE: This is different from UC_HOOK_BLOCK in 2 ways:
        //       1. The hook is called before executing code.
        //       2. The hook is only called when generation is triggered.
        UC_HOOK_EDGE_GENERATED = 1 << 15,
        // Hook on specific tcg op code. The usage of this hook is similar to
        // UC_HOOK_INSN.
        UC_HOOK_TCG_OPCODE = 1 << 16,
    } uc_hook_type;
    

    看一个例子如下:

    #include <string.h>
    
    #include "unicorn/unicorn.h"
    
    int syscall_abi[] = {
        UC_X86_REG_RAX, UC_X86_REG_RDI, UC_X86_REG_RSI, UC_X86_REG_RDX,
        UC_X86_REG_R10, UC_X86_REG_R8, UC_X86_REG_R9
    };
    
    uint64_t vals[7] = { 200, 10, 11, 12, 13, 14, 15 };
    void* ptrs[7];
    
    void uc_perror(const char* func, uc_err err)
    {
        fprintf(stderr, "Error in %s(): %s\n", func, uc_strerror(err));
    }
    
    #define BASE 0x10000
    
    
    // mov rax, 100; mov rdi, 1; mov rsi, 2; mov rdx, 3; mov r10, 4; mov r8, 5; mov r9, 6; syscall
    #define CODE "\x48\xc7\xc0\x64\x00\x00\x00\x48\xc7\xc7\x01\x00\x00\x00\x48\xc7\xc6\x02\x00\x00\x00\x48\xc7\xc2\x03\x00\x00\x00\x49\xc7\xc2\x04\x00\x00\x00\x49\xc7\xc0\x05\x00\x00\x00\x49\xc7\xc1\x06\x00\x00\x00\x0f\x05" 
    
    void hook_code(uc_engine *uc, uint64_t address, uint32_t size,
                          void *user_data)
    {
        printf("HOOK_CODE: 0x%" PRIx64 ", 0x%x\n", address, size);
    }
    
    int main() {
        int i;
        uc_hook sys_hook;
        uc_err err;
        uc_engine* uc;
        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;
        }
        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; 
        }
        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("%" PRIu64, vals[i]);
        }
        printf("}\n");
        // syscall
        printf("\n");
        printf("running shellcode\n");
        if ((err = uc_hook_add(uc, &sys_hook, UC_HOOK_CODE, hook_code, NULL, 1, 0))) {
            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;
        }
            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("%" PRIu64, vals[i]);
        }
        printf("}\n");
        return 0; 
    }
    

    对应的输出如下:

    reg_write_batch({200, 10, 11, 12, 13, 14, 15})
    reg_read_batch = {200, 10, 11, 12, 13, 14, 15}
    
    running shellcode
    HOOK_CODE: 0x10000, 0x7
    HOOK_CODE: 0x10007, 0x7
    HOOK_CODE: 0x1000e, 0x7
    HOOK_CODE: 0x10015, 0x7
    HOOK_CODE: 0x1001c, 0x7
    HOOK_CODE: 0x10023, 0x7
    HOOK_CODE: 0x1002a, 0x7
    HOOK_CODE: 0x10031, 0x2
    reg_read_batch = {100, 1, 2, 3, 4, 5, 6}
    

    此时每个指令执行时,都会被hook到。
    看下如下函数:

    uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback,
            void *user_data, uint64_t begin, uint64_t end, ...);
    

    注册hook事件的回调,当hook事件被触发将会进行回调。

    unicorn与Android

    再看一个unicorn调试Android的例子,看看如何在unicorn中模拟arm环境,执行Android上的so。首先写一个helloworld。

    #include <stdio.h>
    
    int main() {
      printf("Hello World\n");
      return 0;
    }
    

    使用交叉编译成android上的bin文件。查看file信息:

    a.bin: ELF 64-bit LSB pie executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /system/bin/linker64, not stripped
    

    我目前在macos上,肯定是执行不了这个bin,那接下来就需要让unicorn加载该代码,也就是把整个so都读到内存中。这儿需要考虑到代码里调用了printf这样libc的函数,unicorn里是访问不到的,那就需要跳过该地址,具体操作就是遇到执行printf的指令,也就是lr,那就直接修改pc为下一条指令。

    这儿会有一个小问题,让unicorn从哪儿开始执行呢?肯定不是从so的0地址开始执行,entry_point算是一个地址,可是我们更希望是从main开始执行,那如何做到呢?其实很简单,找一个反编译软件看下就可以了,我这边查到的结果如下:


    WeChatWorkScreenshot_e2f3fe94-2922-4412-9cf8-0977ff8ae8e2.png

    这样偏移就有了。接下来为了让指令显示更清晰下,就顺便反编译了下,这儿借助capstone就做到了。最后的执行结果如下:

    code is 0xd10083ff
    0x0:    sub sp, sp, #0x20
        op_count: 3
            operands[0].type: REG = sp
            operands[0].access: WRITE
            operands[1].type: REG = sp
            operands[1].access: READ
            operands[2].type: IMM = 0x20
            operands[2].access: READ
        Registers read: sp
        Registers modified: sp
    
    HOOK_CODE: 0x65c, 0x4
    code is 0xa9017bfd
    0x0:    stp x29, x30, [sp, #0x10]
        op_count: 3
            operands[0].type: REG = fp
            operands[0].access: READ
            operands[1].type: REG = lr
            operands[1].access: READ
            operands[2].type: MEM
                operands[2].mem.base: REG = sp
                operands[2].mem.disp: 0x10
            operands[2].access: READ | WRITE
        Registers read: fp lr sp
    
    HOOK_CODE: 0x660, 0x4
    code is 0x910043fd
    0x0:    add x29, sp, #0x10
        op_count: 3
            operands[0].type: REG = fp
            operands[0].access: WRITE
            operands[1].type: REG = sp
            operands[1].access: READ
            operands[2].type: IMM = 0x10
            operands[2].access: READ
        Registers read: sp
        Registers modified: fp
    
    HOOK_CODE: 0x664, 0x4
    code is 0x2a1f03e8
    0x0:    mov w8, wzr
        op_count: 2
            operands[0].type: REG = w8
            operands[0].access: WRITE
            operands[1].type: REG = wzr
            operands[1].access: READ
        Registers read: wzr
        Registers modified: w8
    
    HOOK_CODE: 0x668, 0x4
    code is 0xb9000be8
    0x0:    str w8, [sp, #8]
        op_count: 2
            operands[0].type: REG = w8
            operands[0].access: READ
            operands[1].type: MEM
                operands[1].mem.base: REG = sp
                operands[1].mem.disp: 0x8
            operands[1].access: READ | WRITE
        Registers read: w8 sp
    
    HOOK_CODE: 0x66c, 0x4
    code is 0xb81fc3bf
    0x0:    stur    wzr, [x29, #-4]
        op_count: 2
            operands[0].type: REG = wzr
            operands[0].access: READ
            operands[1].type: MEM
                operands[1].mem.base: REG = fp
                operands[1].mem.disp: 0xfffffffc
            operands[1].access: READ | WRITE
        Registers read: wzr fp
    
    HOOK_CODE: 0x670, 0x4
    code is 0xf0ffffe0
    0x0:    adrp    x0, #0xfffffffffffff000
        op_count: 2
            operands[0].type: REG = x0
            operands[0].access: WRITE
            operands[1].type: IMM = 0xfffffffffffff000
            operands[1].access: READ
        Registers modified: x0
    
    HOOK_CODE: 0x674, 0x4
    code is 0x91142000
    0x0:    add x0, x0, #0x508
        op_count: 3
            operands[0].type: REG = x0
            operands[0].access: WRITE
            operands[1].type: REG = x0
            operands[1].access: READ
            operands[2].type: IMM = 0x508
            operands[2].access: READ
        Registers read: x0
        Registers modified: x0
    
    HOOK_CODE: 0x678, 0x4
    code is 0x94000015
    0x0:    bl  #0x54
        op_count: 1
            operands[0].type: IMM = 0x54
            operands[0].access: READ
        Registers modified: lr
    
    HOOK_CODE: 0x67c, 0x4
    skip it
    code is 0xb9400be0
    0x0:    ldr w0, [sp, #8]
        op_count: 2
            operands[0].type: REG = w0
            operands[0].access: WRITE
            operands[1].type: MEM
                operands[1].mem.base: REG = sp
                operands[1].mem.disp: 0x8
            operands[1].access: READ
        Registers read: sp
        Registers modified: w0
    
    HOOK_CODE: 0x680, 0x4
    code is 0xa9417bfd
    0x0:    ldp x29, x30, [sp, #0x10]
        op_count: 3
            operands[0].type: REG = fp
            operands[0].access: WRITE
            operands[1].type: REG = lr
            operands[1].access: WRITE
            operands[2].type: MEM
                operands[2].mem.base: REG = sp
                operands[2].mem.disp: 0x10
            operands[2].access: READ
        Registers read: sp
        Registers modified: fp lr
    
    HOOK_CODE: 0x684, 0x4
    code is 0x910083ff
    0x0:    add sp, sp, #0x20
        op_count: 3
            operands[0].type: REG = sp
            operands[0].access: WRITE
            operands[1].type: REG = sp
            operands[1].access: READ
            operands[2].type: IMM = 0x20
            operands[2].access: READ
        Registers read: sp
        Registers modified: sp
    
    HOOK_CODE: 0x688, 0x4
    

    最后看下完整代码:

    #include <string.h>
    #include <stdlib.h>
    
    #include "unicorn/unicorn.h"
    #include <capstone/platform.h>
    #include <capstone/capstone.h>
    
    #define BASE 0x0
    
    static csh handle;
    
    uint64_t skip_list[] = {0x67c,};
    
    void uc_perror(const char* func, uc_err err)
    {
        fprintf(stderr, "Error in %s(): %s\n", func, uc_strerror(err));
    }
    
    
    static void print_string_hex(const char *comment, unsigned char *str, size_t len)
    {
        unsigned char *c;
    
        printf("%s", comment);
        for (c = str; c < str + len; c++) {
            printf("0x%02x ", *c & 0xff);
        }
    
        printf("\n");
    }
    
    static void print_insn_detail(cs_insn *ins)
    {
        cs_arm64 *arm64;
        int i;
        cs_regs regs_read, regs_write;
        unsigned char regs_read_count, regs_write_count;
        unsigned char access;
    
        // detail can be NULL if SKIPDATA option is turned ON
        if (ins->detail == NULL)
            return;
    
        arm64 = &(ins->detail->arm64);
        if (arm64->op_count)
            printf("\top_count: %u\n", arm64->op_count);
    
        for (i = 0; i < arm64->op_count; i++) {
            cs_arm64_op *op = &(arm64->operands[i]);
            switch(op->type) {
                default:
                    break;
                case ARM64_OP_REG:
                    printf("\t\toperands[%u].type: REG = %s\n", i, cs_reg_name(handle, op->reg));
                    break;
                case ARM64_OP_IMM:
                    printf("\t\toperands[%u].type: IMM = 0x%" PRIx64 "\n", i, op->imm);
                    break;
                case ARM64_OP_FP:
    #if defined(_KERNEL_MODE)
                    // Issue #681: Windows kernel does not support formatting float point
                    printf("\t\toperands[%u].type: FP = <float_point_unsupported>\n", i);
    #else
                    printf("\t\toperands[%u].type: FP = %f\n", i, op->fp);
    #endif
                    break;
                case ARM64_OP_MEM:
                    printf("\t\toperands[%u].type: MEM\n", i);
                    if (op->mem.base != ARM64_REG_INVALID)
                        printf("\t\t\toperands[%u].mem.base: REG = %s\n", i, cs_reg_name(handle, op->mem.base));
                    if (op->mem.index != ARM64_REG_INVALID)
                        printf("\t\t\toperands[%u].mem.index: REG = %s\n", i, cs_reg_name(handle, op->mem.index));
                    if (op->mem.disp != 0)
                        printf("\t\t\toperands[%u].mem.disp: 0x%x\n", i, op->mem.disp);
    
                    break;
                case ARM64_OP_CIMM:
                    printf("\t\toperands[%u].type: C-IMM = %u\n", i, (int)op->imm);
                    break;
                case ARM64_OP_REG_MRS:
                    printf("\t\toperands[%u].type: REG_MRS = 0x%x\n", i, op->reg);
                    break;
                case ARM64_OP_REG_MSR:
                    printf("\t\toperands[%u].type: REG_MSR = 0x%x\n", i, op->reg);
                    break;
                case ARM64_OP_PSTATE:
                    printf("\t\toperands[%u].type: PSTATE = 0x%x\n", i, op->pstate);
                    break;
                case ARM64_OP_SYS:
                    printf("\t\toperands[%u].type: SYS = 0x%x\n", i, op->sys);
                    break;
                case ARM64_OP_PREFETCH:
                    printf("\t\toperands[%u].type: PREFETCH = 0x%x\n", i, op->prefetch);
                    break;
                case ARM64_OP_BARRIER:
                    printf("\t\toperands[%u].type: BARRIER = 0x%x\n", i, op->barrier);
                    break;
            }
    
            access = op->access;
            switch(access) {
                default:
                    break;
                case CS_AC_READ:
                    printf("\t\toperands[%u].access: READ\n", i);
                    break;
                case CS_AC_WRITE:
                    printf("\t\toperands[%u].access: WRITE\n", i);
                    break;
                case CS_AC_READ | CS_AC_WRITE:
                    printf("\t\toperands[%u].access: READ | WRITE\n", i);
                    break;
            }
    
            if (op->shift.type != ARM64_SFT_INVALID &&
                    op->shift.value)
                printf("\t\t\tShift: type = %u, value = %u\n",
                        op->shift.type, op->shift.value);
    
            if (op->ext != ARM64_EXT_INVALID)
                printf("\t\t\tExt: %u\n", op->ext);
    
            if (op->vas != ARM64_VAS_INVALID)
                printf("\t\t\tVector Arrangement Specifier: 0x%x\n", op->vas);
    
            if (op->vector_index != -1)
                printf("\t\t\tVector Index: %u\n", op->vector_index);
        }
    
        if (arm64->update_flags)
            printf("\tUpdate-flags: True\n");
    
        if (arm64->writeback)
            printf("\tWrite-back: %s\n", arm64->post_index ? "Post" : "Pre");
    
        if (arm64->cc)
            printf("\tCode-condition: %u\n", arm64->cc);
    
        // Print out all registers accessed by this instruction (either implicit or explicit)
        if (!cs_regs_access(handle, ins,
                    regs_read, &regs_read_count,
                    regs_write, &regs_write_count)) {
            if (regs_read_count) {
                printf("\tRegisters read:");
                for(i = 0; i < regs_read_count; i++) {
                    printf(" %s", cs_reg_name(handle, regs_read[i]));
                }
                printf("\n");
            }
    
            if (regs_write_count) {
                printf("\tRegisters modified:");
                for(i = 0; i < regs_write_count; i++) {
                    printf(" %s", cs_reg_name(handle, regs_write[i]));
                }
                printf("\n");
            }
        }
    
        printf("\n");
    }
    
    void hook_code(uc_engine *uc, uint64_t address, uint32_t size,
                          void *user_data)
    {
    
        uint32_t code;
        if(uc_mem_read(uc,address, &code, sizeof(code))) {
            printf("Failed to read emulation code to memory, quit!\n");
            return;
        }
        printf("code is 0x%x\n", code);
    
        cs_insn *insn;
        int count = cs_disasm(handle, (const uint8_t*)(&code), size, 0x00, 0, &insn);
        if (count) {
                size_t j;
    
                for (j = 0; j < count; j++) {
                    printf("0x%" PRIx64 ":\t%s\t%s\n", insn[j].address, insn[j].mnemonic, insn[j].op_str);
                    print_insn_detail(&insn[j]);
                }
                //printf("0x%" PRIx64 ":\n", insn[j-1].address + insn[j-1].size);
    
                // free memory allocated by cs_disasm()
                cs_free(insn, count);
            } else {
                printf("ERROR: Failed to disasm given code!\n");
        }
    
        printf("HOOK_CODE: 0x%" PRIx64 ", 0x%x\n", address, size);
    
        uint64_t next_addr = address + size;
        for (int i = 0; i < sizeof(skip_list); i++) {
            if (address == skip_list[i]) {
                printf("skip it\n");
                uc_reg_write(uc, UC_ARM64_REG_PC, &next_addr);
            }
        }
    }
    
    bool init_capstone() {
        cs_err err = cs_open(CS_ARCH_ARM64, CS_MODE_ARM, &handle);
        if (err) {
            printf("Failed on cs_open() with error returned: %u\n", err);
            return false;
                
        }
        cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON);
        return true;
    }
    
    int main() {
        int i;
        uc_hook sys_hook;
        uc_err err;
        uc_engine* uc;
        char *data = NULL;
      
        if ((err = uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &uc))) {
            uc_perror("uc_open", err);
            return 1;
        }
    
        if (!init_capstone()) {
            goto end;
        }
        
        FILE *ptr = fopen("./a.bin", "rb");
        if (ptr == NULL) {
            printf("open fail\n");
            return 1;
        }
        fseek(ptr, 0l, SEEK_END);
        int file_size = ftell(ptr);
        fseek(ptr, 0l, SEEK_SET);
        if (file_size <= 0) {
             printf("invalid file size\n");
             goto end;
        }
    
        data = (char *)malloc(file_size);
        if (data == NULL) {
            printf("malloc fail\n");
            goto end;
        }
    
        int read_size = fread(data, 1, file_size, ptr);
        if (read_size != file_size) {
            printf("read fail\n");
            goto end;
        }
    
        if ((err = uc_mem_map(uc, BASE, 8 * 0x1000, UC_PROT_ALL))) {
            uc_perror("uc_mem_map", err);
            return 1;
        }
    
    
        if ((err = uc_mem_write(uc, BASE, data, read_size))) {
            uc_perror("uc_mem_write", err);
            return 1;
        }
    
        uint64_t stack_top = BASE + read_size + 0x1000 -0x8;
        uc_reg_write(uc, UC_ARM64_REG_SP, &stack_top);
    
        uint64_t start_addr = BASE + 0x65c;
        uint64_t end_addr = BASE + 0x68c;
    
        if ((err = uc_hook_add(uc, &sys_hook, UC_HOOK_CODE, hook_code, NULL, start_addr, end_addr))) {
            uc_perror("uc_hook_add", err);
            return 1;
        }
    
        if ((err = uc_emu_start(uc, start_addr, end_addr, 0, 0))) {
            uc_perror("uc_emu_start", err);
            return 1;
        }
    
    end:
        if (ptr != NULL) {
            fclose(ptr);
            ptr = NULL;
        }
        if (data != NULL) {
            free(data);
            data = NULL;
        }
        return 0; 
    }
    

    这样就大概介绍了下unicorn的使用,还是很有趣的。

    相关文章

      网友评论

          本文标题:unicorn 使用介绍

          本文链接:https://www.haomeiwen.com/subject/wcuhzdtx.html