这个题目来自上周的BCTF比赛,题目是海报探秘(300),一张png图片中隐藏了KEY,解出KEY,具体报告,
请下载:http://download.csdn.net/detail/l0g1n/7042787
我对217战队的这个题目报告进行了学习,对他的代码进行注释,理解。
我至少学习到了三点:png文件的解压,文件对齐的处理,还有这优雅的代码。分享给大家:
#include <bits/stdc++.h>
#include <zlib.h>
typedef unsigned char Byte;
//把二进制的大小转换为长度
inline unsigned convert_uint(Byte *b)
{
unsigned ret = 0;
for(int i = 0;i < 4; i++)
ret = ret << 8 | b[i];
return ret;
}
Byte chunk_len_buf[4];
Byte chunk_name[4];
Byte chunk_data[8 << 10];
Byte raw_data[8 << 20];
int main(int argc, char *argv[])
{
//原始文件路径
FILE *fin = fopen(argv[1], "r");
//要输出的文件路径
FILE *fout = fopen(argv[2], "w");
//跳过png文件头部分
fseek(fin, 8 + 4 + 4 + 13 + 4, SEEK_CUR);
//zlib中用来解压的模块
z_stream zs;
//清0
memset(&zs, 0, sizeof(zs));
//初始化zs
inflateInit(&zs);
//设置用来保存解压后数据的路径
zs.next_out = raw_data;
//大小
zs.avail_out = sizeof(raw_data);
//读取节的长度
while(fread(chunk_len_buf, 1, 4, fin) == 4)
{
//转换为unsigned
unsigned chunk_len = convert_uint(chunk_len_buf);
//读取每个节的名称
fread(chunk_name, 1, 4, fin);
//读取每一节的数据
fread(chunk_data, 1, chunk_len, fin);
//跳过CRC校验部分
fseek(fin, 4, SEEK_CUR);
//节的名称比较,只解压IDAT节
if(memcmp(chunk_name, "IDAT", 4) == 0)
{
//输入的数据
zs.next_in = chunk_data;
//输入的长度
zs.avail_in = chunk_len;
//执行解压
inflate(&zs, Z_SYNC_FLUSH);
}
}
//解压结束
inflateEnd(&zs);
//这里看了很长时间,查了资料才明白,1003×654是像素点的个数乘以4,转换为bits,最后加654,是因为1003除以4不整除,这里是字节对齐的处理。
unsigned raw_png_len = 1003 * 654 * 4 + 654;
//out_len要生成新文件(被隐藏的数据)的长度,申请的内存空间-剩余可用的内存空间-图片应有的长度
unsigned out_len = sizeof(raw_data) - zs.avail_out - raw_png_len;
//生成数据。
fwrite(raw_data + raw_png_len, 1, out_len, fout);
fclose(fin);
fclose(fout);
return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)