安卓Native逆向之MOO\QQ音樂解密( .bkcflac,bkcmp3檔案解密)
- 1、背景
- 2、Java層逆向
- 3、Native層逆向
- 4、Java實作
1、背景
本文寫于2021年1月5日,解密演算法適用于目前最新版的MOO加密和QQ音樂加密,之前加密方式和目前加密方式并不完全相同
支持的格式
MOO音樂 :.bkcflac,bkcmp3
QQ音樂:.qmcflac,.qmc0,qmc2,qmc3,
2018年鵝廠推出了一款名為MOO的音樂APP,設計風格獨特,采用QQ音樂曲庫,可以看作是QQ音樂的輕奢款,可以是因為設計風格太過獨特,MOO音樂只在一些小圈子里流行,一直不溫不火,
不過從2019年末開始,MOO音樂就開始免費送VIP,到現在持續了一年多,由于MOO音樂曲庫的曲庫和QQ音樂的曲庫一致,所以,相當于免費送綠鉆,
條件也很容易達到,每日聽夠一個小時的歌,就送一天的VIP,有了VIP后,就可以將喜歡的音樂下載下來,
但不幸的是,MOO音樂下載的檔案是加密的,目前最新的加密格式是
.bkcflac,bkcmp3

2、Java層逆向
用jadx打開MOO音樂,經過一番分析,確定了檔案的解密是在這里做的(搜decrypt分析一下)

具體來說,在這個函式里面讀取了本地加密檔案,然后在
PayProcessor.d(i, bArr, read);
這個函式里面解密,追到內部,發現是個native函式,可以知道加密函式在
libpay_encrypt.so里面實作
public class PayProcessor {
private static final String TAG = "PayProcessor";
private static boolean hXR = true;
private static native int native_decrypt(int i, byte[] bArr, int i2);
private static native int native_encrypt(int i, byte[] bArr, int i2);
static {
try {
System.loadLibrary("pay_encrypt");
b.a.i(TAG, "[static initializer] load success", new Object[0]);
} catch (Throwable th) {
b.a.e(TAG, "static initializer", th);
}
}
public static int c(int i, byte[] bArr, int i2) {
if (hXR) {
return native_encrypt(i, bArr, i2);
}
b.a.e(TAG, "[encrypt] sLoad = false", new Object[0]);
return -1;
}
public static int d(int i, byte[] bArr, int i2) {
if (hXR) {
return native_decrypt(i, bArr, i2);
}
b.a.e(TAG, "[encrypt] sLoad = false", new Object[0]);
return -1;
}
}
3、Native層逆向
把MOO安裝包解壓后 ,我們可以在lib\armeabi-v7a目錄下找到這個so檔案

用IDA Pro打開這個so檔案,我們可以定位帶加密函式

最終可以定位到這里,加密函式的邏輯很簡單,對整個檔案的每個位元組與一個字典進行異或操作,解密也是用的同一個函式,例如 假設某個資料為a,字典里的值為b,加密后的資料為c
那么加密的程序就是 c=a^b
解密的程序就是a=c^b
當然,在MOO音樂這里,還是做了一些額外的操作,IDA的偽代碼里已經寫得很清楚,不多作介紹了



4、Java實作
將上面我們逆向后得到的資料,翻譯成Java代碼
public class FileDecrypt {
private static final int[] map={0x77,0x48,0x32,0x73,0xDE,0xF2,0xC0,0xC8,0x95,0xEC,0x30,0xB2,0x51,0xC3,0xE1,0xA0,0x9E,0xE6,0x9D,0xCF,0xFA,0x7F,0x14,0xD1,0xCE,0xB8,0xDC,0xC3,0x4A,0x67,0x93,0xD6,0x28,0xC2,0x91,0x70,0xCA,0x8D,0xA2,0xA4,0xF0,8,0x61,0x90,0x7E,0x6F,0xA2,0xE0,0xEB,0xAE,0x3E,0xB6,0x67,0xC7,0x92,0xF4,0x91,0xB5,0xF6,0x6C,0x5E,0x84,0x40,0xF7,0xF3,0x1B,2,0x7F,0xD5,0xAB,0x41,0x89,0x28,0xF4,0x25,0xCC,0x52,0x11,0xAD,0x43,0x68,0xA6,0x41,0x8B,0x84,0xB5,0xFF,0x2C,0x92,0x4A,0x26,0xD8,0x47,0x6A,0x7C,0x95,0x61,0xCC,0xE6,0xCB,0xBB,0x3F,0x47,0x58,0x89,0x75,0xC3,0x75,0xA1,0xD9,0xAF,0xCC,8,0x73,0x17,0xDC,0xAA,0x9A,0xA2,0x16,0x41,0xD8,0xA2,6,0xC6,0x8B,0xFC,0x66,0x34,0x9F,0xCF,0x18,0x23,0xA0,0xA,0x74,0xE7,0x2B,0x27,0x70,0x92,0xE9,0xAF,0x37,0xE6,0x8C,0xA7,0xBC,0x62,0x65,0x9C,0xC2,8,0xC9,0x88,0xB3,0xF3,0x43,0xAC,0x74,0x2C,0xF,0xD4,0xAF,0xA1,0xC3,1,0x64,0x95,0x4E,0x48,0x9F,0xF4,0x35,0x78,0x95,0x7A,0x39,0xD6,0x6A,0xA0,0x6D,0x40,0xE8,0x4F,0xA8,0xEF,0x11,0x1D,0xF3,0x1B,0x3F,0x3F,7,0xDD,0x6F,0x5B,0x19,0x30,0x19,0xFB,0xEF,0xE,0x37,0xF0,0xE,0xCD,0x16,0x49,0xFE,0x53,0x47,0x13,0x1A,0xBD,0xA4,0xF1,0x40,0x19,0x60,0xE,0xED,0x68,9,6,0x5F,0x4D,0xCF,0x3D,0x1A,0xFE,0x20,0x77,0xE4,0xD9,0xDA,0xF9,0xA4,0x2B,0x76,0x1C,0x71,0xDB,0,0xBC,0xFD,0xC,0x6C,0xA5,0x47,0xF7,0xF6,0,0x79,0x4A,0x11};
public static boolean decrypt(String fullPath){
try {
String sign="";
if(fullPath.contains(".bkc")){
sign=".bkc";
}else if(fullPath.contains(".qmc")){
sign=".qmc";
}else {
return false;
}
String decryptFilePath=fullPath.replace(sign,".");
String postFix=decryptFilePath.substring(decryptFilePath.indexOf("."));
if(postFix.equals(".0")||postFix.equals(".2")||postFix.equals(".3")){
decryptFilePath.replace(postFix,".mp3");
}
File file=new File(fullPath);
FileInputStream is=new FileInputStream(file);
FileOutputStream fout=new FileOutputStream(decryptFilePath);
byte[] b=new byte[8192];
int len=0;
long total=0;
while ((len=is.read(b))!=-1){
for (int i=0;i<len;i++){
b[i]^=encMap(total+i);
}
fout.write(b,0,len);
total+=len;
}
is.close();
fout.close();
return true;
}catch (Exception e){
e.printStackTrace();
}
return false;
}
private static int encMap(long len){
int pos= (int) (len%0x7fff);
return map[(pos*pos+80923)%256];
}
最后

歡迎關注我的微信公眾號:從來不想
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/245748.html
標籤:其他
上一篇:最實用的chrome插件
