V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
atfeel
V2EX  ›  Android

安卓开发收费会员系统,被反编译,一个用户的返回数据无数人嫖用!

  •  2
     
  •   atfeel · 2020-07-10 10:18:32 +08:00 · 18850 次点击
    这是一个创建于 1595 天前的主题,其中的信息可能已经有所发展或是发生改变。

    一直对安卓的安全性很担忧,被反编译的可能性很高,反编译了竟然还能重新打包!!!无语了

    APP 用 360 免费加固,不知道有没有 5%的可能性被完美反编译。

    破解者用一个正常的账号从服务器请求到正常的会员信息,途中无论用什么加密。

    因为 APP 被反编译了,在客户端最终会得到解密后的明文。

    破解者是不是就可以用解密的明文肆无忌惮地免费用软件,还重新打包拿去倒卖

    这样的局该如何破呢。。

    好头痛,还是异想天开了?完全没有思路了

    第 1 条附言  ·  2020-07-10 10:58:08 +08:00
    不是会员,是登录账号,才能使用 APP 的收费功能,差点误导大家了
    68 条回复    2020-07-13 17:10:26 +08:00
    kzfile
        1
    kzfile  
       2020-07-10 10:22:30 +08:00
    不大明白你的这个会员信息是什么类型的,没有多登录限制吗?
    spcharc
        2
    spcharc  
       2020-07-10 10:25:57 +08:00
    你的 app 如果提供的是本地服务,那么无论如何都可以破的
    提供在线服务,就服务端验证呗,怎么样都破不了的
    jimliang
        3
    jimliang  
       2020-07-10 10:26:49 +08:00
    把加密的逻辑和安全要求比较高的代码用 native 实现(例如 c++或者 rust ),增加破解的成本。
    tctc4869
        4
    tctc4869  
       2020-07-10 10:28:39 +08:00
    不要信任客户端,所有关键的用户服务,尽量放在服务器上,加固服务端的校验就可以了。
    wujieyuan
        5
    wujieyuan  
       2020-07-10 10:31:08 +08:00   ❤️ 17
    首先要说明, 不管用何种加固方案, 都有对应的脱壳方法然后修改代码重新打包, 对此是没有任何办法的. 所以软件混淆要尽量复杂,可以自定义混淆字典,让代码越难看越好.
    我的解决方法有两种:
    1.是在软件里面埋点, 比如隔一段时间上报软件的签名 sha1,md5 等校验信息, 重新打包之肯定会改变, 然后在服务器冻结这些账号. 上报的代码尽量隐蔽, 上传频率尽量低. 比如在 so 中写几份,java 中写几份
    2.远程执行代码, 利用 socket 推送消息,执行相应代码(sha1,md5 等)并上报到指定域名, 这个域名一定不要在软件中写死,容易被发现,写在 socket 消息中, 隔个几天发送一次检测消息,一般人很难发现
    murmur
        6
    murmur  
       2020-07-10 10:34:14 +08:00
    是的,在国内做工具类软件的结局只有死,ios 可能有情怀用户付费
    wujieyuan
        7
    wujieyuan  
       2020-07-10 10:35:17 +08:00   ❤️ 1
    其实我也深受此种破解方法的困扰, 导致收费软件损失惨重, 楼上说的什么服务端校验,服务端逻辑根本行不通, 破解者只要代理服务器 api, 就可以通过一个付费账号代理无数个免费账号, 客户端只要重新打包或者 hook 修改即可
    wujieyuan
        8
    wujieyuan  
       2020-07-10 10:40:08 +08:00   ❤️ 2
    最后还有一个无奈的方法, 就是限制关键 api 的每日访问次数, 就算服务端被一个付费账号代理了, 也只能使用一段时间, 破解者只能购买多个付费账号, 可以降低一些损失. 当然如果破解者爬取了所有的服务端数据,提供离线访问, 完全切断和服务器的连接, 那就神仙都救不了了
    takemeaway
        9
    takemeaway  
       2020-07-10 10:49:06 +08:00
    没有用的,只能想能否用另外的方式提供服务。
    spcharc
        10
    spcharc  
       2020-07-10 10:49:41 +08:00
    @wujieyuan #7
    遇到这种异常访问的,那就封号呗。说不正当使用,违反某条反正也没人看的用户协议
    这样破解者的会员账号被封几次他就不想破解了吧?
    wujieyuan
        11
    wujieyuan  
       2020-07-10 10:50:57 +08:00   ❤️ 4
    @spcharc 你完全低估了这些破解者的耐心, 只要有钱赚他就会搞你, 没钱赚也会 DDOS 恶心你
    atfeel
        12
    atfeel  
    OP
       2020-07-10 10:57:20 +08:00
    @kzfile APP 要会员登录才能使用区安监部功能,那是不是要验证用户信息呢,要不要登录账号呢,要不要返回站好信息呢
    miv
        13
    miv  
       2020-07-10 10:59:33 +08:00 via iPhone
    @wujieyuan 学到了,谢谢老哥分享,感觉搞这方面非常不容易
    Cheons
        14
    Cheons  
       2020-07-10 11:04:23 +08:00 via Android
    好奇什么服务
    ggght
        15
    ggght  
       2020-07-10 11:06:53 +08:00
    客户端不要认为有任何安全性,就当成浏览器环境就行。安全啥的应该交给服务端来保证。
    zjsxwc
        16
    zjsxwc  
       2020-07-10 11:08:05 +08:00
    盗版网络小说被禁了吗?

    目前可行的解决办法就是参考方正字体这种高额版权费呗。
    hugedeffing
        17
    hugedeffing  
       2020-07-10 11:09:34 +08:00
    目前也没有好的方案,建议就是将用户和设备进行识别绑定,一般认为一个正常会员最多 2-3 个手机,新设备加入需要抵掉旧设备,可以直接提示修改密码,让其邮件验证等,提高验证水平。
    locoz
        18
    locoz  
       2020-07-10 11:11:48 +08:00   ❤️ 5
    我用攻击者角度,给你分析一下吧:
    360 免费加固这种是可以秒脱的,毫无难度,甚至淘宝都有卖脱壳服务的,花点小钱就搞定了。但高级的加固也好不到哪去,无非就是多了个修复步骤而已;然后你前面说被反编译了之后还重新打包了,说明你没有采用一些能让反编译工具出错的防范措施,导致别人可以直接反编译出非常清晰的代码并直接导出使用。如果人家不需要大改你的 APP 的话,甚至直接在 smali 层面植入自己的东西就能搞完。
    基本的安全措施没有做到位,发生这种事情很正常。

    话说你所说的这种情况,是有人重打包了你的 APP 然后放到网上骗了一些普通用户,普通用户在你这充了会员之后,重打包的那人通过这个 APP 得到了普通用户的登录态,并用普通用户的登录态来免费用你的软件?
    这基本无解的啊,你只能是尽量确保所有正规下载渠道(应用商店)都覆盖到你的正版 APP,避免普通用户下到重打包的盗版。或者,通过法律手段解决问题。

    然后是楼下的建议:
    在线服务、服务端验证...这种都可以忽略了,这种会员可见的模式只能通过反逆向和风控来限制。
    加密逻辑或安全要求比较高的代码采用 native 实现可行,但也只能是增加成本而已。
    代码里埋坑是可以的,但必须得要让人难以分辨出是干什么用的,不要混在主要逻辑中,要不然很容易被发现。另外,由于对方已经反编译并重打包过你的 APP,所以如果你要埋坑的话,一定要先把代码混淆和加固弄好了再发出去,要不然别人可以很轻易地通过代码对比发现你埋的坑。

    ---

    其实所有设备 ID 、签名信息之类的都不可信,说白了就是客户端生成一下的事情...还是得要结合实际业务逻辑来做风控。
    jdgui
        19
    jdgui  
       2020-07-10 11:13:31 +08:00
    360 这些都有成熟的反编译方案了
    你真的想要防止反编译,就把校验的部分放 so 库里。
    但是这些并不能从根本上解决,只能说增加成本,从而让破解者感觉划不来
    ksssdh123
        20
    ksssdh123  
       2020-07-10 11:23:28 +08:00
    移动端能做安全策略很有限的,只要有利可图,破解者分分钟夸张点,少则 1 天多则几天的功夫就把你给破解了,然后重新打包上架赚广告费或者自己做运营都有可能

    道高一尺,魔高一丈,通过移动端去做只是增加了破解者破解的时间,你更应该从后台的反爬虫策略出发,还有就是楼上说的,保证几个正规的大渠道分发的都是你的包即可

    至于后台的反爬虫策略,我不记得是豆瓣还是哪个平台,人家就算是收费用户在连续看了前几十页的内容后,后面的内容就不给看了,认为是爬虫程序在爬数据,为了反爬都做到这种地步了
    zdd2389
        21
    zdd2389  
       2020-07-10 11:32:10 +08:00
    改用 flutter,目前是无法反编译的
    doudouwu
        22
    doudouwu  
       2020-07-10 11:42:18 +08:00
    如 #wujieyuan 所说
    客户端和服务端都有破解思路,这两方面都需要考虑到
    其实不说应用本身,防盗版方面 Surge 这个软件真的可以当做范本了
    Android 方面客户端确实更不安全,所以保持高频率的迭代,每次迭代都有吸引力也是一个好办法
    silencht
        23
    silencht  
       2020-07-10 13:11:17 +08:00
    做 iOS
    dilu
        24
    dilu  
       2020-07-10 13:17:00 +08:00
    建议这样:抽一个核心的东西放到服务端进行运算,然后取 device_id 判断用户是不是重复登录 如果是重复登录就直接把上个设备的退登掉
    maokabc
        25
    maokabc  
       2020-07-10 13:27:54 +08:00 via Android
    尽量弄 so 里,起码比 dex 反编译难度大,可以挡掉部分人。
    InkStone
        26
    InkStone  
       2020-07-10 13:42:32 +08:00
    用 flutter 确实是个可行方案,比免费的加固安全得多。不过真要有利可图,被破解也是迟早的事儿。
    wujieyuan
        27
    wujieyuan  
       2020-07-10 13:45:23 +08:00
    @dilu device_id 代码可以被修改, 使所有破解客户端都返回同一个 device_id,你如果判断?
    WebKit
        28
    WebKit  
       2020-07-10 13:47:25 +08:00 via Android
    IOS 都可以重新打包。何况安卓呢。。
    WebKit
        29
    WebKit  
       2020-07-10 13:47:57 +08:00 via Android
    @silencht iOS 也可以被反编译,而且很简单
    natsji
        30
    natsji  
       2020-07-10 13:50:20 +08:00 via Android
    寄律师函
    buger88
        31
    buger88  
       2020-07-10 13:54:26 +08:00
    没有不能反编译的 APP 反编译交流的可以撩我,我拉群+V: ali88pay
    ochatokori
        32
    ochatokori  
       2020-07-10 14:21:01 +08:00 via Android
    正常,只要你的数据是一次性付费获取的,就算不反编译也会各种网盘分享
    buger88
        33
    buger88  
       2020-07-10 14:56:17 +08:00
    Felldeadbird
        34
    Felldeadbird  
       2020-07-10 14:57:28 +08:00
    一个账号限制端在线数。

    其实应该高兴发现这种事情,攻防很有意思的。
    leapV3
        35
    leapV3  
       2020-07-10 15:11:06 +08:00
    服务端做登录验证,同一时间只允许一个设备登录(爱奇艺??),更新 token
    永远不要相信客户端传的数据
    tctc4869
        36
    tctc4869  
       2020-07-10 16:40:08 +08:00
    @wujieyuan 如果这样呢,依据 设备 id+用户信息+ip 信息 呢?但若仅仅凭借服务端用户体系的话,有哪些策略么?
    wujieyuan
        37
    wujieyuan  
       2020-07-10 16:52:38 +08:00
    @tctc4869 设备 id,用户信息都可以通过修改客户端伪造, ip 信息不可靠无法判断是一个人在用还是一群人在用. 没什么好的策略
    joyhub2140
        38
    joyhub2140  
       2020-07-10 16:54:32 +08:00
    其实我很想说,账号和 APP 破解没什么联系,就算 APP 加固到无坚不摧,账号被共享了还是得跪,不如考虑多终端同时登录就干掉之前的 token 吧?踢人可以让正常用户感知账号被泄漏,然后迫使自己改密码。
    winglight2016
        39
    winglight2016  
       2020-07-10 16:58:55 +08:00
    @jimliang 似乎没啥用,非常容易破解。有个朋友只花了几分钟就搞定了一个 so 包。

    据我了解,付费的商业加密有些比较高级的方法,是内存级的混淆,这个在我浅薄的 java 知识看来已经很难破解了。
    wujieyuan
        40
    wujieyuan  
       2020-07-10 17:02:54 +08:00
    @joyhub2140 也行不通, 破解者会代理服务器, 所有破解客户端都连接破解者的服务器, 然后转发到你的服务器, 你看到的 token 始终只有一个,当然付费账号也只有一个,破解者可以无限转卖 vip
    wupher
        41
    wupher  
       2020-07-10 17:27:06 +08:00
    1. 不要信任所有的客户端请求,包括浏览器,App
    2. 在服务端进行安全验证和控制,返回相应的数据。
    tctc4869
        42
    tctc4869  
       2020-07-10 17:39:25 +08:00
    @wujieyuan 代理服务器的破解方式,服务端有没有什么办法?
    Vclow
        43
    Vclow  
       2020-07-10 17:46:07 +08:00
    只能增加反编译成本,铁了心搞你真心很难反抗。
    wujieyuan
        44
    wujieyuan  
       2020-07-10 18:00:13 +08:00
    @tctc4869 代理服务器的话, 服务端没有办法, 我目前能想到的我上面的帖子已经说过了, 就是埋单上报, 看看客户端是不是篡改了域名, 签名等等, 如果破解者够耐心或者够聪明, 删掉了上报代码, 那就没有任何办法了
    wujieyuan
        45
    wujieyuan  
       2020-07-10 18:02:07 +08:00
    @tctc4869 我说的上报其实比较笼统, 可以灵活运用, 也不一定需要上报, 比如在 native 中检测, 如果发现异常直接退出等等, 不过这些手段都可以被干掉, 无非就是增加一点破解难度
    tctc4869
        46
    tctc4869  
       2020-07-10 18:30:22 +08:00
    @wujieyuan 拿这种方式可以不,就是动态编译(如果 java 有的话),

    把一部分代码从主程序里移出,放到服务器上,登录后从服务器下载加密的源代码,动态编译后,来实现这部分功能。这样只要他不登录,本地的代码无论如何都是缺失的,不可能跑起来。这个方式有哪些可行的可能?
    libook
        47
    libook  
       2020-07-10 19:02:31 +08:00
    其实 iOS 安装包本身的安全性可能还不如安卓,只不过 iOS 大家一般用非越狱系统,统一从 App Store 下载应用可以规避很多安全问题,顺便提一下,如果 iOS 应用加固力度过强可能会被 App Store 拒绝,因为会被怀疑是马甲 App (让人琢磨不透的苹果¯\_(ツ)_/¯)。

    客户端是不可信任的环境,客户端加固只能增加破解成本,但不能彻底避免破解问题,所以安全方面最好尽可能在服务端做。
    可以尝试做互踢,同一个账号多人登录会踢掉当前已经登录的设备,服务端需要记录用户登录会话的状态,如果有重复登录的情况出现则强制让统一账号的所有现有的用户会话失效;这样被踢出的用户需要重新登录,可以使用基于后端判断的验证码等方式来提升登录操作成本(无法自动化登录,必须人工干预);以及检测到违规使用的情况就封禁账号,必须联系客服反映情况来解封,相应的风控规则最好写到用户协议里,避免投诉和法律风险。
    dingwen07
        48
    dingwen07  
       2020-07-10 19:34:54 +08:00 via iPhone   ❤️ 3
    之前听说过一个防止账号共享的方法:
    让改邮箱和密码变得极为简单 不需要邮件验证什么的
    hongfushi
        49
    hongfushi  
       2020-07-10 19:54:59 +08:00 via Android
    有意思,看来还是只能从经济角度考虑,不然总有破解方法。
    no1xsyzy
        50
    no1xsyzy  
       2020-07-10 20:10:16 +08:00
    最终解“按量付费”。
    听你的说法这是个 SaaSS,就按计算发生的次数付费。
    一种比较可用的变形是限制单位时间的使用次数,这个次数限制对大部分用户来说基本不可能用完。
    比如见过每分钟 20 次查询的限额,转手代理服务器卖就很难不超过 20/min 。
    并且一旦发现这样的服务,立刻向各个渠道宣传。
    让众包羊毛党薅死他这个转包的羊毛党。
    no1xsyzy
        51
    no1xsyzy  
       2020-07-10 20:14:19 +08:00
    俺寻思按量付费也不是什么新鲜玩意。
    为什么在整个互联网 ICP 基础设施全面转向按量付费的情况下,程序员的诸位想不到按量付费?
    (bgm38)深深地表示惋惜!
    iyaozhen
        52
    iyaozhen  
       2020-07-10 20:27:47 +08:00
    帐号互踢不就行了

    然后一个 cookie 的有效期短一点


    代理服务器的话可以判断请求 ip,除非别人服务器很多(成本问题)。然后可以做一些简单的异常分析,比如访问 A 页面的同时又在访问 B 页面
    HappyFox
        53
    HappyFox  
       2020-07-10 20:40:57 +08:00   ❤️ 1
    这个是风控的问题,如果不是职业相关,个人开发者想解决这些问题其实怪麻烦的。说一下我的思路,抛砖引玉。

    1.对自己的用户有足够的了解,在用户行为上做出限制。
    正常用户用 app,肯定有操作路径,如果没有相应的操作直接请求接口,直接拒绝+黑名单。
    用户协议写死了不能用第三方客户端,否可予以封号。

    2.app 数据采集足够详细,该埋点往死里埋点,用户的操作详情以改善用户体验的名义上传。

    具体展开可以看这篇文章:
    https://mp.weixin.qq.com/s?subscene=23&__biz=MzI2MzE2NDczMw==&mid=2649738162&idx=1&sn=7337af200665862fd6592b263e1dad16&chksm=f25b6de0c52ce4f67e026c8066379c5fec6a9899811471ccef6bb74ccf4e22ac5d3c2f702b0e&scene=7&key=2cc21493b77c18de07e0c7b2f0c7df8284c8c3382227dbb70403bf33ff118eb1aa836e22afaf2401057c07a7ebc0303d6902fd5257415215568ed7bec797b5400f82817fd2941c78dbf293fbee052a6f&ascene=0&uin=MjkxMjAyOTM0MA%3D%3D&devicetype=Windows+10+x64&version=62090529&lang=zh_CN&exportkey=AdbThuhPM7pHajrPpqX9ttQ%3D&pass_ticket=VpiFKjDhyGkOpEoF9Jh97zJ8O2hp5nGA2EvbnN1ADuSy%2Fld71hBU1Ad49FE6Owz5

    策略看这张图片:
    SenLief
        54
    SenLief  
       2020-07-10 20:49:18 +08:00
    客户端返回的信息都是不可信的。
    如果不是多端的话那就互踢是最省事的,比如爱奇艺。
    最直接的手段就是限制设备的个数,比如 1 手机 1pc,然后接着互踢。
    再次一点就是拉黑名单,比如 1 天请求登陆了很多次,那肯定是搞事的,直接把账号 ban 了,并发账号被盗,解封。
    最直接的就是迭代版本的速度快一点,每次换个方式混肴,也会大大增大难度了。
    Jirajine
        55
    Jirajine  
       2020-07-10 20:56:13 +08:00 via Android
    @wujieyuan 一众“流媒体解锁”服务不就是这么搞得么,通过服务器反代+共享账号,netfl1x 都没什么好办法应对。
    hoyixi
        56
    hoyixi  
       2020-07-10 21:11:32 +08:00
    自己合法吗,合法的话,损失大可以报案。
    jones2000
        57
    jones2000  
       2020-07-11 01:37:50 +08:00
    只要数据是在后台的,前端怎么破解都没关系的呀, 最后的验证都在后台服务器的, 账户通过在线数来限制,1 个账户允许 2-3 个设备在线,在多的连接就直接剔,或直接锁账户, 让用户手机验证改密码解锁。
    billccn
        58
    billccn  
       2020-07-11 02:10:29 +08:00
    我有一个终极的办法:把你的客户端变成 VNC,所有逻辑和 UI 在服务器上跑。这样他也没法把几个账号复用了,因为同一个账号同时只能有一个人能正常操作,账号复用多个人同时操作要打架了。

    如果你内容是纯静态的(比如文字),你还可以把屏幕转成视频直播,然后套上第三方支持 TrustZone 等的硬件级 DRM,这样抓屏都很困难,就不可能转给别人用。

    如果你不舍得服务器资源,那可以简单一点,UI 在客户端渲染,但是 UI 逻辑全部在服务端,就是说所有用户的输入(比如坐标,事件类型)都是传到服务器,服务器计算 UI 要怎么更新,再发到客户端渲染,Java 里全部可以通过反射和 proxy 实现。然后你要限制比如说用户最快每秒点一次(因为点快了也来不及处理),他就很难复用账号了。

    你还可以在内容 /UI 中加入一些识别是不是同一个人使用的验证,比如每过一段时间就要用户选则哪个操作是用户最近做过的才能继续(类似淘宝验证),账户复用的话,用户是不知道其他用户都做了什么的。

    还可以恶心共享账户的人,比如强制绑定一个支付渠道,然后设置一些内付几毛钱才能使用的功能。

    如果你觉得最终用户不知道他们是下了假的软件,可以偶尔把正常内容替换成验证信息,比如软件是授权给谁,举报账号复用有奖等。
    Niphor
        59
    Niphor  
       2020-07-11 10:09:30 +08:00
    付费账号 只准一个 IP 在线
    loginbygoogle
        60
    loginbygoogle  
       2020-07-11 11:26:50 +08:00 via iPhone
    flutter 教它做人
    silencht
        61
    silencht  
       2020-07-11 12:17:47 +08:00
    @WebKit 问题的关键不在于被不被反编译,在于 iOS 平台付费意愿比例远高于安卓
    TransAM
        62
    TransAM  
       2020-07-11 15:11:38 +08:00 via Android
    你就不会按量计费嘛?
    wujieyuan
        63
    wujieyuan  
       2020-07-11 20:59:27 +08:00
    @tctc4869 这个就是远程执行代码, 可以的, 远程执行 dex, 但是如果被破解者发现, 他不仅可以修改这个机制, 甚至可以利用这个机制执行自己的代码,连破解重新打包都省了
    KasuganoSoras
        64
    KasuganoSoras  
       2020-07-12 08:16:11 +08:00
    @billccn #58 这个想法是可行的,就是有点耗服务器宽带,之前我们群里搞活动有个 H5 小游戏就是通过服务端渲染的方式实现的,渲染出画面后再通过 canvas 在客户端显示,然后二十个人在线服务器宽带占用就飙升到 30Mbps,可能也和图像压缩算法有关
    lijianqiang12
        65
    lijianqiang12  
       2020-07-12 13:35:44 +08:00 via Android
    在 ndk 中校验一下签名,不对的话就终止进程,与服务端通信过程中依赖 ndk 中运算的字段,我用这个方法杜绝了破解,百分之九十九点九的破解者都是靠着 mt 这样的软件反编译修复的小菜鸡。
    tctc4869
        66
    tctc4869  
       2020-07-13 08:36:48 +08:00
    @wujieyuan 不,这得看远程执行的代码是什么样的,如果这个远程代码和用户登录状态是强关联,那就有很强的反破解效果。
    keventseng
        67
    keventseng  
       2020-07-13 11:49:14 +08:00
    客户端只做操作,数据、校验等在线上才能解决本地破解的问题。本地化基本很难防破解。。
    xiner
        68
    xiner  
       2020-07-13 17:10:26 +08:00
    Android So 库高强度加密保护 https://www.kiwisec.com/product/KiwiVM-so.html
    将 C/C++代码指令转化为私有指令,运行在受保护的私有虚拟机中,能有效解决因逆向工程引起的安全问题。
    支持对 Android JNI 项目的 C/C++代码进行虚拟化、混淆、字符串加密等安全保护。该系统基于 Clang 编译器扩展实现, 能够对项目的源代码进行安全编译,并且在编译阶段可以对指定的函数实施代码虚拟化、代码混淆等加密处理。其中代码虚拟化功能凭借自定义 CPU 指令的特性,代码一旦加密,永不解密,攻击者无法还原代码,分析核心业务逻辑。可帮助中大型企业在通信、支付、算法、核心技术等模块进行深度加密,避免因逆向破解问题造成的经济损失。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1908 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 16:19 · PVG 00:19 · LAX 08:19 · JFK 11:19
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.