Keep and carry on.

前言

这一周对4399游戏盒登录过程的网络协议进行了分析,截止到3月24日,4399游戏盒最新版本为3.1.0.64。这次网络协议的分析会涉及到so文件,加密过程调用了openssl的des加密库。所以跟上周相比,这次软件的安全机制做得更好,但是除了将关键函数写在so文件中,并没有对软件做任何保护,甚至可以说在so文件中,所有函数也是直接可以看出来,并且逻辑简单,我们可以直接静态分析就将整个流程分析出来。

分析过程

Java层代码分析

在分析过程中遇到了一些困难,首先我们抓取登录过程中的数据包

4

可以看到登录过程中的数据包跟我们上周分析的数据包相似,但是他对密码进行了加密,对整个数据包完整性校验也是同样通过sign值进行判断。接下来就要进行全局搜索找到生成这个hashmap的代码位置

3

我们对请求的url进行搜索,直接搜索log-in,但是显示未找到结果。由于之前对2.8的版本进行过分析,在那个版本中我们对url进行搜索是可以得到结果然后就直接分析出他的map生成过程,但是这里搜索到什么都没有。我最先是猜想是不是软件对hashmap中的键值进行解密后再放入网络数据包中。所以全局搜索没有搜索到。

那么问题出在哪里呢,我对比了2.8的数据包后发现同样密码加密后的值都是相等的。由于之前较为简单地版本我们可以直接分析出加密方式为DES,所以我全局搜索desCbcEncrypt。发现这个函数在AppNativeHelper中这个函数的位置已经跟之前的包名不一样,但是函数名却是一样的,所以照着函数名SignDataProvider搜索,找到了关键代码

5

可以看到并没有用之前猜想的对键值进行解密之后再存入hashmap中,并且会在继承类中实现buildSignRequestParams这个方法,这个方法我们猜想就是生成password,username等map的方法,但是全局搜索这个方法名依然没有结果。看到这里可以肯定的就是程序一定是采用动态加载的方法,加载入新的apk或者dex文件然后所有方法在那个文件中实现。所以解压apk后,在assets/Plugin目录中果然找到了一个apk。

6

在这个apk文件中全局搜索之前的buildSignRequestParams方法果然就找到了我们的协议生成过程

1

这个类继承之前的SignDataProvider类,并且在这个类中也找到了url地址

2

整个网络数据包逻辑非常简单,跟之前的差不多,区别在于这个sign值生成的参数是所有value值组合在一起然后取hash。接下来就要进入到so层函数,对password加密过程和sign值生成hash的过程进行分析了

Native层代码分析

直接搜索desCbcEncrypt函数就可以找到

7

继续跟进这个函数

8

9

继续进入到里边就是DESCbc加密。对于DES,他有很多版本比如DES,3DES。而且DES又有很多填充模式,如Np-padding,PKCS5Padding。所以在这里我们需要对DES算法和填充模式进行选择。前边说过这个DES使用了openssl的DES算法。我们进入到这个函数中去后也跟实现流程一模一样的。

10

我们在进行解密的过程中需要找一个带有IV向量的DES解密方法,IV向量如果不指定一般为八个字节0(CBC模式才有,ECB模式不用指定)。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public byte[] EncryptionByteData(byte[] SourceData) throws Exception {
byte[] retByte = null;
// Create SecretKey object
byte[] EncryptionByte = EncryptionString.getBytes();//明文转为byte
DESKeySpec dks = new DESKeySpec(EncryptionByte);//声明一个具体加密构造器的特别密钥special key
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
//声明了一个DES的密钥工厂
SecretKey securekey = keyFactory.generateSecret(dks); //密钥生成器产生真正的DES密钥
// Create IvParameterSpec object with initialization vector
IvParameterSpec spec = new IvParameterSpec(EncryptionIV);
// Create Cipter object
Cipher cipher = Cipher.getInstance(DES);
// Initialize Cipher object
cipher.init(Cipher.ENCRYPT_MODE, securekey, spec); //初始化加密构造器
// Encrypting data
retByte = cipher.doFinal(SourceData); //完成加密
return retByte; //返回加密的byte
}

我们在代码中定义IV向量、DES密钥和DES模式

1
2
3
4
private String EncryptionString;
// The initialization vector should be 8 bytes
private final byte[] EncryptionIV = {0x12,0x34,0x56,0x78,(byte) 0x90,(byte) 0xAB,(byte) 0xCD,(byte) 0xEF }; //初始化向量
private final static String DES = "DES/CBC/PKCS5Padding"; //DES模式

将加密结果进行base64编码然后运行程序就是我们之前抓包到的password的值。

11

密码加密过程找到后,我们该寻找sign值的hash方法了。同样搜索getServerApi这个函数,这里看到openssl的md5算法是带密钥的,所以我们只有使用openssl库才能对这个md5进行还原,key值为ef2vx#sf^FlklSD9sdf(m$&qw%d7po在这里就不对这个值进行构造了。

总结

这周的应用分析与上周相比难度更大,一方面这次涉及到so文件的分析,并且程序针对原来版本改动较大,但是这些改动更多的是结构函数名的修改,整体流程和实现过程并没有进行任何改变,so文件没有做任何保护,所以非常易懂。整体来说这款软件的网络协议分析还是非常简单的。

Read More
⬆︎TOP