1. 运行
点击右上按钮,出现输入Key的界面。

随便输入几个字符,发现报错。

2. 定位关键代码
根据报错信息 Your licence key is incorrect...! Please try again with another
,定位关键代码。
private void checkLicenceKey(final Context context) {//检测是否已绑定证书if (this.app.getDataHelper().getConfig().hasLicence()) {showAlertDialog(context, OK_LICENCE_MSG);return;}View promptsView = LayoutInflater.from(context).inflate(R.layout.propmt, null);Builder alertDialogBuilder = new Builder(context);alertDialogBuilder.setView(promptsView);final EditText userInput = (EditText) promptsView.findViewById(R.id.editTextDialogUserInput);alertDialogBuilder.setCancelable(false).setPositiveButton("Continue", new OnClickListener() {public void onClick(DialogInterface dialog, int id) {if (KeyVerifier.isValidLicenceKey(userInput.getText().toString(), MainActivity.this.app.getDataHelper().getConfig().getSecurityKey(), MainActivity.this.app.getDataHelper().getConfig().getSecurityIv())) {MainActivity.this.app.getDataHelper().updateLicence(2014);MainActivity.isRegisterd = true;MainActivity.this.showAlertDialog(context, MainActivity.OK_LICENCE_MSG);return;}MainActivity.this.showAlertDialog(context, MainActivity.NOK_LICENCE_MSG);}}).setNegativeButton("Cancel", new OnClickListener() {public void onClick(DialogInterface dialog, int id) {dialog.cancel();}});alertDialogBuilder.create().show();}
3.详细分析
3.1 分析参数
观察得出,关键代码为
KeyVerifier.isValidLicenceKey(
userInput.getText().toString(), MainActivity.this.app.getDataHelper().getConfig().getSecurityKey(), MainActivity.this.app.getDataHelper().getConfig().getSecurityIv()
)
共有三个参数
1.用户输入的字符串
2.函数getSecurityKey()
、getSecurityIv()
public AppConfig getConfig() {boolean z = true;AppConfig agency = new AppConfig();Cursor cursor = this.myDataBase.rawQuery(SELECT_QUERY, null);if (cursor.moveToFirst()) {agency.setId(cursor.getInt(0));agency.setName(cursor.getString(1));agency.setInstallDate(cursor.getString(2));if (cursor.getInt(3) <= 0) {z = false;}agency.setValidLicence(z);agency.setSecurityIv(cursor.getString(4));agency.setSecurityKey(cursor.getString(5));agency.setDesc(cursor.getString(7));}return agency;}
数据库相关信息:
private static String DB_NAME = "db.db";private static String DB_PATH = "/data/data/edu.sharif.ctf/databases/";public static final String SELECT_QUERY = ("SELECT* FROM " + TABLE_NAME + " WHERE a=1");private static String TABLE_NAME = "config";
逻辑:
1.Cursor cursor = this.myDataBase.rawQuery(SELECT_QUERY, null);
获取表config的首行
2.agency.setSecurityIv(cursor.getString(4));
表中第四行赋值给Iv
3.agency.setSecurityKey(cursor.getString(5));
表中第五行赋值给Key
用jeb打开apk,导出db.db ,用 DB browser 打开。

SecurityIv:a5efdbd57b84ca36SecurityKey: 37eaae0141f1a3adf8a1dee655853714
3.2 分析加密算法
package edu.sharif.ctf.security;
import java.security.Key;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class KeyVerifier {public static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";public static final String VALID_LICENCE = "29a002d9340fc4bd54492f327269f3e051619b889dc8da723e135ce486965d84";public KeyVerifier() {super();}public static String bytesToHexString(byte[] arg8) {StringBuilder v1 = new StringBuilder();int v4 = arg8.length;int v2;for(v2 = 0; v2 < v4; ++v2) {v1.append(String.format("%02x", Integer.valueOf(arg8[v2] & 0xFF)));}return v1.toString();}public static String encrypt(String arg8, String arg9, String arg10) {String v3;try {SecretKeySpec v5 = new SecretKeySpec(KeyVerifier.hexStringToBytes(arg9), "AES");Cipher v0 = Cipher.getInstance("AES/CBC/PKCS5Padding");v0.init(1, ((Key)v5), new IvParameterSpec(arg10.getBytes()));v3 = KeyVerifier.bytesToHexString(v0.doFinal(arg8.getBytes()));}catch(Exception v1) {v1.printStackTrace();}return v3;}public static byte[] hexStringToBytes(String arg7) {int v6 = 16;int v2 = arg7.length();byte[] v0 = new byte[v2 / 2];int v1;for(v1 = 0; v1 < v2; v1 += 2) {v0[v1 / 2] = ((byte)((Character.digit(arg7.charAt(v1), v6) << 4) + Character.digit(arg7.charAt(v1 + 1), v6)));}return v0;}// 调用加密算法public static boolean isValidLicenceKey(String arg2, String arg3, String arg4) {boolean v1 = KeyVerifier.encrypt(arg2, arg3, arg4).equals("29a002d9340fc4bd54492f327269f3e051619b889dc8da723e135ce486965d84") ? true : false;return v1;}
}
加密算法为AES/CBC/PKCS5Padding,写出对应的解密算法
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class Main {public static void main(String[] args) {// write your code hereString encrypted = "29a002d9340fc4bd54492f327269f3e051619b889dc8da723e135ce486965d84";String securityKey = "37eaae0141f1a3adf8a1dee655853714";String securityIv = "a5efdbd57b84ca36";String result = decrypt(encrypted, securityKey, securityIv);System.out.println(result);}public static String bytesToHexString(byte[] paramArrayOfByte) {StringBuilder localStringBuilder = new StringBuilder();int i = paramArrayOfByte.length;for (int j = 0; ; j++) {if (j >= i)return localStringBuilder.toString();int k = paramArrayOfByte[j];Object[] arrayOfObject = new Object[1];arrayOfObject[0] = Integer.valueOf(k & 0xFF);localStringBuilder.append(String.format("%02x", arrayOfObject));}}public static String decrypt(String paramString1, String paramString2, String paramString3) {try {SecretKeySpec localSecretKeySpec = new SecretKeySpec(hexStringToBytes(paramString2), "AES");Cipher localCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");localCipher.init(Cipher.DECRYPT_MODE, localSecretKeySpec, new IvParameterSpec(paramString3.getBytes()));byte[] bytes = localCipher.doFinal(hexStringToBytes(paramString1));String flag = "";for (byte b : bytes) {flag += (char) b;}return flag;} catch (Exception localException) {localException.printStackTrace();}return "";}public static byte[] hexStringToBytes(String paramString) {int i = paramString.length();byte[] arrayOfByte = new byte[i / 2];for (int j = 0; ; j += 2) {if (j >= i)return arrayOfByte;arrayOfByte[(j / 2)] = (byte) ((Character.digit(paramString.charAt(j), 16) << 4) + Character.digit(paramString.charAt(j + 1), 16));}}
}
运行得到结果:
fl-ag-IS-se-ri-al-NU-MB-ER