首页 > 解决方案 > IDA 调试 Android 内核 - 查找 check_flags() 地址

问题描述

IDA 的新手,不确定我看到的是正确还是错误。

从我的手机(aarch64,三星 S7 Edge)加载 zImage 内核图像。加载 kallsyms,将其添加到 IDA

想用ptmx_fops地址覆盖check_flags,通过反转fcntl syscall得到check_flags偏移量

试图找到这里使用的 check_flags() 函数的偏移量:

fs/fcntl.c

#define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | O_DIRECT | O_NOATIME)

static int setfl(int fd, struct file * filp, unsigned long arg)
{
    struct inode * inode = file_inode(filp);
    int error = 0;

    /*
     * O_APPEND cannot be cleared if the file is marked as append-only
     * and the file is open for write.
     */
    if (((arg ^ filp->f_flags) & O_APPEND) && IS_APPEND(inode))
        return -EPERM;

    /* O_NOATIME can only be set by the owner or superuser */
    if ((arg & O_NOATIME) && !(filp->f_flags & O_NOATIME))
        if (!inode_owner_or_capable(inode))
            return -EPERM;

    /* required for strict SunOS emulation */
    if (O_NONBLOCK != O_NDELAY)
           if (arg & O_NDELAY)
           arg |= O_NONBLOCK;

    if (arg & O_DIRECT) {
        if (!filp->f_mapping || !filp->f_mapping->a_ops ||
            !filp->f_mapping->a_ops->direct_IO)
                return -EINVAL;
    }

    if (filp->f_op->check_flags)
        error = filp->f_op->check_flags(arg);
    if (error) 
        return error;

    /*
     * ->fasync() is responsible for setting the FASYNC bit.
     */
    if (((arg ^ filp->f_flags) & FASYNC) && filp->f_op->fasync) {
        error = filp->f_op->fasync(fd, filp, (arg & FASYNC) != 0);
        if (error < 0)
            goto out;
        if (error > 0)
            error = 0;
    }
    spin_lock(&filp->f_lock);
    filp->f_flags = (arg & SETFL_MASK) | (filp->f_flags & ~SETFL_MASK);
    spin_unlock(&filp->f_lock);

 out:
    return error;
}

听说:

fcntl.c 的 setfl() 中使用了 check_flags 函数。大多数时候它内联在 sys_fcntl 中,因此您可以从 kallsyms 中找到该地址并从那里找到它。

在 IDA 但是我看到了这个:

在此处输入图像描述

在此处输入图像描述

在此处输入图像描述

问题:

  1. 如何在这里找到 check_flags() 的偏移量(在代码中:)if (filp->f_op->check_flags)?使用什么方法?
  2. 为什么反汇编指向 unk_* 部分?他们指向 DCB 的位置?那些是什么?
  3. 试图做一个快捷方式

也有内核的源代码并尝试导出

fs/btrfs/ioctl.c

static int check_flags(unsigned int flags)
{
    if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \
              FS_NOATIME_FL | FS_NODUMP_FL | \
              FS_SYNC_FL | FS_DIRSYNC_FL | \
              FS_NOCOMP_FL | FS_COMPR_FL |
              FS_NOCOW_FL))
        return -EOPNOTSUPP;

    if ((flags & FS_NOCOMP_FL) && (flags & FS_COMPR_FL))
        return -EINVAL;

    return 0;
}

EXPORT_SYMBOL(check_flags);

重新编译,但符号不在 vmlinux 和 System.map 中:/

内核配置:

CONFIG_KALLSYMS=y
CONFIG_KALLSYMS_ALL=y

有任何想法吗?

也许这也有帮助:

驱动程序/tty/pty.c

static struct file_operations ptmx_fops;

ptmx_fops.open = ptmx_open;

知道如何计算 check_flags 的偏移量:

驱动程序/tty/pty.c

struct file_operations {
    struct module *owner;
    loff_t (*llseek) (struct file *, loff_t, int);
    ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
    ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
    ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
    ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
    ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
    ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
    int (*iterate) (struct file *, struct dir_context *);
    unsigned int (*poll) (struct file *, struct poll_table_struct *);
    long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
    long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
    int (*mmap) (struct file *, struct vm_area_struct *);
    int (*open) (struct inode *, struct file *);
    int (*flush) (struct file *, fl_owner_t id);
    int (*release) (struct inode *, struct file *);
    int (*fsync) (struct file *, loff_t, loff_t, int datasync);
    int (*aio_fsync) (struct kiocb *, int datasync);
    int (*fasync) (int, struct file *, int);
    int (*lock) (struct file *, int, struct file_lock *);
    ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
    unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
    int (*check_flags)(int);
    int (*flock) (struct file *, int, struct file_lock *);
    ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
    ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
    int (*setlease)(struct file *, long, struct file_lock **, void **);
    long (*fallocate)(struct file *file, int mode, loff_t offset,
              loff_t len);
    int (*show_fdinfo)(struct seq_file *m, struct file *f);
    struct file* (*get_lower_file)(struct file *f);
};

更新1:

静态结构文件操作ptmx_fops;

ptmx_fops.open = ptmx_open;

该结构似乎有 15 个字节大

/usr/bin/aarch64-linux-gnu-nm -a --target elf64-littleaarch64 vmlinux| grep ptmx_fops
ffffffc00229aa00 b ptmx_fops
ffffffc00229aaf0 b ptmx_fops2

在这里,我在 drivers/tty/pty.c 中将 check_flags 导出为静态

/usr/bin/aarch64-linux-gnu-nm -a --target elf64-littleaarch64 vmlinux| grep check_flags
ffffffc0001aa098 t bad_file_check_flags
ffffffc0003ff854 t check_flags
ffffffc0001a0c04 T fiemap_check_flags
ffffffc00042416c t kbase_check_flags

但是我想用系统一.....那么如何在struct中找到15字节的check_flags是哪个字节呢?

更新 2

Puuuuuh ...我做到了...将我的自定义内核上传到三星S7 Edge ....现在我可以调试它了

更新 3

其实我成功了

https://github.com/marcinguy/CVE-2019-2215#update-5

标签: androiddisassemblyida

解决方案


推荐阅读