fengyutongzhou 发表于 2024-5-7 16:52

frida HOOK实战,对移动欺诈家族逆向分析

前沿:今天拿到一个恶意软件样本,属于BOOMSLANG(树蚺)移动欺诈家族。引用文章:https://www.4hou.com/posts/m04A,文章里提到了这类家族使用了TG(电报)安卓端源代码,并且为了防止拦截在网络配置里引入 DoH 技术,随着时间线慢慢进化现在到我手里的已经没那么简单了。咱们今天登场的主角,我给他定为DOH变种+(OSS混淆+server)变种升级版。这类软件主要技术就是运用在反拦截上,所以在这里咱们只分析网络行为。还是老样子过程写的比较啰嗦,主要是分享思路和研究成果,讨论技术问题。此文章无向导,无结论。样本不传,只展示目录结构。环境及工具:夜神模拟器Android9、frida16.2.1、面具、LSP、算法助手、JADX、charles、Proxifier。
APP界面


看一眼目录结构。im.xsgxqmfdca.tgnet目录里有个NetworkConfig类。用来初始化网络配置,这里可以看到默认连接地址和DOH服务地址以及DOH用来解析的域名。阿里云DOH说明书:https://www.alibabacloud.com/help/zh/dns/dns-over-https
算法助手HOOK一下,发现解密出一堆URL这里就是OSS服务里存的server配置文件,看到调用堆栈是get0ssUrl。


定位一下方法get0ssUrl,发现反编译失败了。不过没关系看看其他版本反编译,Smali有点难就不看了,这里点击Simple。由于我没做过开发所以不太懂这里的原因,为什么反编译JAVA失败了,Simple里就没问题,有懂得大佬给解释一下。

回到正文看get0Url方法,这段代码通过构建URL、发起HTTP请求、读取和解析响应数据,来创建一个OSS存储服务请求解析过程。阿里云oss域名是经过混淆的,刚好最近在学frida一把梭哈今天就实战一把。

打开安卓逆向第十三节教学视频,定位到21分55秒这里拷贝代码。

插一条信息,版号固定写在这里。
package im.xsgxqmfdca.ui.hui.friendscircle.okhttphelper;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/* loaded from: classes43.dex */
public class MD5Utils {
    protected static char[ hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
    protected static MessageDigest messagedigest;

    static {
      messagedigest = null;
      try {
            messagedigest = MessageDigest.getInstance("MD5");
      } catch (NoSuchAlgorithmException nsaex) {
            System.err.println(MD5Utils.class.getName() + "初始化失败,MessageDigest不支持MD5Util。");
            nsaex.printStackTrace();
      }
    }

    public static String getMD5String(String s) {
      return getMD5String(s.getBytes());
    }

    public static boolean checkPassword(String password, String md5PwdStr) {
      String s = getMD5String(password);
      return s.equals(md5PwdStr);
    }

    public static String getFileMD5String(File file) throws IOException {
      InputStream fis = new FileInputStream(file);
      byte[ buffer = new byte[1024;
      while (true) {
            int numRead = fis.read(buffer);
            if (numRead > 0) {
                messagedigest.update(buffer, 0, numRead);
            } else {
                fis.close();
                return bufferToHex(messagedigest.digest());
            }
      }
    }

    public static String getFileMD5String_old(File file) throws IOException {
      FileInputStream in = new FileInputStream(file);
      FileChannel ch = in.getChannel();
      MappedByteBuffer byteBuffer = ch.map(FileChannel.MapMode.READ_ONLY, 0L, file.length());
      messagedigest.update(byteBuffer);
      in.close();
      return bufferToHex(messagedigest.digest());
    }

    public static String getMD5String(byte[ bytes) {
      messagedigest.update(bytes);
      return bufferToHex(messagedigest.digest());
    }

    private static String bufferToHex(byte[ bytes) {
      return bufferToHex(bytes, 0, bytes.length);
    }

    private static String bufferToHex(byte[ bytes, int m, int n) {
      StringBuffer stringbuffer = new StringBuffer(n * 2);
      int k = m + n;
      for (int l = m; l < k; l++) {
            appendHexPair(bytes[l, stringbuffer);
      }
      return stringbuffer.toString();
    }

    private static void appendHexPair(byte bt, StringBuffer stringbuffer) {
      char[ cArr = hexDigits;
      char c0 = cArr[(bt & 240) >> 4;
      char c1 = cArr[bt & 15;
      stringbuffer.append(c0);
      stringbuffer.append(c1);
    }

    public static void main(String[ args) throws IOException {
      long begin = System.currentTimeMillis();
      File file = new File("C:/test.txt");
      if (!file.exists()) {
            System.out.println("不存在");
      }
      String md5 = getFileMD5String(file);
      long end = System.currentTimeMillis();
      PrintStream printStream = System.out;
      printStream.println("md5:" + md5 + " time:" + ((end - begin) / 1000) + "s");
      System.out.println(file.getPath());
    }
}


填好信息,注意这里有个重载,要标注我们这个方法传入的值是String类型。
输出结果看到传入的str值结构,版号+日期+字符1或空或Android。后面返回的MD5值是三级域名。需要注意的是子域名是由时间戳因素哈希来的所以每天请求的OSS域名是一直在变化的。最后通过每天及时在OSS更新资源的方法来维持连接。题外话:如果放到C2木马身上是不是对情报工作也有很大挑战。

isolands 发表于 2024-5-8 11:16

学习了,感谢分享

absktv 发表于 2024-5-8 12:44

这对于我一个小白来说,有点深奥,更要努力学习了

yinsel 发表于 2024-5-8 22:19

我目前有很多这种样本,也在这种类型的APP对抗,但是介于技术能力实在不足,能建立个交流技术群吗方面讨论相关样本的技术

wengl123 发表于 2024-5-9 08:27

正在看公众号推的视频,刚好看到这个贴学习下,感谢大佬分享

141847901 发表于 2024-5-9 10:12

跟着学习下,感谢大佬分享

N1nE7 发表于 2024-5-15 22:19

跟着学习一下

wuweiwuwei 发表于 2024-5-23 09:11

感谢分享

dwiafi 发表于 2024-5-23 11:15

最近也遇到类似的样本,但对frida还是不太熟悉, 感谢分享!
页: [1]
查看完整版本: frida HOOK实战,对移动欺诈家族逆向分析