题目给出程序 showyourflag
以及用该程序加密后的文件 yourflag
。
可以通过命令行执行:
showyourflag [infile] [outfile]
程序首先对输入文件的内容进行逐字节变换,位于函数 sub_401FC0
。
v8 = ~__ROL1__(v8, 1);
随后实现了一个类似于压缩的算法,位于函数 sub_4023D0
。
函数先对子串开头的三个字节进行哈希,随后在字典中查找之前是否出现过相同的哈希值。
若存在则求出两个子串相同部分长度的最大值,随后将两个子串相差的距离 dis
以及匹配的长度 len
进行编码,并将编码结果存储到输出文件中。
若不存在则直接将子串内容存储到输出文件中。
while ( 1 ) { tri_bytes = *now_ptr & 0xFFFFFF; hash = (0x9E3779B9 * tri_bytes) >> 18; last_pos = dict[hash]; dict[hash] = now_ptr - a1; last_ptr = &a1[last_pos]; dis = now_ptr - last_ptr; if ( (now_ptr - last_ptr) <= 0x1FFF ) { if ( now_ptr >= tail_13 ) goto LABEL_21; v10 = (now_ptr + 1); if ( tri_bytes != (*last_ptr & 0xFFFFFF) ) goto LABEL_10; if ( tail_13 <= v10 ) goto LABEL_21; if ( v9 < now_ptr ) copy_raw(now_ptr - v9, v9, output_); len_d2 = len_prefix(last_ptr + 3, (now_ptr + 3), tail_4); dis_d1 = dis - 1; len_d2_remain = len_d2; // dis <= 0x1FFF for ( hi_dis_d1 = (dis - 1) >> 8; len_d2_remain > 0x106; *(output - 1) = dis - 1 ) { // loop n times *output = hi_dis_d1 - 0x20; // high_byte(dis_d1) - 0x20 // 0xE0 ~ 0xFF len_d2_remain -= 0x106; output += 3; *(output - 2) = 0xFD; // 0xFD } // low_byte(dis_d1) if ( len_d2_remain > 6 ) { // case len_d2 : 7 ~ 0x106 output[2] = dis_d1; output_ = output + 3; *output = hi_dis_d1 - 0x20; // high_byte(dis_d1) - 0x20 // 0xE0 ~ 0xFF output[1] = len_d2_remain - 7; // len_d2 - n * 0x106 - 7 // 0x0 ~ 0xFF } // low_byte(dis_d1) else { output[1] = dis_d1; // case len_d2 : 1 ~ 6 output_ = output + 2; *output = hi_dis_d1 + 0x20 * len_d2_remain;// // high_byte(dis_d1) + 0x20 * len_d2 // 0x20 ~ 0xDF } // low_byte(dis_d1) v22 = (v18 + len_d2); v23 = *v22; now_ptr = (v22 + 2); dict[(0x9E3779B9 * (v23 & 0xFFFFFF)) >> 18] = v22 - a1; v9 = v22 + 2; dict[(0x9E3779B9 * (v23 >> 8)) >> 18] = v22 + 1 - a1; if ( tail_13 <= v22 + 2 ) goto LABEL_21; } else { if ( now_ptr >= tail_13 ) goto LABEL_21; v10 = (now_ptr + 1); LABEL_10: now_ptr = v10; } } LABEL_21: return result;
提取子串相差的距离 dis
以及匹配的长度 len
后还原原串内容即可。
#include <cstdio> #include <cstdlib> int main(){ FILE *pFile, *pFile2; long lSize; unsigned char *buffer,*buffer2; size_t result; pFile = fopen ( "yourflag" , "rb" ); pFile2 = fopen ( "flag.png" , "wb+" ); fseek (pFile , 0 , SEEK_END); lSize = ftell (pFile); rewind (pFile); buffer = (unsigned char*) malloc (sizeof(char)*lSize); buffer2 = (unsigned char*) malloc (sizeof(char)*lSize); result = fread (buffer,1,lSize,pFile); int i=0,dis=0,len,cnt=0; while(i<lSize-2){ printf("%02X ",buffer[i]); if (0<=buffer[i]&&buffer[i]<0x20){ for (int j=1;j<=buffer[i]+1;j++){ buffer2[cnt++]=buffer[i+j]; } i+=buffer[i]+2; dis=0; len=0; } else if (0x20<=buffer[i]&&buffer[i]<0xE0){ len=(buffer[i]&0xE0)/0x20+2; dis=buffer[i+1]+((buffer[i]&0x1F)<<8)+1; i+=2; } else if (0xE0<=buffer[i]&&buffer[i]<0x100){ len=buffer[i+1]+9; dis=((buffer[i]-0xE0)<<8)+buffer[i+2]+1; i+=3; } for (int j=0;j<len;j++){ buffer2[cnt]=buffer2[cnt-dis]; cnt++; } } for (int i=0;i<lSize;i++){ int t=~buffer2[i]; buffer2[i]=((t&0xFE)>>1)+((t&0x01)<<7); } fwrite(buffer2,1,lSize,pFile2); fclose (pFile); fclose (pFile2); free (buffer); return 0; }
运行后得到解密的 flag.png
,内容如下: