请选择 进入手机版 | 继续访问电脑版
点击联系客服
客服QQ: 客服微信:
查看: 72|回复: 50

对抗苹果的“勇士”:公开iOS没有修复漏洞后使用《恶意软件进 App Store 指南》

[复制链接]

1

主题

1

帖子

-7

积分

限制会员

积分
-7
发表于 2021-9-30 07:41:53 | 显示全部楼层 |阅读模式
被称为“围墙花园”的苹果一直以“安全”为由,坚持各种外部的霸道规则。为了安全,禁止第三方更换产品电池。为了安全起见,我不同意开放第三方应用商店。为了安全起见,不允许使用“横向负载”应用程序.

一切都是为了安全,一切都是为了用户。那么为什么应用商店里不断出现恶意软件呢?为什么最近安全研究员说苹果长期无视iOS  15上剩下的3个0天漏洞?

对此,开发者Denis  Tokarev否定了对应用商店安全的主张,并详细说明了恶意软件进入应用商店的过程。“苹果不允许任何 App  Store  替代品的真正原因是,这样他们就能从所有应用内购中抽取 30% 的佣金,这对他们来说是一项非常有利可图的业务





一、被态度敷衍的苹果激怒

Denis  Tokarev突然这么愤慨是因为他今年3~5月向苹果公司陆续报告了iOS存在的4个0天漏洞。苹果承诺将这些漏洞添加到安全内容列表中,但食言了。

在4个漏洞中,苹果公司仅在iOS  14.7更新中悄悄修复了其中一个漏洞,没有将其添加到安全内容列表中,到iOS  15为止,还剩下3个0天的漏洞。

Denis  Tokarev让Denis  Tokarev感到不满。Denis  Tokarev认为,苹果不仅对系统漏洞的发现漠不关心,还掩盖了在iOS  14.7更新中修复漏洞的行为,这一切都是为了不向Denis  Tokarev支付安全奖金计划下的10万美元。

Denis  Tokarev试图就这个问题与苹果沟通,但对方始终没有回答。生气地写道,他还没有恢复的3个0天漏洞和批评其安全奖金计划的博客文章,3个漏洞分别是Gamed、Nehelper  installed  apps和Nehelper  wifi  info。

苹果公司因这句话引起了公众的关注,并最终回复了Denis  Tokarev。

“我们看了你关于这个问题的博客和其他报告。对延迟回复表示歉意。但是,为了保护客户,我们正在调查和考虑如何解决这些问题。(大卫亚设,Northern  Exposure(美国电视),答复延迟)再次感谢您抽出时间向我们报告这些问题。我们感谢你的帮助。如果你有问题,请告诉我。单击

但是一切都晚了,Denis  Tokarev再次对对苹果公司几乎“强制”的反应感到愤怒,并对恶意代码能否实际进入应用商店提出疑问感到遗憾。“他们这么怀疑我是可以理解的,因为苹果总是一遍又一遍地重复,让人们相信 App  Store  是安全的
/strong>。”

因此,Denis Tokarev 再度提笔,详细说明了恶意软件是如何通过审核进入 App Store 的整个过程(包括源代码)。

二、混淆函数名称的字符串即可
首先,Denis Tokarev 指出,当 App 的二进制文件上传到苹果服务器时,会被进行静态分析。但其实这个过程除了根据预定义的私有 API 集(这些 API 只有苹果自己的 App 才允许使用)检查二进制文件中的字符串列表外,并不会做太多其它工作。

如果在 App 中检测到了私有 API 的使用,苹果就不会上传该 App 的二进制文件,并向 App 作者发送一封邮件:


“我们发现你最近交付的 App [APP_NAME_AND_VERSON] 中存在一个或多个问题,请请更正以下问题,然后重新上传。

ITMS-90338:使用非公共 API - App 包含或继承了 [APP_NAME]
中的非公共类:GKFamiliarPlayerInternal,GKFriendPlayerInternal,GKLocalPlayerInternal。如果你源代码中的方法名称与上面列出的私有苹果
API 一致,请更改你的方法名称以避免该 App 在未来提交时被标记。此外,如果上述一个或多个 API 也存在于你 App
附带的静态库中,那它们必须被删除。如需更多信息,请访问
http://developer.apple.com/support/technical/。”


这种情况下,该怎么办呢?Denis Tokarev 给出了两种方法:

  • 如果这是一个 Objective-C 的 API,那么可以通过 Objective-C 运行时对其动态调用。
    例如,先找到一个类GKLocalPlayerInternal(这是 Gamed 漏洞中会使用的一个类),就像 NSClassFromString(“GKLocalPlayerInternal”)。由于 GKLocalPlayerInternal 属于私有 API,因此在分析二进制文件时会被发现。但是,开发者可以通过多种方式对它进行隐藏,比如,可以将 GKLocalPlayerInternal 简单分为几个部分:NSClassFromString([“GKLoc”,“lPlayerInternal”].joined(separator: “a”)),这样就不会被静态分析检测到。

    Gamed 漏洞就是通过这种方法混淆了所有私有 API 的使用,因此在接受苹果静态分析时未被发现

  • 使用凯撒密码(这是一种替换加密的技术,明文中的所有字母都在字母表上向后或向前按照一个固定数目进行偏移后被替换成密文)。
    Denis Tokarev 表示,他发现 App Store 上有一个下载量高达几亿次的 App 就采用了这种方法。该 App 支持 iOS 9,因此开发者必须使用私有 API 来解决 UIKit 漏洞,并为那些无法安装最新 iOS 版本的人改善体验(苹果认为有些设备已过时,因此放弃了对它们的支持)。

    举个例子,自 iOS 7 开始,苹果就为 App 图标使用了一种特殊的圆角设计,并将这种设计覆盖到了 App 中包括按钮、警报等所有 UI 组件。但是,这种圆角设计只在 iOS 13 中为第三方开发者提供,同时苹果早在 iOS 11 中就开始调用 CALayer 类的私有方法 setContinuousCorners 用于自己的 App 和系统组件,因此,如果应用开发者想让旧 iOS 版本的用户体验到一致的 App 界面,就必须使用私有 API,而这违反了 App Store 规则

    除了 Gamed 漏洞,Denis Tokarev 另外发现的三个漏洞(Analyticsd、Nehelper installed apps 和 Nehelper wifi info)都使用了苹果认为是私有 API 一部分的 C 函数,而他已经更新了这三个漏洞的源代码,使其能动态调用这些函数,使躲过苹果的静态分析

    三、实操过程及代码
    理论有了,接下来,Denis Tokarev 分享了要如何通过凯撒密码具体实现这一过程。

    首先,dlopen 和 dlsym 函数可以加载动态库并解析其中的符号,但考虑到这可能会被 App Store 审核团队检测到,因此开发者可以“曲线救国”:每个 iOS 二进制文件都会导入一个名为 dyld_stub_binder 的符号,而它导自与 dlopen 和 dlsym 相同的库——也就是说,开发者可以通过计算 dlopen 和 dlsym 函数在内存中与 dyld_stub_binder 的距离,然后仅使用这些函数的地址来调用它们

    有一点需要注意,Denis Tokarev 表示,这个距离,也就是偏移量,会根据 iOS 版本和设备型号这两个参数而有所变化,他在 Github 上分享的 3 个漏洞源代码中的偏移量是对应 iPhone 7 Plus 和 iOS 15.0 的值,所以如果这与开发者的实际设备不符,则需重新计算。

    以下为计算偏移量的方法:

    printf("%lld\n",(long long)dyld_stub_binder - (long long)dlopen);
    printf("%lld\n",(long long)dyld_stub_binder - (long long)dlsym);

    当有了偏移量后,开发者便可以通过定义自己的函数来调用 dlopen 和 dlsym:

    // dlopen
    void * normal_function1(const char * arg1, int arg2) {
        return ((void *(*)(const char *, int))((long long)dyld_stub_binder - 20780))(arg1, arg2);
    }
    // dlsym
    void * normal_function2(void * arg1, const char * arg2) {
        return ((void *(*)(void *, const char *))((long long)dyld_stub_binder - 20648))(arg1, arg2);
    }

    在 Swift 中将其导入后,开发者便可以重写检查 App 是否已安装的代码,在这过程中无需导入和引用任何符号(除了已被二进制文件默认导入的 dyld_stub_binder):

    let dylib = normal_function1("/usr/lib/system/libxpc.dylib", 0)
    let normalFunction3 = unsafeBitCast(normal_function2(dylib, "xpc_connection_create_mach_service"), to: (@convention(c) (UnsafePointerCChar>, DispatchQueue?, UInt64) -> (OpaquePointer)).self)
    let normalFunction4 = unsafeBitCast(normal_function2(dylib, "xpc_connection_set_event_handler"), to: (@convention(c) (OpaquePointer, @escaping (OpaquePointer) -> Void) -> Void).self)
    let normalFunction5 = unsafeBitCast(normal_function2(dylib, "xpc_connection_resume"), to: (@convention(c) (OpaquePointer) -> Void).self)
    let normalFunction6 = unsafeBitCast(normal_function2(dylib, "xpc_dictionary_create"), to: (@convention(c) (OpaquePointer?, OpaquePointer?, Int) -> OpaquePointer).self)
    let normalFunction7 = unsafeBitCast(normal_function2(dylib, "xpc_dictionary_set_uint64"), to: (@convention(c) (OpaquePointer, UnsafePointerCChar>, UInt64) -> Void).self)
    let normalFunction8 = unsafeBitCast(normal_function2(dylib, "xpc_dictionary_set_string"), to: (@convention(c) (OpaquePointer, UnsafePointerCChar>, UnsafePointerCChar>) -> Void).self)
    let normalFunction9 = unsafeBitCast(normal_function2(dylib, "xpc_connection_send_message_with_reply_sync"), to: (@convention(c) (OpaquePointer, OpaquePointer) -> OpaquePointer).self)
    let normalFunction10 = unsafeBitCast(normal_function2(dylib, "xpc_dictionary_get_value"), to: (@convention(c) (OpaquePointer, UnsafePointerCChar>) -> OpaquePointer?).self)
    func isAppInstalled(bundleId: String) -> Bool {
        let connection = normalFunction3("com.apple.nehelper", nil, 2)
        normalFunction4(connection, { _ in })
        normalFunction5(connection)
        let xdict = normalFunction6(nil, nil, 0)
        normalFunction7(xdict, "delegate-class-id", 1)
        normalFunction7(xdict, "cache-command", 3)
        normalFunction8(xdict, "cache-signing-identifier", bundleId)
        let reply = normalFunction9(connection, xdict)
        if let resultData = normalFunction10(reply, "result-data"), normalFunction10(resultData, "cache-app-uuid") != nil {
            return true
        }
        return false
    }

    简单来说,这一切的目的就是为了不被静态分析检测到,所以要使用凯撒密码混淆包含函数名称的字符串,或者像第一种方法那样将其分成几块。

    Denis Tokarev 对这两种方法非常自信:“如果苹果敢说这样也能在审查期间发现,那我会想出不同的应对方法并将它全部发布出来。”

    四、主观性很强的审核流程
    在“骗”过静态分析后,App 就会进入 App Store 的审核流程,而 Denis Tokarev 认为在这一过程中,主观性很强:基本上就是一个随机分配的测试人员把 App 下载到自己的 iPad 上,然后满屏幕地点击,再根据他们自己对 App Store 规则的理解和主观意见做出是否允许上架的决定。

    可是,这个过程具有很明显的缺点:一般而言,恶意软件都会连接到远程服务器,发送有关当前用户会话的详细信息,并询问是否要执行某些恶意操作。而苹果服务器只会检测苹果测试员或普通用户是否正在使用 App,并基于此发送响应。这意味着,审核人员只会看到一个外表“良善”的恶意 App,发现不了任何可疑之处,并允许它进入 App Store

    因此,这些年来 App Store 中的恶意软件总是层出不穷,而苹果也总是在被别人发现后才下架这些 App,甚至某些情况下还会对举报者视若无睹:有一位开发者 Kosta Eleftheriou 曾明确指出 App Store 中存在许多带有虚假评论的盗版 App,它们向用户收取高昂的费用却提供不了什么功能,因此 Eleftheriou 想让苹果删除这些 App。但最终,苹果并没有怎么听取 Kosta Eleftheriou 的建议,这在 Denis Tokarev 看来,是因为苹果也从这些盗版 App 中获益了:高昂订阅费中 30% 的抽成

    另外,Denis Tokarev 还例举了一些他亲身经历过的经验,以证明 App Store 的审核是有多么“主观随性”:

  • 他提交了一款有关占星术、星座运势、手相和算命的免费 App,却被 App Store 审核团队拒绝,理由是“在 App Store 上已经有足够多的此类 App”。可 App Store 中却有一个 8 美元/周、带有虚假评论的星座 App。
  • 他开发的一款名为 Hobo Simulator 的游戏被 App Store 突然下架,理由之一是他们不喜欢“hobo”(流浪的失业工人)这个词以及游戏内容,但彼时甚至直到如今 App Store 中还有许多类似应用,例如“Hobo Life”、“Hobo - Real Life Simulator”——只有 Denis Tokarev 的“hobo”主题游戏被下架了。
  • 在 Hobo Simulator 被下架后,有人完整克隆了 Denis Tokarev 的这款游戏并且成功在 App Store 中上架。在 Denis Tokarev 向苹果提出关于知识产权的投诉时,苹果回复道 Denis Tokarev 应该自己去和那个抄袭 App 的开发者解决这个问题。
  • 2020 年 7 月,Denis Tokarev 在 App Store 中重新创建了一个 ID,并再次提交了他的“Hobo Simulator”App,而这次,App Store 允许它上架了。

    因此,Denis Tokarev 表示,苹果这些行为完全属于反竞争,并且还含有对部分开发者歧视的意味,就算最近苹果因美国集体诉讼允许应用的第三方支付,这也还不够。

    他呼吁道,人们必须向苹果施加压力,让他们开放平台,允许 App Store 替代品和侧载的存在,并让开发者获得公平待遇:“面对压迫和不公正,我们必须站在一起,为自由而战!

    那么,对于 Denis Tokarev 的做法与呼吁,你有什么看法吗?

    参考链接:

  • https://habr.com/en/post/580272/
  • https://habr.com/en/post/579714/
  • https://en.wikipedia.org/wiki/Caesar_cipher
  • 回复

    使用道具 举报

    1

    主题

    355

    帖子

    -169

    积分

    限制会员

    积分
    -169
    发表于 2021-9-30 07:50:48 | 显示全部楼层
    没看完~~~~~~ 先顶,好同志
    回复

    使用道具 举报

    1

    主题

    388

    帖子

    -178

    积分

    限制会员

    积分
    -178
    发表于 2021-9-30 08:12:01 | 显示全部楼层
    不错
    回复

    使用道具 举报

    1

    主题

    374

    帖子

    -113

    积分

    限制会员

    积分
    -113
    发表于 2021-9-30 08:32:03 | 显示全部楼层
    真是 收益 匪浅
    回复

    使用道具 举报

    1

    主题

    368

    帖子

    -176

    积分

    限制会员

    积分
    -176
    发表于 2021-9-30 08:57:22 | 显示全部楼层
    好帖,来顶下
    回复

    使用道具 举报

    1

    主题

    353

    帖子

    -158

    积分

    限制会员

    积分
    -158
    发表于 2021-9-30 09:19:23 | 显示全部楼层
    过来看看的
    回复

    使用道具 举报

    1

    主题

    362

    帖子

    -146

    积分

    限制会员

    积分
    -146
    发表于 2021-9-30 09:46:17 | 显示全部楼层
    路过,学习下
    回复

    使用道具 举报

    1

    主题

    378

    帖子

    -114

    积分

    限制会员

    积分
    -114
    发表于 2021-9-30 10:09:25 | 显示全部楼层
    好好 学习了 确实不错
    回复

    使用道具 举报

    1

    主题

    377

    帖子

    -149

    积分

    限制会员

    积分
    -149
    发表于 2021-9-30 10:30:12 | 显示全部楼层
    没看完~~~~~~ 先顶,好同志
    回复

    使用道具 举报

    1

    主题

    360

    帖子

    -168

    积分

    限制会员

    积分
    -168
    发表于 2021-9-30 10:55:50 | 显示全部楼层
    前排支持下分享
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|无图版|手机版|小黑屋|汕头@IT精英团

    Powered by Discuz! X3.4 © 2021 Comsenz Inc.

    GMT+8, 2021-10-25 02:56 , Processed in 0.343201 second(s), 19 queries .

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