android ctf 密码破解

目录

1.样本概况... 3

1.1 样本信息... 3

1.2 测试环境及工具... 3

1.3 分析目标... 3

2.具体分析... 4

2.1 加固情况... 4

2.2 代码片段分析... 4

1样本概况

1.1 样本信息

名称:dc3c4ec3ea5b7de2de4feb122e33b1a2e91d9ffa

MD5值:5d21be09f3a1fcf545afaf0f81844fea

SHA1值:dc3c4ec3ea5b7de2de4feb122e33b1a2e91d9ffa

CRC32:d6741def

主界面:

1.2 测试环境及工具

Nexus5 + IDA pro

1.3 分析目标

破解密码

2.具体分析

2.1 加固情况

2.2 代码片段分析

    直接对样本进行调试,使用apktool反编译样本,获取包名及类名,确定JNI_OnLoad的偏移,在JNI_OnLoad中通过寄存器调用,可以确定是RegisterClass,查看寄存器,在R2中调用了aMUMU,转到内存可以确定对应的函数地址。如下图所示:

如下所示为attachBaseContext地址,跳转到该地址,并下断点

如下所示为onCreate地址跳转到该地址,并下断点

在跟进到此处时跳出,程序直接运行起来,说明B loc_75252EAE里加载了dex

重新启动调试,后跟进这个跳转,如下图所示:

中断后重新附加调试函数地址会改变,不能按照上一次断点跟踪,如下图所示:

再次分析_Z9parse_dexP7_JNIEnvPx函数,该函数会在log中打印日志,显示dex的内存地址及dex大小等信息,如下下图所示:

调用opendexfile, 如下图所示:

可以根据寄存器R8的值知道dex的位置,然后根据dex文件格式可知0x752A9028为dex文件大小(0x19cf4),计算结束地址为:0x752C2CFC,如下图所示:

执行完成之后进入onCreate函数,如下图所示:

onCreate函数结束,进入libdvm.so模块,

这个时候dex已经在上述的内存地址出还原,在_ZN3ali16dex_juicer_patchEPhjPKc函数中可以使用下图所示关键字在ddms中过滤log信息

在ddms中查看log,如下所示:

根据上面分析的起始地址和偏移计算出结束地址,再使用IDC脚本将其dump到文件中,

static main(void)

{

auto fp, begin, end, dexbyte;

fp = fopen("d:\\dumpali.so", "wb");

begin = 0x752AA008;

end = begin + 0x30090;

for ( dexbyte = begin; dexbyte < end; dexbyte ++ )

fputc(Byte(dexbyte), fp);

}

然后使用jadx工具查看dump出来的结果,代码已经还原,如下图所示:

    脱壳成功,使用GDA检测如下图所示:

然后进行动态调试获取密码:通过动态调试smali获取到加密后的字符串:
000a0a0a0a0202aa5458d715704493d8e6b9bd38f8b6be0e

key = 1f98ceab209770efa875c245853ece761f98ceab209770ef

根据以上分析和dump出的smali代码,对解密代码进行编写:

import javax.crypto.*;
import
javax.crypto.spec.IvParameterSpec;
import
javax.crypto.spec.SecretKeySpec;
import
java.io.UnsupportedEncodingException;
import
java.security.*;
import
java.security.spec.AlgorithmParameterSpec;
/**
 * Created by y0n on 2017/8/22.
 */

public class Main {
   
private static String a = "DESede";
    private static
Key b;
    private static int
c = 5;
    public static byte
[] step1_string(String arg9) {
       
byte[] v1 = arg9.getBytes();
        int
v2 = v1.length;
        byte
[] v3 = new byte[v2 / 2];
        int
v0;
        for
(v0 = 0; v0 < v2; v0 += 2) {
            v3[v0 /
2] = ((byte)Integer.parseInt(new String(v1, v0, 2), 16));
       
}
       
return v3;
   
}
   
public static String step3_byte(byte[] arg6) {

        StringBuffer v2 =
new StringBuffer();
        int
v1;
        for
(v1 = 0; v1 < arg6.length; ++v1) {
            System.
out.print(arg6[v1] + " ");
           
String v0 = Integer.toHexString(arg6[v1] & 255);
            if
(v0.length() == 1) {
                v0 = String.valueOf(
'0') + v0;
           
}
            v2.append(v0)
;
        
}
       
//System.out.println(v2);
       
return v2.toString();
   
}
   
public static byte[] step3_string(String arg6) {
        String arg16[] =
new String[32];
        byte
[] abyte = new byte[32];
        for
(int i = 0; i < arg16.length; i = i+2){
            arg16[i] = arg6.substring(i
, i+2);
           
Integer in = Integer.parseInt(arg16[i], 16);
            byte
intnum = in.byteValue();
           
abyte[i] = (byte) (intnum & 255);
           
System.out.print(abyte[i] + " ");
       
}
       
return abyte;
   
}
   
private static byte[] step2_key(byte[] arg7, byte[] arg8) {
        IvParameterSpec v0 =
new IvParameterSpec(arg7);
       
Cipher v1 = null;
        try
{
            v1 = Cipher.getInstance(String.valueOf(
a) + "/CBC/PKCS5Padding");
           
v1.init(1, b, ((AlgorithmParameterSpec)v0));
           
c = v1.getBlockSize();
            byte
[] v0_1 = v1.doFinal(arg8);
            byte
[] v1_1 = new byte[v0_1.length + c];
           
System.arraycopy(arg7, 0, v1_1, 0, c);
           
System.arraycopy(v0_1, 0, v1_1, c, v0_1.length);
            return
v1_1;
       
} catch (NoSuchAlgorithmException e) {
            e.printStackTrace()
;
       
} catch (NoSuchPaddingException e) {
            e.printStackTrace()
;
       
} catch (BadPaddingException e) {
            e.printStackTrace()
;
       
} catch (InvalidKeyException e) {
            e.printStackTrace()
;
       
} catch (IllegalBlockSizeException e) {
            e.printStackTrace()
;
       
} catch (InvalidAlgorithmParameterException e) {
            e.printStackTrace()
;
       
}
       
return null;
   
}
   
private static byte[] step2_dekey(byte[] arg7, byte[] arg8) {

        IvParameterSpec v0 =
new IvParameterSpec(arg7);
       
Cipher v1 = null;
        try
{
            v1 = Cipher.getInstance(String.valueOf(
a) + "/CBC/NoPadding");
           
v1.init(Cipher.DECRYPT_MODE, b, ((AlgorithmParameterSpec)v0)); // 操作模式为解密,key为密钥
           
byte[] sourceText = v1.doFinal(arg8);
           
System.out.println();
            for
(int j = 0 ; j < sourceText.length; j++){
                System.
out.print(sourceText[j] + " ");
           
}
           
return sourceText;
       
}catch (BadPaddingException e) {
            e.printStackTrace()
;
       
}catch (IllegalBlockSizeException e) {
            e.printStackTrace()
;
       
}catch (InvalidKeyException e) {
            e.printStackTrace()
;
       
} catch (NoSuchPaddingException e) {
            e.printStackTrace()
;
       
} catch (NoSuchAlgorithmException e) {
            e.printStackTrace()
;
       
} catch (InvalidAlgorithmParameterException e) {
            e.printStackTrace()
;
       
}
       
return null;
   
}
   
public static Key get_key(byte[] arg4) {
        SecretKey v0_1 =
null;
        try
{

           
if(arg4 == null) {
                KeyGenerator v0 = KeyGenerator.getInstance(
a);
               
v0.init(new SecureRandom());
               
v0_1 = v0.generateKey();
           
}
           
else {
                SecretKeySpec v0_2 =
new SecretKeySpec(arg4, a);
                return
((Key)v0_2);
           
}


        }
catch (NoSuchAlgorithmException e) {
            e.printStackTrace()
;
       
}
       
return ((Key)v0_1);
   
}
   
public static void main(String []args){
        //加密模拟
       
//1.key  b 赋值  v0.a(v0.a(a.a(arg5)));
        //argc5 = 1f98ceab209770efa875c245853ece761f98ceab209770ef
       
b = get_key(step1_string("1f98ceab209770efa875c245853ece761f98ceab209770ef"));
       
//2.获取 arg6 = a.a(v0.a(a.a("000a0a0a0a0202aa"), arg6.getBytes()));
       
String result = step3_byte(step2_key(step1_string("000a0a0a0a0202aa"), "日天@土侸".getBytes()));
       
System.out.println(result);

       
//解密部分
       
//000a0a0a0a0202aa5458d715704493d8e6b9bd38f8b6be0e
        //step2_key
返回的字节数组:84 88 -41 21 112 68 -109 -40 -26 -71 -67 56 -8 -74 -66 14
       
step3_string("5458d715704493d8e6b9bd38f8b6be0e");
       
//构造解密的字节
       
byte[] bytedecode = new byte[16];
        
bytedecode[0] = 84;
       
bytedecode[1] = 88;
       
bytedecode[2] = -41;
       
bytedecode[3] = 21;
       
bytedecode[4] = 112;
       
bytedecode[5] = 68;
       
bytedecode[6] = -109;
       
bytedecode[7] = -40;
       
bytedecode[8] = -26;
       
bytedecode[9] = -71;
       
bytedecode[10] = -67;
       
bytedecode[11] = 56;
       
bytedecode[12] = -8;
       
bytedecode[13] = -74;
       
bytedecode[14] = -66;
       
bytedecode[15] = 14;

       
step2_dekey(step1_string("000a0a0a0a0202aa"), bytedecode);
       
//-26 -105 -91 -27 -92 -87 64 -27 -100 -97 -28 -66 -72 3 3 3
       
byte[] sourcebyte = new byte[16];
       
sourcebyte[0] = -26;
       
sourcebyte[1] = -105;
       
sourcebyte[2] = -91;
       
sourcebyte[3] = -27;
       
sourcebyte[4] = -92;
       
sourcebyte[5] = -87;
       
sourcebyte[6] = 64;
       
sourcebyte[7] = -27;
       
sourcebyte[8] = -100;
       
sourcebyte[9] = -97;
       
sourcebyte[10] = -28;
       
sourcebyte[11] = -66;
       
sourcebyte[12] = -72;
       
sourcebyte[13] = 3;
       
sourcebyte[14] = 3;
       
sourcebyte[15] = 3;
        try
{
            String str =
new String(sourcebyte, "utf-8");
           
System.out.println(str);
       
} catch (UnsupportedEncodingException e) {
            e.printStackTrace()
;
       
}
        System.
out.println();
        for
(int i = 0; i < sourcebyte.length; i++){
            System.
out.print(sourcebyte[i] + " ");
       
}
    }
}

运行结果如下所示:

 

 

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值