某安卓入群题

某入群题 安卓

首先拿到app,拖入运行看看

image_1d4sisqgl1a6rvqi15gu1lvaci59.png-51.4kB

然后拖入android killer分析,image_1d4siuobh16p31bgvtg01ov6dtom.png-173.3kB

可以看到有一个x86架构的so(吐血,竟然只给x86的),然后入口activity为NdkTest,进入看下,loadlibrary导入了这个动态链接库,看下校验点

image_1d4sj1n88imt1dd31u8f15mn9al13.png-27.9kB
so中导出的函数名字叫JniTest,然后把输入传入这个函数进行操作,如果返回的值是yingyingying,则就是正确的,如果传入的不是yingyingying,就返回wrong,ok,话不多说,直接去看so

image_1d4skm0qe1ib518ojusiccphtt2g.png-26.7kB

so中出了按照正常jni命名规则进行命名的导出函数外,还有一堆蜜汁函数,不管了,也没有jnionload,直接去逆导出函数即可

image_1d4sko4rkjd350dg7i6c01mu2t.png-83.7kB
可以看到,首先校验了长度是否为17,然后对encode函数进行了异或解密,打开encode进去是无法f5的,外加有很多不被识别的数据,是smc无误了,进行调试即可(注意x86的so只能在模拟器上调试)

image_1d4sl3tn5rro6ivrbtg7n14i13a.png-20.6kB

切记在ida中选择debugger时要选择Linux debugger,否则会提示incompatible debugger,ok,进行调试后进入encode函数进行分析,按p建立函数后,查看下函数大致流程,
image_1d4slu60m1i62di1m1l1bet196u3n.png-53.5kB

这一步进行了base64表的二次打乱,打乱后表为

image_1d4smo34510031tun1cg61b9gg8m.png-15.3kB

然后传入两个参数,也就是输入和base64table进入了base64编码

image_1d4smrn9n10vs1gqkk6lbq31do61j.png-31kB

可以看到是经典的base64编码,然后我们进行解密即可,

public class base64 {
//Constructor
public base64() {

}

private static final String base64Code= "RQPONMLKJIH/+9876543WVUTS210zyxwvutskjicbaZYXGFhgfedEDCBArqponm";

public static String encode(String srcStr) {
    //有效值检查
    if(srcStr == null || srcStr.length() == 0) {
        return srcStr;
    }
    //将明文的ASCII码转为二进制位字串
    char[] srcStrCh= srcStr.toCharArray();
    StringBuilder asciiBinStrB= new StringBuilder();
    String asciiBin= null;
    for(int i= 0; i< srcStrCh.length; i++) {
        asciiBin= Integer.toBinaryString((int)srcStrCh[i]);
        while(asciiBin.length()< 8) {
            asciiBin= "0"+ asciiBin;
        }
        asciiBinStrB.append(asciiBin);
    }
    //跟据明文长度在二进制位字串尾部补“0”
    while(asciiBinStrB.length()% 6!= 0) {
        asciiBinStrB.append("0");
    }
    String asciiBinStr= String.valueOf(asciiBinStrB);
    //将上面得到的二进制位字串转为Value,再跟据Base64编码表将之转为Encoding
    char[] codeCh= new char[asciiBinStr.length()/ 6];
    int index= 0;
    for(int i= 0; i< codeCh.length; i++) {
        index= Integer.parseInt(asciiBinStr.substring(0, 6), 2);
        asciiBinStr= asciiBinStr.substring(6);
        codeCh[i]= base64Code.charAt(index);
    }
    StringBuilder code= new StringBuilder(String.valueOf(codeCh));
    //跟据需要在尾部添加“=”
    if(srcStr.length()% 3 == 1) {
        code.append("==");
    } else if(srcStr.length()% 3 == 2) {
        code.append("=");
    }
    //每76个字符加一个回车换行符(CRLF)
    int i= 76;
    while(i< code.length()) {
        code.insert(i, "\r\n");
        i+= 76;
    }
    code.append("\r\n");
    return String.valueOf(code);
}

public static String decode(String srcStr) {
    //有效值检查
    if(srcStr == null || srcStr.length() == 0) {
        return srcStr;
    }
    //检测密文中“=”的个数后将之删除,同时删除换行符
    int eqCounter= 0;
    if(srcStr.endsWith("==")) {
        eqCounter= 2;
    } else if(srcStr.endsWith("=")) {
        eqCounter= 1;
    }
    srcStr= srcStr.replaceAll("=", "");
    srcStr= srcStr.replaceAll("\r\n", "");
    //跟据Base64编码表将密文(Encoding)转为对应Value,然后转为二进制位字串
    char[] srcStrCh= srcStr.toCharArray();
    StringBuilder indexBinStr= new StringBuilder();
    String indexBin= null;
    for(int i= 0; i< srcStrCh.length; i++) {
        indexBin= Integer.toBinaryString(base64Code.indexOf((int)srcStrCh[i]));
        while(indexBin.length()< 6) {
            indexBin= "0"+ indexBin;
        }
        indexBinStr.append(indexBin);
    }
    //删除因编码而在尾部补位的“0”后得到明文的ASCII码的二进制位字串
    if(eqCounter == 1) {
        indexBinStr.delete(indexBinStr.length()- 2, indexBinStr.length());
    } else if(eqCounter == 2) {
        indexBinStr.delete(indexBinStr.length()- 4, indexBinStr.length());
    }
    String asciiBinStr= String.valueOf(indexBinStr);
    //将上面得到的二进制位字串分隔成字节后还原成明文
    String asciiBin= null;
    char[] ascii= new char[asciiBinStr.length()/ 8];
    for(int i= 0; i< ascii.length; i++) {
        asciiBin= asciiBinStr.substring(0, 8);
        asciiBinStr= asciiBinStr.substring(8);
        ascii[i]= (char)Integer.parseInt(asciiBin, 2);
    }
    return String.valueOf(ascii);
}

public static void main(String[] args) {
    System.out.println(decode("2ifuiJ4F6VMwaY8ATEr7db/="));
    //System.out.println(encode("11111111111111111"));

}

但是,最后又碰到一个坑。。解密出来的部分flag消失了,由于水平不够,没法去看细细逆向,大概推测出的flag为flag{QAQ_???_NO1},最后三位进行爆破了,这里选择使用无障碍服务运行的脚本软件auto.js,进行分析

image_1d4sn33tj10j2lm01qiu1hleudc20.png-23.5kB

本来是可以通过获取那个Text框的值判断结果的。。。但是我硬是等着看完了。。。ok,最后就这样了。