g2uc

TeamBlog

[REVERSE]线上赛 0x02 PictureLock[SP Edition]

0x02 PictureLock[SP Edition]
操作内容:

下载解压文件后得到一个exe,一个dll,和一个.lock文件,查壳后可知exe为upx加壳,解之.dll为无壳pe文件.

运行程序后可知该程序的作用是加密一个图片并以.lock后缀结尾写出文件,因此我们的任务即为找到图片加密算法,写出解密算法,将题目文件中的.lock文件解密为图片,以得到flag

为了弄清楚dll的作用,将其替换为一个毫无联系的dll文件,运行程序报错提示如下:

此时可初步得知sp.dll负责通过enc0函数进行加密操作.

将dll导入ida找到enc0函数,可看到该加密算法的全貌,然后用C++重现一遍代码后再写出逆向解密的代码,即可得到flag.

解密代码如下:

_BYTE key[32] = {
0x64, 0x34, 0x31, 0x64, 0x38, 0x63, 0x64, 0x39, 0x38, 0x66, 0x30, 0x30, 0x62, 0x32, 0x30, 0x34, 
0x65, 0x39, 0x38, 0x30, 0x30, 0x39, 0x39, 0x38, 0x65, 0x63, 0x66, 0x38, 0x34, 0x32, 0x37, 0x65
};



_BYTE unk_36E4[256] = {
0x72, 0x6A, 0x08, 0x96, 0xDE, 0x6E, 0x20, 0xEB, 0x87, 0xDD, 0xE0, 0x12, 0x36, 0xEF, 0xCB,
0x05, 0xEA, 0x4F, 0xB6, 0xAC, 0x2D, 0x56, 0x3F, 0xFA, 0x61, 0xAF, 0x59, 0x00, 0x53, 0xD5,
0xC3, 0xD4, 0x38, 0x8F, 0xDB, 0xC4, 0xB8, 0xEC, 0xBD, 0xCE, 0x7C, 0x94, 0x33, 0xE5, 0x21,
0xE4, 0x17, 0x60, 0xAE, 0x25, 0x1F, 0xCC, 0x3C, 0x27, 0xA3, 0x04, 0x70, 0x52, 0x49, 0xED,
0x5A, 0x88, 0xC2, 0x19, 0xE2, 0x6D, 0x79, 0xF4, 0xAD, 0x85, 0xB9, 0x77, 0x03, 0xA2, 0xBF,
0xF3, 0x1B, 0x5D, 0xC9, 0xD1, 0xF8, 0x62, 0x69, 0xC5, 0x2F, 0xF1, 0xA1, 0xCA, 0x44, 0x98,
0x3B, 0x6F, 0xE7, 0xFB, 0x16, 0x78, 0x0B, 0x45, 0x5B, 0xFF, 0x24, 0x42, 0x15, 0x2C, 0x75,
0x14, 0x5F, 0xC0, 0xB1, 0x97, 0x64, 0xAB, 0x41, 0x46, 0xD3, 0x30, 0x9D, 0x93, 0x7F, 0xA9,
0x55, 0x51, 0x2B, 0x1A, 0x4A, 0x9C, 0xB4, 0xE8, 0xD7, 0x73, 0xC1, 0x9E, 0xDA, 0xE9, 0x91,
0x2E, 0x09, 0x9A, 0x7A, 0x01, 0xFC, 0xF2, 0x6C, 0xD2, 0x47, 0x90, 0xA0, 0xBC, 0x71, 0xEE,
0xA5, 0xF7, 0xCF, 0x1D, 0x32, 0xD6, 0x5C, 0x13, 0x4B, 0x0D, 0x65, 0xDC, 0x86, 0xAA, 0x63,
0xB3, 0x50, 0x1C, 0xB0, 0x07, 0x4D, 0x76, 0xBA, 0x7B, 0xC8, 0x80, 0x67, 0x81, 0x3E, 0x99,
0x7E, 0x54, 0x8B, 0xB2, 0x06, 0x8D, 0x29, 0xA8, 0x43, 0x82, 0x5E, 0x8A, 0xE6, 0x9B, 0x68,
    0x3A, 0xD8, 0xFE, 0x1E, 0x6B, 0xDF, 0xA7, 0x22, 0x66, 0x0A, 0x37, 0x74, 0x58, 0x48, 0x83,
0x31, 0x7D, 0x39, 0xBB, 0xD9, 0x4C, 0xF0, 0x0E, 0x3D, 0x26, 0xA6, 0xC7, 0xE1, 0xB7, 0x89,
    0x34, 0x8E, 0xB5, 0x23, 0x4E, 0x8C, 0x92, 0xF6, 0xC6, 0x0F, 0x02, 0x9F, 0x11, 0x57, 0xE3,
0x95, 0x28, 0x18, 0x2A, 0xD0, 0xF5, 0xCD, 0x0C, 0xBE, 0xFD, 0xF9, 0x40, 0x35, 0x84, 0x10, 0xA4
};



void dec1(_BYTE *result, int *a2);
void dec2(_BYTE *result);
void dec3(_BYTE *result);
void enc1(_BYTE *result, int *a2);
void enc2(_BYTE *result);
void sub_162C(unsigned __int8 *result);
void enc3(_BYTE *result);



int main() {
int i;
FILE* in;
FILE* out;
char *v3;  //读取的数据 
_BYTE *v2; //加密后数据 
char *v27; 
size_t Rsize;
size_t RsizeNew;
int *v30;
int *v9; // [esp+34h] [ebp-24h]

_BYTE *v36 = (_BYTE *)malloc(sizeof(_BYTE) * 16);
v9 = (int *)malloc(0x180u);
    for ( i = 0; i <= 383; ++i )
      *((_BYTE *)v9 + i) = *(_BYTE *)(i % 32 + key) ^ i;
in = fopen("1.bmp.lock", "rb");
if(in){
out = fopen("1.bmp","wb");
if(out){
v3 = (char *)malloc(256); //分配空间 
v2 = (uint8 *)malloc(256);
for(i = 0; ; ++i ){
char v24 = *(_BYTE *)(key + (i & 0x1F));
Rsize = fread(v3, 1, v24 , in);
//printf("%d|%d\n",key [i % 32],Rsize);
if(!Rsize)
goto LABEL_31;
RsizeNew = Rsize;

if (Rsize <= 15){
v27 = &v3[Rsize];
int v28 = 16 - (RsizeNew & 0xF);
if((RsizeNew & 0xF) != 16){
memset(v27, 16 - (Rsize & 0xF), (unsigned __int8)(16 - (Rsize & 0xF)));
v27 = &v3[v28 + RsizeNew];
}
RsizeNew = 16;
*v27 = 0;
}
v30 = (int *)(v9 + 48);
if(!(v24 & 1))
v30 = (int *)v9;
        v36[0] = *v3;                           // 初步打乱,交换顺序
        v36[4] = v3[1];
        v36[8] = v3[2];
        v36[12] = v3[3];
        v36[1] = v3[4];
        v36[5] = v3[5];
        v36[9] = v3[6];
        v36[13] = v3[7];
        v36[2] = v3[8];
        v36[6] = v3[9];
        v36[10] = v3[10];
        v36[14] = v3[11];
        v36[3] = v3[12];
        v36[7] = v3[13];
        v36[11] = v3[14];
        v36[15] = v3[15];

        dec1(v36, v30 + 40);

        dec3(v36);
        dec2(v36);
        dec1(v36, v30 + 36);

dec3(v36);
dec2(v36);
dec1(v36, v30 + 32);

dec3(v36);
dec2(v36);
dec1(v36, v30 + 28);

dec3(v36);
dec2(v36);
dec1(v36, v30 + 24);

dec3(v36);
dec2(v36);
dec1(v36, v30 + 20);

dec3(v36);
dec2(v36);
dec1(v36, v30 + 16);

dec3(v36);
dec2(v36);
dec1(v36, v30 + 12);

dec3(v36);
dec2(v36);
dec1(v36, v30 + 8);

dec3(v36);
dec2(v36);
dec1(v36, v30 + 4);

dec3(v36);
dec2(v36);
dec1(v36, v30);

        *v2 = v36[0];
        v2[1] = v36[4];
        v2[2] = v36[8];
        v2[3] = v36[12];
        v2[4] = v36[1];
        v2[5] = v36[5];
        v2[6] = v36[9];
        v2[7] = v36[13];
        v2[8] = v36[2];
        v2[9] = v36[6];
        v2[10] = v36[10];
        v2[11] = v36[14];
        v2[12] = v36[3];
        v2[13] = v36[7];
        v2[14] = v36[11];
        v2[15] = v36[15];
if(RsizeNew >= 17){  // 16之后的字节按这个加密
int v31 = 16;
_BYTE *v32 = key;
do{
v2[v31] = v3[v31] ^ *(_BYTE *)(v32 + v31 % 32);
++v31;
}while (v31 < RsizeNew);
}
if(fwrite(v2, 1, RsizeNew, out) != RsizeNew)
break;
}

}

} 
LABEL_31:
free(v3);
free(v2);
fclose(in);
fclose(out);
system("pause");
return 0;
}


void  dec1(_BYTE *result, int *a2)
{
  int v2; // r2
  int v3; // r2
  int v4; // r2
  int v5; // r1

  v2 = *a2;
  result[0] ^= (unsigned int)*a2 >> 24; //取高8位 
  result[4] ^= BYTE2(v2);
  result[8] ^= BYTE1(v2);
  result[12] ^= v2;
  v3 = a2[1];
  result[1] ^= HIBYTE(v3);
  result[5] ^= BYTE2(v3);
  result[9] ^= BYTE1(v3);
  result[13] ^= v3;
  v4 = a2[2];
  result[2] ^= HIBYTE(v4);
  result[6] ^= BYTE2(v4);
  result[10] ^= BYTE1(v4);
  result[14] ^= v4;
  v5 = a2[3];
  result[3] ^= HIBYTE(v5);
  result[7] ^= BYTE2(v5);
  result[11] ^= BYTE1(v5);
  result[15] ^= v5;
}
void dec2(_BYTE *result)
{
  for(int i2=0;i2<16;i2++) {
   for(int i=0;i<256;i++){
     if(result[i2]==unk_36E4[i]){
      result[i2]=i;
      break;
   }
   }
  }


}

void dec3(_BYTE *result)
{
  char v1; // r1
  char v2; // r1
  char v3; // r1
  char v4; // r1

  v1 = result[7];
  result[7] = result[6];
  result[6] = result[5];
  result[5] = result[4];
  result[4] = v1;

  v2 = result[8];
  result[8] = result[11];
  result[11] = v2;

  v3 = result[13];
  result[13] = result[14];
  result[14] = result[15];
  result[15] = result[12];
  result[12] = v3;

  v4 = result[10];
  result[10] = result[9];
  result[9] = v4;
  v4=result[0];
  v4=result[1];
}

其中值得一提的是unk_36E4的数据内容在dll中即可找到,而key的数据内容在exe文件中,在调用enc0时传参给dll

调用方式:enc0(待加密图片路径,输出加密文件路径,32字节的key)

此处我采用的方法是编写一个动态库注入到exe中,hook其enc0的调用函数,然后即可得知传入的key的指针地址,再用CheatEngine读取其地址复制出key的内容.

FLAG值:
flag{simp1er_picture_l0cker!}

发表评论:

搜索
标签列表
网站分类
文章归档
站点信息
  • 文章总数:20
  • 页面总数:0
  • 分类总数:4
  • 标签总数:7
  • 评论总数:1
  • 浏览总数:566
控制面板
您好,欢迎到访网站!
  查看权限

Powered By Z-BlogPHP 1.5.2 Zero

Copyright g2uc Rights Reserved.

公告

请把不属于分类中比赛的题目wp发布在essay分类!另外,题解文章请记得在标签里标注题目类型!