예제 #1
0
static void print_insn_detail(cs_insn *ins)
{
	cs_arm64 *arm64;
	int i;
	cs_regs regs_read, regs_write;
	uint8_t regs_read_count, regs_write_count;

	// 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:
				printf("\t\toperands[%u].type: FP = %f\n", i, op->fp);
				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;
		}

		uint8_t 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->vess != ARM64_VESS_INVALID)
			printf("\t\t\tVector Element Size Specifier: %u\n", op->vess);

		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: True\n");

	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");
}
예제 #2
0
void emulate_constructor(dmp_ctx_t *ctx, uint64_t constructor_address, struct hierarchy_entry_head *head)
{
    if (!ctx)
        return;
    if (!ctx->kimage_mh || !ctx->map || !ctx->reg_map)
        return;
    
    uint64_t kimage_base = find_kimage_base(ctx->kimage_mh);
    uint64_t kimage_os_metaclass_constructor = find_kimage_os_metaclass_constructor(ctx->kimage_mh, kimage_base);
    
    csh handle;
    cs_insn *insn;
    size_t count;
    
    cs_regs regs_read = {0}, regs_write = {0};
    uint8_t read_count, write_count;
    
    if (cs_open(CS_ARCH_ARM64, CS_MODE_ARM, &handle) != CS_ERR_OK)
        return;
    
    cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON);
    
    uint8_t *constructor_code = (uint8_t *)KERNEL_ADDR_TO_MAP(ctx->kimage_mh, kimage_base, constructor_address);
    uint64_t constructor_size = get_constructor_size(ctx->kimage_mh, constructor_address, kimage_base);
    
    count = cs_disasm(handle, constructor_code, constructor_size, constructor_address, 0, &insn);
    if (count > 0) {
        size_t j;
        for (j = 0; j < count; j++) {
            if (cs_regs_access(handle, &insn[j], regs_read, &read_count, regs_write, &write_count) == 0) {
                switch (insn[j].id) {
                    case ARM64_INS_ADR: {
                        
                        uint64_t adr_addr = 0;
                        int is_adrp = 0;
                        uint32_t rd = 0;
                        int32_t off = 0;
                        if (aarch64_decode_adr(*(uint32_t *)(&insn[j].bytes), &is_adrp, &rd, &off)) {
                            adr_addr = insn[j].address + off;
                        }
                        
                        get_ctx_reg_map_reg(ctx, regs_write[0]) = adr_addr;
                        break;
                    }
                        
                    case ARM64_INS_ADRP: {
                        
                        uint64_t adr_addr = 0;
                        int is_adrp = 0;
                        uint32_t rd = 0;
                        int32_t off = 0;
                        if (aarch64_decode_adr(*(uint32_t *)(&insn[j].bytes), &is_adrp, &rd, &off)) {
                            adr_addr = ((insn[j].address + off) >> 12) << 12;
                        }
                        
                        get_ctx_reg_map_reg(ctx, regs_write[0]) = adr_addr;
                        break;
                    }
                        
                    case ARM64_INS_LDR: {
                        
                        uint64_t ldr_addr = 0;
                        int is_w = 0;
                        int is64 = 0;
                        uint32_t rt = 0;
                        
                        int32_t s_off = 0;
                        uint32_t u_off = 0;
                        
                        if (aarch64_decode_ldr_literal(*(uint32_t *)(&insn[j].bytes), &is_w, &is64, &rt, &s_off)) {
                            ldr_addr = insn[j].address + s_off;
                            uint64_t ldr_deref = *(uint64_t *)KERNEL_ADDR_TO_MAP(ctx->kimage_mh, kimage_base, ldr_addr);
                            get_ctx_reg_map_reg(ctx, regs_write[0]) = ldr_deref;
                        } else if (aarch64_decode_ldr_immediate(*(uint32_t *)(&insn[j].bytes), &u_off)) {
                            uint64_t op1 = get_ctx_reg_map_reg(ctx, regs_read[0]);
                            op1 += u_off;
                            
                            uint64_t ldr_addr = *(uint64_t *)KERNEL_ADDR_TO_MAP(ctx->kimage_mh, kimage_base, op1);
                            get_ctx_reg_map_reg(ctx, regs_write[0]) = ldr_addr;
                        }
                        
                        break;
                    }
                        
                    case ARM64_INS_ADD: {

                        uint32_t off = 0;
                        if (aarch64_decode_add(*(uint32_t *)(&insn[j].bytes), &off)) {
                            uint64_t op1 = get_ctx_reg_map_reg(ctx, regs_read[0]);
                            op1 += off;
                            get_ctx_reg_map_reg(ctx, regs_write[0]) = op1;
                        }
                        
                        break;
                    }
                        
                    case ARM64_INS_MOV: {
                        
                        uint64_t op1 = get_ctx_reg_map_reg(ctx, regs_read[0]);
                        get_ctx_reg_map_reg(ctx, regs_write[0]) = op1;
                        
                        break;
                    }
                     
                    /* ugly. libdump should be independent of iokitdumper, but I was lazy and this was the quickest way to map constructors lmao */
                    case ARM64_INS_BL: {
                        
                        int is_bl = 0;
                        int32_t off = 0;
                        if (aarch64_decode_b(*(uint32_t *)(&insn[j].bytes), &is_bl, &off)) {
                            if (insn[j].address + off == kimage_os_metaclass_constructor) {
                                
                                const char *kext_name = get_kext_name(ctx->map, ctx->kimage_mh);
                                
                                struct hierarchy_entry *entry = malloc(sizeof(struct hierarchy_entry));
                                
                                strncpy(entry->class_name, (char *)KERNEL_ADDR_TO_MAP(ctx->kimage_mh, kimage_base, get_ctx_reg_map_reg(ctx, REG_X1)), sizeof(entry->class_name));
                                if (kext_name)
                                    strncpy(entry->kext_name, kext_name, sizeof(entry->kext_name));
                                else {
                                    if (((void *)ctx->map->map_data == (void *)ctx->kimage_mh)) {
                                        strncpy(entry->kext_name, "kernel", sizeof(entry->kext_name));
                                    } else {
                                        strncpy(entry->kext_name, "unknown", sizeof(entry->kext_name));
                                    }
                                }
                                
                                struct hierarchy_regs_set set = {0};
                                set.reg_x0 = get_ctx_reg_map_reg(ctx, REG_X0);
                                set.reg_x1 = get_ctx_reg_map_reg(ctx, REG_X1);
                                set.reg_x2 = get_ctx_reg_map_reg(ctx, REG_X2);
                                
                                entry->set = set;
                                
                                if (head) {
                                    if (SLIST_EMPTY(head)) {
                                        SLIST_INSERT_HEAD(head, entry, entries);
                                        prev = entry;
                                    } else {
                                        SLIST_INSERT_AFTER(prev, entry, entries);
                                        prev = entry;
                                    }
                                } else {
                                    free(entry);
                                }
                            }
                        }
                        
                        break;
                    }
                }
            }
        }