首页
论坛
课程
招聘
雪    币: 1291
活跃值: 活跃值 (2691)
能力值: ( LV7,RANK:140 )
在线值:
发帖
回帖
粉丝

[原创]对抗一款 App 的 token 验证

2020-5-12 09:02 9634

[原创]对抗一款 App 的 token 验证

2020-5-12 09:02
9634

目录

1. 前言

最近又找了个不符合核心价值观的 App 练手,比上篇帖子中的那个还要过分,本来还在犹豫要不要写帖子发出来,后 @r0ysue 巨佬说这是伸张正义打击违法犯罪的事情表彰还来不及,遂仔细整理了下分析思路和经验来发帖子了,给像我一样的入门者提供一个完整的案例来分析练手,以提升巩固学习到的零碎的技术,顺便打击下违法犯罪。

2. App 简单分析

由于这个 App 的每一个界面都十分违规就不展示了,这里让我们脱离 App 的内容本身,把重点放在技术方向上。

 

 

 

当我们看到这里时候,第一直觉是以破解内购的思路去购买 vip,本地修改观影次数改成无限次,但是这样是不行通的,在分析过程中逐步会发现这个 App 的防护工作做的蛮好的,首先是加了壳,然后通信过程中给数据进行了加密,最重要的是这个 App 是在服务器进行了 token 的管理和验证的,和简单内购就可以破解的 App 呈现截然不同的样子,下面让我们通过一点点分析这个 App,来熟悉 App 的一些简单的防护策略和对应的逆向思路。

3. 脱壳

3.1 脱壳的一些说明

首先是脱壳,App 是加了梆梆的免费版壳,我们这里依然可以采用 frida-unpack 来直接脱壳,关于 frida-unpack 的使用以及使用过程中碰到的问题解决,具体操作可以看我的上一篇帖子(https://bbs.pediy.com/thread-258776.htm)的脱壳部分,这里不详细说了,直接放出代码。

#-*- coding:utf-8 -*-
import frida
import sys

def on_message(message, data):
    if message['type'] == 'send':
        base = message['payload']['base']
        size = int(message['payload']['size'])
        print(hex(base), size)
    elif message['type'] == 'error':
        for i in message:
            if i == "type":
                print("[*] %s" % "error:")
                continue
            if type(message[i]) is str:
                print("[*] %s" %
                      i + ":\n    {0}".format(message[i].replace('\t', '    ')))
            else:
                print("[*] %s" %
                      i + ":\n    {0}".format(message[i]))
    else:
        print(message)
    # print session
    # dex_bytes = session.read_bytes(base, size)
    # f = open("1.dex","wb")
    # f.write(dex_bytes)
    # f.close()

    #

# 9.0 arm 需要拦截 _ZN3art13DexFileLoader10OpenCommonEPKhjS2_jRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPKNS_10OatDexFileEbbPS9_NS3_10unique_ptrINS_16DexFileContainerENS3_14default_deleteISH_EEEEPNS0_12VerifyResultE
# 7.0 arm:_ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_10OatDexFileEPS9_

package = "com.hello.qqc"
print( "dex 导出目录为: /data/data/%s"%(package))
device = frida.get_usb_device()
pid = device.spawn(package)
session = device.attach(pid)
src = """
var exports = Module.enumerateExportsSync("libart.so");
    for(var i=0;i<exports.length;i++){
        if(exports[i].name == "_ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_10OatDexFileEPS9_"){
            var openMemory = new NativePointer(exports[i].address);
            }
     }

Interceptor.attach(openMemory, {
    onEnter: function (args) {

        var begin = args[1]

        console.log("magic : " + Memory.readUtf8String(begin))

        var address = parseInt(begin,16) + 0x20

        var dex_size = Memory.readInt(ptr(address))

        console.log("dex_size :" + dex_size)

        var file = new File("/data/data/%s/" + dex_size + ".dex", "wb")
        file.write(Memory.readByteArray(begin, dex_size))
        file.flush()
        file.close()

        var send_data = {}
        send_data.base = parseInt(begin,16)
        send_data.size = dex_size
        send(send_data)
    },
    onLeave: function (retval) {
        if (retval.toInt32() > 0) {
        }
    }
});
"""%(package)

script = session.create_script(src)

script.on("message" , on_message)

script.load()
device.resume(pid)
sys.stdin.read()

要提一下的是我这里的环境是 夜神模拟器 Android 7.1.2 版本,其他的安卓版本可能跑不了这个脚本,需要进行修改或者找其他的 hook 点,比如 Android 8.1 版本的可以去 hook OpenCommon 函数,再比如Android 9.0 的 OpenMemroy 的参数不一样,arg[1] 不是 dex 的内存地址,是 dex 的大小等等。这些问题如果碰到的话,就需要自己去探索原理解决了,上篇帖子的评论区的一些讨论很有参考价值,如果不熟悉或者碰到 的话可以去看一下。

3.2 脱壳后重打包

现在我们成功脱壳,并且可以在“/data/data/com.hello.qqc”目录下找到 4 个脱出来的 dex 文件,下面我们进行脱壳后的重打包操作。

 

 

 

首先把四个 dex 文件改名为 classes.dex,classes2.dex,classes3.dex,classes4.dex,然后替换掉原来加壳 apk 中的 classes.dex 文件。

 

然后就是修改 AndroidManifest.xml 文件中 application 节点下的 android:name 属性,原来的是 android:name="com.SecShell.SecShell.ApplicationWrapper",这是梆梆壳启动的地方,现在我们需要修改为脱壳后的 dex 中继承了 Application 的类,我们搜索“ extends Appliaction”,可以找到是“cn.net.tokyo.ccg.base.App”

 

 

 

现在我们改成 android:name="cn.net.tokyo.ccg.base.App",然后进行签名后安装,可以发现能够正常运行。

4. 抓包

4.1 Aes 加密

当我们尝试用 Charles 开启 https 代理然后抓包时候,发现数据被加密了。

 

 

例如这个,我们注意到加密数据都是以 “d”开头的,值得注意的是第一个加密数据“d:xxxxxxxxxxxx”是在 https 请求报文头里面的,每个 https 请求的报文头都会写入一个这样的加密数据,我们猜测它是和用户的身份认证有关。像第二个和第三个加密数据就分别是请求参数和返回数据的加密了。

4.2 代码解密数据

我们进行分析寻找,在 “cn.net.tokyo.ccg.base.encrypt.EncryUtil”找到加解密代码部分,可以发现是 Aes 加密,key 和 iv 也能找到。

 

 

 

 

我们可以写出 Aes 解密的 Java 代码来解密我们想要解密的数据,代码如下,我们先来解密一下刚才我们好奇的每个 https 请求的报文头都写入的加密数据是什么。

package AesDecrypt;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.Key;
import java.util.Base64;

public class EncryUtil {

    public static void main(String []args) throws Exception {
        String str ="suh8B7nUE/BRq3WsTT1R7YpRKA8PfI7xAnwisnYUT2I/Agp8iMWbc7ihFNosWg7oqn/g5Zw/fPqxTUjRvcO5CigHWtsR2KRL6pOTxu9IXufRGafuHOLLFU1bLOpAqW2Y0lPG5L2PjyW1tXM5ZaXs9m3wfV5nTbRWe+hcNom+1Ly2yQwiXFBBEnl5QOH78j3ow2Ho7qx5i2Gfr5fJTgb3jtmJT7qtep7FMeJoqzdotNVdiRPrG/yShHe1blD2KmK6+3CfxdzqNyvd6OcxpnS+n52LvAerjDwVA5I0Nlgxj94qZ4I0rpl99vr97Yc2lmszjICIJUPx0+/XyjjonCAZO99AklJCtgguCeQxwDKP4x86mNLB498ckcLPxFD+gARWujdeG9K3t1cGpm35rz+1SgOc0qnZA59SHmssxn50MKsYeY1t7JM8gopFO+e8EFHiqjZ19EPVq+RdnKIWrBG2DzWg7WX25d3MKg8IiqU7ZUseWwg1u/SW6ufAuuDhJva2MunqhBJNVky4E4NyzTe5jg==";
      System.out.println(decryptFromBase64(str));
    }

    public static String decryptFromBase64(String arg1) {
        String v0 = "UTF-8";
        try {
            Base64.Decoder decoder = Base64.getDecoder();
            return new String(decrypt( decoder.decode(arg1.getBytes())), v0);
        }
        catch(UnsupportedEncodingException v1) {
            throw new RuntimeException("decrypt fail!", ((Throwable)v1));
        }
    }
    public static byte[] decrypt(byte[] arg3) {
        String v0 = "AES";

        byte[] arg4 = "xPxo2S5uGPhKHx5g".getBytes();
        byte[] arg5 = "0a1b2c3d4e5f6789".getBytes();
        if(arg4.length == 16) {
            try {
                SecretKeySpec v1 = new SecretKeySpec(new SecretKeySpec(arg4, v0).getEncoded(), v0);
                Cipher v4 = Cipher.getInstance("AES/CBC/PKCS5Padding");
                v4.init(2, ((Key)v1), new IvParameterSpec(arg5));
                return v4.doFinal(arg3);
            }
            catch(Exception v3) {
                v3.printStackTrace();
                throw new RuntimeException("decrypt fail!", ((Throwable)v3));
            }
        }

        throw new RuntimeException("Invalid AES key length (must be 16 bytes)");
    }
}

解密的结果是{"Connection":"close","app":"3","platform":"1","s":"cd551ab25dc5c0e93def7b9bd42df473","t":"22430220186106","token":"LzF2SHp6NldrVmVBaHFobmVMVys3RFZ3VkxVRnFMYSs4akRYUGlrRnlLL05lTXBPblp6YUJVekxxTjBERG9xNktDVzRackxhY3hCeTdyaWdsVDMyejMxa05oQmVLa2l0UDU4NjZLSWlzN0YzRzZ0V2dDWnM1UmFsbUxGSnNVUW1XWlYvMnp0SldvWUNJKzFjdHlvbFo0c2VYcHMyMERreWFOMUt6b1d0enVpWno1QnIxcXI4TWY2NGQ4NVZpdlVF","version":"1.2.5"}

 

可以看到有个“token”,让我们记住它。

4.3 frida 进行模拟抓包

同时我们还可以使用 frida 来模拟抓包,当我们在寻找 hook 点时候,会发现这个 App 发送请求和接收数据的地方也要比上个帖子中的 App 复杂很多。

4.3.1 hook 请求

分析过程发现请求都被很规范地被封装到了接口类“cn.net.tokyo.ccg.dagger.Apis”中,

 

 

不断地寻找 hook 点,我们在“cn.net.tokyo.ccg.dagger.module.ApiModule”类中找到了 https 请求封装的地方,

 

 

这里我们可以看到熟悉的字符串,就是刚才我们解密的每个 https 请求的报文头都写入的数据,里面的 token 尤其显眼。我们把这里作为打印请求数据的一个 hook 点,hook static Response a(Interceptor$Chain arg1)
在hook函数时候主动调用传入参数的方法arg1.request().url().toString(),即可打印出请求 url。然后在 Aes 加密的地方作为另一个 hook 点,可以打印出加密的请求数据。

    var ApiModule = Java.use("cn.net.tokyo.ccg.dagger.module.ApiModule");
    ApiModule.a.overload('okhttp3.Interceptor$Chain').implementation = function(arg1){
        send("发送请求**********************************************")
        send("request_url:"+arg1.request().url().toString());
        return this.a(arg1);
    }

    var EncryUtil = Java.use("cn.net.tokyo.ccg.base.encrypt.EncryUtil")
    var GsonTools = Java.use("cn.net.tokyo.ccg.base.helper.GsonTools")
    EncryUtil.encryptAes.overload("java.util.Map").implementation = function(arg1){
        send("请求加密数据:")
        send(GsonTools.createGsonString(arg1));
        return this.encryptAes(arg1);
    }

4.3.2 hook 数据接收

不断寻找,数据接收的 hook 点我们选择在 “cn.net.tokyo.ccg.dagger.MoreBaseUrlInterceptor”类中的 intercept 方法,它的参数一是相应报文的一些信息,我们同样可以打印出来。

    var MoreBaseUrlInterceptor = Java.use("cn.net.tokyo.ccg.dagger.MoreBaseUrlInterceptor");
    MoreBaseUrlInterceptor.getResponseString.implementation = function(arg1){
        var result = this.getResponseString(arg1);
        send("接收数据**********************************************");
        send(""+ arg1);
        send(result)
        return result;
    }

4.3.3 效果

比如我们注册一个账号,抓包效果如图。

 

 

5. token 验证

5.1 hook 修改的失败与 token 验证

在开始的时候说到,一般的破解思路首先是尝试内购破解,修改本地的 App 端数据然后更新到服务器,按着这个来的话,我们首先找到存储用户信息的类“cn.net.tokyo.ccg.bean.User”,可以看到里面有很多数据,并且有相应的 getXxx()和 SetXxx()方法。

 

 

然后当我们尝试 hook 去修改 is_vip 和 view_limit_today,也就是 vip 和 每天限制观看次数,发现修改没有作用,观看后还是弹出窗口提示观看次数已看完让充值 vip。

 

 

问题出在哪里了呢,我们在 App 内部尝试搜索这些字符串,没有搜索结果,说明可能是服务器返回的,那就抓包看一下,当弹出这个窗口时候发生了什么。

 

 

 

 

可以看到弹出窗口中的字符串确实是服务器返回的,那么服务器是通过什么来知道用户观看次数已经用完了呢?

 

我们观察附近的请求的参数,能够判断服务器是通过 token 来知道用户观看的次数,不仅是观看次数,用户的各种信息如是否是 vip 服务器都能通过 token 确认,所以现在问题清晰了,由于服务器存在 token 验证,所以一般的内购破解思路是不起效果的。

5.2 token 及其他一些数据的存储—— SPHelper

现在我们就具体分析下 token,首先我们找到一处获得 token 的地方作为一个点开始分析,以“cn.net.tokyo.ccg.dagger.module.ApiModule”为例。

 

 

我们可以看到用到了 SPHelper 类中的 getString()方法,我们具体看下。

 

 

可以看到最终调用的是 getSharedPreferences()方法,也就是从本地存储的数据中获取的,同时我们还可以看到 SPHelper 类中还有着其他的一些数据存储方法。

 

 

作为验证,我们去本地文件查看一下,打开“/data/data/com.hello.qqc/shared_prefs/config.xml”文件,我们可以看到,不仅是 token,其他很多信息也都存储在了这个文件里面,我们需要着重关注的就是 token 和 key_uuid。

 

5.3 token 的获取—— bootstrap 请求与 android_id

现在已经知道 token 是怎么在本地存储的了,然后就是继续分析寻找 tokne 是怎么获取的了,既然 token 肯定是服务器返回的,那么我们就从抓包入手。

 

 

 

 

我们可以看到了这里服务器返回了 token,这条请求的 url 是 https://jk.py49ri..com/api/v2/bootstrap,并且能够看到请求的一些参数,然后我们可以在 App 中搜索这些参数来定位相关代码处。

 

 

然后我们要做什么呢,需要确定是请求中的什么参数影响了服务器返回了 token,观察可以发现 android_id、deviceid 和 mac_address 是一个东西, 而 device_uuid 呢,分析代码可以知道最后也是要有 android_id 影响生成的。

 

 

 

所以我们现在可以初步判断 token 是由 android_id 生成的。

6. 对抗 token 验证

6.1 对抗思路——“无限 token”

当我们发现服务器会进行 token 验证的时候,可能会觉得很棘手,因为这意味在本地的修改似乎没什么用了,像 vip 除了掏真金白银去购买让服务器认可这个 token 是 vip,好像没什么别的办法了。

 

但是,如果根据我们前面的分析仔细思考下的话,可以发现是有对抗思路的,既然 token 是由每台设备的 android_id 得到的,而每台设备的都有唯一的一个 android_id,并且每天都能免费观看一次,那么我们是不是可以对 app 进行修改,每看完一个视频,就可以产生一个新的随机的 android_id,然后获得一个新的 token,就可以继续观看视频了,这样我们相当于有了无数多的 token 了。

6.2 添加生成随机 android_id 的 smali 代码

现在按着上面的对抗思路来行动,我们需要每次观看一个视频就要要重新生成一个新的随机的 android_id,可以选择在 App 中添加一些新的 smali 代码然后调用。

 

首先用 Java 写一个生成16位十六进制的随机数的类。

package fingerprint.me;

public class getRandomDeviceId {
    public static String getString(){
        String str = "";
        for (int i = 0; i < 16; i++) {
            char temp = 0;
            int key = (int) (Math.random() * 2);
            switch (key) {
                case 0:
                    temp = (char) (Math.random() * 10 + 48);//产生随机数字
                    break;
                case 1:
                    temp = (char) (Math.random() * 6 + 'a');//产生a-f
                    break;
                default:
                    break;
            }
            str = str + temp;
        }
        return str;
    }
}

然后我们编译得到相应的 smali 代码。

.class public Lfingerprint/me/getRandomDeviceId;
.super Ljava/lang/Object;
.source "getRandomDeviceId.java"


# direct methods
.method public constructor <init>()V
    .registers 1

    .line 3
    invoke-direct {p0}, Ljava/lang/Object;-><init>()V

    return-void
.end method

.method public static getString()Ljava/lang/String;
    .registers 8

    .line 5
    const-string v0, ""

    .line 6
    .local v0, "str":Ljava/lang/String;
    const/4 v1, 0x0

    .local v1, "i":I
    :goto_3
    const/16 v2, 0x10

    if-ge v1, v2, :cond_48

    .line 7
    const/4 v2, 0x0

    .line 8
    .local v2, "temp":C
    invoke-static {}, Ljava/lang/Math;->random()D

    move-result-wide v3

    const-wide/high16 v5, 0x4000000000000000L  # 2.0

    mul-double v3, v3, v5

    double-to-int v3, v3

    .line 9
    .local v3, "key":I
    if-eqz v3, :cond_28

    const/4 v4, 0x1

    if-eq v3, v4, :cond_17

    goto :goto_36

    .line 14
    :cond_17
    invoke-static {}, Ljava/lang/Math;->random()D

    move-result-wide v4

    const-wide/high16 v6, 0x4018000000000000L  # 6.0

    mul-double v4, v4, v6

    const-wide v6, 0x4058400000000000L  # 97.0

    add-double/2addr v4, v6

    double-to-int v4, v4

    int-to-char v2, v4

    .line 15
    goto :goto_36

    .line 11
    :cond_28
    invoke-static {}, Ljava/lang/Math;->random()D

    move-result-wide v4

    const-wide/high16 v6, 0x4024000000000000L  # 10.0

    mul-double v4, v4, v6

    const-wide/high16 v6, 0x4048000000000000L  # 48.0

    add-double/2addr v4, v6

    double-to-int v4, v4

    int-to-char v2, v4

    .line 12
    nop

    .line 19
    :goto_36
    new-instance v4, Ljava/lang/StringBuilder;

    invoke-direct {v4}, Ljava/lang/StringBuilder;-><init>()V

    invoke-virtual {v4, v0}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    invoke-virtual {v4, v2}, Ljava/lang/StringBuilder;->append(C)Ljava/lang/StringBuilder;

    invoke-virtual {v4}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;

    move-result-object v0

    .line 6
    .end local v2  # "temp":C
    .end local v3  # "key":I
    add-int/lit8 v1, v1, 0x1

    goto :goto_3

    .line 21
    .end local v1  # "i":I
    :cond_48
    return-object v0
.end method

然后我们向有着代码逻辑的 dex 文件中添加新的类。

 

 

 

然后我们将 “cn/net/tokyo/ccg/base/helper/DeviceHelper”类中的 getDeviceID 方法的 smali 代码替换成调用我们加入的“fingerprint.me.getRandomDeviceId”类中的 getString()方法的 smali 代码。

.method public static getDeviceID(Landroid/content/Context;)Ljava/lang/String;
    .registers 2

    invoke-static {}, Lfingerprint/me/getRandomDeviceId;->getString()Ljava/lang/String;

    move-result-object p0

    return-object p0
.end method

6.3 请求 token 的逻辑

好了,现在我们已经完成了第一步,能够生成随机的 android_id 了,然后我们需要思考就是怎么在观看一部视频前或者观看后根据随机生成的 android_id 主动请求一个新的 token,我们先看请求 token 的逻辑。

 

前面我们已经找到了 bootstrap 请求的相关代码,在“cn.net.tokyo.ccg.util.f”类中的 a 方法,我们从这个点往回溯源寻找调用,先是“b.a.a.a.d.a.m0”类中 h 方法,最后是“cn.net.tokyo.ccg.ui.activity.MainActivity”类中的 onEventReceived 方法。

 

 

 

也就是说请求 token 的逻辑是 onEventReceived 方法接收一个 TaskEvent 并且 action 属性的值是 401,这样就好办了,我们对 TaskEvent 进行交叉索引,然后找到一处发送 TaskEvent 的代码进行观察。

 


现在问题变得很简单了,我们已经知道怎么发送 TaskEvent 了,是通过 “org.greenrobot.eventbus.c.c().b()”方法来进行的,相应的 smali 代码我们也可以很容易写出来,并提供给我们进行主动调用。

 new-instance v1, Lcn/net/tokyo/ccg/base/Event$TaskEvent;

    invoke-direct {v1}, Lcn/net/tokyo/ccg/base/Event$TaskEvent;-><init>()V

    const/16 v2, 401

    iput v2, v1, Lcn/net/tokyo/ccg/base/Event$TaskEvent;->action:I

    invoke-static {}, Lorg/greenrobot/eventbus/c;->c()Lorg/greenrobot/eventbus/c;

    move-result-object v2

    invoke-virtual {v2, v1}, Lorg/greenrobot/eventbus/c;->b(Ljava/lang/Object;)V

6.4 在 Activity 生命周期主动更新 token

然后差不多大功告成了,我们只剩下找到合适的点根据随机生成的 android_id 主动请求一个新的 token,以达到我们点击一部视频就能观看的目的,经过分析后选择在视频播放的 VideoDetailActivity 的生命周期中的 onPause() 和 onDestory()开头添加 smali 代码进行主动请求新的 token,然后需要注意的就是我们需要在请求新的 token 前,把本地存储文件也就是“/data/data/com.hello.qqc/shared_prefs/config.xml”中的 “token”给清空,“key_uuid”也给写入一个随机生成的16位十六进制字符串,以及在添加 smali 代码后注意修改寄存器数量,也就是 .registers,不然如果数量不够的重编译打包签名后运行,程序可能会崩溃,添加的 smali 代码如下。

const-string v0, "token"

    const-string v1, ""

    invoke-static {p0, v0, v1}, Lcn/net/tokyo/ccg/base/helper/SPHelper;->saveString(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)V

    const-string v0, "key_uuid"

    invoke-static {}, Lfingerprint/me/getRandomDeviceId;->getString()Ljava/lang/String;

    move-result-object v1

    invoke-static {p0, v0, v1}, Lcn/net/tokyo/ccg/base/helper/SPHelper;->saveString(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)V

    new-instance v1, Lcn/net/tokyo/ccg/base/Event$TaskEvent;

    invoke-direct {v1}, Lcn/net/tokyo/ccg/base/Event$TaskEvent;-><init>()V

    const/16 v2, 0x191

    iput v2, v1, Lcn/net/tokyo/ccg/base/Event$TaskEvent;->action:I

    invoke-static {}, Lorg/greenrobot/eventbus/c;->c()Lorg/greenrobot/eventbus/c;

    move-result-object v2

    invoke-virtual {v2, v1}, Lorg/greenrobot/eventbus/c;->b(Ljava/lang/Object;)V

添加完 smali 代码后我们重编译打包签名,然后就算完工了,这时候就可以不限次数观看视频了,广告和弹窗也是可以自行去掉的。

7. 后记

需要说一下的是,这个 app 下载之后可能会被杀毒软件杀掉,分析过程中没有看到什么可疑的地方,用某安全卫士查了下,具体原因是“包含插件:Riskware.Cloud.Generic.558926 该软件存在危险行为代码,警惕该软件私自下载安装软件,窃取用户隐私信息,造成用户隐私泄露资费消耗。”,应该不算木马,如果想尝试分析下的话,务必在模拟器或其他沙盒环境下进行。

 

 

完整的分析案例总是可遇不可求的,事无巨细地写这么多分享出来,希望能帮助到像我一样正在学习的人学到一些有用的东西,就像我在论坛上跟着很多优秀的帖子学习到了很多那样,当然如果能点个赞就更好了(逃



[公告]看雪论坛2020激励机制上线了!发帖不减雪币了!如何获得积分快速升级?

最后于 2020-5-12 09:17 被0x指纹编辑 ,原因:
最新回复 (68)
雪    币: 45
活跃值: 活跃值 (19)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
chmlqw 活跃值 2020-5-12 09:17
2
0
这个思路厉害了,学习学习
雪    币: 73
活跃值: 活跃值 (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
hehaohw 活跃值 2020-5-12 09:38
3
0
难怪我修改XXvip不起作用,学习了
雪    币: 3010
活跃值: 活跃值 (37)
能力值: (RANK:110 )
在线值:
发帖
回帖
粉丝
LowRebSwrd 活跃值 2 2020-5-12 09:39
4
0
雪    币: 142
活跃值: 活跃值 (35)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Gwyn9 活跃值 2020-5-12 09:39
5
0
学习学习
雪    币: 1603
活跃值: 活跃值 (49)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
whitehack 活跃值 2020-5-12 09:48
6
0
还没仔细看.先收藏了.  感谢大佬分享.
雪    币: 520
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
rookie江 活跃值 2020-5-12 09:59
7
0
前排围观
雪    币: 1220
活跃值: 活跃值 (60)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Ally Switch 活跃值 2020-5-12 10:07
8
0
感谢分享
雪    币: 520
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
rookie江 活跃值 2020-5-12 10:08
9
0
你好,请教 模拟环境是多少 小米 还是其他 android是多少 apk版本是多少
雪    币: 520
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
rookie江 活跃值 2020-5-12 10:08
10
0
雪    币: 1291
活跃值: 活跃值 (2691)
能力值: ( LV7,RANK:140 )
在线值:
发帖
回帖
粉丝
0x指纹 活跃值 3 2020-5-12 10:11
11
1
rookie江 你好,请教 模拟环境是多少 小米 还是其他 android是多少 apk版本是多少

我用的是夜神模拟器,Android 7.1.2,apk 版本是 V1.2.5.60

最后于 2020-5-12 10:13 被0x指纹编辑 ,原因:
雪    币: 520
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
rookie江 活跃值 2020-5-12 10:17
12
0
谢谢
雪    币: 1355
活跃值: 活跃值 (96)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
Vn小帆 活跃值 2020-5-12 10:21
13
0
没有这个token  拿不到 数据 是吧 
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
meilanzhuju 活跃值 2020-5-12 10:31
14
0
这种分析,有样本的很好,尝试复现学习一下
雪    币: 1291
活跃值: 活跃值 (2691)
能力值: ( LV7,RANK:140 )
在线值:
发帖
回帖
粉丝
0x指纹 活跃值 3 2020-5-12 10:38
15
1
Vn小帆 没有这个token 拿不到 数据 是吧
对,是这个意思
雪    币: 3712
活跃值: 活跃值 (91)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
neilwu 活跃值 2020-5-12 10:41
16
0
赞一个
雪    币: 1
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
litianp 活跃值 2020-5-12 10:45
17
0
牛逼,有收获
雪    币: 5771
活跃值: 活跃值 (46)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
tDasm 活跃值 2020-5-12 10:46
18
0
这个APP服务器设置有问题,照道理一个用户一个安卓i d一天一次免费,而不是一个id一天一次。如果那样,你必须每天注册无数个用户同时还要换id。

雪    币: 2323
活跃值: 活跃值 (91)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
MTRush 活跃值 1 2020-5-12 10:57
19
0
点赞
雪    币: 5
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_fhqbnpup 活跃值 2020-5-12 11:07
20
0
老哥,能贴个APP下载地址嘛
雪    币: 520
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
rookie江 活跃值 2020-5-12 11:08
21
0
老铁 apk可以分享下不 都没找到,哪里下载的
雪    币: 1291
活跃值: 活跃值 (2691)
能力值: ( LV7,RANK:140 )
在线值:
发帖
回帖
粉丝
0x指纹 活跃值 3 2020-5-12 11:14
22
1
rookie江 老铁 apk可以分享下不 都没找到,哪里下载的

这是分析样本,仅作技术学习使用 链接:https://pan.baidu.com/s/1OnHPjnNKUyqE-cslZ60Log 提取码:076i

最后于 2020-5-12 11:15 被0x指纹编辑 ,原因:
雪    币: 469
活跃值: 活跃值 (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
小黄鸭爱学习 活跃值 2020-5-12 11:19
23
0
服了论坛老哥们 总能找到这些激情小软件 能告诉我在哪发现的吗,我也去学习学习
雪    币: 441
活跃值: 活跃值 (37)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
青丝梦 活跃值 2020-5-12 13:32
24
0
这个 修改token 的方法思路挺骚的。 但是 如果没有免费观看这个 玩意  ,是不是只能 花钱买vip了分析普通 的 vip 直接的区别了?
雪    币: 3037
活跃值: 活跃值 (45)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
你咋不上天呢 活跃值 2020-5-12 14:50
25
0
学习了,感谢分享
雪    币: 520
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
rookie江 活跃值 2020-5-12 15:32
26
0
老铁 你最后面的 这个添加到 那个smali文件 里的 那个位置 
雪    币: 520
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
rookie江 活跃值 2020-5-12 15:33
27
0
token 的重新调用
雪    币: 1291
活跃值: 活跃值 (2691)
能力值: ( LV7,RANK:140 )
在线值:
发帖
回帖
粉丝
0x指纹 活跃值 3 2020-5-12 16:30
28
1
青丝梦 这个 修改token 的方法思路挺骚的。 但是 如果没有免费观看这个 玩意 ,是不是只能 花钱买vip了分析普通 的 vip 直接的区别了?
对 需要看下服务器那边的配置能不能利用了
雪    币: 1291
活跃值: 活跃值 (2691)
能力值: ( LV7,RANK:140 )
在线值:
发帖
回帖
粉丝
0x指纹 活跃值 3 2020-5-12 16:41
29
1
rookie江 token 的重新调用
就是播放视频界面的活动:“cn.net.tokyo.ccg.ui.activity.VideoDetailActivity”,这个可以打开界面后使用命令“adb shell dumpsys window windows”来查看,还可以用 MT 管理器里面的 Activity 记录服务,启动后打开界面后所在的 acitvity 类名称会显示在浮窗上面
雪    币: 23
活跃值: 活跃值 (21)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
芃杉 活跃值 2020-5-12 17:01
30
0
mark,小电影
雪    币: 1853
活跃值: 活跃值 (56)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
挤蹭菌衣 活跃值 2020-5-12 20:21
31
0
感谢大佬 app已下载
雪    币: 73
活跃值: 活跃值 (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
hehaohw 活跃值 2020-5-13 09:06
32
0
我也有个APP,没有找到贴入点,往楼主给分析下。
雪    币: 11954
活跃值: 活跃值 (114)
能力值: ( LV8,RANK:160 )
在线值:
发帖
回帖
粉丝
nevinhappy 活跃值 2 2020-5-13 09:54
33
0
好文,现在的视频,直播样本基本是这个样本的套路,APP只是一个壳子,像直播源链接啥的,付费的都需要从服务请求到,不过从业务逻辑去对抗这个路子不错。
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_klcosoow 活跃值 2020-5-13 15:33
34
0
感谢老铁 
雪    币: 469
活跃值: 活跃值 (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
小黄鸭爱学习 活跃值 2020-5-13 16:02
35
0
第一步的脱壳重打包就有点意思了 
雪    币: 758
活跃值: 活跃值 (22)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
壹久玖 活跃值 2020-5-13 16:41
36
0
感谢
雪    币: 4929
活跃值: 活跃值 (82)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
gaoweb 活跃值 2020-5-13 17:04
37
0

雪    币: 1291
活跃值: 活跃值 (2691)
能力值: ( LV7,RANK:140 )
在线值:
发帖
回帖
粉丝
0x指纹 活跃值 3 2020-5-13 18:20
38
0
gaoweb
第一次在看雪评论区见到动态图
雪    币: 0
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
allify 活跃值 2020-5-13 20:32
39
0

楼主你好,我想问下这个我的这个方法为什么提示Method was not decompiled

雪    币: 1291
活跃值: 活跃值 (2691)
能力值: ( LV7,RANK:140 )
在线值:
发帖
回帖
粉丝
0x指纹 活跃值 3 2020-5-13 21:54
40
1
allify 楼主你好,我想问下这个我的这个方法为什么提示Method was not decompiled
你用的是什么反编译器,我用jadx有时候就会无法反编译成功,大部分时候用Jeb来分析
雪    币: 359
活跃值: 活跃值 (87)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
_air 活跃值 2020-5-14 08:02
41
0
感谢分享,学习了
雪    币: 454
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
dumBball 活跃值 2020-5-14 09:39
42
0
老哥,注意身体健康
雪    币: 1291
活跃值: 活跃值 (2691)
能力值: ( LV7,RANK:140 )
在线值:
发帖
回帖
粉丝
0x指纹 活跃值 3 2020-5-14 10:49
43
0
dumBball 老哥,注意身体健康
雪    币: 0
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
allify 活跃值 2020-5-14 17:40
44
0
0x指纹 你用的是什么反编译器,我用jadx有时候就会无法反编译成功,大部分时候用Jeb来分析
老哥,我是用的jeb3,只是反编译classes.dex,你有把他们合并吗
雪    币: 1291
活跃值: 活跃值 (2691)
能力值: ( LV7,RANK:140 )
在线值:
发帖
回帖
粉丝
0x指纹 活跃值 3 2020-5-15 08:02
45
0
allify 老哥,我是用的jeb3,只是反编译classes.dex,你有把他们合并吗
我是脱壳后处理下重打包,然后分析重打包的apk
雪    币: 0
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
allify 活跃值 2020-5-15 09:21
46
0
0x指纹 我是脱壳后处理下重打包,然后分析重打包的apk
懂了,谢谢
雪    币: 168
活跃值: 活跃值 (22)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
学编程 活跃值 1 2020-5-15 10:41
47
0
tDasm 这个APP服务器设置有问题,照道理一个用户一个安卓i d一天一次免费,而不是一个id一天一次。如果那样,你必须每天注册无数个用户同时还要换id。
他这个是游客模式
雪    币: 1291
活跃值: 活跃值 (2691)
能力值: ( LV7,RANK:140 )
在线值:
发帖
回帖
粉丝
0x指纹 活跃值 3 2020-5-15 12:13
50
0
傲雪寒梅X 大佬好!有问题请教!破解问题! 有偿 能加个微信吗?V X anhuibiao
有问题在论坛提问就行了...
游客
登录 | 注册 方可回帖
返回