吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 32032|回复: 63
收起左侧

[Android 分享] 逆向修改内核,绕过TracerPID反调试

[复制链接]
527900417 发表于 2018-5-2 16:10
本帖最后由 527900417 于 2018-11-21 00:39 编辑

前言

上次DDCTF结束后,和BinCrack师傅交流,他提到用了自己编译的安卓内核,直接修改源码更改了TracerPID,之后在国赛也遇到了对status的检测,虽然可以修改内存绕过(ref 4),但是还是想试一试把内核patch掉。查阅了很多资料后,大概有三种方法:
1.修改源码,重新编译内核 (ref 2)
2.逆向修改内核文件,patch二进制文件
3.hook fopen 函数,检测/proc/pid/status调用 (ref 3)
比较了几种方法的工作量和自己的基础知识(并没有),选择了第二种方法,以看雪的一篇文章最为典型,但由于机型和版本的区别,遇到了几个坑,找到了一个较为通用的方法。
以下工作基于samsung note3 9008,armeabi-v7a2,第三方官改rom,5.0,twrp rec
原文同时保存在blog

准备工作

boot.img提取

首先确保有root权限
先找到目录
FrjzAn1q1REOE1uVjeqAAdRNZ_F7
将boot导出为boot.img      

dd if=/dev/block/mmcblk0p14 of=/data/local/boot.img
adb pull /data/local/boot.img boot.img
准备bootimg-tools工具

bootimg-tools工具是一款基于mkbootimg开发的boot.img 解包重打包C语言工具,github地址:https://github.com/pbatard/bootimg-tools
git clone https://github.com/pbatard/bootimg-tools.git
下载后进入bootimg-tools目录,执行make 命令编译该项目,在 makebootimg目录下生成了相应的二进制执行文件。
Fn45BYYDxqbHlZYJM58anzcVoN0M
解开boot.img
FnUZUhSF5S9Pzn7fK2Qdd5RIexvb

注:使用其他工具一直提取失败,最后回头来看其实并不重要,如果熟悉boot.img格式的话,手动提取也可以。但是三星的这个文件,试了很多工具,也只有上面提到的这个工具能提取出来,但打包有些问题,后面有相应的解决方法。

提取原始zImage

将kernel文件复制为文件名为zImage.gz的文件,并使用010editor查找十六进制1f 8b 08 00,找到后把前面的数据全删掉,使文件变成标准的gzip压缩文件,这样子就可以使用gunzip解压了。
命令:gunzip zImage.gz
生成文件就是祼二进制文件zImage。
FkC2yIHjESZO3I01isl_G-oNR0dL

内核修改

zImage文件可以直接使用IDA(推荐6.8,7.0的话需要自己尝试定位函数)去打开,但需要设置参数。
FoOzIFTNngyh84Kugw9HdBHOq2JG
在上图,设置处理器类型为ARM Little-endian,点ok后,弹下图
FiJkPZPoiGsNUOvBy9f8XebfF5BY
在ROM start address和Loading address填0xc0008000,点ok,没有函数名,不方便定位代码。

先回到root下的adb shell,输入命令:
echo 0 > /proc/sys/kernel/kptr_restrict
关闭符号屏蔽
再输入以下命令查看这两函数的地址

echo 0 > /proc/sys/kernel/kptr_restrict
cat /proc/kallsyms |grep proc_pid_status
cat /proc/kallsyms |grep __task_pid_nr_ns

FtRMzOapuBcKrx3TeW9iF0CcGDSp
回到IDA,按g跳转到c0964058(__task_pid_nr_ns)地址处,在光标放在在该函数处:
FmrtCdEToGBDhoGtwZOfRcK-HV-J
然后按x,弹出引用搜索框,找到sub_c0888ac0(这里由于解析程度不同,显示和我的会不一样,但是重点在于sub_c0888ac0),双击进入。
FmxiBVfo80w0b-WnOCbdwIoOGqCo
如果IDA没有分析出该函数,就进行以下操作:按shift+f12,搜索TracerPid,找到以下项
Ft9ttPWjfE0jsR2E2jYMqMZEw-Wf
双击
FkP-Bo421kItvfV_cDQsHlkpI3cN
我这里是没有解析出来引用函数的,如果有引用函数,跟进去就可以解析出来sub_c0888ac0了。
在这里,我们强制解析sub_c0888ac0函数,按g输入c0888ac0,如果ida没有识别为函数,按p强制解析。回到c0964058,按x寻找sub_c0888ac0。
跟进去:
FvuNVtEkrbS316dOCQ7wmTEcDvtA
根据其他文章的分析和我的实践,得到的修改方法是把MOVEQ R10, R0替换为MOV R10, #0,机器码为00 A0 A0 E3,指令的文件偏移为(C0889110-C0008000),及把下面第三行的BL sub_C0964058替换为MOV R0, #0,机器码为00 00 A0 E3,指令的文件偏移为(C0889120-C0008000)。根据偏移地址在文件里使用010修改或者使用keypatch插件直接修改。
内核文件修改成功。

另,在更改的过程中联想到直接修改TracerPid的格式字符串值,因为不太熟悉,感觉可能会导致占位符后移而报错,就没考虑这个思路,之后也发现确实可以这样做。原始格式化字符串内容为:\t%s\nTgid:\t%d\nPid:\t%d\nPPid:\t%d\nTracerPid:\t0\t\nUid:\t%d\t%d\t%d\t%d\nGid:\t%d\t%d\t%d\t%d\n
这里应该用到了C语言中的占位符%d,来进行值的填充,那么我们可以把TracerPid那一项的占位符%d,改成'0',但是'%d'是两个字符,所以我们可以改成'00',或者'0\t'(十六进制30 09),或者'0\n';只要保证修改后的字符串内容对齐就好。这样TracerPid这一项的值占位符就失效了,值永远都是0了。

打包boog.img

使用之前的解包时提供的打包方法,打包后刷入失败..
最后探索到的方法是直接修改原boot.img
使用gzip -n -f -9 zImage压缩修改后的内核裸文件,压缩后会比原来的小,必须比原来的文件小才可以。
得到zImage.gz,我们使用010分别打开zImage.gz和boot.img,搜索1F 8B 08 00。
按下insert键,将010改为overwrite,注意这里必须是覆盖,这样就不用考虑插入后大小的问题了,把zImage.gz的内容复制到boot.img的相应位置。
FnAy5kaViLN66ZSB875MZC85tmkc
修改完成,使用twrp rec刷入镜像,选择刷入boot。重启。

调试查看

使用ida调试so文件,查看status文件。
FhnP1YDYiijeHyCo73Mx6Wabyqqj
更改后
FlFP8GeyEiGU_L6ar2KSlmMvY35m
更改成功。

变砖补救

但愿还是能够一次成功的,刷内核失败无限重启或者不能开机也比较正常。在尝试过程中失败了三次,只要之前备份了原始的boot.img,变砖之后重新进入rec,刷入原始的boot.img就好。
如果是使用odin刷入的话,需要将boot.img打包为tar文件才可以。

ref
1.逆向修改手机内核,绕过反调试
2.Android系统内核编译及刷机实战 (修改反调试标志位)
3.基于HOOK的Anti-debug调用点trace和Anti-anti
4.Android动态调试和ptrace反调试之读取进程status文件



作为一只菜鸟,搞了好久才将内核更改成功,斗胆与各位分享自己的经历,希望各位大神多指点。

原文同时保存在blog

免费评分

参与人数 27吾爱币 +31 热心值 +27 收起 理由
m0nst3r + 1 + 1 谢谢@Thanks!
ttimasdf + 2 + 1 哈哈哈哈~博客已mark,棒!
丶咖啡猫丶 + 1 + 1 谢谢@Thanks!
fgdg + 1 + 1 用心讨论,共获提升!
Fury_Vector + 1 + 1 用心讨论,共获提升!
老张有大梦想 + 1 + 1 热心回复!
阿尔卡伊达 + 1 + 1 热心回复!
Jack_007 + 1 + 1 热心回复!
bbn + 1 + 1 我很赞同!
akria00 + 1 + 1 用心讨论,共获提升!
XhyEax + 3 + 1 我很赞同!
hdc8899 + 1 + 1 大佬能不能教下如何在用三星源码编译内核
zzzlucas + 1 + 1 谢谢@Thanks!
liphily + 2 + 1 原来精品不需要太长——
Mfeng + 1 我很赞同!
吾爱_欢迎您 + 1 + 1 我很赞同!
imlk + 1 + 1 谢谢@Thanks!
dibh10 + 1 + 1 用心讨论,共获提升!
一牛神一 + 1 + 1 用心讨论,共获提升!
小白670 + 1 + 1 写的挺好的,有时间自己也尝试一下,谢谢分享
不羁的生命 + 1 + 1 谢谢@Thanks!
60000ak + 1 + 1 热心回复!
e007 + 1 + 1 我很赞同!
夏雨微凉 + 2 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
sumile + 1 + 1 用心讨论,共获提升!
nosilence + 1 + 1 用心讨论,共获提升!
xinkui + 1 + 1 谢谢@Thanks!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

mrnull 发表于 2018-6-27 20:27
先说一下,这里的教程不适用用于大多数机子,我昨天搞了一晚上了,说几个需要注意的
首先是提取boot,有些机子是另一种格式叫什么mtd好像,提取和刷内核的话我还是推荐用第三方的rec的备份和恢复功能,这里需要关闭md5校验
然后是解压boot,mtk和高通好像都不一样,但是好像有通用的工具,所以这个不算一个坑
然后是解压内核,这里不一定是gzip压缩的,需要用binwalk看个究竟,比如我的三星a5就是用lz4压缩的,这是第一个坑,记好
然后调试,cpu有32和64,所以入口又不一样了
修改,修改我并不怎么会,所以说不出什么
压缩,这个真心是个谜,我昨天晚上解压不修改重新压缩回刷都能开不了机子,所以这个看运气吧
整个过程就是在看运气
最后就是最好别先改东西刷入,先试一下不改什么然后压缩再压缩回刷看看有没有问题,再继续下一步,这个真的有必要
连这个都不行的话,就看你自己了= =反正我是不行,似乎头文件的数据是验证来着,不然我不改什么回刷都能开不了机子

免费评分

参与人数 1热心值 +1 收起 理由
527900417 + 1 我很赞同!

查看全部评分

mrnull 发表于 2018-6-27 20:30
然后我贴一下网上找的一段代码吧


[C] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
static inline void task_state(struct seq_file *m, struct pid_namespace *ns,
                struct pid *pid, struct task_struct *p)
{
    struct user_namespace *user_ns = seq_user_ns(m);
    struct group_info *group_info;
    int g;
    struct fdtable *fdt = NULL;
    const struct cred *cred;
    pid_t ppid, tpid;
    rcu_read_lock();
    ppid = pid_alive(p) ?
        task_tgid_nr_ns(rcu_dereference(p->real_parent), ns) : 0;
    tpid = 0;
    if (pid_alive(p)) {
        struct task_struct *tracer = ptrace_parent(p);
        if (tracer)
            tpid = task_pid_nr_ns(tracer, ns);
    }
    cred = get_task_cred(p);
    seq_printf(m,
        "State:\t%s\n"
        "Tgid:\t%d\n"
        "Pid:\t%d\n"
        "PPid:\t%d\n"
        "TracerPid:\t%d\n"
        "Uid:\t%d\t%d\t%d\t%d\n"
        "Gid:\t%d\t%d\t%d\t%d\n",
        get_task_state(p),
        task_tgid_nr_ns(p, ns),
        pid_nr_ns(pid, ns),
        ppid, tpid,
        from_kuid_munged(user_ns, cred->uid),
        from_kuid_munged(user_ns, cred->euid),
        from_kuid_munged(user_ns, cred->suid),
        from_kuid_munged(user_ns, cred->fsuid),
        from_kgid_munged(user_ns, cred->gid),
        from_kgid_munged(user_ns, cred->egid),
        from_kgid_munged(user_ns, cred->sgid),
        from_kgid_munged(user_ns, cred->fsgid));
    task_lock(p);
    if (p->files)
        fdt = files_fdtable(p->files);
    seq_printf(m,
        "FDSize:\t%d\n"
        "Groups:\t",
        fdt ? fdt->max_fds : 0);
    rcu_read_unlock();
    group_info = cred->group_info;
    task_unlock(p);
    for (g = 0; g < group_info->ngroups; g++)
        seq_printf(m, "%d ",
               from_kgid_munged(user_ns, GROUP_AT(group_info, g)));
    put_cred(cred);
    seq_putc(m, '\n');
}
Ericky 发表于 2018-5-2 16:23
 楼主| 527900417 发表于 2018-5-2 16:53
Ericky 发表于 2018-5-2 16:23
https://bbs.pediy.com/thread-207538.htm

对,ref第一条便是您说的看雪的这篇文章。其中几个具体的交叉引用可能无法识别,有一些小改动。感谢。
牛奶君 发表于 2018-5-2 17:07
boot.img中有两个1f 8b 08 00。( ̄(工) ̄)这可怎么办
 楼主| 527900417 发表于 2018-5-2 17:37
牛奶君 发表于 2018-5-2 17:07
boot.img中有两个1f 8b 08 00。( ̄(工) ̄)这可怎么办

可以查一下bootimg.h的结构信息,开头是一个header,之后第一个出现的是kernel,一般情况下第一个1f 8b 08 00就是kernel的位置。
6767 发表于 2018-5-2 22:23
锁死ptraceID的一个风险是,如果有应用ptrace ME去检测就会露馅。。。
不过到目前还没有遇到过这样检测的
神一样的小白 发表于 2018-5-2 23:30 来自手机
看不懂。感觉好牛逼
chenjingyes 发表于 2018-5-3 00:17
感谢楼主分享  哈哈哈
刘留留 发表于 2018-5-3 05:19
学习了,谢谢分享
头像被屏蔽
sstm 发表于 2018-5-3 09:04
看看,了解了解。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-5-25 16:45

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表