吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 25554|回复: 73
收起左侧

[Android 原创] 第二届强网杯-Picturelock-文件AES加密解密

  [复制链接]
skywilling 发表于 2018-5-28 20:11
本帖最后由 skywilling 于 2018-5-28 21:46 编辑

0x00前言

又一次遇到AES加密,莫名有种亲切感。这道题目是第二届强网杯逆向题目中的一道,应该是逆向题目中的压轴题吧(我只收到三个逆向题目,具体情况不是很清楚)。本篇文章带大家温习一下AES,长时间不接触真的会忘记,是时候复习一下以前的知识了!
0x01简单分析运行
题目拿到手里当然要看一下是什么类型的了。这是一道Android题目,直接以压缩包的方式打开:

11.png 12.png
在文件夹里我们发现了两个比较有用的文件,一个是后缀是.lock文件,另一个就是so文件,显然重要的处理方法保存在so文件中。
直接放到虚拟机中运行:

1.png
打开软件,界面很简洁,一个ENCRYPT(加密)按钮,一个REFRESH(刷新)按钮。点击第一个按钮后跳转到了另一个界面:

2.png
这是一个选择图片的界面,继续操作,又回到了主界面:

3.png
这时候界面多了一些信息,文本框多了刚才选中图片的文件名,需要注意的是,文件名后多了(.lock)后缀。同时,弹出了一个土司,里面显示了图片的绝对路径。了解了软件运行情况后,我们开始反编译。
0x02 Java层静态分析
反编译后,我们直接找到点击事件ENCRYPT按钮绑定的OnClick()方法:

4.png
对Android开发有一定了解的话,可以看出,代码首先检查了文件读写的权限,然后打开了图片选择的界面,选择图片后,会调用方法onActivityResult():

5.png
我们先不管这里具体进行了什么操作,可以看到这里有3个方法被调用了,分别是enc(),j(),i()。enc()是native层的方法,所以在这里就不说了,一会儿具体说,重点看一下i()和j()。

6.png
大概可以看出i()使用来显示文本框中的内容,对图片的处理没有影响,这里就不再详细说明。

7.png
这个j()方法就有点意思了,这个方法大概是获取APK包签名的MD5值,具体是什么,我们一会儿动态调试获取。

8.png
根据enc()方法的声明,可以知道,方法需要三个String类型的参数,这三个参数具体是什么,我们用动态调试的方法获取。
0x03 Java层动态分析
动态调试能够快速获取enc()方法的参数。在这里我们使用Android Studio和插件Smalidea。我们直接在方法调用处下断点:

9.png
查看寄存器:

10.png
我们看见第一个参数就是图片的绝对路径,第二个参数是加密后的文件的绝对路径,第三个参数就是方法j()获得的MD5值。需要注意的是我这里的APK包是修改过的,所以这里显示的MD5不是未修改包的MD5值,原包的MD5值应该是f8c49056e4ccf9a11e090eaf471f418d。到这里我们就弄清楚了enc()的三个参数,由此得到,enc(filepath,lockpath,signature)。filepath:图片的绝对路径,lockpath:加密后文件绝对路径,signature:APK包签名的MD5值。一般来说,CTF比赛题目的答案就是一个flag(若干个字符组成的字符串)。前面也提到APK包里有一个加密文件,那么flag极有可能就在解密后的文件中,那么我们就需要深入地分析加密过程了。
0x04Native层分析

直接把so文件拖入IDA分析。查看导出表:

13.png
很幸运,没有经过混淆,直接可以看到enc()方法的入口。直接F5还原成伪C代码:

14.png
在这里我修改了一些函数名,方便分析。通过分析,我们发现sub_51EC7A48是关键的代码段。
[C] 纯文本查看 复制代码
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
int __fastcall sub_51EC7A48(char *filepath, char *lockpath)
{
  int *dwords; // r5
  int bytes_temp; // r6
  char *filepath1; // r9
  char *lockpath1; // r8
  _DWORD *temp; // r0
  _DWORD *temp1; // r6
  int signature_array1; // r0
  int index; // r1
  int v10; // r3
  int index1; // r4
  int a; // r0
  int v13; // r5
  int v14; // r1
  int v15; // r2
  int temp3; // r10
  int temp_192; // r0
  int signature_array2; // r1
  int index2; // r2
  int index3; // r4
  int b; // r0
  int v22; // r1
  char i; // r9
  char c; // r11
  size_t readSize; // r0
  size_t readSize1; // r4
  _BYTE *readEnd; // r0
  int readLast; // r8
  int *v29; // r0
  int *new_temp; // r11
  signed int index4; // r1
  int signature_array3; // r0
  int result; // r0
  FILE *inputstream; // [sp+0h] [bp-28h]
  FILE *outputstream; // [sp+4h] [bp-24h]
  char bytes_temp0; // [sp+8h] [bp-20h]
  char bytes_temp4; // [sp+9h] [bp-1Fh]
  char bytes_temp8; // [sp+Ah] [bp-1Eh]
  char bytes_temp12; // [sp+Bh] [bp-1Dh]
  char bytes_temp1; // [sp+Ch] [bp-1Ch]
  char bytes_temp5; // [sp+Dh] [bp-1Bh]
  char bytes_temp9; // [sp+Eh] [bp-1Ah]
  char bytes_temp13; // [sp+Fh] [bp-19h]
  char bytes_temp2; // [sp+10h] [bp-18h]
  char bytes_temp6; // [sp+11h] [bp-17h]
  char bytes_temp10; // [sp+12h] [bp-16h]
  char bytes_temp14; // [sp+13h] [bp-15h]
  char bytes_temp3; // [sp+14h] [bp-14h]
  char bytes_temp7; // [sp+15h] [bp-13h]
  char bytes_temp11; // [sp+16h] [bp-12h]
  char bytes_temp15; // [sp+17h] [bp-11h]
  int v52; // [sp+18h] [bp-10h]
 
  filepath1 = filepath;
  lockpath1 = lockpath;
  if ( !temp2 )
  {
    temp = malloc(0x180u);
    temp1 = temp;
    temp2 = (int)temp;
    signature_array1 = signature_array;
    index = 0;
    do
    {
      v10 = *(unsigned __int8 *)(signature_array1 + index * 4 + 3);
      temp1[index] = _byteswap_ulong(*(_DWORD *)(signature_array1 + index * 4));
      ++index;
    }
    while ( index != 4 );
    index1 = 0;
    a = temp1[3];
    do
    {
      if ( !((index1 + 4) & 3) )
      {
        v13 = *(int *)((char *)&dword_51EC9F20 + ((index1 + 3 + ((unsigned int)((index1 + 3) >> 31) >> 30)) & 0xFFFFFFFC));
        a = func0(__ROR4__(a, 24)) ^ v13;
      }
      v14 = temp1[index1];
      v15 = (int)&temp1[index1++];
      a ^= v14;
      *(_DWORD *)(v15 + 16) = a;
    }
    while ( index1 != 40 );
    temp3 = temp2;
    temp_192 = temp2 + 192;
    temp_192_1 = temp2 + 192;
    signature_array2 = signature_array;
    index2 = 0;
    do
    {
      bytes_temp = (*(unsigned __int8 *)(signature_array2 + index2 + 17) << 16) | (*(unsigned __int8 *)(signature_array2 + index2 + 16) << 24) | (*(unsigned __int8 *)(signature_array2 + index2 + 18) << 8);
      *(_DWORD *)(temp_192 + index2) = _byteswap_ulong(*(_DWORD *)(signature_array2 + index2 + 16));
      index2 += 4;
    }
    while ( index2 != 16 );
    index3 = 0;
    b = *(_DWORD *)(temp3 + 204);
    dwords = &dword_51EC9F20;
    do
    {
      if ( !((index3 + 4) & 3) )
      {
        bytes_temp = *(int *)((char *)&dword_51EC9F20
                            + ((index3 + 3 + ((unsigned int)((index3 + 3) >> 31) >> 30)) & 0xFFFFFFFC));
        b = func0(__ROR4__(b, 24)) ^ bytes_temp;
      }
      v22 = temp3 + 4 * index3++;
      b ^= *(_DWORD *)(v22 + 192);
      *(_DWORD *)(v22 + 208) = b;
    }
    while ( index3 != 40 );
  }
  inputstream = fopen(filepath1, (const char *)&r);
  if ( inputstream )
  {
    outputstream = fopen(lockpath1, (const char *)&w);
    if ( outputstream )
    {
      bytes_temp = (int)malloc(0x100u);
      lockpath1 = (char *)inputstream;
      dwords = (int *)malloc(0x100u);
      for ( i = 0; ; ++i )
      {
        c = *(_BYTE *)(signature_array + (i & 0x1F));
        readSize = fread((void *)bytes_temp, 1u, *(unsigned __int8 *)(signature_array + (i & 0x1F)), (FILE *)lockpath1);
        readSize1 = readSize;
        if ( !readSize )
          goto LABEL_31;
        if ( readSize <= 0xF )
        {
          readEnd = (_BYTE *)(bytes_temp + readSize);
          readLast = 16 - (readSize1 & 0xF);
          if ( (readSize1 & 0xF) != 16 )
          {
            _aeabi_memset(readEnd, 16 - (readSize1 & 0xF), (unsigned __int8)readLast);
            readEnd = (_BYTE *)(readLast + readSize1 + bytes_temp);
          }
          lockpath1 = (char *)inputstream;
          readSize1 = 16;
          *readEnd = 0;
        }
        v29 = &temp_192_1;
        if ( !(c & 1) )
          v29 = &temp2;
        new_temp = (int *)*v29;
        bytes_temp0 = *(_BYTE *)bytes_temp;
        bytes_temp1 = *(_BYTE *)(bytes_temp + 1);
        bytes_temp2 = *(_BYTE *)(bytes_temp + 2);
        bytes_temp3 = *(_BYTE *)(bytes_temp + 3);
        bytes_temp4 = *(_BYTE *)(bytes_temp + 4);
        bytes_temp5 = *(_BYTE *)(bytes_temp + 5);
        bytes_temp6 = *(_BYTE *)(bytes_temp + 6);
        bytes_temp7 = *(_BYTE *)(bytes_temp + 7);
        bytes_temp8 = *(_BYTE *)(bytes_temp + 8);
        bytes_temp9 = *(_BYTE *)(bytes_temp + 9);
        bytes_temp10 = *(_BYTE *)(bytes_temp + 10);
        bytes_temp11 = *(_BYTE *)(bytes_temp + 11);
        bytes_temp12 = *(_BYTE *)(bytes_temp + 12);
        bytes_temp13 = *(_BYTE *)(bytes_temp + 13);
        bytes_temp14 = *(_BYTE *)(bytes_temp + 14);
        bytes_temp15 = *(_BYTE *)(bytes_temp + 15);
        func1(&bytes_temp0, new_temp);
        func2(&bytes_temp0);
        func3(&bytes_temp0);
        func4((unsigned __int8 *)&bytes_temp0);
        func1(&bytes_temp0, new_temp + 4);
        func2(&bytes_temp0);
        func3(&bytes_temp0);
        func4((unsigned __int8 *)&bytes_temp0);
        func1(&bytes_temp0, new_temp + 8);
        func2(&bytes_temp0);
        func3(&bytes_temp0);
        func4((unsigned __int8 *)&bytes_temp0);
        func1(&bytes_temp0, new_temp + 12);
        func2(&bytes_temp0);
        func3(&bytes_temp0);
        func4((unsigned __int8 *)&bytes_temp0);
        func1(&bytes_temp0, new_temp + 16);
        func2(&bytes_temp0);
        func3(&bytes_temp0);
        func4((unsigned __int8 *)&bytes_temp0);
        func1(&bytes_temp0, new_temp + 20);
        func2(&bytes_temp0);
        func3(&bytes_temp0);
        func4((unsigned __int8 *)&bytes_temp0);
        func1(&bytes_temp0, new_temp + 24);
        func2(&bytes_temp0);
        func3(&bytes_temp0);
        func4((unsigned __int8 *)&bytes_temp0);
        func1(&bytes_temp0, new_temp + 28);
        func2(&bytes_temp0);
        func3(&bytes_temp0);
        func4((unsigned __int8 *)&bytes_temp0);
        func1(&bytes_temp0, new_temp + 32);
        func2(&bytes_temp0);
        func3(&bytes_temp0);
        func4((unsigned __int8 *)&bytes_temp0);
        func1(&bytes_temp0, new_temp + 36);
        func2(&bytes_temp0);
        func3(&bytes_temp0);
        func1(&bytes_temp0, new_temp + 40);
        *(_BYTE *)dwords = bytes_temp0;
        *((_BYTE *)dwords + 1) = bytes_temp1;
        *((_BYTE *)dwords + 2) = bytes_temp2;
        *((_BYTE *)dwords + 3) = bytes_temp3;
        *((_BYTE *)dwords + 4) = bytes_temp4;
        *((_BYTE *)dwords + 5) = bytes_temp5;
        *((_BYTE *)dwords + 6) = bytes_temp6;
        *((_BYTE *)dwords + 7) = bytes_temp7;
        *((_BYTE *)dwords + 8) = bytes_temp8;
        *((_BYTE *)dwords + 9) = bytes_temp9;
        *((_BYTE *)dwords + 10) = bytes_temp10;
        *((_BYTE *)dwords + 11) = bytes_temp11;
        *((_BYTE *)dwords + 12) = bytes_temp12;
        *((_BYTE *)dwords + 13) = bytes_temp13;
        *((_BYTE *)dwords + 14) = bytes_temp14;
        *((_BYTE *)dwords + 15) = bytes_temp15;
        if ( readSize1 >= 0x11 )
        {
          index4 = 16;
          signature_array3 = signature_array;
          do
          {
            *((_BYTE *)dwords + index4) = *(_BYTE *)(bytes_temp + index4) ^ *(_BYTE *)(signature_array3 + index4 % 32);
            ++index4;
          }
          while ( index4 < readSize1 );
        }
        if ( fwrite(dwords, 1u, readSize1, outputstream) != readSize1 )
          break;
      }
    }
  }
  result = -1;
  while ( _stack_chk_guard != v52 )
  {
LABEL_31:
    free((void *)bytes_temp);
    free(dwords);
    fclose((FILE *)lockpath1);
    fclose(outputstream);
    result = 0;
  }
  return result;
}

还原出来的伪C代码,并不是完全可信的,但是还是有很大参考价值的。

15.png
根据伪C代码我们可以还原出C代码:
[C] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
int i = 0, j,k;
temp = (unsigned int*)malloc(0x180);
memset(temp,0,0x180);
do {
  temp[i] = _byteswap_ulong(*(unsigned int*)(signature + i * 4));
  ++i;
} while (i != 4);
i = 0;
a = temp[3];
do {
  if (!((i + 4) & 3)) {
    a = func0(ror(a, 24)) ^ *(unsigned int*)(dwords + ((i + 3 + ((unsigned int)((i + 3) >> 31) >> 30)) & 0xFFFFFFFC));
  }
  a ^= temp[i];
  temp[i+4] = a;
  i++;
} while (i != 40);

这段代码是根据前16个字节扩展出40个双字。

16.png
还原出C代码:
[C] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
i = 0;
do {
  temp[i+48] = _byteswap_ulong(*(unsigned int*)(signature + i*4 + 16));
  i++;
} while (i != 4);
i = 0;
b = temp[51];
do {
  if (!((i + 4) & 3)) {
    b = func0(ror(b, 24)) ^ *(unsigned int*)(dwords + ((i + 3 + ((unsigned int)((i + 3) >> 31) >> 30)) & 0xFFFFFFFC));
  }
  b ^= temp[i+48];
  temp[i+52] = b;
  i++;
} while (i != 40);

这段代码是根据后16个字节扩展出40个双字。

17.png
这就是密钥扩展出来的88个双字,继续往下看。

18.png
这里调用了fopen(),以读模式打开了图片文件,以写模式打开了加密文件。同样可以转换为C代码:
[C] 纯文本查看 复制代码
1
2
fopen_s(&inputstream,filepath, "rb");
fopen_s(&outputstream,lockpath, "wb");

接下来就是读取文件,在这里,根据signature数组获取特定长度的数据,保存到bytes_temp中。

19.png
还原出C代码:
[C] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
if (readSize <= 0xF) {
  readEnd = (unsigned char*)(bytes_temp + readSize);
  readLast = 16 - (readSize & 0xF);
  if ((readSize & 0xF) != 16) {
    memset((void*)readEnd, readLast, readLast);
    readEnd = (unsigned char*)readLast + readSize + (unsigned int)bytes_temp;
  }
  readSize = 16;
  *readEnd = 0;
}

这里是处理了长度不足0x10的数据,该代码段的实际作用就是填充不足0x10的部分数据。

20.png
还原出C代码:
[C] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
if (!(c & 1)) {                //偶数
  new_temp = temp;
}
else {                                //奇数
  new_temp = &temp[48];
}
//转置
for (j=0;j<4;j++) {
  for (k=0;k<4;k++) {
    result[j*4+k]=bytes_temp[k*4+j];
  }
}

这里是根据读取数据长度的奇偶性来决定使用第一段密钥还是第二段密钥。接下来就是把读取数据的前16个字节保存到了新的地方,并进行了转置,也就是保存为了一个4x4矩阵,后面的操作都是基于这个矩阵来进行的。需要注意的是,要看出这里进行了转置,就需要动态调试了。接下来可以看到重复调用几个函数:
[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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
func1(&bytes_temp0, new_temp);
func2(&bytes_temp0);
func3(&bytes_temp0);
func4((unsigned __int8 *)&bytes_temp0);
func1(&bytes_temp0, new_temp + 4);
func2(&bytes_temp0);
func3(&bytes_temp0);
func4((unsigned __int8 *)&bytes_temp0);
func1(&bytes_temp0, new_temp + 8);
func2(&bytes_temp0);
func3(&bytes_temp0);
func4((unsigned __int8 *)&bytes_temp0);
func1(&bytes_temp0, new_temp + 12);
func2(&bytes_temp0);
func3(&bytes_temp0);
func4((unsigned __int8 *)&bytes_temp0);
func1(&bytes_temp0, new_temp + 16);
func2(&bytes_temp0);
func3(&bytes_temp0);
func4((unsigned __int8 *)&bytes_temp0);
func1(&bytes_temp0, new_temp + 20);
func2(&bytes_temp0);
func3(&bytes_temp0);
func4((unsigned __int8 *)&bytes_temp0);
func1(&bytes_temp0, new_temp + 24);
func2(&bytes_temp0);
func3(&bytes_temp0);
func4((unsigned __int8 *)&bytes_temp0);
func1(&bytes_temp0, new_temp + 28);
func2(&bytes_temp0);
func3(&bytes_temp0);
func4((unsigned __int8 *)&bytes_temp0);
func1(&bytes_temp0, new_temp + 32);
func2(&bytes_temp0);
func3(&bytes_temp0);
func4((unsigned __int8 *)&bytes_temp0);
func1(&bytes_temp0, new_temp + 36);
func2(&bytes_temp0);
func3(&bytes_temp0);
func1(&bytes_temp0, new_temp + 40);

整理成C代码是:
[C] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
for (j = 0; j < 9; j++) {
  func1(result, new_temp + 4 * j);
  func2(result);
  func3(result);
  func4(result);
}
 
func1(result, new_temp + 4 * j++);
func2(result);
func3(result);
func1(result, new_temp + 4 * j);

先说func1(),伪C代码是:

21.png
整理后
[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
26
27
28
29
30
31
32
33
34
unsigned char *func1(unsigned char* result, unsigned int*new_temp) {
        unsigned int temp;
        temp=new_temp[0];
        result[0] ^= (temp >> 24);
        result[4] ^= (temp >> 16);
        result[8] ^= (temp >> 8);
        result[12] ^= temp;
        temp = new_temp[1];
        result[1] ^= (temp >> 24);
        result[5] ^= (temp >> 16);
        result[9] ^= (temp >> 8);
        result[13] ^= temp;
        temp = new_temp[2];
        result[2] ^= (temp >> 24);
        result[6] ^= (temp >> 16);
        result[10] ^= (temp >> 8);
        result[14] ^= temp;
        temp = new_temp[3];
        result[3] ^= (temp >> 24);
        result[7] ^= (temp >> 16);
        result[11] ^= (temp >> 8);
        result[15] ^= temp;
        /*
        简化后:
        int i;
        for (i=0;i<4;i++) {
                result[i*4]^=new_temp[i]>>24;
                result[i*4+1]^=new_temp[i]>>16;
                result[i*4+2]^=new_temp[i]>>8;
                result[i*4+3]^=new_temp[i];
        }
        */
        return result;
}

很显然这里进行了异或操作。然后是func2(),伪C代码是:

22.png
整理后是:
[C] 纯文本查看 复制代码
1
2
3
4
5
6
7
unsigned char *func2(unsigned char*result) {
        int i;
        for (i = 0; i < 16; i++) {
                result[i] = s_box[(result[i] & 0xF0) + (result[i] & 0x0F)];
        }
        return result;
}
这里就是S盒的置换操作了。func3()的伪C代码:

23.png
整理后:
[C] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
unsigned char *func3(unsigned char*result) {
        unsigned char temp;
        temp = result[4];
        result[4] = result[5];
        result[5] = result[6];
        result[6] = result[7];
        result[7] = temp;
        temp = result[8];
        result[8] = result[10];
        result[10] = temp;
        temp = result[9];
        result[9] = result[11];
        result[11] = temp;
        temp = result[12];
        result[12] = result[15];
        result[15] = result[14];
        result[14] = result[13];
        result[13] = temp;
        return result;
}

这里进行了正向行移位操作。最后是func4(),伪c代码是:
[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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
unsigned __int8 *__fastcall func4(unsigned __int8 *result)
{
  int result0; // r2
  int result12; // r3
  int result8; // lr
  int result4; // r12
  char result0_byte; // r10
  char result12_byte; // r9
  char v7; // r6
  char v8; // r4
  char v9; // r5
  int result13; // r6
  int result1; // r7
  int result5; // r8
  int result9; // r3
  char result13_byte; // r9
  char result13_byte_1; // r11
  char result1_byte; // r10
  int result14; // r6
  int result2; // r7
  int result6; // r8
  int result10; // r3
  char v21; // r9
  char v22; // r11
  char v23; // r10
  int result15; // r6
  int result3; // r7
  int result7; // r2
  int result11; // r3
  char v28; // r9
  char v29; // r10
 
  result0 = *result;
  result12 = result[12];
  result8 = result[8];
  result4 = result[4];
  result0_byte = byte_51EC9920[6 * result0 + 1];
  result12_byte = byte_51EC9920[6 * result12];
  v7 = result12 ^ result8 ^ byte_51EC9920[6 * result0];
  v8 = byte_51EC9920[6 * result8 + 1];
  v9 = byte_51EC9920[6 * result4] ^ result0;
  LOBYTE(result0) = result0 ^ result4 ^ byte_51EC9920[6 * result8] ^ byte_51EC9920[6 * result12 + 1];
  *result = v7 ^ byte_51EC9920[6 * result4 + 1];
  result[4] = result12 ^ v9 ^ v8;
  result[8] = result0;
  result[12] = result8 ^ result4 ^ result0_byte ^ result12_byte;
  result13 = result[13];
  result1 = result[1];
  result5 = result[5];
  result9 = result[9];
  result13_byte = byte_51EC9920[6 * result13];
  result13_byte_1 = byte_51EC9920[6 * result13 + 1];
  result1_byte = byte_51EC9920[6 * result1 + 1];
  LOBYTE(result8) = byte_51EC9920[6 * result5];
  LOBYTE(result4) = byte_51EC9920[6 * result9];
  result[1] = byte_51EC9920[6 * result5 + 1] ^ result13 ^ result9 ^ byte_51EC9920[6 * result1];
  result[5] = result8 ^ result1 ^ result13 ^ byte_51EC9920[6 * result9 + 1];
  result[9] = result5 ^ result1 ^ result4 ^ result13_byte_1;
  result[13] = result9 ^ result5 ^ result1_byte ^ result13_byte;
  result14 = result[14];
  result2 = result[2];
  result6 = result[6];
  result10 = result[10];
  v21 = byte_51EC9920[6 * result14];
  v22 = byte_51EC9920[6 * result14 + 1];
  v23 = byte_51EC9920[6 * result2 + 1];
  LOBYTE(result8) = byte_51EC9920[6 * result6];
  LOBYTE(result4) = byte_51EC9920[6 * result10];
  result[2] = byte_51EC9920[6 * result6 + 1] ^ result14 ^ result10 ^ byte_51EC9920[6 * result2];
  result[6] = result8 ^ result2 ^ result14 ^ byte_51EC9920[6 * result10 + 1];
  result[10] = result6 ^ result2 ^ result4 ^ v22;
  result[14] = result10 ^ result6 ^ v23 ^ v21;
  result15 = result[15];
  result3 = result[3];
  result7 = result[7];
  result11 = result[11];
  LOBYTE(result8) = byte_51EC9920[6 * result15];
  v28 = byte_51EC9920[6 * result15 + 1];
  LOBYTE(result6) = byte_51EC9920[6 * result3 + 1];
  result[3] = byte_51EC9920[6 * result3] ^ result15 ^ result11 ^ byte_51EC9920[6 * result7 + 1];
  v29 = byte_51EC9920[6 * result11];
  result[7] = byte_51EC9920[6 * result7] ^ result3 ^ result15 ^ byte_51EC9920[6 * result11 + 1];
  result[11] = result7 ^ result3 ^ v29 ^ v28;
  result[15] = result11 ^ result7 ^ result6 ^ result8;
  return result;
}

整理后:
[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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
unsigned char *func4(unsigned char*result) {
        unsigned char a,b,c,d;
        a=result[0];
        b=result[4];
        c=result[8];
        d=result[12];
        result[0] = func5(c,d,a,b);
        result[4] = func5(a,d,b,c);
        result[8] = func5(a,b,c,d);
        result[12] = func5(b,c,d,a);
 
        a=result[1];
        b=result[5];
        c=result[9];
        d=result[13];
        result[1] = func5(c, d, a, b);
        result[5] = func5(a, d, b, c);
        result[9] = func5(a, b, c, d);
        result[13] = func5(b, c, d, a);
 
        a = result[2];
        b = result[6];
        c = result[10];
        d = result[14];
        result[2] = func5(c, d, a, b);
        result[6] = func5(a, d, b, c);
        result[10] = func5(a, b, c, d);
        result[14] = func5(b, c, d, a);
 
        a = result[3];
        b = result[7];
        c = result[11];
        d = result[15];
        result[3] = func5(c, d, a, b);
        result[7] = func5(a, d, b, c);
        result[11] = func5(a, b, c, d);
        result[15] = func5(b, c, d, a);
 
        /*简化后
        int i;
        char a,b,c,d;
        for (i=0;i<4;i++) {
                a=result[i];
                b=result[i+4];
                c=result[i+8];
                d=result[i+12];
                result[i] = func5(c, d, a, b);
                result[i+4] = func5(a, d, b, c);
                result[i+8] = func5(a, b, c, d);
                result[i+12] = func5(b, c, d, a);
        }
        */
 
        return result;
}

其实这里就是列混淆,只是这里的实现方法与以往的不同而已。

24.png
加密流程结束后,又进行了矩阵的转置操作。最后是:

25.png
整理后:
[C] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
//转置
for (j = 0; j<4; j++) {
  for (k = j; k<4; k++) {
    if (j != k) {
      unsigned char temp = result[j * 4 + k];
      result[j * 4 + k] = result[k * 4 + j];
      result[k * 4 + j] = temp;
    }
  }
}
if (fwrite(result, 1, readSize, outputstream) != readSize) {
  break;
}

这里是对读取数据位置大于0x10的数据进行异或操作,最后写入到文件里。到这里这块数据的加密流程就分析完毕了。在这里我们总结一下加密的流程,首先是读取一个特定长度的数据块,然后取出前16个字节进行AES加密,再把剩余的数据进行异或操作,这样一块数据就加密完毕了。对每块数据进行相同的操作,最后得到加密文件。整个加密流程大致就是这样。我们已经知道了加密流程,那么解密方法就很容易得到了,这些代码我都会放到文章最后地附件中。
0x05写在最后
这样我们就可以解密出加密图片了,最后附上结果图:

26.png
附件:https://pan.baidu.com/s/1qrKwTZEqHuajOpADhaPk0A 密码:59dn版权声明:允许转载,但是一定要注明出处

免费评分

参与人数 42吾爱币 +43 热心值 +40 收起 理由
ghsfwy + 1 + 1 我很赞同!
luoyesiqiu + 1 + 1 很详细,思路很清晰
青山依旧在 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
Pwn0k + 1 用心讨论,共获提升!
52lxw + 1 + 1 我很赞同!
gink + 1 + 1 我很赞同!
zhh4827 + 1 + 1 热心回复!
DS_FLY100 + 1 + 1 收藏一波,学习一哈
skiss + 1 + 1 谢谢@Thanks!
数学家是我理想 + 1 我很赞同!
江南小虫虫 + 1 我很赞同!
22222 + 1 + 1 用心讨论,共获提升!
孑遗1 + 1 + 1 谢谢@Thanks!
控控网络 + 1 + 1 谢谢@Thanks!
siuhoapdou + 1 + 1 用心讨论,共获提升!
丶峰宇 + 1 + 1 用心讨论,共获提升!
老张有大梦想 + 1 + 1 热心回复!
530393321 + 1 + 1 谢谢@Thanks!
zxc1998gzp + 1 + 1 谢谢@Thanks!
阿尔卡伊达 + 1 + 1 热心回复!
c0okie5 + 1 用心讨论,共获提升!
LHQ + 1 + 1 谢谢@Thanks!
jnez112358 + 1 + 1 谢谢@Thanks!
zy1234 + 1 + 1 用心讨论,共获提升!
zhouyikun + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
385290864 + 1 + 1 我很赞同!
圣血轩辕 + 1 + 1 说的很精彩我很感动,虽然听不懂。
ask1000 + 1 + 1 谢谢@Thanks!
page_ + 1 + 1 热心回复!
lookerJ + 1 + 1 谢谢@Thanks!
nukin + 1 + 1 谢谢@Thanks!
莫奇 + 1 + 1 谢谢@Thanks!
笙若 + 1 + 1 谢谢@Thanks!
zzzlucas + 1 + 1 谢谢@Thanks!
myouter + 1 + 1 用心讨论,共获提升!
MXWXZ + 3 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
dazhige + 1 + 1 谢谢@Thanks!
CcCody + 1 + 1 用心讨论,共获提升!
Anonymous、 + 2 + 1 精华的节奏
Tomatoman + 1 + 1 用心讨论,共获提升!
DK/F + 1 + 1 用心讨论,共获提升!
bmwgtr + 1 + 1 用心讨论,共获提升!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| skywilling 发表于 2018-5-29 10:39
panwei103012571 发表于 2018-5-29 09:52
这个算不算是因写,如果是可以把图片导出来,再电脑16进制打开,16进制修改图片大小,有可能也可以,以前试 ...

这个不是隐写,程序是涉及到AES加密的
蓝色马蹄莲 发表于 2018-6-4 23:14
skywilling 发表于 2018-5-29 22:44
S盒只是识别特征的一种,有一些修改过的AES加密是会使用非标准S盒的(这个你可以参考我以前分析的题目) ...

小白请教一下:
能否用简短的语言(打比方也可以)描述一下此贴的AES加密和RAR包的加密方式有何不同?

如果有足够的人手,比如100人小团队,每个人能力都和你一样,是不是也能逐步分析并破解一个RAR包呢?(假设此RAR包用12位密码加密,有数字和大小写字母,不含特殊字符)

门外汉的一点好奇,如果问得不妥,请无视,谢谢。

免费评分

参与人数 1吾爱币 +1 收起 理由
少狐 + 1 rar的加密密钥就是密码, 没有密码就只能暴力破解, 这个是拿到了密钥在进行.

查看全部评分

zgy150010318 发表于 2018-5-28 20:37
fq645122 发表于 2018-5-28 20:46
不错不错
bmwgtr 发表于 2018-5-28 20:49
来学习下,写得很详细,感谢分享~
君如兰 发表于 2018-5-28 21:37
看不懂 但是知道楼主是个高手
Setsuro 发表于 2018-5-28 21:58
楼主高手哦 怎么详细的教程
Tomatoman 发表于 2018-5-28 22:20
写的很详细,学习了,谢谢!
幻象 发表于 2018-5-28 23:19 来自手机
大佬哇大佬
幻象 发表于 2018-5-28 23:20 来自手机
大佬哇大佬
trombe108 发表于 2018-5-28 23:41
完全看不懂啊
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-4-1 20:27

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表