在 Android 中对 Log-function 的所有调用中混淆或删除字符串文字



我们正在构建一个Android应用程序,我们使用Timber进行日志输出。我们已经定义了自己的 .e、.d、.v 等函数,并使用if (BuildConfig.DEBUG)来查看我们是否应该输出日志。这解决了我们不想在版本中输出调试日志的问题,但函数调用中使用的所有字符串文字仍然存在于编译的源代码中。我们还使用 ProGuard 进行混淆。例如,在一个类中,我们可以有:

somObj.normalFunction(variable)
Log.d("This secret class achieved its secret mission!");

在我们的版本中,这不会在应用程序日志中看到,但如果您对APK进行逆向工程,您将看到类似以下内容:

q.b(m)
z.a("This secret class achieved its secret mission!");

这可以提示黑客他们正在查看的类。 因此,我们正在寻找的是能够在编译时完全删除所有 Log 函数调用(使用一些预处理、注释或其他东西,但希望不必在每次函数调用之前添加一些东西)或者将所有 String 文字参数混淆到这些函数调用。因此,两个理想的解决方案是,如果源代码在编译之前看起来像:

q.b(m);

q.b(m);
z.a("jgasoisamgp23mmwaföfm,ak,ä")

只是通过思考,我可以看到实现这一点的两种糟糕方法。要么我们用if(BuildConfig.DEBUG)包围所有对Log.d的调用,这将使编译器在编译之前删除它们。但这是非常潮汐的。或者,我们确保每次您想添加日志打印输出时都需要执行

Log.d(LogClass.getLog(1234)) 

然后,您在 LogClass 中定义所有这些日志,然后用if(BuildConfig.DEBUG)删除它们,如果是这种情况,请在 getLog 中返回 null。但这会使每次您想要添加日志时都更加潮汐。

所以最后,有什么好的解决方案吗?

免责声明:我在Preemptive 工作,这家公司生产PreEmptive Protection - DashO。

DashO能够删除对特定方法(例如,日志方法)的调用。虽然这不会删除加载字符串文字的指令,只是删除调用本身,但 DashO 还提供字符串加密,这将为这些字符串文字提供一些保护。

举个例子,我通过DashO运行了这个类:


public class App {
public static void main(String[] args) {
Log.d("Secret message here"); 
}
}

删除对Log.d启用了字符串加密的调用后,反编译输出如下所示:

public class App
{
public static void main(String[] paramArrayOfString)
{
a.replace("Bwpfpb7u|ih}z{?($0&", -12 - -61);
}
}

DashO提供其他保护(例如,控制流混淆),往往会破坏反编译器;我已经关闭了这些演示。

我要做的是以下一项或多项:

  1. 使用 Timber(这样你就不需要费心删除东西或添加if语句)。您只需在Application#onCreate()中执行此操作一次;如果你在调试中,那么你种植一个打印到控制台的调试树。否则,你种了一棵什么都不做的"空树"。

  2. 模拟 Timber,但创建自己的"YourLogger"类并执行相同的操作(如果您不想包含"第三方"库,即使它只是一个类)。所以你会有YourLogger.v("tag", "string"),里面你会做:if (debug) { Log.v(tag, string); }等等,用于所有其他日志类型。

  3. 使用 Proguard 剥离日志记录,以及什么不。

1 和 2 表示您遍历应用并将所有Log.行替换为Timber.YourLogger.选项 3 不需要这样做,因为代码将在混淆期间被删除,并且调用将不执行任何操作,但这在模式上很复杂(我已经很多年没有这样做了,甚至不记得它是如何完成的,可能很容易查找它)。

我会去1。

更新

由于显然我不知道如何阅读,我认为为了实现这一点,您唯一的赌注是针对您要发出/隐藏的实际文本具有某种查找机制。

字符串.xml是最简单的,因为它包含在Android中,您甚至可以本地化错误消息(当然,如果需要的话)。是的,有一个查找时间损失,但我想说,除非您迭代数千个项目并每次或其他内容记录不同的字符串,否则惩罚不会很明显(我没有这方面的数据,你必须进行基准测试)。

或者,您可以只使用文件,读取它,然后将字符串加载到内存中,而不是依赖资源......权衡;您是以简单性和时间来编写解决方案为代价使用更多内存,还是使用内置机制并支付 CPU 时间?

最新更新