LogCat 及 Log 的一些思考
0x00 TOC
- 原理
- smali注入
- 手机查看log并导出
- so打log
- 发布(release)版屏蔽Log输出
- 查看内核日志
- 参考链接
#####0x01 原理
常见的一些打Log的语句
1 | Log.i(TAG, ""); |
Log给开发者开放了6种级别(分别对应info,debug,error,verbose,warning,assert),隐藏了两种级别:
1 | F — Fatal |
通过阅读Log的代码,里面说明了通过println_native(LOG_ID_MAIN, Priority, tag, msg);
代码进行输出了日志。并声明了LOG_ID_MAIN、LOG_ID_RADIO、LOG_ID_EVENTS、LOG_ID_SYSTEM、LOG_ID_CRASH五个缓冲区。
而println_native()
的代码在frameworks/base/core/jni/android_util_log.cpp
,其中判断了msg是否为空,如果为空,抛出空指针异常。
其中levels_t是一个结构体,其中包括了那六种级别,其中assert
,查阅代码可得知,如果利用Log.wtf()方法,就会打印一个标志成ASSERT的错误。
并通过以下函数进行了打印操作。即__android_log_buf_write。在__android_log_buf_write
函数里通过调用write_to_log
函数进行打印。
1 | int res = __android_log_buf_write(bufID, (android_LogPriority)priority, tag, msg); |
然后write_to_log
是怎样的情况呢,在文件45行有以下信息。
1 | static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __write_to_log_init; |
然后追溯到__write_to_log_init
这个函数里,这个函数其中有一些打开文件等的操作,然后__write_to_log_kernel
这个就写入到文件里。
具体底层Log设备Logger机制,就不再阐述,如果细研下去,就是另一篇文章了,并且嵌入式的同学还学到了ioctl
函数,这需要一些Linux驱动方面的知识。
LogCat是如何获取Log的?通过logcat.cpp
,可以知道,定义了一个Log文件目录,即#define LOG_FILE_DIR "/dev/log/"
。具体读取log的过程,可以参考田海立的文章-解读Android LOG机制的实现:(5)获取LOG的应用程序LogCat
。
如何去修改logcat的显示颜色呢,可以通过android studio的设置,也可以安装一个logcat-color直接改变颜色,通过以下命令。
1 | $ logcat-color -e | egrep '(Tag1|Tag2)' |
0x02 smali注入
通过以下命令,进行apktool反编译
1 | apktool d xxx.apk |
在合适位置插入以下语句,其中v0为寄存器,尽量不要随意添加寄存器。
1 | invoke-static {v0, v0}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I |
然后进行打包
1 | apktool b xxx -o xxx.apk |
打包完安装需要签名,由于已经有了android.keystore ,这里使用jarsigner进行签名。
1 | jarsigner -verbose -keystore android.keystore -signedjar android_signed.apk app.apk android.keystore |
运行即可看到Log信息。
0x03 手机查看log并导出
如何在手机上读取其他应用的log并可以导出呢,谷歌在4.1以后禁止了相关权限,改为了signature|system|development
权限。就算有android.PREMISSION.READ_LOGS,也读取不到其他应用的log了。只能root以后查看。
在谷歌Android Developer论坛里也有相关讨论。在4.1之后,禁止了去阅读其他应用log的权限。
并且在google play商店上也有几款手机上查看log的软件,需要root权限。比如CatLog - Logcat Reader!,aLogcat (free) - logcat 等。aLogCat也开源了,地址在GitHub上。
0x04 so打log
如何在so文件,即jni开发中里打log呢
这里如何配置NDK就不再叙述。详细可参考ndk官网
需要在cpp文件中添加以下语句:
1 |
|
然后在build.gradle文件里,修改成以下片段:
1 | ndk { |
引入liblog.h
,或者通过自定义Android.mk
进行导入。
可以通过一些宏定义定义:
1 |
0x05 发布(release)版屏蔽Log输出
一种方法是通过添加一个Log辅助类,配置级别,或者通过变量控制显示。
1 | public class Log { |
使用时直接使用这个Log类打印方法。
release版屏蔽log输出,另外一种方法是,可以通过ProGuard的方式,将log语句删除。
ProGuard是Android SDK的一部分。只需要开启即可。
在android studio中,编辑build.gradle文件,配置如下代码:
1 | android { |
后来gradle的runProguard更名为minifyEnabled,所以直接改为true即可。
1 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' |
注意这段位置,本来按默认的配置一直没有消除成功,直到看了一篇文章以后,改为了proguard-android-optimize.txt
,才屏蔽输出成功。即:
1 | release { |
修改Proguard的配置文件proguard-rules.pro
,添加以下配置:
1 | -assumenosideeffects class android.util.Log { |
即结果。然后打包签名输出就不会有log日志了。
0x06 查看内核日志
1 | ./adb shell |
dmesg是内核中的一个命令,可以查看内核日志,当然,也可以用cat/proc/kmsg
。两者不同的是,dmesg只读取缓冲区中的内核日志,而cat /proc/kmsg
则可以原始的、完整的日志文件。
0x07 参考链接
LogCat 及 Log 的一些思考
https://dbqf.xyz/201606-android-security-logcat-log-thinks.html