好友
阅读权限 10
听众
最后登录 1970-1-1
使用论坛附件上传样本压缩包时必须使用压缩密码保护,压缩密码:52pojie,否则会导致论坛被杀毒软件等误报,论坛有权随时删除相关附件和帖子! 病毒分析分区附件样本、网址谨慎下载点击,可能对计算机产生破坏,仅供安全人员在法律允许范围内研究,禁止非法用途! 禁止求非法渗透测试、非法网络攻击、获取隐私等违法内容,即使对方是非法内容,也应向警方求助!
前沿:今天拿到一个恶意软件样本,属于BOOMSLANG(树蚺)移动欺诈家族。引用文章:https://www.4hou.com/posts/m04A,文章里提到了这类家族使用了TG(电报)安卓端源代码,并且为了防止拦截在网络配置里引入 DoH 技术,随着时间线慢慢进化现在到我手里的已经没那么简单了。咱们今天登场的主角,我给他定为DOH变种+(OSS混淆+server)变种升级版。这类软件主要技术就是运用在反拦截上,所以在这里咱们只分析网络行为。还是老样子过程写的比较啰嗦,主要是分享思路和研究成果,讨论技术问题。此文章无向导,无结论。样本不传,只展示目录结构。环境及工具:夜神模拟器Android9、frIDA 16.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木马身上是不是对情报工作也有很大挑战。
免费评分
查看全部评分
发帖前要善用【论坛搜索 】 功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。