吾爱破解 - LCG - LSG |安卓破解|病毒分析|破解软件|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 8622|回复: 64

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

  [复制链接]
发表于 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] 纯文本查看 复制代码
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] 纯文本查看 复制代码
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] 纯文本查看 复制代码
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] 纯文本查看 复制代码
       
fopen_s(&inputstream,filepath, "rb");
fopen_s(&outputstream,lockpath, "wb");

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

19.png
还原出C代码:
[C] 纯文本查看 复制代码
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] 纯文本查看 复制代码
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] 纯文本查看 复制代码
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] 纯文本查看 复制代码
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] 纯文本查看 复制代码
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] 纯文本查看 复制代码
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] 纯文本查看 复制代码
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] 纯文本查看 复制代码
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] 纯文本查看 复制代码
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] 纯文本查看 复制代码
//转置
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版权声明:允许转载,但是一定要注明出处

免费评分

参与人数 36吾爱币 +38 热心值 +34 收起 理由
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 用心讨论,共获提升!

查看全部评分

本帖被以下淘专辑推荐:

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子分类或者标题加上【已解决】

如何回报帮助你解决问题的坛友,一个好办法就是给对方加【热心】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

 楼主| 发表于 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的加密密钥就是密码, 没有密码就只能暴力破解, 这个是拿到了密钥在进行.

查看全部评分

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子分类或者标题加上【已解决】

如何回报帮助你解决问题的坛友,一个好办法就是给对方加【热心】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

发表于 2018-5-28 20:37 | 显示全部楼层

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子分类或者标题加上【已解决】

如何回报帮助你解决问题的坛友,一个好办法就是给对方加【热心】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

发表于 2018-5-28 20:46 | 显示全部楼层
不错不错

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子分类或者标题加上【已解决】

如何回报帮助你解决问题的坛友,一个好办法就是给对方加【热心】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

发表于 2018-5-28 20:49 | 显示全部楼层
来学习下,写得很详细,感谢分享~

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子分类或者标题加上【已解决】

如何回报帮助你解决问题的坛友,一个好办法就是给对方加【热心】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

发表于 2018-5-28 21:37 | 显示全部楼层
看不懂 但是知道楼主是个高手

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子分类或者标题加上【已解决】

如何回报帮助你解决问题的坛友,一个好办法就是给对方加【热心】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

发表于 2018-5-28 21:58 | 显示全部楼层
楼主高手哦 怎么详细的教程

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子分类或者标题加上【已解决】

如何回报帮助你解决问题的坛友,一个好办法就是给对方加【热心】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

发表于 2018-5-28 22:20 | 显示全部楼层
写的很详细,学习了,谢谢!

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子分类或者标题加上【已解决】

如何回报帮助你解决问题的坛友,一个好办法就是给对方加【热心】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

发表于 2018-5-28 23:19 来自手机 | 显示全部楼层
大佬哇大佬

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子分类或者标题加上【已解决】

如何回报帮助你解决问题的坛友,一个好办法就是给对方加【热心】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

发表于 2018-5-28 23:20 来自手机 | 显示全部楼层
大佬哇大佬

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子分类或者标题加上【已解决】

如何回报帮助你解决问题的坛友,一个好办法就是给对方加【热心】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

发表于 2018-5-28 23:41 | 显示全部楼层
完全看不懂啊

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子分类或者标题加上【已解决】

如何回报帮助你解决问题的坛友,一个好办法就是给对方加【热心】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则


免责声明:
吾爱破解所发布的一切破解补丁、注册机和注册信息及软件的解密分析文章仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。

Mail To:Service@52PoJie.Cn

快速回复 收藏帖子 返回列表 搜索

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

GMT+8, 2018-8-16 20:45

Powered by Discuz!

© 2001-2017 Comsenz Inc.

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