C#中深度解析BinaryFormatter序列化生成的二进制文件

C#中深度解析BinaryFormatter序列化生成的二进制文件

BinaryFormatter序列化时,对象必须有 可序列化特性[Serializable]

一.新建窗体测试程序BinaryDeepAnalysisDemo,将默认的Form1重命名为FormBinaryDeepAnalysis

二.新建测试类Test

Test.cs源程序如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace BinaryDeepAnalysisDemo
{/// <summary>/// 一定要标记该类是可序列化的/// </summary>[Serializable]public class Test{public byte ByteData { get; set; }public short Int16Data { get; set; }public int Id { get; set; }public long Int64Data { get; set; }public float FloatData { get; set; }public double DoubleData { get; set; }public string TestName { get; set; }}
}

三.新建字典与类相互转化类ConversionUtil:

ConversionUtil.cs源程序如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;namespace BinaryDeepAnalysisDemo
{/// <summary>/// 字典Dictionary与自定义类CustomClass属性之间的转化/// 斯内科 2024-05-10/// </summary>public class ConversionUtil{/// <summary>/// 将一个实体类的属性转化为键值对集合,键为属性名PropertyName,值为对应的值/// </summary>/// <typeparam name="T">一种自定义类,该类必须已实例化</typeparam>/// <param name="obj">实例化后的类对象</param>/// <returns>返回转化后的字典</returns>public static Dictionary<string, object> CustomClassToDictionary<T>(T obj) where T : class, new(){Dictionary<string, object> dict = new Dictionary<string, object>();Type type = typeof(T);PropertyInfo[] propertyInfos = type.GetProperties();for (int i = 0; i < propertyInfos.Length; i++){string key = propertyInfos[i].Name;object val = propertyInfos[i].GetValue(obj);dict.Add(key, val);}return dict;}/// <summary>/// 将字典转化为实例化类,如果类的属性名称在字典中存在该键key,就使用该键对应的值为类的属性key赋值【注意,转化可能因值的类型、范围等不同而导致失败】/// 如果类的属性名称在字典中不存在该键key,则不进行赋值,只是按属性对应类型的默认值处理/// </summary>/// <typeparam name="T">要转化的目标类型</typeparam>/// <param name="dict">键值对字典</param>/// <returns>要获取的目标实例化类对象,如果字典为空,则按类的默认值处理</returns>public static T DictionaryToCustomClass<T>(Dictionary<string, object> dict) where T : class{T obj = default(T);if (dict == null || dict.Count == 0){return obj;}Type type = typeof(T);obj = (T)Activator.CreateInstance(type);PropertyInfo[] propertyInfos = type.GetProperties();for (int i = 0; i < propertyInfos.Length; i++){string key = propertyInfos[i].Name;if (dict.ContainsKey(key)){propertyInfos[i].SetValue(obj, dict[key]);}}return obj;}}
}

四.测试窗体设计器相关代码如下

文件FormBinaryDeepAnalysis.Designer.cs


namespace BinaryDeepAnalysisDemo
{partial class FormBinaryDeepAnalysis{/// <summary>/// 必需的设计器变量。/// </summary>private System.ComponentModel.IContainer components = null;/// <summary>/// 清理所有正在使用的资源。/// </summary>/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>protected override void Dispose(bool disposing){if (disposing && (components != null)){components.Dispose();}base.Dispose(disposing);}#region Windows 窗体设计器生成的代码/// <summary>/// 设计器支持所需的方法 - 不要修改/// 使用代码编辑器修改此方法的内容。/// </summary>private void InitializeComponent(){this.panel1 = new System.Windows.Forms.Panel();this.rtxtMessage = new System.Windows.Forms.RichTextBox();this.btnSerial = new System.Windows.Forms.Button();this.btnDeserial = new System.Windows.Forms.Button();this.SuspendLayout();// // panel1// this.panel1.Location = new System.Drawing.Point(12, 12);this.panel1.Name = "panel1";this.panel1.Size = new System.Drawing.Size(300, 532);this.panel1.TabIndex = 0;// // rtxtMessage// this.rtxtMessage.Location = new System.Drawing.Point(511, 12);this.rtxtMessage.Name = "rtxtMessage";this.rtxtMessage.ReadOnly = true;this.rtxtMessage.Size = new System.Drawing.Size(482, 532);this.rtxtMessage.TabIndex = 1;this.rtxtMessage.Text = "";// // btnSerial// this.btnSerial.Location = new System.Drawing.Point(360, 78);this.btnSerial.Name = "btnSerial";this.btnSerial.Size = new System.Drawing.Size(63, 23);this.btnSerial.TabIndex = 2;this.btnSerial.Text = "序列化";this.btnSerial.UseVisualStyleBackColor = true;this.btnSerial.Click += new System.EventHandler(this.btnSerial_Click);// // btnDeserial// this.btnDeserial.Location = new System.Drawing.Point(360, 155);this.btnDeserial.Name = "btnDeserial";this.btnDeserial.Size = new System.Drawing.Size(63, 23);this.btnDeserial.TabIndex = 3;this.btnDeserial.Text = "反序列化";this.btnDeserial.UseVisualStyleBackColor = true;this.btnDeserial.Click += new System.EventHandler(this.btnDeserial_Click);// // FormBinaryDeepAnalysis// this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;this.ClientSize = new System.Drawing.Size(1001, 556);this.Controls.Add(this.btnDeserial);this.Controls.Add(this.btnSerial);this.Controls.Add(this.rtxtMessage);this.Controls.Add(this.panel1);this.Name = "FormBinaryDeepAnalysis";this.Text = "序列化生成的二进制进行深度解析";this.Load += new System.EventHandler(this.FormBinaryDeepAnalysis_Load);this.ResumeLayout(false);}#endregionprivate System.Windows.Forms.Panel panel1;private System.Windows.Forms.RichTextBox rtxtMessage;private System.Windows.Forms.Button btnSerial;private System.Windows.Forms.Button btnDeserial;}
}

五.窗体FormBinaryDeepAnalysis相关示例代码如下

文件FormBinaryDeepAnalysis.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;namespace BinaryDeepAnalysisDemo
{public partial class FormBinaryDeepAnalysis : Form{public FormBinaryDeepAnalysis(){InitializeComponent();}/// <summary>/// 显示文本/// </summary>/// <param name="contents"></param>private void DisplayMessage(string contents) {if (!IsHandleCreated)return;this.BeginInvoke(new Action(() =>{if (rtxtMessage.TextLength >= 20480) {rtxtMessage.Clear();}rtxtMessage.AppendText($"{contents}\n");rtxtMessage.ScrollToCaret();}));}private void FormBinaryDeepAnalysis_Load(object sender, EventArgs e){Test test = new Test(){ByteData = 234,Int16Data = 23456,Id = 12345678,Int64Data = 9876543210123L,FloatData = 60.25F,DoubleData = -87654321.3125,TestName = "ABC123abc"};Dictionary<string, object> dict = ConversionUtil.CustomClassToDictionary(test);for (int i = 0; i < dict.Count; i++){KeyValuePair<string, object> keyValuePair = dict.ElementAt(i);Label label = new Label();label.Name = $"lbl{keyValuePair.Key}";label.Text = keyValuePair.Key;label.Location = new Point(3, 3 + 30 * i);TextBox textBox = new TextBox();textBox.Name = $"txb{keyValuePair.Key}";textBox.Text = Convert.ToString(keyValuePair.Value);textBox.Location = new Point(100, 3 + 30 * i);textBox.Size = new Size(160, 25);textBox.Tag = keyValuePair.Key;panel1.Controls.AddRange(new Control[] { label, textBox });}}private void btnSerial_Click(object sender, EventArgs e){try{Dictionary<string, object> dict = new Dictionary<string, object>();for (int i = 0; i < panel1.Controls.Count; i++){Control control = panel1.Controls[i];if (control is TextBox){object val = control.Text;switch (Convert.ToString(control.Tag)){case "ByteData":val = byte.Parse(control.Text);break;case "Int16Data":val = short.Parse(control.Text);break;case "Id":val = int.Parse(control.Text);break;case "Int64Data":val = long.Parse(control.Text);break;case "FloatData":val = float.Parse(control.Text);break;case "DoubleData":val = double.Parse(control.Text);break;}dict.Add(Convert.ToString(control.Tag), val);}}Test test = ConversionUtil.DictionaryToCustomClass<Test>(dict);System.Runtime.Serialization.Formatters.Binary.BinaryFormatter binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();string path = $"{AppDomain.CurrentDomain.BaseDirectory}test.bin";using (System.IO.FileStream stream = new System.IO.FileStream(path, System.IO.FileMode.Create)){binaryFormatter.Serialize(stream, test);}byte[] buffer = System.IO.File.ReadAllBytes(path);DisplayMessage($"长度:{buffer.Length}\n字节流:\n{string.Join(",", buffer)}");DisplayMessage("------打印每个属性的字节流编码,以及查找序列化的二进制数据------");SeekData(TypeCode.Byte, "ByteData", test.ByteData, buffer);SeekData(TypeCode.Int16, "Int16Data", test.Int16Data, buffer);SeekData(TypeCode.Int32, "Id", test.Id, buffer);SeekData(TypeCode.Int64, "Int64Data", test.Int64Data, buffer);SeekData(TypeCode.Single, "FloatData", test.FloatData, buffer);SeekData(TypeCode.Double, "DoubleData", test.DoubleData, buffer);SeekData(TypeCode.String, "TestName", test.TestName, buffer);DisplayMessage("------打印可转换为ASCII的字符,如果是看不到的特殊字符,显示源字节------");string ascii = "";for (int i = 0; i < buffer.Length; i++){if (buffer[i] >= 32 && buffer[i] <= 126){ascii += (char)buffer[i];}else{ascii += $"【{buffer[i]}】";}}DisplayMessage(ascii);}catch (Exception ex) {DisplayMessage($"序列化时出现异常:【{ex.Message}】");}}/// <summary>/// 从字节流中查找数据/// </summary>/// <param name="typeCode"></param>/// <param name="propertyName"></param>/// <param name="val"></param>/// <param name="buffer"></param>private void SeekData(TypeCode typeCode, string propertyName, object val, byte[] buffer) {int byteCount = 0;//类型所占用的字节个数byte[] dataBuffer = new byte[0];switch (typeCode){case TypeCode.Byte:byteCount = sizeof(byte);//类型所占用的字节个数dataBuffer = new byte[] { (byte)val };break;case TypeCode.Int16:byteCount = sizeof(short);dataBuffer = BitConverter.GetBytes((short)val);break;case TypeCode.Int32:byteCount = sizeof(int);dataBuffer = BitConverter.GetBytes((int)val);break;case TypeCode.Int64:byteCount = sizeof(long);dataBuffer = BitConverter.GetBytes((long)val);break;case TypeCode.Single:byteCount = sizeof(float);dataBuffer = BitConverter.GetBytes((float)val);break;case TypeCode.Double:byteCount = sizeof(double);dataBuffer = BitConverter.GetBytes((double)val);break;default:dataBuffer = Encoding.ASCII.GetBytes(Convert.ToString(val));byteCount = dataBuffer.Length;break;}DisplayMessage($"{propertyName}属性的值为【{val}】,字节流【{string.Join(",", dataBuffer)}】");List<int> listIndex = new List<int>();for (int i = 0; i < buffer.Length - byteCount; i++){bool[] bArray = new bool[byteCount];for (int cnt = 0; cnt < byteCount; cnt++){bArray[cnt] = buffer[i + cnt] == dataBuffer[cnt];}//查找所有元素是否都为trueif (Array.FindAll(bArray, x => x).Length == byteCount) {listIndex.Add(i);}}DisplayMessage($"\x20\x20\x20【{propertyName}】数据的地址查找到的起始索引有【{string.Join(",", listIndex)}】");}private void btnDeserial_Click(object sender, EventArgs e){Test test = null;string path = $"{AppDomain.CurrentDomain.BaseDirectory}test.bin";System.Runtime.Serialization.Formatters.Binary.BinaryFormatter binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();using (System.IO.FileStream stream = new System.IO.FileStream(path, System.IO.FileMode.Open)){test = binaryFormatter.Deserialize(stream) as Test;}if(test == null) {return;}Dictionary<string, object> dict = ConversionUtil.CustomClassToDictionary(test);for (int i = 0; i < panel1.Controls.Count; i++){Control control = panel1.Controls[i];if (control is TextBox){control.Text = "";switch (Convert.ToString(control.Tag)){case "ByteData":control.Text = Convert.ToString(test.ByteData);break;case "Int16Data":control.Text = Convert.ToString(test.Int16Data);break;case "Id":control.Text = Convert.ToString(test.Id);break;case "Int64Data":control.Text = Convert.ToString(test.Int64Data);break;case "FloatData":control.Text = Convert.ToString(test.FloatData);break;case "DoubleData":control.Text = Convert.ToString(test.DoubleData);break;default:control.Text = test.TestName;break;}}}}}
}

六.窗体运行如图:

我们可以发现 生成的字节码中 含有 程序集和类信息,以及属性名和对应的值

程序集和版本信息

类和属性字段以及相关数据类型信息

<TestName> 这里的TestName就是属性字段,如果需要获取该字段的类型,可以使用System.Reflection反射来获取具体的数据类型

具体数值区域

这里的数据大多都是使用BitConverter.GetBytes(数据值)进行字节流转化

七.BinaryFormatter序列化的不安全性

 如果将二进制文件读取出来,然后篡改指定的字节码,生成新的二进制文件,然后重新读取,结果就会发现数据被篡改了.很多单机游戏的存档文件修改就是这么干的.

这也是不提倡使用BinaryFormatter类进行序列化的原因,可能被劫持篡改二进制文件,因此在最新的net 5.0中会被标记为不安全的和过时的原因

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

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

相关文章

深度学习在医疗影像分析中的应用

引言 随着人工智能技术的快速发展&#xff0c;深度学习在各个领域都展现出了巨大的潜力。特别是在医疗影像分析中&#xff0c;深度学习的应用不仅提高了诊断的准确性&#xff0c;还大大缩短了医生的工作时间&#xff0c;提升了医疗服务的质量。本文将详细介绍深度学习在医疗影像…

计算机领域QPM、TPM分别是什么并发指标,还有其他类似指标吗?

在计算机领域&#xff0c;QPM和TPM是两种不同的并发指标&#xff0c;它们分别用于衡量系统处理请求的能力和吞吐量。 QPM&#xff08;每分钟请求数&#xff09; QPM&#xff08;Query Per Minute&#xff09;表示每分钟系统能够处理的请求数量。它通常用于衡量系统在单位时间…

【安当产品应用案例100集】036-视频监控机房权限管理新突破:安当windows操作系统登录双因素认证解决方案

一、机房管理痛点&#xff1a;权限失控下的数据泄露风险 在智慧城市与数字化转型浪潮下&#xff0c;视频监控系统已成为能源、金融、司法等行业的核心安防设施。然而&#xff0c;传统机房管理模式中&#xff0c;值班人员通过单一密码即可解锁监控画面的操作漏洞&#xff0c;正…

Unity抖音云启动测试:如何用cmd命令行启动exe

相关资料&#xff1a;弹幕云启动&#xff08;原“玩法云启动能力”&#xff09;_直播小玩法_抖音开放平台 1&#xff0c;操作方法 在做云启动的时候&#xff0c;接完发现需要命令行模拟云环境测试启动&#xff0c;所以研究了下。 首先进入cmd命令&#xff0c;CD进入对应包的文件…

< OS 有关 > 利用 google-drive-ocamlfuse 工具,在 Ubuntu 24 系统上 加载 Google DRIVE 网盘

Created by Dave On 8Feb.2025 起因&#xff1a; 想下载 StableDiffusion&#xff0c;清理系统文件时把 i/o 搞到 100%&#xff0c;已经删除到 apt 缓存&#xff0c;还差 89MB&#xff0c;只能另想办法。 在网上找能不能挂在 Google 网盘&#xff0c;百度网盘&#xff0c;或 …

【LITS游戏——暴力DFS+剪枝优化】

题目 代码 #include <bits/stdc.h> using namespace std; using pll pair<int, int>; #define x first #define y second const int N 51; pll d[4][4][4] {{{{0, 0}, {1, 0}, {2, 0}, {2, 1}}, {{0, 0}, {1, 0}, {1, -1}, {1, -2}}, {{0, 0}, {0, 1}, {1, 1},…

Redisson全面解析:从使用方法到工作原理的深度探索

文章目录 写在文章开头详解Redisson基本数据类型基础配置字符串操作列表操作映射集阻塞队列延迟队列更多关于Redisson详解Redisson 中的原子类详解redisson中的发布订阅模型小结参考写在文章开头 Redisson是基于原生redis操作指令上进一步的封装,屏蔽了redis数据结构的实现细…

用Python进行websocket接口测试

这篇文章主要介绍了用Python进行websocket接口测试&#xff0c;帮助大家更好的理解和使用python&#xff0c;感兴趣的朋友可以了解下 我们在做接口测试时&#xff0c;除了常见的http接口&#xff0c;还有一种比较多见&#xff0c;就是socket接口&#xff0c;今天讲解下怎么用P…

【RocketMQ 存储】- 同步刷盘服务 GroupCommitService

文章目录 1. 前言2. 参数3. 队列相关4. 核心逻辑 run4.1 waitForRunning4.2 doCommit4.3 flush 5. 小结 本文章基于 RocketMQ 4.9.3 1. 前言 RocketMQ 存储部分系列文章&#xff1a; 【RocketMQ 存储】- RocketMQ存储类 MappedFile【RocketMQ 存储】- 一文总结 RocketMQ 的存…

基于yolov11的阿尔兹海默症严重程度检测系统python源码+onnx模型+评估指标曲线+精美GUI界面

【算法介绍】 基于YOLOv11的阿尔兹海默症严重程度检测系统是一种创新的医疗辅助工具&#xff0c;旨在通过先进的计算机视觉技术提高阿尔兹海默症的早期诊断和病情监测效率。阿尔兹海默症是一种渐进性的神经退行性疾病&#xff0c;通常表现为认知障碍、记忆丧失和语言障碍等症状…

IDEA编写SpringBoot项目时使用Lombok报错“找不到符号”的原因和解决

目录 概述|背景 报错解析 解决方法 IDEA配置解决 Pom配置插件解决 概述|背景 报错发生背景&#xff1a;在SpringBoot项目中引入Lombok依赖并使用后出现"找不到符号"的问题。 本文讨论在上述背景下发生的报错原因和解决办法&#xff0c;如果仅为了解决BUG不论原…

【异常解决】在idea中提示 hutool 提示 HttpResponse used withoud try-with-resources statement

博主介绍&#xff1a;✌全网粉丝22W&#xff0c;CSDN博客专家、Java领域优质创作者&#xff0c;掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围&#xff1a;SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…

搜维尔科技:提供人形机器人传感器的应用案例分析

视觉传感器 • 家庭服务场景&#xff1a;在家庭清洁机器人中&#xff0c;视觉传感器可以识别家具、障碍物的位置和形状&#xff0c;规划清洁路径&#xff0c;避开桌椅、宠物玩具等。如小米扫地机器人&#xff0c;通过视觉传感器与算法结合&#xff0c;能构建房间地图&#xff…

虹科波形小课堂 | 三分钟掌握车辆相对压缩测试!不拆发动机、不测缸压就能判断故障缸!

不拆发动机、不测缸压&#xff0c;只测个电流也能知道哪个缸压缩有问题&#xff1f;没错&#xff01;做个相对压缩测试&#xff0c;测下起动电流就行&#xff0c;简单又实用&#xff01;今天&#xff0c;从原理到方法&#xff0c;几分钟教会你&#xff01; 我们都知道&#xf…

自然语言处理NLP_[1]-NLP入门

文章目录 1.自然语言处理入门1. 什么是自然语言处理2.自然语言处理的发展简史3 自然语言处理的应用场景1. **机器翻译**2. **文本分类**3. **情感分析**4. **问答系统**5. **文本生成**6. **信息抽取**7. **语音识别与合成**8. **文本摘要**9. **搜索引擎优化**10. **聊天机器人…

无限使用Cursor

原理&#xff1a;运行程序获得15天的免费试用期&#xff0c;重新运行程序重置试用期&#xff0c;实现无限使用。免费的pro账号&#xff0c;一个月有250的高级模型提问次数。 前提&#xff1a;已安装cursor cursor-vip工具&#xff1a;https://cursor.jeter.eu.org?p95d60efe…

LIMO:少即是多的推理

25年2月来自上海交大、SII 和 GAIR 的论文“LIMO: Less is More for Reasoning”。 一个挑战是在大语言模型&#xff08;LLM&#xff09;中的复杂推理。虽然传统观点认为复杂的推理任务需要大量的训练数据&#xff08;通常超过 100,000 个示例&#xff09;&#xff0c;但本文展…

一种基于Leaflet.Legend的图例动态更新方法

目录 前言 一、场景再现 1、需求描述 2、核心方法介绍 3、存在的问题 二、问题解决 1、重复解决办法 2、图例不展示解决办法 3、成果展示 三、总结 前言 在当今数字化时代&#xff0c;地理信息系统&#xff08;GIS&#xff09;技术已经广泛应用于各个领域&#xff0c;…

【AI时代】使用ollama私有化部署deepseek的过程及问题记录

文章目录 说明下载模型通过ollama下载通过modelscope下载 部署open-webui问题记录临时目录空间不足单机多卡部署后台启动 说明 对于DeepSeek的私有化部署&#xff0c;现在网上已经有很全面的资料了&#xff0c;本文主要记录部署以及部署过程中遇到的问题。目前对于这些问题&am…

使用 SDKMAN! 在 Mac(包括 ARM 架构的 M1/M2 芯片)上安装 Java 8

文章目录 1. 安装 SDKMAN!2. 查找可用的 Java 8 版本3. 安装 Java 84. 验证安装5. 切换 Java 版本&#xff08;可选&#xff09;6. 解决 ARM 架构兼容性问题总结 可以使用 SDKMAN! 在 Mac&#xff08;包括 ARM 架构的 M1/M2 芯片&#xff09;上安装 Java 8。SDKMAN! 是一个强大…