我正在为Android开发一款支付处理应用程序,我想防止黑客访问APK文件中的任何资源、资产或源代码。

如果有人将.apk扩展名更改为.zip,那么他们可以将其解压缩并轻松访问应用程序的所有资源和资产,并且可以使用dex2jar和Java反编译器访问源代码。对Android APK文件进行反向工程非常容易-有关更多详细信息,请参阅堆栈溢出问题从APK文件到项目的反向工程。

我已经使用了Android SDK提供的Proguard工具。当我对使用签名密钥库和Proguard生成的APK文件进行反向工程时,我得到了混淆的代码。

然而,Android组件的名称保持不变,一些代码(如应用程序中使用的关键值)保持不变。根据Proguard文档,该工具无法混淆Manifest文件中提到的组件。

现在我的问题是:

如何完全防止Android APK的反向工程?这可能吗?我如何保护应用程序的所有资源、资产和源代码,使黑客无法以任何方式破解APK文件?有没有办法让黑客攻击变得更加困难甚至不可能?我还能做什么来保护APK文件中的源代码?


当前回答

Android 7.0中的APK签名方案v2(Nougat)

PackageManager类现在支持使用APK签名方案v2验证应用程序。APK签名方案v2是一个完整的文件签名方案,通过检测对APK文件的任何未经授权的更改,显著提高了验证速度并加强了完整性保证。

为了保持向后兼容性,APK必须在使用v2签名方案签名之前使用v1签名方案(JAR签名方案)签名。使用v2签名方案,如果在使用v2方案签名后使用附加证书对APK进行签名,则验证失败。

APK签名方案v2支持稍后将在N开发者预览版中提供。

http://developer.android.com/preview/api-overview.html#apk_signature_v2

其他回答

不,不可能!

你的三个问题围绕着100%保护应用程序不被阅读。原则上这是做不到的。而且,你在尝试做这件事上投入的越多,你的体验就会越差,最终,无论哪台机器只想读你的应用。想想HTTP的HTTPS本质上有多慢,因为需要处理安全层和数学。层数越多,有人打开它的速度就越慢,但如果你真的想让它被阅读,那就永远不可能,这就是为什么它会被打包并交付的原因。

一个简单的类比是将任何给定的隐藏对象交给某人。如果那个人能看到里面的东西,那么他们就可以拍一张照片,做一些完全类似的事情。更重要的是,在代码的情况下,有足够的专业人员可以创建该对象的精确副本,即使使用完全不同的过程。

假安全感

作为一个处理应用程序,你不应该关心你认为可以在二进制代码中创建的任何安全性,也不应该关心整个系统的完整性。假设来自客户机的任何信息都可能很快变得不可靠。保持应用程序简单、流畅、快速。相反,请担心您的服务器。例如,制定一个严格的通信协议以方便地监控服务器。这是我们唯一可以依靠的。

现在,坚持我的另一个想法,如何改进服务器端。。。

嘴上的钱

我正在开发支付处理应用程序

谷歌通过使用一种简单的财务方法来“保护”谷歌Chrome,在总体上成功地避免了恶意黑客,我引述如下:

我们有50000美元的奖励,奖励参与者可以在客户模式下使用Chromebook或Chromebox进行设备持久性测试

我们真正接近100%“安全”的最佳选择是为我们的金钱价值选择正确的斗争。也许大多数人都无法提供50k的奖励,但即使是1k的奖励也会有很长的路要走,而且这也比将这些钱投资于设计任何类型的bug捕捉器要便宜得多。

投资于人工智能来识别资金流动模式,以预测潜在风险并发现小的泄漏,这也比通过任何工程来防止这两种情况要便宜得多。

明显的例外

当然,这并不能保护我们免受“疯子”和“幸运的恶作剧者”的伤害。。。但什么都不会。同时,如果设置得当,当系统重新调整时,后一组只会享受很少的时间。而一个疯子,我们只需要担心,以防它大到有一个克星。无论如何,这将是一个伟大的故事!:)

太长;没有阅读;

换言之,也许一个更好的问题可以问你自己,而不是“如何避免在我的应用程序中进行逆向工程”,而是“如何设计一个更安全的支付处理系统”,并专注于你实际想要实现的目标:一个安全的系统。

很久以前,我曾尝试写更多关于以上所有内容的文章,以回答一些问题,比如为什么我在引号中加上“安全”和“保护”(它们到底是什么意思?)。

Android 7.0中的APK签名方案v2(Nougat)

PackageManager类现在支持使用APK签名方案v2验证应用程序。APK签名方案v2是一个完整的文件签名方案,通过检测对APK文件的任何未经授权的更改,显著提高了验证速度并加强了完整性保证。

为了保持向后兼容性,APK必须在使用v2签名方案签名之前使用v1签名方案(JAR签名方案)签名。使用v2签名方案,如果在使用v2方案签名后使用附加证书对APK进行签名,则验证失败。

APK签名方案v2支持稍后将在N开发者预览版中提供。

http://developer.android.com/preview/api-overview.html#apk_signature_v2

AFAIK,您不能再保护/res目录中的文件,因为它们现在受到保护。

然而,您可以采取一些步骤来保护源代码,或者至少保护它的功能(如果不是所有功能)。

使用ProGuard等工具。这些将使您的代码变得模糊,如果不是不可能的话,在反编译时更难阅读。将服务中最关键的部分从应用程序中移出,并隐藏在服务器端语言(如PHP)后面的Web服务中。例如,如果你有一个花费了一百万美元编写的算法。你显然不希望人们从你的应用程序中窃取它。移动算法,让它在远程服务器上处理数据,然后使用应用程序简单地向它提供数据。或者使用NDK将它们本机写入.so文件,这比apk更不容易被反编译。我认为目前还没有一个.so文件的反编译器(即使存在,也不如Java反编译器)。此外,正如@nikolay在评论中提到的,在服务器和设备之间进行交互时,应该使用SSL。在设备上存储值时,不要以原始格式存储。例如,如果您有一个游戏,并且您正在SharedPreferences中存储用户的游戏货币数量。假设是10000枚硬币。不要直接保存10000,而是使用((货币*2)+1)/13这样的算法保存。因此,您将1538.53846154保存到SharedPreferences中,而不是10000。然而,上面的例子并不完美,你必须努力想出一个不会因舍入误差而失去货币价值的公式。您可以对服务器端任务执行类似的操作。现在举个例子,让我们来看看你的支付处理应用。假设用户必须支付200美元。不要向服务器发送一个200美元的原始值,而是发送一系列较小的预定义值,这些值加起来可以达到200美元。例如,在服务器上有一个文件或表,它将单词与值等同。假设查理相当于47美元,约翰相当于3美元。所以,你不需要寄200美元,而是可以寄查理四次,约翰四次。在服务器上,解释它们的含义并将其相加。这可以防止黑客向您的服务器发送任意值,因为他们不知道哪个单词对应什么值。作为一种额外的安全措施,您可以使用类似于第3点的公式,并每隔n天更改关键字。最后,你可以在你的应用程序中插入随机无用的源代码,这样黑客就可以大海捞针了。插入包含来自互联网的片段的随机类,或者只是用于计算诸如斐波那契序列之类的随机事物的函数。确保这些类可以编译,但不会被应用程序的实际功能所使用。添加足够多的这些虚假类,黑客将很难找到真正的代码。

总而言之,没有办法100%保护您的应用程序。你可以让它更难,但不是不可能。你的网络服务器可能会被破坏,黑客可以通过监控多个交易金额和你发送的关键字来找出你的关键字,黑客可以费力地通过源代码找出哪个代码是伪代码。

你只能反击,但永远不会赢。

1.如何完全避免Android APK的反向工程?这可能吗?

那是不可能的

2.如何保护应用程序的所有资源、资产和源代码,使黑客无法以任何方式破解APK文件?

开发人员可以采取一些措施,例如使用ProGuard之类的工具来混淆他们的代码,但到目前为止,要完全阻止某人对应用程序进行反编译还是相当困难的。

这是一个非常棒的工具,可以增加“反转”代码的难度,同时缩小代码的占地面积。

集成ProGuard支持:ProGuard现在与SDK工具一起打包。开发人员现在可以将其代码作为发布构建的集成部分进行模糊处理。

3.有没有办法让黑客攻击变得更加困难甚至不可能?我还能做什么来保护APK文件中的源代码?

在研究期间,我了解了HoseDex2Jar。此工具将保护您的代码不被反编译,但似乎不可能完全保护您的。

一些有用的链接,你可以参考它们。

Proguard、Android和许可服务器保护Android LVL应用程序堆栈溢出问题:保护Android应用程序不受反向工程的影响真的不可能吗?堆栈溢出问题如何防止Android APK文件反向工程以保护代码?

应用程序安全的第一条规则:攻击者获得不受限制的物理或电子访问权限的任何机器现在都属于您的攻击者,无论其实际位置或您为此支付的费用。应用程序安全的第二条规则:任何离开攻击者无法穿透的物理边界的软件现在都属于您的攻击者,无论您花费了多少时间对其进行编码。第三条规则:任何离开攻击者无法穿透的物理边界的信息都属于您的攻击者,无论它对您有多大价值。

信息技术安全的基础是基于这三个基本原则;唯一真正安全的计算机是被锁在法拉代笼子里的保险箱里,被锁在钢笼子里。有些计算机的大部分使用寿命都处于这种状态;每年一次(或更少),他们为可信的根认证机构生成私钥(在一大群目击者面前,摄像机记录下他们所在房间的每一寸)。

现在,大多数计算机不在这些类型的环境下使用;他们在户外,通过无线电台连接到互联网。简而言之,他们很脆弱,他们的软件也是如此。因此,他们不值得信任。为了有用,计算机及其软件必须知道或做某些事情,但必须小心确保它们永远不会知道或做足够的事情来造成损坏(至少不会造成超出单个机器范围的永久性损坏)。

你已经知道这一切了;这就是为什么要保护应用程序的代码。但是,其中存在第一个问题;混淆工具可以使代码变得一团糟,让人类试图挖掘,但程序仍然必须运行;这意味着应用程序的实际逻辑流及其使用的数据不受混淆的影响。只要有一点韧性,攻击者就可以简单地对代码进行反混淆,在某些情况下,这甚至是不必要的,在这种情况下,他所看到的不是其他东西,而是他正在寻找的东西。

相反,你应该努力确保攻击者不能对你的代码做任何事情,无论他多么容易获得代码的清晰副本。这意味着,没有硬编码的秘密,因为一旦代码离开你开发它的建筑,这些秘密就不是秘密。

这些硬编码的键值应该从应用程序的源代码中完全删除。相反,他们应该在三个地方之一;设备上的易失性内存,攻击者很难(但仍然不是不可能)获得的脱机副本;永久位于服务器集群上,您可以使用铁腕控制访问;或者存储在与您的设备或服务器无关的第二个数据存储中,例如物理卡或用户的存储器中(这意味着它最终将存储在易失性存储器中,但不需要很长时间)。

考虑以下方案。用户将应用程序的凭据从内存输入设备。不幸的是,您必须相信用户的设备尚未被键盘记录器或木马程序破坏;在这方面,你能做的最好的就是实现多因素安全,记住关于用户使用过的设备的难以伪造的识别信息(MAC/IP、IMEI等),并提供至少一个额外的通道,通过该通道可以验证在陌生设备上的登录尝试。

凭证一旦输入,就会被客户端软件混淆(使用安全散列),并丢弃纯文本凭证;他们达到了目的。混淆后的凭据通过安全通道发送到证书认证服务器,该服务器再次对它们进行散列,以生成用于验证登录有效性的数据。这样,客户端就永远不知道与数据库值实际比较的内容,应用程序服务器永远不知道它接收到的验证内容背后的明文凭证,数据服务器永远不了解它存储的验证数据是如何生成的,中间的人即使安全通道被破坏,也只会看到胡言乱语。

一旦验证,服务器将通过信道发回令牌。令牌仅在安全会话中有用,由随机噪声或会话标识符的加密(因此可验证)副本组成,客户端应用程序必须在同一信道上向服务器发送此令牌,作为任何请求的一部分。客户机应用程序会多次这样做,因为它不能做任何涉及金钱、敏感数据或其他可能会对其造成损害的事情;它必须改为要求服务器执行此任务。客户端应用程序永远不会将任何敏感信息写入设备本身的永久内存,至少不会以明文形式写入;客户端可以通过安全通道向服务器请求对称密钥来加密服务器将记住的任何本地数据;在稍后的会话中,客户端可以向服务器请求相同的密钥来解密数据以在易失性存储器中使用。这些数据也不会是唯一的副本;客户机存储的任何内容也应以某种形式传输到服务器。

显然,这使您的应用程序严重依赖Internet访问;客户端设备不能在没有与服务器的正确连接和服务器的认证的情况下执行其任何基本功能。真的和Facebook没什么不同。

现在,攻击者想要的计算机是你的服务器,因为它而不是客户端应用程序/设备是可以让他赚钱或让其他人痛苦的东西。没关系;与试图保护所有客户机相比,您花费金钱和精力来保护服务器会获得更大的回报。该服务器可以位于各种防火墙和其他电子安全装置的后面,此外,还可以在钢铁、混凝土、钥匙卡/插针访问和24小时视频监控的后面进行物理保护。您的攻击者需要非常老练才能直接访问服务器,而且您应该立即了解这一点。

攻击者所能做的最好的事情就是窃取用户的电话和凭据,并使用客户端的有限权限登录到服务器。如果发生这种情况,就像丢失一张信用卡一样,合法用户应该被指示从他们可以访问的任何电话拨打一个800号码(最好是容易记住的号码,而不是在钱包、钱包或公文包中携带的卡背面,这可能会在移动设备旁边被盗),该电话可以直接连接到您的客户服务。他们声明自己的手机被盗,提供一些基本的唯一标识符,账户被锁定,攻击者可能处理的任何交易都被回滚,攻击者又回到了原点。