记一次Android逆向算法分析《阿里聚安全攻防挑战赛预赛第一题》

作者: skywilling 分类: Android逆向,逆向 发布时间: 2017-06-23 16:57

转自https://www.52pojie.cn/thread-606216-1-1.html

0x00前言
之前因为学习过Android编程,所以对Android逆向一直抱着强烈的兴趣,这就像网络中的攻与防,两者相互促进、相互发展,所以说搞开发的或者搞安全的都很有必要学习研究一下当前研究领域的对立领域,这或许会在将来发挥出意想不到的作用。前面说的有点正式了,其实吧,搞逆向,说白了就是破解,好了,废话就不再多说了,下面开始正题。
0x01效果图
下面是运行的结果图,很简单的界面只有两个控件,一个输入框,一个按钮。
              

0x02Java代码
Java代码很简单,可以看出来,我们要找的就是native层的verify()方法

[Java] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class MainActivity
  extends Activity
{
  public static String TAG = "hellojni";
  
  public static native boolean verify(String paramString);
  
  protected void onCreate(Bundle paramBundle)
  {
    super.onCreate(paramBundle);
    requestWindowFeature(1);
    setContentView(2130903065);
    Button localButton = (Button)findViewById(2131427338);
    localButton.setBackgroundResource(2130837579);
    localButton.setOnClickListener(new View.OnClickListener()
    {
      public void onClick(View paramAnonymousView)
      {
        System.loadLibrary("crackme");
        Object localObject = ((EditText)MainActivity.this.findViewById(2131427333)).getText().toString();
        String str = "warnning! it is an incorrect key!";
        int i = Color.rgb(255, 0, 0);
        if (MainActivity.verify((String)localObject))
        {
          str = "congratulation! You found the key!";
          i = Color.rgb(0, 255, 0);
        }
        localObject = (TextView)MainActivity.this.findViewById(2131427336);
        ((TextView)localObject).setTextColor(i);
        ((TextView)localObject).setText(str);
      }
    });
  }

0x03分析so文件
分析so文件我们一般都用动态调试的方法,静态调试对这个问题来说不太适合。
这里我就不再说明动态调试的方法,默认读者都会。
这里我主要想说的是该算法的加密过程(一般只要写出了加密的代码,写出解密的代码就很轻松了,所以在这里,只说一下加密的过程)。
下面是加密的大概流程:
1.异或0x7E
2.异或0x21
3.异或0x40
4.异或0x23
5.加密1
6.异或0x24
7.加密2
8.异或0x25
流程1,2,3,4,6,8的异或方式是input[index]=input[index]^(index+0x00).
要重点说明一下的是,在流程4和5之间有一个判断字符串长度是否大于0x10(在我首次分析的时候忽略了这个判断条件,以至于用重新分析了一遍,真是蛋疼),在流程4结束后,比较字符串长度,如果小于0x10,以(0x10-len)扩充字符串到0x10,如果大于0x10,以(0x20-len)扩充到0x20。这里我想说的是,这道题目的key的长度是大于0x10,所以我们在调试时,就要输入一个长度大于0x10的数据作为测试数据。
0x04加密1
下面的话,我会完全结合我写的加密代码来进行,所以也请读者结合文章结尾附件中的加密代码来看。
在这里我将加密1的过程用分为了三个步骤:
步骤一:

[C] 纯文本查看 复制代码
1
2
3
4
5
6
7
8
func1(in,table0);
    func1(in,table0);
    func6(out,in,table1,table0);
    func7(in,table0);
    func1(in+0x10,table0);
    func1(in+0x10,in);
    func6(out,in+0x10,table1,table0);
    func7(in+0x10,table0);

方法的名字有些难以理解,就将就看吧,其实整个过程下来,也就这几个方法。
简单说一下这几个方法的作用,
func1(), 简单来说就是和table0(一个置换表,学过密码学的都应该了解)进行异或操作,in=in^table0;
func6(),这是一个比较复杂的加密,

[C] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
void func6(unsigned char*out,unsigned char* in,unsigned char*table,unsigned char*table1){    int i=1;
    for(i=1;i<0xA;i++){
        strcopy(out,in,0x10);
        func2(in,out,table);
        func4(in);
        func5(in,table1,i);
    }
     strcopy(out,in,0x10);
     func2(in,out,table);
}

可以看出func6实际上就是需要func2,func4,func5依次加密9次,再进行一次func2加密的结果,可以算作一个整体。
func2,也是一种置换,代码如下

[C] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void func2(unsigned char*out,unsigned char*in,unsigned char*table){
    unsigned char n=in[0];
    out[0]=func3(n,table);
    out[1]=func3(in[5]&0xFF,table);
    out[2]=func3(in[0xA]&0xFF,table);
    out[3]=func3(in[0xF]&0xFF,table);
    n=in[4]&0xFF;
    out[4]=func3(n,table);
    out[5]=func3(in[9]&0xFF,table);
    out[6]=func3(in[0xE]&0xFF,table);
    out[7]=func3(in[3]&0xFF,table);
    n=in[8]&0xFF;
    out[8]=func3(n,table);
    out[9]=func3(in[0xD]&0xFF,table);
    out[0xA]=func3(in[2]&0xFF,table);
    out[0xB]=func3(in[7]&0xFF,table);
    n=in[0xC]&0xFF;
    out[0xC]=func3(n,table);
    out[0xD]=func3(in[1]&0xFF,table);
    out[0xE]=func3(in[6]&0xFF,table);
    out[0xF]=func3(in[0xB]&0xFF,table);
}
unsigned char func3(unsigned char*table,int i){
    return table;
}

func4,具体我也不清楚这个加密的意图,我是按照汇编语言翻译过来的,

[Asm] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
void func4(unsigned char*in){
    unsigned char r0,r1,r2,r3,r4,r5,r6,r7,r9;
    unsigned char r8=0;
    int i=0;
    for(i=0;i<0x10;i+=4){
        r0=in;
        r1=in[i+1];
        r2=in[i+2];
        r3=in[i+3];
        r4=r1^r0;
        r5=r4&0xFF;
        r6=r4^r2;
        r7=r8-(r5>>7);
        r7=r7&0x1B;
        r5=r7^(r5<<1);
        r7=r6^r3;
        r9=r7^r0;
        r5=r9^r5;
        in=r5;
        r5=r7^r1;
        r7=r2^r1;
        r7=r7&0xFF;
        r1=r8-(r7>>7);
        r1=r1&0x1B;
        r7=r1^(r7<<1);
        r5=r5^r7;
        r7=r3^r2;
        r7=r7&0xFF;
        in[i+1]=r5;
        r5=r3^r4;
        r2=r8-(r7>>7);
        r2=r2&0x1B;
        r7=r2^(r7<<1);
        r5=r5^r7;
        in[i+2]=r5;
        r5=r3^r0;
        r5=r5&0xFF;
        r7=r8-(r5>>7);
        r7=r7&0x1B;
        r5=r7^(r5<<1);
        r5=r5^r6;
        in[i+3]=r5;
    }

func5,这个加密还是有一定的规律的,

[C] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
void func5(unsigned char*in,unsigned char*table, unsigned char n){    unsigned char r7,r1,r0;
    int i=0;
    r7=n;
    r1=in[0];
    r0=table[r7<<4];
    r0=r1^r0;
    in[0]=r0;
    for(i=1;i<0x10;i++){
        r0=i;
        r0=r0|(r7<<4);
        r1=in;
        r0=table[r0];
        r0=r1^r0;
        in=r0;
    }
}

func7,这个加密和func1差不多,只是开始的位置不同,in=in^table[i+0xA0]
以上就是加密1的步骤一。
步骤二:

[C] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
//1
    func1(next,table2);
    func6(out,next0,table1,table2);
    func7(next0,table2);
    //2
    func1(next+0x10,next0);
    strcopy(next0+0x10,next+0x10,0x10);
    func1(next0+0x10,table2);
    func6(out,next0+0x10,table1,table2);
    func7(next0+0x10,table2);
    //3
    memset(next+0x20,0x10,0x10);
    func1(next+0x20,next0+0x10);
    strcopy(next0+0x20,next+0x20,0x10);
    func1(next0+0x20,table2);
    func6(out,next0+0x20,table1,table2);
    func7(next0+0x20,table2);

步骤三:

[C] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
func7(key1,table2);
    func11(out,key1,table3,table2);
    func1(key1,table2);
    func1(key1,table2);
    //2
    func7(key1+0x10,table2);
    func11(out,key1+0x10,table3,table2);
    func1(key1+0x10,table2);
    func1(key1+0x10,next0);
    //3
    func7(key1+0x20,table2);
    func11(out,key1+0x20,table3,table2);
    func1(key1+0x20,table2);
    func1(key1+0x20,next0+0x10);

这里唯一不一样的就是,func6变成了func11,说一下,func6与func11的关系,
=======
func6 table1 table0
func11  table3  table0
=======
func6  table1  table2
func11  table3  table2
=======
func6  table1  table4
func11 table3  table4
=======
两两互为逆过程,也就是加解密过程,所以这里方便了加解密代码的编写。
0x05加密2
加密又可分为两个步骤:
步骤一:

[C] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
//1
    func1(key3,table4);
    strcopy(key2,key3,0x10);
    func1(key3,table4);
    func6(out,key3,table1,table4);
    func7(key3,table4);
    //2
    func1(key2+0x10,key3);
    strcopy(key3+0x10,key2+0x10,0x10);
    func1(key3+0x10,table4);
    func6(out,key3+0x10,table1,table4);
    func7(key3+0x10,table4);
    //3
    func1(key2+0x20,key3+0x10);
    strcopy(key3+0x20,key2+0x20,0x10);
    func1(key3+0x20,table4);
    func6(out,key3+0x20,table1,table4);
    func7(key3+0x20,table4);

步骤二:

[C] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
//1
   func7(key4,table4);
   func11(out,key4,table3,table4);
   func1(key4,table4);
   func1(key4,table4);
   //2
   strcopy(key4+0x10,key3+0x10,0x10);
   func7(key4+0x10,table4);
    func11(out,key4+0x10,table3,table4);
   func1(key4+0x10,table4);
   func1(key4+0x10,key3);
   //3
   strcopy(key4+0x20,key3+0x20,0x10);
   func7(key4+0x20,table4);
    func11(out,key4+0x20,table3,table4);
    func1(key4+0x20,table4);
    func1(key4+0x20,key3+0x10);

0x06结语
第一次发帖有点小紧张,凡事都有第一次,谨以此文纪念第一次在吾爱发帖。当然,更多的是,在n年以后,想起我曾在某某知名论坛发过贴,想想也有一种欣慰。最后,希望本文可以对新手们有所启发。
附件:链接:http://pan.baidu.com/s/1cEOxFC 密码:mwxa
版权声明:允许转载,但是一定要注明出处。

5条评论
  • 套图网

    10月20日 上午8:45

    阅读博客获得的进步不亚于阅读一本书。

  • 套图网

    10月24日 上午6:54

    不止一次的来,不止一次的去,来来去去,这就是这个博客的魅力!

  • 健康网

    10月26日 上午9:55

    学海无涯,博客有道!拜读咯!

  • 三五创业网

    11月16日 下午4:33

    潜心学习,认真拜读!

  • 中青看点

    12月15日 下午2:52

    这样精彩的博客越来越少咯!

发表评论

电子邮件地址不会被公开。 必填项已用*标注