png图片隐写实例之隐藏二维码

news/2024/11/14 18:09:37/文章来源:https://www.cnblogs.com/HelloQLQ/p/18546534
图片隐写技术介绍:
【如何在图片中塞入二维码不被发现】 https://www.bilibili.com/video/BV12R4y1G72d/?share_source=copy_web&vd_source=d944df449598b7e51bbc29cddb033275
png图片格式介绍:
https://www.cnblogs.com/senior-engineer/p/9548347.html
https://zhuanlan.zhihu.com/p/23890809
图片隐写,借助的是图片的每个像素点的RGB值,比如取RGB中的B值,这个值的二级制的最低位是0还是1,在肉眼上看看不出丝毫区别,我们就可以利用这个数据位,我们知道二维码一般都是两种颜色,黑色和白色,黑色的像素点用1表示,白色用0表示,我们就把二维码的每个像素点转换成1和0,在把这些1和0存到承载二维码的本体图片的像素的一个颜色值通道的二进制值的最低位上。这就是大概原理。
如果要从载体图片读取二维码,需要知道二维码的长和宽,以便读取正确的二维码的1和0值,然后在把1和0反转成黑色或白色,就能解析出构成二维码了。所以我们需要把二维码的长和宽写入到载体图片中。
这就需要png格式的图片一定是要符合png的标准,否则在这一步会让图片损坏。要辨别png格式,不能只看文件的扩展名为png,需要看文件的署名是否是png规定的署名。符合png标准的png的文件用二进制编辑器打开,最开始的8个字节一定是:0x89 0x50 0x4e 0x47 0x0d 0x0a 0x1a 0x0a。只有先确认了这样的字节,才能进行接下来的步骤。
我们需要把二维码图片的长和宽的值写入png文件中,借助png的辅助数据块的格式tEXt,可以实现该目的。我们还需要知道一个IEND数据块,它一定是位于png二级制文件的最后,数据格式是固定的{x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82}。知道这些,我们就可以把tExt块写入iEND块之前。为了后续读取这个tExt块,需要把tExt的块的数据区域的最后一个位置写成整个tExt块数组的长度。具体看代码。
这就是我对实现png格式图片隐写二维码的总结。
扩展:处理隐藏二维码,其实还可以把一些数据编码成二级制也是可以隐藏这些信息的。RGB三个通道都可以同时做这样的写值处理。如果二维码不只是两种颜色,而且想要还原的时候保持与原二维码图一致的话,我的思路是,隐写二维码的像素点的颜色值前23位,载体的每个像素的RGB值的最低位按顺序写入二维码的23个二进制,这要求载体图片的长和宽大概是二维码图片的长和宽的8倍甚至更多,思路是一样的,只不过解析的时候,需要做像素之间的对应关系。
全部代码:代码中的路径使用了硬编码,如果需要运行代码,要自己准备图片和改路径名称
    public class PicHide{private Bitmap _map = null;private Bitmap _qrMap = null;private int _w = 0;private int _h = 0;private string _path = string.Empty;private string _qrPath = string.Empty;private int _qw = 0, _qh = 0;public PicHide(string picName, string qrPath){_path = picName;_qrPath = qrPath;_map = new Bitmap(picName);_w = _map.Width;_h = _map.Height;_qrMap = new Bitmap(qrPath);_qw = _qrMap.Width;_qh = _qrMap.Height;if (_qw > _w || _qh > _h){throw new Exception("隐写的二维码长宽必须小于图片本身的长宽");}}public Color GetRGB(int x, int y){var c = _map.GetPixel(x, y);return c;}public void HidePic(){for (int i = 0; i < _w; i++){for (int j = 0; j < _h; j++){if (i < _qw && j < _qh){var rgb = _qrMap.GetPixel(i, j);int cBit = 0;if (rgb.R >= 128 && rgb.B >= 128 && rgb.G >= 128){cBit = 1;}var curColor = _map.GetPixel(i, j);var hideColor = convertRGB(curColor, cBit);setColor(i, j, hideColor);}else{var c = GetRGB(i, j);var nc = convertRGB(c);setColor(i, j, nc);}}}_map.Save("new1.png");_map.Dispose();_qrMap.Dispose();_qrMap = null;_map = null;AddQrCodeWH("new1.png", _qw, _qh);}public int b(int x, int y){return GetRGB(x, y).B;}public static string GetHideQrCode(string path){var str = GetWh(path);var arr = str.Split(",");int w = int.Parse(arr[0].Replace("w=", ""));int h = int.Parse(arr[1].Replace("h=", ""));var map = new Bitmap(path);var qrMap = new Bitmap(w, h);for (int i = 0; i < w; i++){for (int j = 0; j < h; j++){var color = map.GetPixel(i, j);int val = GetqrColorbit(color);if (val == 0){qrMap.SetPixel(i, j, Color.Black);}else{qrMap.SetPixel(i, j, Color.White);}}}map.Dispose();qrMap.Save("newCode.png");qrMap.Dispose();map = null;qrMap = null;return "";}public static string GetWh(string path){var file = File.OpenRead(path);var iEnd = new byte[12] { 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82 };file.Seek(file.Length - iEnd.Length - 5, SeekOrigin.Begin);var allLenArr = new byte[1];file.Read(allLenArr, 0, 1);var allLen = allLenArr[0];file.Seek(file.Length - iEnd.Length - allLen, SeekOrigin.Begin);var lenArr = new byte[4];file.Read(lenArr, 0, 4);file.Seek(4, SeekOrigin.Current);var len = (lenArr[0] << 24) | (lenArr[1] << 16) | (lenArr[2] << 8) | (lenArr[3]);var payload = new byte[len - 1];file.Read(payload, 0, len - 1);var str = System.Text.Encoding.UTF8.GetString(payload);file.Close();file.Dispose();return str;}public int bRemoveLast(int b){var val = 0xFE;return b & val;}public Color convertRGB(Color c){Color removeColor = Color.FromArgb(c.A, c.R, c.G, bRemoveLast(c.B));return removeColor;}public Color convertRGB(Color c, int i){Color hideColor = Color.FromArgb(c.A, c.R, c.G, (bRemoveLast(c.B) | i));return hideColor;}public void setColor(int x, int y, Color c){_map.SetPixel(x, y, c);}public static int GetqrColorbit(Color c){var x = 0x01;return c.B & x;}private uint getCrc32(byte[] inStr){uint[] crc32Table = new uint[256];uint i, j;uint crc;// 生成 CRC32 表for (i = 0; i < 256; i++){crc = i;for (j = 0; j < 8; j++){if ((crc & 1) != 0){crc = (crc >> 1) ^ 0xEDB88320;}else{crc >>= 1;}}crc32Table[i] = crc;}crc = 0xffffffff;for (i = 0; i < inStr.Length; i++){crc = (crc >> 8) ^ crc32Table[(crc & 0xFF) ^ inStr[i]];}crc ^= 0xFFFFFFFF;return crc;}public void AddQrCodeWH(string fileName, int w, int h){var file = File.Open(fileName, FileMode.Open, FileAccess.ReadWrite);string payLoad = $"w={w},h={h}";var payArr = System.Text.Encoding.UTF8.GetBytes(payLoad);var len = payArr.Length + 1;var buf = new byte[12 + payArr.Length + 1];buf[0] = (byte)(len >> 24 & 0xff);buf[1] = (byte)(len >> 16 & 0xff);buf[2] = (byte)(len >> 8 & 0xff);buf[3] = (byte)(len & 0xff);buf[4] = Convert.ToByte('t');buf[5] = Convert.ToByte('E');buf[6] = Convert.ToByte('X');buf[7] = Convert.ToByte('t');for (int j = 0; j < payArr.Length; j++)buf[j + 8] = payArr[j];buf[payArr.Length + 8] = (byte)buf.Length;var crc = this.getCrc32(payArr);buf[len + 8] = (byte)(crc >> 24 & 0xff);buf[len + 9] = (byte)(crc >> 16 & 0xff);buf[len + 10] = (byte)(crc >> 8 & 0xff);buf[len + 11] = (byte)(crc & 0xff);var iEnd = new byte[12] { 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82 };var lenArr = new byte[4];file.Seek(file.Length - iEnd.Length, SeekOrigin.Begin);file.Write(buf, 0, buf.Length);file.Write(iEnd, 0, iEnd.Length);file.Close();file.Dispose();file = null;}//public string testwhInfo()//{//    var file = File.OpenRead(_path);//    var iEnd = new byte[12] { 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82 };//    file.Seek(file.Length - iEnd.Length-5, SeekOrigin.Begin);//    var allLenArr = new byte[1];//    file.Read(allLenArr, 0, 1);//    var allLen = allLenArr[0];//    file.Seek(file.Length - iEnd.Length - allLen, SeekOrigin.Begin);//    var lenArr = new byte[4];//    file.Read(lenArr, 0, 4);//    file.Seek(4, SeekOrigin.Current);//    var len = (lenArr[0] << 24) | (lenArr[1] << 16) | (lenArr[2] << 8) | (lenArr[3]);//    var payload=new byte[len-1];//    file.Read(payload, 0, len-1);//    var str=System.Text.Encoding.UTF8.GetString(payload);//    return str;//}//public void AddQrCodeWH(int w, int h)//{//    var file = File.Open(_path, FileMode.Open, FileAccess.ReadWrite);//    string payLoad = $"w={w},h={h}";//    var payArr = System.Text.Encoding.UTF8.GetBytes(payLoad);//    var len = payArr.Length + 1;//    var buf = new byte[12 + payArr.Length + 1];//    buf[0] = (byte)(len >> 24 & 0xff);//    buf[1] = (byte)(len >> 16 & 0xff);//    buf[2] = (byte)(len >> 8 & 0xff);//    buf[3] = (byte)(len & 0xff);//    buf[4] = Convert.ToByte('t');//    buf[5] = Convert.ToByte('E');//    buf[6] = Convert.ToByte('X');//    buf[7] = Convert.ToByte('t');//    for (int j = 0; j < payArr.Length; j++)//        buf[j + 8] = payArr[j];//    buf[payArr.Length + 8] = (byte)buf.Length;//    var crc = this.getCrc32(payArr);//    buf[len + 8] = (byte)(crc >> 24 & 0xff);//    buf[len + 9] = (byte)(crc >> 16 & 0xff);//    buf[len + 10] = (byte)(crc >> 8 & 0xff);//    buf[len + 11] = (byte)(crc & 0xff);//    var iEnd = new byte[12] { 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82 };//    var lenArr = new byte[4];//    file.Seek(file.Length - iEnd.Length, SeekOrigin.Begin);//    file.Write(buf, 0, buf.Length);//    file.Write(iEnd, 0, iEnd.Length);//    file.Close();//    file.Dispose();//    file = null;//}}
View Code
 internal class Program{static PicHide picHide = null;static void Main(string[] args){Console.WriteLine("Hello, World!");picHide = new PicHide("o.png", "qrCode.png");picHide.HidePic();Console.WriteLine("hiden ok");Thread.Sleep(3000);PicHide.GetHideQrCode("new1.png");}}
调用

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/833526.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Windows环境安装Scrapy

虽然可以使用 pip 在 Windows 上安装 Scrapy,但还是建议用 Anaconda 安装教程 1.创建虚拟环境(可选但推荐) 打开 Anaconda Prompt,执行以下命令: conda create -n scrapy_env python=3.12(这里假设使用 Python 3.12,你可以根据需要选择其他版本)。 2.激活虚拟环境: co…

openssh 漏洞修复 openssl升级 OpenSSH_9.8p1麒麟系统

第一步:准备好要升级的包 下图所示 使用命令:yum install *.rpm或 rpm -ivh *rpm 如果使用 yum install *.rpm 安装不了,在使用 rpm -ivh *rpm 提示已有旧的版本 可以使用 rpm -Uvh *.rpm 可以替换安装,根据不通的系统 有可能安装后会重启不成功, 所以需要使用:sudo sy…

5.7 与 8.0 对相同文件的 LOAD DATA 语句结果不同

5.7 与 8.0 对相同文件的 LOAD DATA 语句结果不同 问题描述 某客户现场支持,由MySQL 5.7.21升级MySQL 8.0.25后,通过LOAD DATA导入文件,当同一会话连续导入不同的编码(UTF8/GB18030)文件时会出现乱码。数据库版本未升级之前,相同的导入操作在MySQL 5.7.21未出现乱码。 问…

用命令行启动 docker 报错:Redirecting to /bin/systemctl start docker.service 解决方法

docker安装成功后,用 sudo service docker start 启动docker报这个错误,看提示应该是需要用systemctl的命令。 使用systemctl start docker命令启动成功了,做下记录。 以下是启动doker常用的几个命令: # 启动 docker:systemctl start docker # 停止 docker:systemctl sto…

CCF - 网易雷火基金项目成果:基于大小模型协同的低资源标注技术|CNCC 2024 演讲实录

在科技蓬勃发展的时代浪潮中,人工智能领域的每一次突破都离不开持续的科研投入和对前沿技术的不懈探索。2023 年,网易伏羲与中国计算机学会(CCF)共同发起了 “CCF - 网易雷火联合基金”,致力于发挥和利用多方资源优势,加强与海内外青年学者的科研合作,促进中国人工智能等…

VisualVM 使用说明

VisualVM 简介:一个轻量级的Java进程监控软件 VisualVM 安装介绍(Mac 使用 brew 安装) ➜ ~ brew uninstall visualvm==> Uninstalling Cask visualvm ==> Backing App VisualVM.app up to /opt/homebrew/Caskroom/visualvm/2.1.10/VisualVM.app ==> Removing App /…

Java方法(四)

设计方法原则:本意为功能块,是实现某个功能语句块的结合,设计方法时保持原子性(一个方法完成一个功能)public class operator {public static void main(String[] args) {int sum = add(1,3);System.out.println(sum);}//加法public static int add(int a,int b){return a…

11.14,python之自动化

python+selenium selenium是一个第三方库,python有很多库; 1、什么是ui自动化? 通过模拟手工操作用户ui页面的方式,用代码去实现自动化操作和验证的行为。 2、ui自动化的优点? (1)解决重复性的功能测试和验证 (2)减少测试人员在回归测试时用例漏测和验证点的漏测 (3)…

快来验 踩CTH !!!

题目 别样的,验个数据验成这使样还怎么玩? 谁跟谁的都不一样

python自动化之selenium

python+selenium selenium是一个第三方库,python有很多库; 1、什么是ui自动化? 通过模拟手工操作用户ui页面的方式,用代码去实现自动化操作和验证的行为。 2、ui自动化的优点? (1)解决重复性的功能测试和验证 (2)减少测试人员在回归测试时用例漏测和验证点的漏测 (3)…

高级语言程序设计第七次个人作业

班级链接:https://edu.cnblogs.com/campus/fzu 作业要求链接:https://edu.cnblogs.com/campus/fzu/2024C/homework/13304 学号:102400130 姓名:杨子旭

GDPC-CSACTF Round2 WP Web篇

先从简单的开始 ezupload题目都把解题方法拍脸上了,随便上网找一个php一句话木马上传后拿webshell软件(我用的是蚁剑antsword)脸上就可以翻服务器了,最后在usr找到flag,比较搞笑的是我第一次出了点问题还以为要提权,经典把题目做难ezcmd 同样是几乎送分题,跟一轮一样直接…