Android ashmem hacking

/**********************************************************************
 *                     Android ashmem hacking
 * 声明:
 *     最近有些东西涉及到binder,而binder又涉及到ashmem,于是先跟一下这
 * 部分的内容。
 *
 *                                    2016-1-12 深圳 南山平山村 曾剑锋
 *********************************************************************/

/**
 * 参考文章:
 *     Android系统匿名共享内存Ashmem(Anonymous Shared Memory)驱动程序源代码分析
 *         http://blog.csdn.net/luoshengyang/article/details/6664554
 */

/*
 * ashmem_area - anonymous shared memory area
 * Lifecycle: From our parent file‘s open() until its release()
 * Locking: Protected by `ashmem_mutex‘
 * Big Note: Mappings do NOT pin this structure; it dies on close()
 */
struct ashmem_area {
    char name[ASHMEM_FULL_NAME_LEN];/* optional name for /proc/pid/maps */
    struct list_head unpinned_list;    /* list of all ashmem areas */
    struct file *file;        /* the shmem-based backing file */
    size_t size;            /* size of the mapping, in bytes */
    unsigned long prot_mask;    /* allowed prot bits, as vm_flags */
};                                                                                                  

/*
 * ashmem_range - represents an interval of unpinned (evictable) pages
 * Lifecycle: From unpin to pin
 * Locking: Protected by `ashmem_mutex‘
 */
struct ashmem_range {
    struct list_head lru;        /* entry in LRU list */
    struct list_head unpinned;    /* entry in its area‘s unpinned list */
    struct ashmem_area *asma;    /* associated area */
    size_t pgstart;            /* starting page, inclusive */
    size_t pgend;            /* ending page, inclusive */
    unsigned int purged;        /* ASHMEM_NOT or ASHMEM_WAS_PURGED */
};                                                                                                  

module_init(ashmem_init);             ----------+
module_exit(ashmem_exit);                       |
                                                |
static int __init ashmem_init(void)   <---------+
{
    int ret;                                                                                        

    // static struct kmem_cache *ashmem_area_cachep __read_mostly;
    ashmem_area_cachep = kmem_cache_create("ashmem_area_cache",
                      sizeof(struct ashmem_area),
                      0, 0, NULL);
    if (unlikely(!ashmem_area_cachep)) {
        printk(KERN_ERR "ashmem: failed to create slab cache\n");
        return -ENOMEM;
    }                                                                                               

    ashmem_range_cachep = kmem_cache_create("ashmem_range_cache",
                      sizeof(struct ashmem_range),
                      0, 0, NULL);
    if (unlikely(!ashmem_range_cachep)) {
        printk(KERN_ERR "ashmem: failed to create slab cache\n");
        return -ENOMEM;
    }                                                                                               

    ret = misc_register(&ashmem_misc);             -------------------+
    if (unlikely(ret)) {                                              |
        printk(KERN_ERR "ashmem: failed to register misc device!\n"); |
        return ret;                                                   |
    }                                                                 |
                                                                      |
    register_shrinker(&ashmem_shrinker);                              |
                                                                      |
    printk(KERN_INFO "ashmem: initialized\n");                        |
                                                                      |
    return 0;                                                         |
}                                                                     |
                                                                      |
static struct file_operations ashmem_fops = {      <-------+          |
    .owner = THIS_MODULE,                                  |          |
    .open = ashmem_open,                            -------*-+        |
    .release = ashmem_release,                             | |        |
        .read = ashmem_read,                               | |        |
        .llseek = ashmem_llseek,                           | |        |
    .mmap = ashmem_mmap,                    ---------------*-*--------*---------+
    .unlocked_ioctl = ashmem_ioctl,         ---------------*-*--------*-------+ |
    .compat_ioctl = ashmem_ioctl,                          | |        |       | |
};                                                         | |        |       | |
                                                           | |        |       | |
static struct miscdevice ashmem_misc = {           <-------*-*--------+       | |
    .minor = MISC_DYNAMIC_MINOR,                           | |                | |
    .name = "ashmem",                                      | |                | |
    .fops = &ashmem_fops,                          --------+ |                | |
};               +-------------------------------------------+                | |
                 V                                                            | |
static int ashmem_open(struct inode *inode, struct file *file)                | |
{                                                                             | |
    struct ashmem_area *asma;                                                 | |
    int ret;                                                                  | |
                                                                              | |
    ret = generic_file_open(inode, file);                                     | |
    if (unlikely(ret))                                                        | |
        return ret;                                                           | |
                                                                              | |
    // static struct kmem_cache *ashmem_area_cachep __read_mostly;            | |
    // ashmem_area_cachep = kmem_cache_create("ashmem_area_cache",            | |
    //                   sizeof(struct ashmem_area),                          | |
    //                   0, 0, NULL);                                         | |
    asma = kmem_cache_zalloc(ashmem_area_cachep, GFP_KERNEL);                 | |
    if (unlikely(!asma))                                                      | |
        return -ENOMEM;                                                       | |
                                                                              | |
    INIT_LIST_HEAD(&asma->unpinned_list);                                     | |
    // #define ASHMEM_NAME_PREFIX "dev/ashmem/"                               | |
    // #define ASHMEM_NAME_PREFIX_LEN (sizeof(ASHMEM_NAME_PREFIX) - 1)        | |
    // #define ASHMEM_FULL_NAME_LEN (ASHMEM_NAME_LEN + ASHMEM_NAME_PREFIX_LEN)| |
    memcpy(asma->name, ASHMEM_NAME_PREFIX, ASHMEM_NAME_PREFIX_LEN);           | |
    // #define PROT_MASK        (PROT_EXEC | PROT_READ | PROT_WRITE)          | |
    asma->prot_mask = PROT_MASK;                                              | |
    // can get this asma struct in other function                             | |
    file->private_data = asma;                                                | |
                                                                              | |
    return 0;     +-----------------------------------------------------------+ |
}                 |                                                             |
                  V                                                             |
static long ashmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)|
{                                                                               |
    struct ashmem_area *asma = file->private_data;                              |
    long ret = -ENOTTY;                                                         |
                                                                                |
    switch (cmd) {                                                              |
    case ASHMEM_SET_NAME:                                                       |
        ret = set_name(asma, (void __user *) arg);      -------+                |
        break;                                                 |                |
    case ASHMEM_GET_NAME:                                      |                |
        ret = get_name(asma, (void __user *) arg);      -------*-----+          |
        break;                                                 |     |          |
    case ASHMEM_SET_SIZE:                                      |     |          |
        ret = -EINVAL;                                         |     |          |
        if (!asma->file) {                                     |     |          |
            ret = 0;                                           |     |          |
            asma->size = (size_t) arg;                         |     |          |
        }                                                      |     |          |
        break;                                                 |     |          |
    case ASHMEM_GET_SIZE:                                      |     |          |
        ret = asma->size;                                      |     |          |
        break;                                                 |     |          |
    case ASHMEM_SET_PROT_MASK:                                 |     |          |
        ret = set_prot_mask(asma, arg);                        |     |          |
        break;                                                 |     |          |
    case ASHMEM_GET_PROT_MASK:                                 |     |          |
        ret = asma->prot_mask;                                 |     |          |
        break;                                                 |     |          |
    case ASHMEM_PIN:                                           |     |          |
    case ASHMEM_UNPIN:                                         |     |          |
    case ASHMEM_GET_PIN_STATUS:                                |     |          |
        ret = ashmem_pin_unpin(asma, cmd, (void __user *) arg);|     |          |
        break;                                                 |     |          |
    case ASHMEM_PURGE_ALL_CACHES:                              |     |          |
        ret = -EPERM;                                          |     |          |
        if (capable(CAP_SYS_ADMIN)) {                          |     |          |
            struct shrink_control sc = {                       |     |          |
                .gfp_mask = GFP_KERNEL,                        |     |          |
                .nr_to_scan = 0,                               |     |          |
            };                                                 |     |          |
            ret = ashmem_shrink(&ashmem_shrinker, &sc);        |     |          |
            sc.nr_to_scan = ret;                               |     |          |
            ashmem_shrink(&ashmem_shrinker, &sc);              |     |          |
        }                                                      |     |          |
        break;                                                 |     |          |
    }                                                          |     |          |
                                                               |     |          |
    return ret;                                                |     |          |
}               +----------------------------------------------+     |          |
                V                                                    |          |
static int set_name(struct ashmem_area *asma, void __user *name)     |          |
{                                                                    |          |
    int ret = 0;                                                     |          |
                                                                     |          |
    mutex_lock(&ashmem_mutex);                                       |          |
                                                                     |          |
    /* cannot change an existing mapping‘s name */                   |          |
    if (unlikely(asma->file)) {                                      |          |
        ret = -EINVAL;                                               |          |
        goto out;                                                    |          |
    }                                                                |          |
                                                                     |          |
    if (unlikely(copy_from_user(asma->name + ASHMEM_NAME_PREFIX_LEN, |          |
                    name, ASHMEM_NAME_LEN)))                         |          |
        ret = -EFAULT;                                               |          |
    asma->name[ASHMEM_FULL_NAME_LEN-1] = ‘\0‘;                       |          |
                                                                     |          |
out:                                                                 |          |
    mutex_unlock(&ashmem_mutex);                                     |          |
                                                                     |          |
    return ret;                                                      |          |
}             +------------------------------------------------------+          |
              V                                                                 |
static int get_name(struct ashmem_area *asma, void __user *name)                |
{                                                                               |
    int ret = 0;                                                                |
                                                                                |
    mutex_lock(&ashmem_mutex);                                                  |
    if (asma->name[ASHMEM_NAME_PREFIX_LEN] != ‘\0‘) {                           |
        size_t len;                                                             |
                                                                                |
        /*                                                                      |
         * Copying only `len‘, instead of ASHMEM_NAME_LEN, bytes                |
         * prevents us from revealing one user‘s stack to another.              |
         */                                                                     |
        len = strlen(asma->name + ASHMEM_NAME_PREFIX_LEN) + 1;                  |
        if (unlikely(copy_to_user(name,                                         |
                asma->name + ASHMEM_NAME_PREFIX_LEN, len)))                     |
            ret = -EFAULT;                                                      |
    } else {                                                                    |
        if (unlikely(copy_to_user(name, ASHMEM_NAME_DEF,                        |
                      sizeof(ASHMEM_NAME_DEF))))                                |
            ret = -EFAULT;                                                      |
    }                                                                           |
    mutex_unlock(&ashmem_mutex);                                                |
                                                                                |
    return ret;                                                                 |
}                                                                               |
                                                                                |
static int ashmem_mmap(struct file *file, struct vm_area_struct *vma)  <--------+
{
    struct ashmem_area *asma = file->private_data;
    int ret = 0;                                                                                    

    mutex_lock(&ashmem_mutex);                                                                      

    /* user needs to SET_SIZE before mapping */
    if (unlikely(!asma->size)) {
        ret = -EINVAL;
        goto out;
    }                                                                                               

    /* requested protection bits must match our allowed protection mask */
    if (unlikely((vma->vm_flags & ~calc_vm_prot_bits(asma->prot_mask)) &
                        calc_vm_prot_bits(PROT_MASK))) {
        ret = -EPERM;
        goto out;
    }
    vma->vm_flags &= ~calc_vm_may_flags(~asma->prot_mask);                                          

    if (!asma->file) {
        char *name = ASHMEM_NAME_DEF;
        struct file *vmfile;                                                                        

        if (asma->name[ASHMEM_NAME_PREFIX_LEN] != ‘\0‘)
            name = asma->name;                                                                      

        /* ... and allocate the backing shmem file */
        vmfile = shmem_file_setup(name, asma->size, vma->vm_flags);
        if (unlikely(IS_ERR(vmfile))) {
            ret = PTR_ERR(vmfile);
            goto out;
        }
        asma->file = vmfile;
    }
    // #define get_file(x)    atomic_long_inc(&(x)->f_count)
    get_file(asma->file);                                                                           

    if (vma->vm_flags & VM_SHARED)
        shmem_set_file(vma, asma->file);   --------------+
    else {                                               |
        if (vma->vm_file)                                |
            fput(vma->vm_file);                          |
        vma->vm_file = asma->file;                       |
    }                                                    |
    vma->vm_flags |= VM_CAN_NONLINEAR;                   |
                                                         |
out:                                                     |
    mutex_unlock(&ashmem_mutex);                         |
    return ret;                                          |
}             +------------------------------------------+
              v
void shmem_set_file(struct vm_area_struct *vma, struct file *file)
{
    if (vma->vm_file)
        fput(vma->vm_file);                -------------+
    vma->vm_file = file;                                |
    vma->vm_ops = &shmem_vm_ops;                        |
    vma->vm_flags |= VM_CAN_NONLINEAR;                  |
}                                                       |
                                                        |
void fput(struct file *file)               <------------+
{
    if (atomic_long_dec_and_test(&file->f_count))
        __fput(file);
}                                                                                                   
时间: 2024-12-08 08:29:50

Android ashmem hacking的相关文章

mokoid android open source HAL hacking in a picture

/************************************************************************** * mokoid android HAL hacking in a picture * 声明: * 之前已经对mokoid开源项目源代码进行跟踪分析,但是总感觉对其中的工作 * 机制运行理解不到位,所以索性这次采用更直观的分析方式,用图来表示她的工 * 做原理,调用机制. * * 2016-1-3 深圳 南山平山村 曾剑锋 ***********

Android 开发之 ---- 底层驱动开发(一)

驱动概述 说到 Android 驱动是离不开 Linux 驱动的.Android 内核采用的是 Linux2.6 内核 (最近Linux 3.3 已经包含了一些 Android 代码).但 Android 并没有完全照搬 Linux 系统内核,除了对Linux 进行部分修正,还增加了不少内容.android 驱动 主要分两种类型:Android 专用驱动 和 Android 使用的设备驱动(linux). Android 专有驱动程序: 1)Android Ashmem 匿名共享内存: 为用户空

Android native进程间通信实例-binder结合共享内存

在android源码的驱动目录下,一般会有共享内存的相关实现源码,目录是:kernel\drivers\staging\android\ashmem.c.但是本篇文章不是讲解android共享内存的功能实现原理,而是讲怎么运用它. 1. 在linux中,不同进程间拥有自己独立的内存空间,32位操作系统中好像一个进程能用的内存大小是4G吧.而且一般不同进程间不能够互相使用各自内存的数据. 当然不同进程间共享数据方法很多,比如之前说的进程间通信binder,socket等等,不过android出了一

第一章读书笔记

ndroid系统移植的主要工作 系统移植:让android操作系统在某一个特定平台上运行,条件是 操作系统支持硬件平台的CPU架构.移植linux驱动.移植HAL(HAL位于第二层,android SDK通过HAL直接访问linux驱动),后两个是android系统移植的主要工作. 应用移植:第四层的应用程序一直到一个特定平台上,由于硬件平台之间有差异,android SDK API有可能存在差异,需要对源代码进行修改,并不涉及驱动和HAL程序库. 说到 Android 驱动是离不开 Linux

移动安全初探:窃取微信聊天记录、Hacking Android with Metasploit

在这篇文章中我们将讨论如何获取安卓.苹果设备中的微信聊天记录,并演示如何利用后门通过Metasploit对安卓设备进行控制.文章比较基础.可动手性强,有设备的童鞋不妨边阅读文章边操作,希望能激发大家对移动终端的安全兴趣. (文章内容存在一定攻击性,目的在于普及终端安全知识.提高安全意识,如有非法使用,后果自负) “如何获取Android.iPhone手机上的微信聊天记录? ” 0×00 条件: 安卓设备已获取root权限,安装SSHDroid(通过ssh.ftp连接手机) Apple设备越狱,安

I.MX6 android BatteryService jni hacking

/**************************************************************************** * I.MX6 android BatteryService jni hacking * 声明: * 本文主要是为了知道Android的获取的电源管理的数据的jni是从Linux系统的 * 什么位置获取的,获取的机制是什么. * * 2016-2-22 深圳 南山平山村 曾剑锋 ********************************

Android custom View AirConditionerView hacking

package com.example.arc.view; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.RectF; import android.graphics.SweepGradient; import android.util.Attr

AM335x Android eMMC mkmmc-android.sh hacking

# AM335x Android eMMC mkmmc-android.sh hacking # # 1. 有空解读一下android的分区文件. # 2. 代码来源:https://github.com/hendersa/bbbandroid-external-ti_android_utilities/blob/master/am335x/mk-mmc/mkmmc-android.sh # # 2016-9-8 深圳 南山平山村 曾剑锋 #!/bin/bash # 如果参数只有一个,这里就会直

‘【译】android的审计和hacking工具

原文:Best Android Tools For Security Audit and Hacking          (不开心,找点事情做<<<) android系统占移动市场份额的80%且有恶意软件,这是一个问题.Hacker会对手机恶意操作,不只是发送扣费短信.在本文,将会介绍对各式各样的app进行渗透测试和攻击(包含网络测试.网络攻击.嗅探等). Hackode:使用教程 Hackode是一个app.它是黑客的工具箱,可以为渗透测试者.白帽子.IT管理员和计算机安全从业者提供