本帖最后由 JoyChou 于 2014-7-29 17:11 编辑
博客:www.joychou.org
邮箱:shellcode@joychou.org
作者:JoyChou
apk没什么其他保护,直接看smali和java代码。
0x1. 关键位置 很明显看到一个关键比较,经过对程序分析,要想得到str6,就必须得知道str5。要想得到str5就必须得知道str4,不过MainActivity.b(this.a).getText().toString().substring(2, 9); 的getText的内容是已知的,为ccfd02dec871e41eae537f6bdc755441。最后要想知道str4,就必须得对8374207E83372393B9B8964F6D7415E7F88FC24BDD1B2201A924C8723A3AE668FCDF7BFFB7EFD4AA1E64832345264B7FF99A2D145A8D1FB4解密。分析到此over,很简单的一个流程。 [Java] 纯文本查看 复制代码 public void onClick(View paramView)
{
String str1 = MainActivity.a(this.a).getDeviceId();
String str2 = MainActivity.a(this.a).getSubscriberId();
String str3 = MainActivity.a(this.a).getSimSerialNumber();
String str4 = str1 + "@" + str2 + "@" + str3;
try
{
if ("8374207E83372393B9B8964F6D7415E7F88FC24BDD1B2201A924C8723A3AE668FCDF7BFFB7EFD4AA1E64832345264B7FF99A2D145A8D1FB4".equals(b.a(str4)))
{
String str5 = str4.toString().substring(10, 19) + MainActivity.b(this.a).getText().toString().substring(2, 9);
String str6 = com.wow.dbm.a.a.a(a("439288a71bb2b74c077f0237f21d8696053d60f2ada12cbbc18406808d2fb34d7e94ebb575949bf9e25a304051a385f8"), str5);
Toast.makeText(this.a.getApplicationContext(), "快抄下来!" + str6, 1).show();
Log.d("dbi_AES_De_n", str6);
return;
}
Toast.makeText(this.a.getApplicationContext(), "身份校验失败,请使用预设手机!", 0).show();
return;
}
catch (Exception localException)
{
Toast.makeText(this.a.getApplicationContext(), "解密失败!", 0).show();
}
}
}
0x2. 怎样解密
如果直接修改smali会发现不好操作。那就写java代码。 分析下des的加密过程: Plain_Text进行des加密成byte类型,再转换成16进制字符串。(其实相当于,des加密成byte类型后,转换为String不一定是规则的ascii,所以为了字符能够显示,最好人为进行一个编码,平时一般用base64,这里只是转化成了16进制的字符串)。
比如des加密后的字节的16进制为0x12, 0x34,那最后的结果为"1234"字符串。
所以解密的时候,要先将16进制的字符串转换为byte类型,再进行des解密。
比如"1234"字符串,转换为0x12, 0x34的byte数组,再进行des解密。
Tips:在看java算法代码的时候,如果对代码不是很熟悉,一般把代码比较有特征的部分进行百度,就能够看出这段算法代码的功能。
将8374207E83372393B9B8964F6D7415E7F88FC24BDD1B2201A924C8723A3AE668FCDF7BFFB7EFD4AA1E64832345264B7FF99A2D145A8D1FB4转化成字节的形式,可以写java代码转,或者用py转,我这里写了一个py
[Python] 纯文本查看 复制代码 #coding:utf-8
def Add_Something(c):
n = ""
while c:
f = c[0:2]
n += "(byte)0x" + f + ','
c = c[2:]
return n
if __name__ == '__main__':
fp = open('1.txt', 'wb')
str = Add_Something('8374207E83372393B9B8964F6D7415E7F88FC24BDD1B2201A924C8723A3AE668FCDF7BFFB7EFD4AA1E64832345264B7FF99A2D145A8D1FB4')
fp.write(str)
fp.close();
解密代码为: Main.java [Java] 纯文本查看 复制代码 byte[] des_encode = {(byte)0x83,(byte)0x74,(byte)0x20,(byte)0x7E,(byte)0x83,(byte)0x37,(byte)0x23,(byte)0x93,(byte)0xB9,(byte)0xB8,(byte)0x96,(byte)0x4F,(byte)0x6D,(byte)0x74,(byte)0x15,(byte)0xE7,(byte)0xF8,(byte)0x8F,(byte)0xC2,(byte)0x4B,(byte)0xDD,(byte)0x1B,(byte)0x22,(byte)0x01,(byte)0xA9,(byte)0x24,(byte)0xC8,(byte)0x72,(byte)0x3A,(byte)0x3A,(byte)0xE6,(byte)0x68,(byte)0xFC,(byte)0xDF,(byte)0x7B,(byte)0xFF,(byte)0xB7,(byte)0xEF,(byte)0xD4,(byte)0xAA,(byte)0x1E,(byte)0x64,(byte)0x83,(byte)0x23,(byte)0x45,(byte)0x26,(byte)0x4B,(byte)0x7F,(byte)0xF9,(byte)0x9A,(byte)0x2D,(byte)0x14,(byte)0x5A,(byte)0x8D,(byte)0x1F,(byte)0xB4};
String des_result = b.a_decry(des_encode);
System.out.println(des_result);
b.java [Java] 纯文本查看 复制代码 package Test;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class b
{
//整个加密流程为,加密的字符串先加成
public static String a(String paramString)
{
try{
DESedeKeySpec localDESedeKeySpec = new DESedeKeySpec("ebcd3c24a64c2e056f430d11".getBytes());
SecretKey localSecretKey = SecretKeyFactory.getInstance("desede").generateSecret(localDESedeKeySpec);
Cipher localCipher = Cipher.getInstance("desede/CBC/PKCS5Padding");
localCipher.init(Cipher.ENCRYPT_MODE, localSecretKey, new IvParameterSpec("01234567".getBytes()));
return a(localCipher.doFinal(paramString.getBytes("utf-8")));
//return localCipher.doFinal(paramString.getBytes());
}
catch(Exception e){
System.out.println("exception_jc");
e.printStackTrace();
}
return null;
}
// 作用:将字符串123转换为字符串313233
// 可以动态调用a("123".getBytes())
public static String a(byte[] paramArrayOfByte)
{
if (paramArrayOfByte == null)
return "";
StringBuffer localStringBuffer = new StringBuffer(2 * paramArrayOfByte.length);
for (int i = 0; ; i++)
{
if (i >= paramArrayOfByte.length)
return localStringBuffer.toString();
a(localStringBuffer, paramArrayOfByte);
}
}
private static void a(StringBuffer paramStringBuffer, byte paramByte)
{
paramStringBuffer.append("0123456789ABCDEF".charAt(0xF & paramByte >> 4)).append("0123456789ABCDEF".charAt(paramByte & 0xF));
}
public static String a_decry(byte[] paramString)
{
try{
DESedeKeySpec localDESedeKeySpec =
new DESedeKeySpec("ebcd3c24a64c2e056f430d11".getBytes());
SecretKey localSecretKey =
SecretKeyFactory.getInstance("desede").generateSecret(localDESedeKeySpec);
Cipher localCipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
localCipher.init(Cipher.DECRYPT_MODE, localSecretKey, new IvParameterSpec("01234567".getBytes()));
//return a(localCipher.doFinal(paramString));
byte[] decry_data = localCipher.doFinal(paramString);
return new String(decry_data);
}
catch(Exception e){
System.out.println("exception_jc");
e.printStackTrace();
}
return null;
}
} 结果为A00000381F8F05@460030767299044@89860313100281802653
搞定掉DES,接下来是AES,由于在java中并没有AES/ECB/ZeroBytePadding这种AES加密,在android有,所以不能用java代码来解,这里纠结了很久。
那就改smali吧。 [Java] 纯文本查看 复制代码 if("8374207E83372393B9B8964F6D7415E7F88FC24BDD1B2201A924C8723A3AE668FCDF7BFFB7EFD4AA1E64832345264B7FF99A2D145A8D1FB4".equals(b.a(str4)))
{
String str5 = str4.toString().substring(10, 19) + MainActivity.b(this.a).getText().toString().substring(2, 9);
String str6 = com.wow.dbm.a.a.a(a("439288a71bb2b74c077f0237f21d8696053d60f2ada12cbbc18406808d2fb34d7e94ebb575949bf9e25a304051a385f8"), str5);
Toast.makeText(this.a.getApplicationContext(), "快抄下来!" + str6, 1).show();
Log.d("dbi_AES_De_n", str6);
return;
}
只需要将str5改为正确的值即可解密出来,还是用上面的java代码,得到str5为8F05@4600fd02dec,作为AES解密的密钥key,128个bytes。
修改smali的地方:
198行, if-nez v0, :cond_0 #change 1 原始为:if-eqz 118行,.locals 7 原始为.locals6 256行,改为
[Asm] 纯文本查看 复制代码 move-result-object v1
const-string v6, "8F05@4600fd02dec"
invoke-static {v1, v6}, Lcom/wow/dbm/a/a;->a([BLjava/lang/String;)Ljava/lang/String;
最后打包,运行,即可看到flag,
或者adb logcat -s
0x3. 总结
这题的关键就是逆向解密,最基本的思想。
假设对字符串A加密:经过md5加密,再经过base64加密。
那解密为:先base64解密,再md5解密。
就是这样最基本的思想就可以解决这题了。
附件:
DBM_OUT_0910.7z
(69.33 KB, 下载次数: 56)
|