/* 转载请注明出处:http://www.cnblogs.com/Martinium/p/wechall_stegano.html */

  最近迷上了 www.wechall.net 网站,里面都是些与计算机相关的题目挑战。题目又分很多类型,例如:加密与解密、隐写术、网络攻防、趣味编程、数学逻辑等。题目有的简单,有的很难,需要一些知识和技巧。与其他题目挑战的网站不同的是,在其他类似性质的网站注册的用户可以绑定到 WeChall 网站,然后 WeChall 提供排名信息,而且也分得很细,什么按总分全球排名、什么在自己国家的排名、什么解答某种语言网站题目的排名等。可以从解题的人数判断题目的难易程度,有兴趣的朋友可以去注册,解题中也能学到很多知识。国内的学校和公司也有举办网络攻防大赛。与玩 ACM 解题不同的是:ACM 提供给定的输入和输出,中间的黑盒部分需要你来完成,需要提供一种更好更快的算法;这类攻防挑战题目可能需要更多的计算机知识,从一堆垃圾数据中发现有用的信息、越过不同的障碍终于发现答案等。

  注:Steganography 是隐写术,它与 Cryptography (密码术)是不同的。

题目1 stegano1 给了一张彩色的 BMP 图片,让你从中发现答案。

  不管是图片、音频文件,还是二进制文件,首先都可以尝试以文本文件打开,查看是否存在可疑的字符串。文件太大了就不要这么做了,鼠标会转圈好久的。
图片很小,才 102 bytes。将图片文件拖到文本编辑器里,就可以看到答案了。Notepad++ 是 Windows 上最好的文本编辑器,没有之一。体积小巧,功能齐全。
Linux 上用 gedit 打开,或者使用 vim 命令,输入 :%!xxd 切换到二进制模式,答案显而易见。
xxd 是另外一个命令,以十六进制现实内容。再输入 :%!xxd -r 命令执行,切换到原来的摸样(r 是 reverse )。
注意 vim 的 -b 选项,是否以二进制模式打开。图片是二进制文件,所以要加此选项,否则处理会有问题。
还有一个命令 strings,来的更快,直接输出文件中可打印的字符,通常用来显示二进制中的字符串常量。
strings 命令的选项 -n VALUE 或 --bytes=VALUE 选项控制输出连续字符的最短长度,这个的默认值 VALUE 是 4。
还有 -t RADIX 或 --radix=RADIX 选项以后也会用上的,用来显示每个字符串的偏移量。C++ 的 static 字符串变量需要这个偏移量索引字符串。

  你我都是做题的,但是怎么出题呢?破解别人的软件,写一个序列号注册机相对容易。但是如何写一个加壳、混淆的难以破解的程序就有点难度了,毕竟建房子拆房子简单。
我们需要了解一下 BMP 文件格式,BMP 图片很占空间,没有压缩,或者用 RLE (Run-Length Encoding)压缩一下,体积大所以很少在网络上传播。 BITMAPFILEHEADERBITMAPINFOHEADER

    const char* buffer = "put your message here";
FILE *file = fopen(path, "wb");
if (!file)
{
fprintf(stderr, "can't open %s\n", path);
return false;
} BITMAPFILEHEADER file_header;
BITMAPINFOHEADER info_header; file_header.bfType = (WORD)('B'|'M'<<); // Windows BMP file tag
file_header.bfSize = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+len;
file_header.bfReserved1 = ;
file_header.bfReserved2 = ;
file_header.bfOffBits = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER); info_header.biSize = sizeof(BITMAPINFOHEADER);
info_header.biWidth = width;
info_header.biHeight = height;
info_header.biPlanes = ;
info_header.biBitCount = ;
info_header.biCompression = ; // BI_RGB, An uncompressed format.
info_header.biSizeImage = len; // size in bytes. This may be set to zero for BI_RGB bitmaps
info_header.biXPelsPerMeter = ;
info_header.biYPelsPerMeter = ;
info_header.biClrUsed = ;
info_header.biClrImportant = ; fwrite(&file_header, sizeof(file_header), , file);
fwrite(&info_header, sizeof(info_header), , file);
fwrite(buffer, len, , file);
fclose(file);

  这样写,太容易被发现了。我们可以通过对字符串先加密再隐写,或者用循环移位、异或操作增加难度。
  知道 BMP 格式支持颜色索引模式(GIF、PNG 格式也支持),图片里会有一个调色板用来存储使用的颜色值,相当于一个数组存储 RGB 值,然后图片只用数组索引值找到对应的颜色并显示出来,于是你也可以这样隐藏你的信息到图片中。我们用两种颜色作图,在白纸写黑字,存储为索引模式图,于是调色板会有两个值 #000000 和 #FFFFFF,颜色只需一位 0/1 就可以表示黑白颜色了(查表法从24位压缩到1位,这个压缩是可观的,其实还可以用 RLE 行程编码对图片继续无损压缩)。将数组中的 #000000 值篡改成 #FFFFFF,也就是黑色改成白色,其他数据不用动,保存后用再打开图片看发现,字消失了!写一些想说的话,然后把图片发给暗恋对象,对方会说你怎么发了一张空白图片,于是留给对方想象的空间。说了这么多,自己动手尝试一下吧~

题目2 Stegano Attachment 
答案在图片中吗?不,答案在附件(attachment)里。等你做出了这道题,就明白前面一句话的意思。有时候,题目会给出提示容易忽视的信息,而这个可能就是解题的关键。
稍微留心一下图片 http://www.wechall.net/challenge/training/stegano/attachment/attachment.php ,是不是很坏?后缀被人改成 PHP 网页后缀。用文本编辑软件打开,发现一堆乱码。不同文件会有不同的文件头,即不同的 Magic Number,如上面的 BMP 格式图片的 “BM” 标志,PNG 图片有八字节头 “\x89PNG\r\n\x1A\n”,用 Visual Studio 调式 C++ 代码出现很多的“烫烫烫烫”,其实是编译期初始化栈空间为 “\xCC\xCC\xCC\xCC”(0xCC 对应 x86 的 INT 3 中断指令,你应该知道为什么这么做),编译 Java 文件生成的 .class 文件的文件头有 “CAFEBABE”。从 attachment.php 里我们看到了字符 "JFIF",应该就是 JPG 图片了。更好的方法是用 linux 上的 file 命令查看文件类型,文件名后缀随你怎么该。改成 .jpg 后缀后,打开图片后,是电影 Ghostbusters (1984) 的海报,我们追到了这里,电影我没看过,看介绍好像很不错的样子。一边下载一边解题吧~

martin@M2037:~/Desktop$ file attachment.php
attachment.php: JPEG image data, JFIF standard 1.01

我们稍微了解一下 JPEG 格式规范。JPEG 文件以 “\xFF\xD8” 打头,以 “\xFF\xD9” 结尾。JPEG/JFIF 文件会出现 “JFIF” 字符,JPEG/Exif 文件会出现 "Exif" 字符。

jpg 图片采用有损压缩,不支持 alpha 通道。编码时,颜色从 RGB 色彩空间转到 YUV 色彩空间,根据颜色分量的重要性和人眼的感知剔除不重要的信息,缩减采样 4:4:4 4:2:2 4:2:0,接着 分割图片成 8x8 子区域进行离散余弦变换,量化编码,支流系数用差分编码,交流系数用 RLE 编码。

我们发现图片是以 "\xFF\xD8" 开头的,但是结尾却不是 "\xFF\xD9",好像明白了什么。
我们用题目1学到的 strings 命令搜到了可疑字符串 solution.txt 和 solution.txtPK,恰恰是放文件最后的。
PK 字眼熟悉不?最常用的 ZIP 格式压缩文件头的 magic number 是 “PK\x03\x04”,而且文件中确实存在这四个字节。而且这四个字节的前面也恰好是 "\xFF\xD9"。想想之前的题目 attachment。看来,是谁把一个 ZIP 压缩文件追加到一个 JEPG 图像文件的后面了。我们需要提取出 ZIP 文件,答案离我们不远了。。

ZIP 文件的偏移量用题目1学到的 vim :%!xxd 搜索定位查看并计算,或者用 grep 命令搜索下。
我们需要复制从 0004f06 到最后 0004f8d (长度 0x88=136)到新的文件里去。

复制粘贴文件或者段落用 Ctrl+C、Ctrl+V,可是复制二进制文件流呢,也可以这么做吗?好像不行。
Notepad++ 不愧是最好用最实用的文本编辑器,选择菜单 Edit -> Paste Special,二级菜单中出现了 Copy|Cut|Paste Binary Cotent,接下来你知道怎么做啦~
或者使用 linux 的 dd 命令,还记得大学初学 linux 操作系统时,让记那么多命令和参数干嘛,现在就派上用场了。
如果你不嫌麻烦,甚至可以自己编写小段 C/C++ 代码,打开文件、复制文件、关闭文件。

martin@M2037:~/Desktop$ printf "%d\n" 0x0004f06
20230
martin@M2037:~/Desktop$ dd if=attachment.jpg of=solution.zip skip=20230 bs=1 count=136
136+0 records in
136+0 records out
136 bytes (136 B) copied, 0.0021692 s, 62.7 kB/s

martin@M2037:~/Desktop$ unzip solution.zip
Archive: solution.zip
inflating: solution.txt

打开 solution.txt 文件,就是最终的答案了。

从中,我们学习了另外一种隐藏文件的方法,将一个文件附属到另外一个文件末尾,打开的时候只解析第一个文件,附属文件被忽略了。
将信息 message.txt 隐藏到图片 carrier.jpg 中(注意命令行中的先后顺序):
linux 终端下, cat carrier.jpg message >> mixed.jpg
Windows 控制台下,copy carrier.jpg /b + message.txt /a mixed.jpg
cat 是 concatenate 的简写,如果有多个序列文件(比如 file1.txt file2.txt file3.txt)合并,可以优雅地写成 cat file{1,2,3}.txt >> new.txt
/A /B 分别代表文本文件和二进制文件,详情请查看 copy /? 命令。

题3 LSB - The least significant bit

  WeChall 网站使用了 cookie 和 session 来产生动态的答案,所以不同的人在每一次登录时,答案是不同的。我在这里贴出我的答案,你复制过去一般就是错误的答案,这样可以提防不动脑子只粘贴答案的人。
这道题目有链接提示,链接的颜色是 #EEE,接近背景色白色 #FFF,还是很明显看得出来的,看来作者没有有意隐藏这一提示。家里网没能打开这个链接,原因还没查出,公司网可以打开。steganabara 原来是一个 .jar 包,下载 steganabara.jar 文件并运行程序 java -jar steganabara-1.1.1.jar ,将隐藏信息的图片拖进来。似乎是很正常的一张图片,LED 数码管显示了作者的大名 Gizmore。查了一下,gizmor 英文是小发明的意思。当然,这只是作者创作题目的署名,与解题没有任何关系。解题偶尔能有额外的收获。

  这张图片是 RGB 格式,没有 alpha 通道,随便勾选 RGB 某一通道的某一位,共有 3*8=24 种单项选择(复合选择暂未考虑进来,从简单到复杂嘛~)。点击菜单 Filter -> Bit Mask,从低位到高位一个一个勾选盲试的话,很容易试出答案来。思路是这样的,你的答案不一定是这样的。注意勾上 Amplify 选项,否则很难辨认。
  借助事实分析和判断,点击菜单 Analyse -> Histogram 给出 RGB 各分量的柱状图,范围是 0~255,有 3 个连续分布图和 1 个离散分布(斑马带)图,可以怀疑出是哪个通道有问题。相邻柱子的间距是周期,可以推断出是哪个比特位被篡改,导致出现重复的模式。

  LSB (least significant bit) 最低有效位,权重最小的位,也是修改最不容易引起注意的位;与之对应的是 MSB (most significant bit) 最高有效位,修改后很容易被察觉。上面之所以需要增强信号(Amplify) 就是因为隐藏的信息在 LSB 上不易被发觉。这个是图片与图片的操作,我想到了一种字符串与图片混合的办法。
  将字符串信息(也就是需要隐藏的信息 ASCII 码值)拆开成比特位,分别藏在图像中的连续像素中的最低位。思路是读取承载信息的图片,然后把需要隐藏的信息以比特流的形式连续覆盖图片 RGB 值的最低位,为了进一步增加难度,可以只覆盖其中某一个分量,可以不用放最低位,如果比特位用完了,信息可以从头循环再覆盖,直到覆盖所有。例如此题采用的是 Blue 通道的第 4 位。

#include <stddef.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h> #include "libpng16/png.h" int main()
{
png_image image; memset(&image, , sizeof image);
image.version = PNG_IMAGE_VERSION;
image.format = PNG_FORMAT_RGB; // no alpha channel const char* message = "No 300 taels of silver buried here.";
const int BITS = strlen(message) * CHAR_BIT; const char* original = "g2YMC634NSqoEhXe.png";
const char* stegano = "stegano.png";
if(png_image_begin_read_from_file(&image, original))
{
size_t size = PNG_IMAGE_SIZE(image);
png_bytep buffer = (png_bytep)malloc(size);
if(buffer != NULL)
{
// blend text bits to image's least significant bit
int bit = ;
for(size_t i = ; i < size; ++i)
{
char test = (original[bit/] & (<<(bit%))) ?:;
buffer[i] = (buffer[i]&0xFE) | test; ++bit;
if(bit >= BITS)
bit = ; // repeat message
} if(png_image_finish_read(&image, NULL/*background*/, buffer,
/*row_stride*/, NULL/*colormap for PNG_FORMAT_FLAG_COLORMAP*/))
{
if(png_image_write_to_file(&image, stegano, /*convert_to_8bit*/,
buffer, /*row_stride*/, NULL/*no colormap*/))
fprintf(stdout, "write to file %s successfully.\n", stegano);
else
fprintf(stderr, "write %s: %s\n", stegano, image.message); free(buffer);
}
else
{
fprintf(stderr, "read %s: %s\n", original, image.message); /* This is the only place where a 'free' is required; libpng does
* the cleanup on error and success, but in this case we couldn't
* complete the read because of running out of memory.
*/
png_image_free(&image);
}
}
else
fprintf(stderr, "out of memory: %lu bytes\n",
(unsigned long)PNG_IMAGE_SIZE(image));
}
else
fprintf(stderr, "%s: %s\n", original, image.message); return ;
}

lsb.cpp

to be continued...

wechall.net/stegano 解题心得的更多相关文章

  1. leetcode网解题心得——61. 旋转链表

    目录 leetcode网解题心得--61. 旋转链表 1.题目描述 2.算法分析: 3.用自然语言描述该算法 4.java语言实现 5.C语言实现 leetcode网解题心得--61. 旋转链表 1. ...

  2. Zerojudge解题心得

    我进入娄山中学已经有1年多了,也就是说我学习编程也有1年多了,在这一年多的时间中,我已经对编程有了初步的了解.其实只要抓住平时的空闲时间加以利用,哪怕每个星期就做那么三四题,经过了一段时间沉淀,也会有 ...

  3. 我的ZJ解题心得

    想要学好程序设计第一是要养成你的编程思维,也就是你对编程的一种概念和思维定式,长期的解题会让你产生解题经验进而形成一种思维定式,比如看到一个题目就立即想出这题要用什么方法解题这样.编程思维我认为还包括 ...

  4. POJ1159解题心得

    题目:http://poj.org/problem?id=1159 刚开始,从样例的特征去思考.总让我从回文数的角度去思考,想出几个方案,可都用了数据去检验,发现不行.如:ABCDDCB,BACDCA ...

  5. 树状数组:CDOJ1583-曜酱的心意(树状数组心得)

    曜酱的心意 Time Limit: 3000/1000MS (Java/Others) Memory Limit: 131072/131072KB (Java/Others) Description ...

  6. 题目1203:IP地址

    题目: http://ac.jobdu.com/problem.php?pid=1203 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:3052 解决:1504 题目描述: 输入一个ip地 ...

  7. HDU 2602 Bone Collector WA谁来帮忙找找错

    Problem Description Many years ago , in Teddy’s hometown there was a man who was called “Bone Collec ...

  8. 2106 Problem F Shuffling Along 中石油-未提交-->已提交

    题目描述 Most of you have played card games (and if you haven’t, why not???) in which the deck of cards ...

  9. 2101 Problem A Snake Filled

    题目描述 “What a boring world!”Julyed felt so bored that she began to write numbers on the coordinate pa ...

随机推荐

  1. Fiddler 抓包工具总结

    阅读目录 1. Fiddler 抓包简介 1). 字段说明 2). Statistics 请求的性能数据分析 3). Inspectors 查看数据内容 4). AutoResponder 允许拦截制 ...

  2. 【BZOJ-3643】Phi的反函数 数论 + 搜索

    3643: Phi的反函数 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 141  Solved: 96[Submit][Status][Discuss ...

  3. MapReduce实现手机上网日志分析(排序)

    一.背景 1.1 流程 实现排序,分组拍上一篇通过Partitioner实现了. 实现接口,自动产生接口方法,写属性,产生getter和setter,序列化和反序列化属性,写比较方法,重写toStri ...

  4. 使用 zssh 进行 Zmodem 文件传输

    Zmodem 最早是设计用来在串行连接(uart.rs232.rs485)上进行数据传输的,比如,在 minicom 下,我们就可以方便的用 Zmodem (说 sz .rz 可能大家更熟悉)传输文件 ...

  5. php 月初,月末时间大统计

    //PHP获取指定月份的月初月尾时间 //获取上月月初月尾时间: $startday=strtotime(date("Y-m-d H:i:s",mktime(0,0,0,date( ...

  6. TAC Alpha版本 冲冲冲!!!

    第1天 第2天 第3天 第4天 第5天 第6天 第7天 第8天 第9天 第10天 测试随笔 冲刺总结

  7. 【Alpha版本】十天冲刺——日志集合贴

    No Bug 031402401鲍亮 031402402曹鑫杰 031402403常松 031402412林淋 031402418汪培侨 031402426许秋鑫 Day1 Day2 Day3 Day ...

  8. C#中精确计时的一点收获 【转】

    C#中精确计时的一点收获 [转] 以下所有代码运行环境:Windows 2003, Intel(R) Core(TM) 2 Duo CPU E8400 @  3.00GHz 2.99GHz,2.96G ...

  9. 大熊君JavaScript插件化开发------(实战篇之DXJ UI ------ ProcessBar)

    一,开篇分析 Hi,大家好!大熊君又和大家见面了,还记得前两篇文章吗.主要讲述了以“jQuery的方式如何开发插件”,以及过程化设计与面向对象思想设计相结合的方式是 如何设计一个插件的,两种方式各有利 ...

  10. vijos1404 遭遇战

    描述 今天,他们在打一张叫DUSTII的地图,万恶的恐怖分子要炸掉藏在A区的SQC论坛服务器!我们SQC的人誓死不屈,即将于恐怖分子展开激战,准备让一个人守着A区,这样恐怖分子就不能炸掉服务器了.(一 ...