android kernel启用kprobe

查看是否启用

 cat /proc/kallsyms | grep register_kprobe

 

 

 
默认配置

# CONFIG_KPROBES is not set
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_OPTPROBES=y
CONFIG_HAVE_KPROBES_ON_FTRACE=y

CONFIG_MODULES=y
# CONFIG_MODULE_FORCE_LOAD is not set
CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_FORCE_UNLOAD is not set

改成
CONFIG_KPROBES=y

参考资料:
http://kuester.multics.org/blog/2015/03/24/how-to-build-custom-kernel-with-kprobes/

Android Kernel Build with KProbe

具体到android

将  https://github.com/torvalds/linux/blob/master/arch/x86/configs/x86_64_defconfig 中的 CONFIG_KPROBES=y
放到 arch/x86/configs/x86_64_ranchu_defconfig

CONFIG_KPROBES=y
CONFIG_MODULES=y

编译android qemu内核

小米手机上使用sqlite3命令行工具

小米手机官方版本 不会带sqlite3

可以从 谷歌Android ARM emulator 上 pull 下来 

adb -e pull /system/xbin/sqlite

然后复制到 手机的 tmp目录

adb -d push sqlite3 /data/local/tmp/
adb -d shell
chmod a+x /data/loccal/tmp/sqlite3
/data/local/tmp/sqlite3

有些手机版本比较老, 会报错:

SQLite header and source version mismatch
….

那么需要将对应的动态链接库 也复制过去

adb -e pull /system/lib64/libsqlite.so

adb -d push libsqlite.so /data/local/tmp/
adb -d shell

LD_LIBRARY_PATH=/data/local/tmp /data/local/tmp//sqlite3

就可以正常运行

编译android emualator

定制android

https://android.googlesource.com/platform/external/qemu/+/master/docs/DEVELOPMENT.TXT

cd asop
#切换到模拟器分支
repo init -b emu-2.8-release
repo sync



cd external/qemu/android/
./rebuild.sh --no-tests
cd  ../objs
./emulator -avd  Nexus

或者

cd external/qemu/android
./configure.sh
make -j8

Linux系统调用-设置内存区别读写保护

int mprotect(void *addr, size_t len, int prot);

对调用者 进程空间的内存页(地址范围 addr 到 add+len-1) 的访问保护 进行修改.
addr 必须 页边界 对齐

prot 是 下面的访问标志的组合:
PROT_NONE : 完全不能访问
PROT_READ : 能读
PROT_WRITE : 能写
PROT_EXEC : 能执行
PROT_SEM   :  能用于 原子操作
PROT_SAO   :  强访问顺序 (PowerPC)

成功,返回0
失败, 返回 -1

————–
mmap函数 发生错误, 返回  MAP_FAILED (也就是 (void *) -1)

检测arm模拟器

代码

#include <stdio.h>
#include <sys/mman.h>

#define PROT PROT_EXEC|PROT_WRITE|PROT_READ
#define LOGI printf


int (*asmcheck)(void);

int a = -1;
int b = -1;

int detect() {
    char code[] =
            "\xF0\x41\x2D\xE9"
            "\x00\x70\xA0\xE3"
            "\x0F\x80\xA0\xE1"
            "\x00\x40\xA0\xE3"
            "\x01\x70\x87\xE2"
            "\x00\x50\x98\xE5"
            "\x01\x40\x84\xE2"
            "\x0F\x80\xA0\xE1"
            "\x0C\x80\x48\xE2"
            "\x00\x50\x88\xE5"
            "\x0A\x00\x54\xE3"
            "\x02\x00\x00\xAA"
            "\x0A\x00\x57\xE3"
            "\x00\x00\x00\xAA"
            "\xF6\xFF\xFF\xEA"
            "\x04\x00\xA0\xE1"
            "\xF0\x81\xBD\xE8";

    void *exec = mmap(NULL, (size_t) getpagesize(), PROT, MAP_ANONYMOUS | MAP_PRIVATE, -1, (off_t) 0);
    if (exec == (void *) -1) {
        LOGI(" mmap faild \n");
        int fd = fopen("/dev/zero", "w+");
        exec = mmap(NULL, (size_t) getpagesize(), PROT, MAP_SHARED, fd, (off_t) 0);
        LOGI(" mmap zero %x %x %x \n", fd, exec, exec);
        if (exec == (void *) -1) {
            return 10;
        }
    }
    
    memcpy(exec, code, sizeof(code) + 1);
    LOGI(" mmap sucess exec  %x\n", exec);
    asmcheck = (void *) exec;
    a = asmcheck();
    LOGI("a= %d  \n", a);
    munmap(exec, getpagesize());
    return a;
}


int main()
{
    int ret = detect();
    LOGI("%d detect \n", ret);
}

编译

快速编译Android C代码

~/Android/Sdk/ndk-bundle/build/tools/make_standalone_toolchain.py --arch arm --api 19   --install-dir=/dev/shm/native


export PATH=/bin:/usr/bin:/dev/shm/native/bin


target_host=arm-linux-androideabi
export AR=$target_host-ar
export AS=$target_host-clang
export CC=$target_host-clang
export CXX=$target_host-clang++
export LD=$target_host-ld
export STRIP=$target_host-strip


$CC -fPIE -pie emu.c -o ed

arm模拟器上输出 1
真机上 输出   10

参考资料:
https://wiki.koeln.ccc.de/images/d/d5/Openchaos_qemudetect.pdf
https://github.com/happylishang/CacheEmulatorChecker

第2种写法

#include <stdio.h>
#include <sys/mman.h>

__attribute__ ((naked)) int test_arm_cache()
{
  asm (
        //"STMFD   SP!, {R4-R8,LR}\n\t"
        "PUSH    {R4-R8,LR}\n\t"
        "MOV     R7, #0\n\t"
        "MOV     R8, PC\n\t"
        "MOV     R4, #0\n\t"
        "ADD     R7, R7, #1\n\t"
        "LDR     R5, [R8]\n\t"
    "YYY:\n\t"
        "ADD     R4, R4, #1\n\t"
        "MOV     R8, PC\n\t"
        "SUB     R8, R8, #0xC\n\t"
        "STR     R5, [R8]\n\t"
        "CMP     R4, #0xA\n\t"
        "BGE     exit\n\t"
        "CMP     R7, #0xA\n\t"
        "BGE     exit\n\t"
        "B       YYY\n\t"
    "exit:\n\t"
        "MOV     R0, R4\n\t"
        //"LDMFD   SP!, {R4-R8,PC}\n\t"
        "POP     {R4-R8,PC}\n\t"
  );
}


int main() {
    int status = mprotect ((int)test_arm_cache & 0xFFFFF000, 4096, PROT_READ|PROT_WRITE|PROT_EXEC);
    if(status == 0) {
        int a = test_arm_cache();
        printf("test arm cache=%d\n", a);
    }
        
    return 0;
}

编译

$CC -fPIE -pie test.c -O2  -o arm2

上述代码为了在 armeabi 设置下编译下通过,需要魔改

android-ndk-r15c/build/cmake/android.toolchain.cmake

# Toolchain and ABI specific flags.
if(ANDROID_ABI STREQUAL armeabi)
list(APPEND ANDROID_COMPILER_FLAGS
# -march=armv5te
-march=armv7-a
-mtune=xscale
-msoft-float)
endif()

....

if(ANDROID_ABI MATCHES "^armeabi(-v7a)?$")
set(ANDROID_SYSROOT_ABI arm)
set(ANDROID_TOOLCHAIN_NAME arm-linux-androideabi)
set(ANDROID_TOOLCHAIN_ROOT ${ANDROID_TOOLCHAIN_NAME})
set(ANDROID_HEADER_TRIPLE arm-linux-androideabi)
if(ANDROID_ABI STREQUAL armeabi)
#set(CMAKE_SYSTEM_PROCESSOR armv5te)
#set(ANDROID_LLVM_TRIPLE armv5te-none-linux-androideabi)
set(CMAKE_SYSTEM_PROCESSOR armv7-a)
set(ANDROID_LLVM_TRIPLE armv7-none-linux-androideabi)
elseif(ANDROID_ABI STREQUAL armeabi-v7a)
set(CMAKE_SYSTEM_PROCESSOR armv7-a)
set(ANDROID_LLVM_TRIPLE armv7-none-linux-androideabi)
endif()

.....


if(DEFINED ANDROID_FORCE_ARM_BUILD AND NOT ANDROID_ARM_MODE)
  if(ANDROID_FORCE_ARM_BUILD)
    set(ANDROID_ARM_MODE arm)
  else()
    set(ANDROID_ARM_MODE thumb)
  endif()
endif()
....
if(ANDROID_ARM_MODE STREQUAL arm)
  set(ANDROID_FORCE_ARM_BUILD TRUE)
endif()


.....

所以


  defaultConfig {
...
        externalNativeBuild {
            cmake {
                arguments "-DANDROID_ARM_MODE=arm"
            }
        }
... 
  }


    externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt"
        }
    }

linux系统调用–得到目录条目

int getdents(unsigned int fd, struct linux_dirent *dirp, unsigned int count);

类似于C库中的 readdir

https://linux.die.net/man/2/getdents64
http://man7.org/linux/man-pages/man2/getdents.2.html

在 read 之前 必须 open
所以, 守住 openat就可以了

linux系统调用-检查一个文件的用户权限

access 和 faccessat

int access(const char *pathname, int mode);

int faccessat(int dirfd, const char *pathname, int mode, int flags);

access检查 调用进程 是否 能 访问 pathname
如果 pathname 是一个符号链接, 那么要进行解析.
    mode的值 可以为 F_OK, R_OK, W_OK, X_OK等.
         F_OK 测试文件是否存在
         R_OK, W_OK, X_OK检查是否由读,写, 执行权限.
     检查会使用 调用进程 真实的 UID和GID

geteuid ()
getuid ()

Android多用户

术语定义:

用户(User)
每个用户 被不同的人使用, 每个用户都有不同的应用程序数据和一些独特的设置。当另一个用户处于活动状态时,用户可以在后台运行;系统会在适当的时候管理关闭用户以节省资源。辅用户 可以直接通过 主用户 界面或从设备管理应用程序创建。
     

    
帐号(Account)
帐户包含在用户中,但不是由用户定义的,也不是由任何给定帐户定义或关联的用户。用户和个人资料(Profile)包含他们自己的唯一帐户,但不要求帐户具有功能。帐户列表因用户而异。

    

配置(Profile)
   配置文件有单独的app数据,但共享一些系统范围的设置(例如,Wi-Fi和蓝牙)。配置文件是用户存在的一个子集,并与用户绑定。用户可以有多个配置文件。它们是通过设备管理应用程序创建的。配置文件始终与父用户具有不可变关联,由创建配置文件的用户定义。配置文件不会超出创建用户的生命周期。

应用(App)
应用程序的数据存在于每个关联的用户中。应用程序数据 跟 同一用户内的其他应用程序进行沙盒隔离。同一用户中的应用程序可以通过IPC交互。

Profile类型
   1.  Managed  由一个含有工作数据和应用的应用程序创建.  它们仅由配置文件所有者(创建公司配置文件的应用程序)管理。 启动器,通知和最近的任务由主用户和公司配置文件共享.
   2.  Restricted   使用基于主要用户的帐户,主要用户可以控制受限个人资料中可用的应用程序。 仅适用于平板电脑和电视设备。

受管配置文件可以由主用户中的任何应用程序创建。在创建之前向用户通知管理的配置文件行为和策略实施。

受管配置文件中的应用程序,通知和窗口小部件始终带有标记,并且通常与主用户的用户界面(UI)元素一起提供。

受管配置文件中的帐户与主要用户明显不同。无法跨 Profile-User边界访问凭据(credentials)。只有各自上下文中的应用才能访问其各自的帐户。

当主用户和受管配置文件中存在相同的应用程序时,应用程序将只能看到自己的分隔数据。通常,应用程序彼此独立运行,并且无法在Profile-User边界上彼此直接通信。

Intent意图
管理员 控制 意向是否在 受管配置中,resolved in/out。
来自受管配置文件的应用程序的默认范围是保留在 受管配置文件 中(也就是主用户看不到), 但是 Device Policy API例外。

托管配置文件是作为一种新的辅助用户实现的,例如:

uid = 100000 * userid + appid

他们有像普通用户一样的独立应用数据:
/数据/用户/ <用户ID>

新的Launcher API允许启动器显示带标记的应用程序,并将托管配置文件中的小部件与主配置文件中的应用程序一起白名单,而无需切换用户。

配置文件的所有者是一个应用程序, 比如 testdpc, island, 或者双开设置

设备策略客户端(DPC)应用程序通常用作配置文件所有者。 DPC应用通常由企业移动性管理(EMM)合作伙伴提供,例如Google Apps Device Policy。

android managed profiles

https://github.com/googlesamples/android-BasicManagedProfile
https://github.com/googlesamples/android-testdpc

https://play.google.com/store/apps/details?id=com.afwsamples.testdpc
https://www.coolapk.com/apk/com.oasisfeng.island

device policy controller
work profile

https://developer.android.com/work/managed-profiles
===============
pm list users
Users:
UserInfo{0:机主:13} running
UserInfo{10:security space:50000010} running
UserInfo{999:XSpace:800010} running

============================================================

Users:
UserInfo{0:机主:13} running
UserInfo{10:Island:30} running
UserInfo{11:zhiwei:10}
UserInfo{12:新用户:0}
UserInfo{13:新用户:0}
UserInfo{14:新用户:0}
UserInfo{999:Multi-App:4000030} running
============================================================

am start --user  0 -n "com.tencent.mm/.ui.LauncherUI" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
am start --user  10  -n "com.tencent.mm/.ui.LauncherUI" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
am start --user  999  -n "com.tencent.mm/.ui.LauncherUI" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER

都能正确执行

Managed Profile可以与用户的个人Profile共存

开发者应该明白,除非管理员明确允许,Android Intention是无法跨Profile的。而Managed Profile包含的应用数量有限,因此,可能会没有合适的应用来处理Managed Profile中的Intent,这会导致功能缺失,甚至在处理不当时应用闪退。为了避免这种情况,开发者必须调用Intent.resolveActivity()来检查自己的Intent是否有对应的处理对象。如果失败,则尽可能清晰地通知用户。此外,开发者也不要假设所有设备功能都是有效的,因为管理员可以在Managed Profile中禁用某些功能。

另一个问题源于Profile拥有独立的存储区域。这意味着文件URI无法跨Profile传递。如果Managed Profile的应用触发Intent并传递一个文件URI,而这个文件URI是由用户个人Profile中的应用处理时,将会导致失败。文件URI应该使用FileProvider.getUriForFile()包装成Content URI再传递。