- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
在上一期,我主要讲了讲自己对于 隐写分析 、 信息搜集 和 直接附加 的一些浅薄理解,这一期我们继续对隐写分析的学习,开始讲隐写分析最喜欢考的一项—— 图片隐写 ,我们首先学习的是图片隐写中最基础的 PNG 图片隐写。(此文并非教学,我只是在这里记下我的笔记、我的心得、我的体会,请辩证看待、理性思考,不要全都当成真理) 。
图片隐写的方式有很多种。广义上,只要通过某种方式将信息隐藏到图片中而难以通过普通方式发现,就可以称为 图片隐写 。由于我太菜,本系列只对一些常见的图片隐写方式进行简单介绍,其它进阶技巧请大家自行尝试.
一个 PNG 文件格式为:
文件头(89 50 4E 47 0D 0A 1A 0A) + 数据块 + 数据块 + 数据块…… + 文件尾(00 00 00 00 49 45 4E 44 AE 42 60 82)
PNG 定义了两种类型的 数据块 ,一种是称为 关键数据块 ,这是标准的数据块,另一种叫做 辅助数据块 ,这是可选的数据块。关键数据块定义了4个标准数据块,每个 PNG 文件都必须包含它们.
每个数据块都有着统一的结构,由 4 个部分组成:
其中CRC域中的值是对数据块类型码和数据进行计算得到的,CRC具体算法定义在ISO 3309和ITU-T V.42中,其值按CRC码生成多项式进行计算 我们可以用 pngcheck 去查看PNG文件数据块信息。 PS:结构什么的看看就行,最好能掌握,掌握不了也没关系,咱可以做中学 。
第一块是 文件头数据块 ( IHDR ),它由第11——32字节组成(从0开始),包含有 PNG 文件中存储的图像数据的基本信息,数据从第 16字节开始,有13个字节,其前8字节分别用4个字节规定了图片的宽和高(十六进制,以像素为单位).
它存储实际的数据,在数据流中可包含多个 连续顺序 的 图像数据块 。它采用 LZ77 算法的派生算法进行压缩,可以用 zlib 解压缩.
IHDR 的前8字节规定了图片的宽和高,我们可以用十六进位文件编辑器更改它们以使得这张图片显示不完整,从而达到隐藏信息的目的。此时它的图片数据并没有变,在Windows图片查看器中超过规定的图片宽高的部分只是不显示了.
细心的同学会发现在 Kali Linux 中是打不开这张图片的,会提示 IHDR CRC error,这是因为在每个数据块的最后4字节都有CRC(循环冗余检测)用来检测是否有错误和被篡改。聪明的同学自然就想到是不是可以用CRC反推图片原来的宽和高,答案是肯定的,我们可以利用 python 脚本反推图片原宽高,然后用十六进制编辑器打开图片修改图片宽高得到原图片.
#使用 python [脚本文件名] [图片文件名]
import zlib
import struct
import sys
filename = sys.argv[1]
with open(filename, 'rb') as f:
all_b = f.read()
crc32key = int(all_b[29:33].hex(),16)
data = bytearray(all_b[12:29])
n = 4095
for w in range(n):
width = bytearray(struct.pack('>i', w))
for h in range(n):
height = bytearray(struct.pack('>i', h))
for x in range(4):
data[x+4] = width[x]
data[x+8] = height[x]
crc32result = zlib.crc32(data)
if crc32result == crc32key:
print("宽为:",end="")
print(width)
print("高为:",end="")
print(height)
exit(0)
PNG 文件中的图像像数一般是由 RGB 三原色(红绿蓝)组成(有的图片还包含A通道表示透明度),每一种颜色占用8位,取值范围为0x00至0xFF。LSB 隐写就是修改 RGB 颜色分量的最低二进制位(LSB),它修改了每个像数颜色的最低的1 bit,而人类的眼睛不会注意到这前后的变化,这样每个像素可以携带3比特的信息.
如果是要寻找这种 LSB 隐藏痕迹的话,有一个工具 Stegsolve 是个神器,可以来辅助我们进行分析。通过下方的按钮观察每个通道的信息,我们可以捕捉异常点,抓住 LSB 隐写的蛛丝马迹(这玩意儿很难说,一般就是一看就感觉奇怪的n行或n列颜色块),进而利用 Stegsolve --> Analyse --> Data Extract 功能指定通道进行提取.
对于PNG和BMP文件中的 LSB 等常见的隐写方式,我们也可以使用 **zsteg **工具直接进行自动化的识别和提取.
IDAT 块只有当上一个块充满(正常length最大65524)时,才会继续一个新的块。程序读取图像的时候也会在 第一个未满的块停止 (查了下W3C标准,其实是PNG图片在压缩的时候会在最后一个块的标记位标明这是最后一个数据块)。所以如果某一块没有满但后面却还有 IDAT 块则说明后面的块是“假”的.
我们可以用 pngcheck -v [文件名] 去查看PNG文件数据块信息,然后利用 python zlib 解压多余IDAT块的内容,此时注意剔除 长度 、 数据块类型 及末尾的 CRC校验值 .
import zlib
import binascii
IDAT = " ".decode('hex') #双引号中填IDAT数据
result = binascii.hexlify(zlib.decompress(IDAT))
print(result)
找了半天没找齐合适的例题,自己写了一个,大家凑合做 。
例题链接: https://pan.baidu.com/s/15xDrjIPRX06ygRxhPZiA8Q 提取码:6666 。
大家可以自己先尝试一下,一共有 4个flag (有两个flag1,我打错了),如果有困难再去看下面的题解.
日常先打开编辑器看一下,没发现明显问题。枚举一波,先试试 LSB 隐写,打开 Stegsolve ,查看不同轨道,发现在Red/Green/Blue plane 0的上方均有明显隐写痕迹(那一条奇怪的黑白码).
打开 Stegsolve --> Analyse --> Data Extract ,选中那三个有痕迹的轨道,先点 Preview ,确实有PNG文件藏在里面,点击 Sava Bin 保存文件为 1.png。( Stegsolve 具体怎么用可能有缘写~,现在就这样用也差不多) 。
打开 1.png,是个二维码,用 QR Reserch 扫描得到 Flag1.
还剩下3个 flag,把图片扔到 Kali Linux 里,发现图片无法查看,说明 IHDR 被篡改,用上面的脚本 爆破 IHDR 得到宽高.
用 Winhex 打开,找到 IHDR 中的宽高,更改一下(上面的“\x00”代表一个字节,第四个是符号是因为他刚好属于可打印字节,把它打到右边就行),保存,确定更新.
打开图片,看到 flag1(其实是 flag3 ,打错了).
还有两个 flag,我们把更改过的图片扔到 Kali Linux 里,惊奇地发现(真的很惊奇,以前没见过没这种情况)还是没有预览,但是在图片查看器里可以正常显示,在火狐浏览器中无法显示却不报错,用 binwalk 分析一下,有个 zlib 文件,只能说很正常,没啥问题,再用 pngcheck 检查一下,发现异常,第二个 IDAT 块只有9895的长度,在没有满的情况一般来说是不会出现下一个块的,说明最后一个块是“假块”(那个 CRC ERROR 请忽略,只是我出题时懒得算CRC而已,真正做题是不会给你留这个 bug 的).
我们重新用 Winhex 打开图片,搜索“IDAT”找到最后一个 IDAT 块,把里面的数据(只要数据,不要长度位、“IDAT”和那4位 CRC )复制到新文件里(CRC 是我瞎写的,所以上面会报错),保存成1.txt(没错,为了偷懒我压根没压缩成 zlib,你用 binwalk 是分离不出来的).
得到一串奇葩文字,搜索得知这是 与佛论禅加密 .
打开 在线解密工具 ,解密得到 flag4.
最后还剩一个 flag,还记得我们扫出 flag1 的那个二维码吗?我们用 binwalk -e 扫描提取,发现能检测到 zip 尾,但是提取不出来。。。改用 foremost 提取,得到一个 zip 文件,打开看到里面有一个名字乱码的文本文件(无语),打开又是一堆迷惑代码.
这回是符号所以不太好搜索,只能靠经验得知这是 Brainfuck 代码,利用 在线解密工具 “Brainfuck to text”解密得到 flag2.
顺便说一下为什么“我们刚才用 binwalk -e 扫描提取,发现能检测到 zip 尾,但是却提取不出来”,用 WinHex 打开,发现在PNG文件尾与ZIP文件尾之间有“脏东西”,导致 binwalk 找不到文件头提取失败。(说实话,这个地方还能再出个 flag,我上一期说的两个同类型文件 夹在一块也是这种情况,如果你们遇到类似的情况也要注意看一下头尾之间有没有藏信息) 。
补充题: [BUUCTF] Flag (不是很明显,需要仔细看) 。
本期就先说到这里,主要讲了讲隐写分析中的 PNG 图片隐写,写的不太好的地方还请包涵并提出您宝贵的建议,我们下期再见。(顺便说一下,我发现在Winhex 里,“粘贴”是插入,“写入”是覆盖后面的) 。
[1] CTF WIKI: https://ctf-wiki.org/misc/introduction/ 。
[2] GAMERES: https://dev.gameres.com/Program/Visual/Other/PNGFormat.htm 。
[3] W3C 规范: https://www.w3.org/TR/2003/REC-PNG-20031110/ 。
以上内容仅供参考,水平不高,大佬见笑.
作者: CHTXRT 。
出处: https://www.cnblogs.com/chtxrt/ 。
本文使用「 CC BY-ND 4.0 」创作共享协议,转载请在文章明显位置注明作者及出处.
最后此篇关于从0开始学杂项第三期:隐写分析(2)PNG图片隐写的文章就讲到这里了,如果你想了解更多关于从0开始学杂项第三期:隐写分析(2)PNG图片隐写的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在对一款流行游戏 (Minecraft) 进行一些修改,我在地形生成中看到了这些线条, double d4 = 1.0D; d4 *= d4; d4 *= d4; d4 = 1.0D - d4;
如何在没有浮点单元的处理器上执行 float 学运算?例如低端 8 位微 Controller 。 最佳答案 看看这篇文章:http://www.edwardrosten.com/code/fp_te
抱歉这个冗长的标题。我的代码针对没有浮点单元的微 Controller (msp430),但这应该适用于任何类似的 MCU。 如果我将一个大的运行时变量与通常被认为是浮点十进制数 (1.8) 相乘,M
我偶尔会在这个方法中遇到 stackoverflow 异常。 double norm_cdf(const double x) { double k = 1.0/(1.0 + 0.2316419
这是一个让我在过去几个小时里完全困惑的问题...... 我的程序中有一个硬编码的方程式: double s2; s2 = -(0*13)/84+6/42-0/84+24/12+(6*13)/42; 每
我知道 float 学充其量是丑陋的,但我想知道是否有人可以解释以下怪癖。在我测试的大多数编程语言中,将 0.4 添加到 0.2 会产生轻微错误,而 0.4 + 0.1 + 0.1 则不会。 两者计算
随着数据量持续增长,对合格数据专业人员的需求也会增长。具体而言,对SQL流利的专业人士的需求日益增长,而不仅仅是在初级层面。 因此,Stratascratch的创始人Nathan Rosidi以及我觉
当使用 c++ 或 -O0 编译时,以下 -O1 程序给出了数值不同的结果。 #include #include #include #include int main() { std::a
我正在尝试使用 SVG 在 map 上绘制飞行路径。我在 Leaflet 之上使用 d3,但所使用的框架不会对我的问题产生影响 - 这是三 Angular 关系。 http://fiddle.jshe
使用 IEEE754 float (在 JavaScript 中)时,与数学相关的精度损失风险是什么? 10*.1 即整数乘以有理数。 最佳答案 注意:该问题经过编辑,在发布此答案后很长时间添加了“t
我需要为网站 UI 做一些基本的 float 学运算(金钱的加法和乘法)。我知道 Javascript float 由于存储方式的原因并不准确,但我也知道以某种方式,可以获得我所需的准确度。我知道这一
我有一些像下面这样的宏: #define THING_LENGTH (512) #define MAX_COUNT (4096*8) #define MAX_LENGTH ((int32)((floa
我认为这是一个非常基本的问题 - 我正在执行此功能: private double convertMetersToFeet(double meters) { //function converts
我想在不损失太多精度的情况下替换这些函数中的 float 学,因为我没有 FPU。这可能吗?我认为逗号后的 3 个数字就足够了。 inline float smaller_f(float value,
我需要一个类来表示 double vector (在数学意义上)。 我需要的特殊功能: 任意维度 vector (我通常使用 10 - 100,000 维度) 高性能(用于受 CPU 限制的数字代码)
此社区 Wiki 问题的公认答案:What are best practices that you use when writing Objective-C and Cocoa?说 iPhone 不能
This question already has an answer here: Trouble with float on C [duplicate]
以下代码有问题: private const int movementMultiplier = 2; void Test() { XmlNode xnXCoordinate = xd.Sele
大家早上好 我在 float 学方面遇到了一些问题,完全迷失在“.to_f”、“*100”和“.0”中! 我希望有人能帮助我解决我的具体问题,并准确解释他们的解决方案为何有效,以便我下次理解这一点。
我的嵌入式 C 代码在具有单精度 FPU 的 Cortex M4F 上运行。我担心编译器多久将基于软件的 double 学放在诸如 ** float_var1 = 3.0 * int_var / fl
我是一名优秀的程序员,十分优秀!