<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
<title><![CDATA[木子屋 - Win编程]]></title>
<link>http://www.mzwu.com/</link>
<description><![CDATA[Dnawo&#39;s BLOG]]></description>
<language>zh-cn</language>
<copyright><![CDATA[Copyright 2005 PBlog3 v2.8]]></copyright>
<webMaster><![CDATA[service@mzwu.com(Dnawo)]]></webMaster>
<generator>PBlog2 v2.4</generator> 
<image>
	<title>木子屋</title>
	<url>http://www.mzwu.com/images/logos.gif</url>
	<link>http://www.mzwu.com/</link>
	<description>木子屋</description>
</image>

			<item>
			<link>http://www.mzwu.com/article.asp?id=5209</link>
			<title><![CDATA[豆包和千问等大模型客户端删除聊天记录对上下文影响测试]]></title>
			<author>service@mzwu.com(dnawo)</author>
			<category><![CDATA[Win编程]]></category>
			<pubDate>Fri,10 Apr 2026 01:07:53 +0800</pubDate>
			<guid>http://www.mzwu.com/default.asp?id=5209</guid>
		<description><![CDATA[今天忽然萌生一个疑问：在豆包、千问等大模型客户端的对话中，删除部分聊天记录后，这些内容是否仍会被纳入上下文？于是当即动手，对多款 APP 进行了实测。<br/><div class="UBBPanel quotePanel"><div class="UBBTitle"><img src="http://www.mzwu.com/images/quote.gif" style="margin:0px 2px -3px 0px" alt="引用内容"/> 引用内容</div><div class="UBBContent"><i>【测试步骤】：先问1+1等于多少？再问2+2等于多少？然后查看当前对话上下文，接着删除2+2等于多少的聊天记录，再次查看当前对话上下文。</i></div></div><br/><strong>一、豆包APP</strong><br/><br/><img width="640" height="710" src="http://www.mzwu.com/pic/202604/015.jpg" border="0" alt=""/><br/><br/><i>Tips：豆包官方助手和智能体有个开启新话题功能，它不会删除当前对话聊天记录，但上下文会被清空，这和创建新对话不同。</i><br/><br/><strong>二、千问APP</strong><br/><br/><img width="640" height="710" src="http://www.mzwu.com/pic/202604/017.jpg" border="0" alt=""/><br/><br/><strong>结论</strong>：DeepSeek、Kimi、智谱清言和讯飞星火不支持删除聊天记录，豆包和千问删除部分聊天记录时，这些记录在上下文中也会同步删除。]]></description>
		</item>
		
			<item>
			<link>http://www.mzwu.com/article.asp?id=5205</link>
			<title><![CDATA[SQLite 时区坑：datetime (&#39;now&#39;) UTC 时差引发的数据查询 BUG 修复]]></title>
			<author>service@mzwu.com(dnawo)</author>
			<category><![CDATA[Win编程]]></category>
			<pubDate>Fri,03 Apr 2026 21:26:37 +0800</pubDate>
			<guid>http://www.mzwu.com/default.asp?id=5205</guid>
		<description><![CDATA[豆包帮忙写了一段C#代码，功能是查询SQLite最近两小时的数据，代码如下：<br/><br/><img src="http://www.mzwu.com/pic/202604/004.jpg" border="0" alt=""/><br/><br/>当前21点，却搜出了上午11点的数据，10个小时，将SQL语句复制到数据库中执行：<br/><br/><img src="http://www.mzwu.com/pic/202604/005.jpg" border="0" alt=""/><br/><br/>也是一样的，那么问题可能在datetime(&#39;now&#39;)上了，单独执行看下：<br/><br/><img src="http://www.mzwu.com/pic/202604/006.jpg" border="0" alt=""/><br/><br/>果然，datetime(&#39;now&#39;)是UTC时间，跟北京时间差了八个小时，改下SQL语句，问题解决：<br/><br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code2613);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.mzwu.com/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code2613><i>Sel&#101;ct id, price, cr&#101;ate_time <br/>&nbsp;&nbsp;&nbsp;&nbsp;FROM tablename<br/>&nbsp;&nbsp;&nbsp;&nbsp;Wh&#101;re cr&#101;ate_time &gt;= datetime(&#39;now&#39;, <span style="color:red">&#39;localtime&#39;,</span> &#39;-2 hours&#39;) <br/>&nbsp;&nbsp;&nbsp;&nbsp;o&#114;DER BY cr&#101;ate_time ASC</i></div></div>]]></description>
		</item>
		
			<item>
			<link>http://www.mzwu.com/article.asp?id=5023</link>
			<title><![CDATA[C#声明List和Dictionary直接初始化示例]]></title>
			<author>service@mzwu.com(dnawo)</author>
			<category><![CDATA[Win编程]]></category>
			<pubDate>Fri,09 Dec 2022 10:36:03 +0800</pubDate>
			<guid>http://www.mzwu.com/default.asp?id=5023</guid>
		<description><![CDATA[<img src="http://www.mzwu.com/pic/202212/006.jpg" border="0" alt=""/><br/><br/><strong>1、List直接初始化示例</strong><br/><br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code94327);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.mzwu.com/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code94327>List&lt;string&gt; lst = new List&lt;string&gt;() { &#34;www&#34;, &#34;mzwu&#34;, &#34;com&#34; };<br/>Console.WriteLine(lst[0]);</div></div><br/><strong>2、Dictionary直接初始化示例</strong><br/><br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code72301);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.mzwu.com/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code72301>Dictionary&lt;string, string&gt; dit = new Dictionary&lt;string, string&gt;() { { &#34;name&#34;, &#34;Jack&#34; }, { &#34;age&#34;, &#34;30&#34; } };<br/>Console.WriteLine(dit[&#34;name&#34;]);</div></div>]]></description>
		</item>
		
			<item>
			<link>http://www.mzwu.com/article.asp?id=4758</link>
			<title><![CDATA[锟斤拷等常见文本乱码产生原因对照表]]></title>
			<author>service@mzwu.com(dnawo)</author>
			<category><![CDATA[Win编程]]></category>
			<pubDate>Sun,07 Feb 2021 10:53:44 +0800</pubDate>
			<guid>http://www.mzwu.com/default.asp?id=4758</guid>
		<description><![CDATA[<img width="630" height="555" src="http://www.mzwu.com/pic/202102/002.jpg" border="0" alt=""/>]]></description>
		</item>
		
			<item>
			<link>http://www.mzwu.com/article.asp?id=4729</link>
			<title><![CDATA[C#将图片音频等文件转成Base64字符串示例]]></title>
			<author>service@mzwu.com(dnawo)</author>
			<category><![CDATA[Win编程]]></category>
			<pubDate>Sat,31 Oct 2020 12:24:12 +0800</pubDate>
			<guid>http://www.mzwu.com/default.asp?id=4729</guid>
		<description><![CDATA[<div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code18053);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.mzwu.com/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code18053>class Program<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;static void Main(string[] args)<br/>&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.Write(&#34;文件地址：&#34;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string file = Console.ReadLine();<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine(&#34;转换结果：{0}&#34;, FileToBase64String(file));<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.ReadLine();<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;static string FileToBase64String(string file)<br/>&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string result = string.Empty;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;using (FileStream stream = new FileStream(file, FileMode.Open))<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;byte[] bt = new byte[stream.Length];<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stream.Read(bt, 0, bt.Length);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result = Convert.ToBase64String(bt);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;catch { }<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return result;<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/>}</div></div><br/><strong>HTML5使用示例</strong><br/><br/>图片：<br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code99491);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.mzwu.com/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code99491>&lt;img src=&#34;data:image/png;base64,转换的Base64字符串&#34;/&gt;</div></div><br/>音频：<br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code81737);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.mzwu.com/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code81737>&lt;audio src=&#34;data:audio/wav;base64,转换的Base64字符串 /&gt;</div></div>]]></description>
		</item>
		
			<item>
			<link>http://www.mzwu.com/article.asp?id=4672</link>
			<title><![CDATA[C#大图片压缩算法]]></title>
			<author>service@mzwu.com(dnawo)</author>
			<category><![CDATA[Win编程]]></category>
			<pubDate>Sat,13 Jun 2020 23:32:43 +0800</pubDate>
			<guid>http://www.mzwu.com/default.asp?id=4672</guid>
		<description><![CDATA[<div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code8440);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.mzwu.com/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code8440>using System.Drawing;<br/>using System.Drawing.Imaging;<br/>using System.IO;<br/><br/>public class ImageHelper<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// GetEncoderInfo<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;/summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;param name=&#34;mimeType&#34;&gt;&lt;/param&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;returns&gt;&lt;/returns&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;private static ImageCodecInfo GetEncoderInfo(string mimeType)<br/>&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ImageCodecInfo[] encoders = ImageCodecInfo.GetImageEncoders();<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (int i = 0; i &lt; encoders.Length; ++i)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (encoders[i].MimeType == mimeType)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return encoders[i];<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return null;<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// 图片压缩(降低质量以减小文件的大小)<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;/summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;param name=&#34;srcBitmap&#34;&gt;传入的Bitmap对象&lt;/param&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;param name=&#34;destStream&#34;&gt;压缩后的Stream对象&lt;/param&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;param name=&#34;level&#34;&gt;压缩等级，0-100&lt;/param&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;private static void Compress(Bitmap srcBitmap, Stream destStream, long level)<br/>&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ImageCodecInfo myImageCodecInfo;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Encoder myEncoder;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;EncoderParameter myEncoderParameter;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;EncoderParameters myEncoderParameters;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Get an ImageCodecInfo object that represents the JPEG codec.<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myImageCodecInfo = GetEncoderInfo(&#34;image/jpeg&#34;);<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Cr&#101;ate an Encoder object based on the GUID<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// for the Quality parameter category.<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myEncoder = Encoder.Quality;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Cr&#101;ate an EncoderParameters object.<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// An EncoderParameters object has an array of EncoderParameter<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// objects. In this case, there is only one<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// EncoderParameter object in the array.<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myEncoderParameters = new EncoderParameters(1);<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Save the bitmap as a JPEG file with 给定的 quality level<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myEncoderParameter = new EncoderParameter(myEncoder, level);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myEncoderParameters.Param[0] = myEncoderParameter;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;srcBitmap.Save(destStream, myImageCodecInfo, myEncoderParameters);<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// 图片压缩(降低质量以减小文件的大小)<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;/summary&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;param name=&#34;srcFile&#34;&gt;&lt;/param&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;param name=&#34;destFile&#34;&gt;&lt;/param&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;/// &lt;param name=&#34;level&#34;&gt;&lt;/param&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;public static void Compress(string srcFile, string destFile, long level)<br/>&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;using (Image image = Image.FromFile(srcFile))<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;using (Bitmap bitmap = new Bitmap(image))<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;using (FileStream destStream = new FileStream(destFile, FileMode.Cr&#101;ate))<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Compress(bitmap, destStream, level);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/>}</div></div><br/>调用示例:<br/><br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code28330);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.mzwu.com/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code28330>ImageHelper.Compress(@&#34;C:\mzwu_com.jpg&#34;, @&#34;C:\mzwu_net.jpg&#34;, 50L);</div></div>]]></description>
		</item>
		
			<item>
			<link>http://www.mzwu.com/article.asp?id=4617</link>
			<title><![CDATA[软件破解与防破解的那些事[转]]]></title>
			<author>service@mzwu.com(dnawo)</author>
			<category><![CDATA[Win编程]]></category>
			<pubDate>Sat,18 Apr 2020 13:46:38 +0800</pubDate>
			<guid>http://www.mzwu.com/default.asp?id=4617</guid>
		<description><![CDATA[首先我们要明确一点:<br/><br/><strong>理论上不存在无法破解的软件，但也并不是说破解软件比开发容易一万倍，<br/>防破解的目的不是要做一个无法破解的软件，而是让破解软件的成本远大于购买软件的成本！</strong><br/><br/>现在笔者简略表演几个有代表性的软件破解，当然，要看懂下面的内容，需要一点点C语言的编程基础。<br/><br/>我们先来一个最最简单的软件破解，假设我们写了一个软件，它的注册手段代码如下：<br/><br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code76523);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.mzwu.com/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code76523>#include &#34;stdio.h&#34;<br/>#include &#34;string.h&#34;<br/>int main()<br/>{<br/>&#160;&#160;&#160;&#160;char Key[32];<br/>&#160;&#160;&#160;&#160;printf(&#34;请输入注册码:&#34;);<br/>&#160;&#160;&#160;&#160;gets(Key);<br/>&#160;&#160;&#160;&#160;if (strcmp(Key,&#34;abc123456&#34;)==0)<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;printf(&#34;注册成功&#34;);<br/>&#160;&#160;&#160;&#160;else<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;printf(&#34;注册失败&#34;);<br/>}</div></div><br/>把他编译成exe，运行一下<br/><br/><img width="630" height="500" src="http://www.mzwu.com/pic/202004/126.gif" border="0" alt=""/><br/><br/>要破解怎么办呢?超简单的，你把这个程序后缀改成txt然后打开，搜索注册码。然后翻一翻key就找到了：<br/><br/><img width="630" height="500" src="http://www.mzwu.com/pic/202004/127.gif" border="0" alt=""/><br/><br/>别笑，就算是今天，仍然有一大堆软件采用这种软件保护机制，不过这类软件要不大多不怎么值钱比如xx管理系统，计算器之类的，要不就是软件作者别有用心防君子不防小人。你可能会问了，问题出在那了呢，这类保护机制的问题是，目前大部分的编译器都会将字符串常量直接存储在可执行文件结构中，所以你要是硬编码key，那么上面这种破解方法几乎是屡试不爽甚至不需要什么逆向破解知识就能搞定。<br/><br/>那么，让我们进入防破解V2.0时代，为了与时俱进，我们稍微把上面的代码改一下：<br/><br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code75859);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.mzwu.com/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code75859>#include &#34;stdio.h&#34;<br/>#include &#34;string.h&#34;<br/>#include &#34;windows.h&#34;<br/>#include &#34;math.h&#34;<br/><br/>int main()<br/>{<br/>&#160;&#160;&#160;&#160;char iKey[32];<br/>&#160;&#160;&#160;&#160;char Key[32];<br/>&#160;&#160;&#160;&#160;char ID[32];<br/>&#160;&#160;&#160;&#160;int iID=0xabc1d3f;<br/>&#160;&#160;&#160;&#160;sprintf(Key,&#34;%x&#34;,iID*8+123456);<br/>&#160;&#160;&#160;&#160;printf(&#34;你的机器码是%x\n&#34;,iID);<br/>&#160;&#160;&#160;&#160;printf(&#34;请输入注册码:&#34;);<br/>&#160;&#160;&#160;&#160;gets(iKey);<br/>&#160;&#160;&#160;&#160;if (strcmp(Key,iKey)==0)<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;MessageBoxA(0,&#34;注册成功&#34;,&#34;&#34;,MB_OK);<br/>&#160;&#160;&#160;&#160;else<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;MessageBoxA(0,&#34;注册失败&#34;,&#34;&#34;,MB_OK);<br/>}</div></div><br/><img src="http://www.mzwu.com/pic/202004/128.jpg" border="0" alt=""/><br/><br/>现在&#34;TXT&#34;破解法已经不顶用了，你看，key找不到了：<br/><br/><img src="http://www.mzwu.com/pic/202004/129.jpg" border="0" alt=""/><br/><br/>怎么样，这种保护手段是不是熟悉的味道熟悉的配方，这个机器码可以从网卡MAC，CPU型号，内存大小等等等等去生成，当然，key的算法也可以拉上MD5，SHA等等等等手段来弄而不是简简单单的乘一个8再加上123456，总之从机器码到注册码的算法你能玩出花。<br/><br/>但，这又有什么卵用呢，打开ollydbg，对MessageBoxA下断点(也就是弹窗的函数)：<br/><br/><img width="630" height="437" src="http://www.mzwu.com/pic/202004/130.jpg" border="0" alt=""/><br/><br/>然后输入一个错误的注册码，命中断点，很快，我们来到了判断注册码是否正确的逻辑处理代码：<br/><br/><img width="630" height="371" src="http://www.mzwu.com/pic/202004/131.jpg" border="0" alt=""/><br/><br/>你猜猜，要是我们把这个判断注册码是否正确的代码给它删了)(nop指令填充)会怎么样：<br/><br/><img width="630" height="342" src="http://www.mzwu.com/pic/202004/132.jpg" border="0" alt=""/><br/><br/>你会发现，握草，不管我输入什么，都是注册成功：<br/><br/><img src="http://www.mzwu.com/pic/202004/133.jpg" border="0" alt=""/><br/><br/>那么问题出在哪了呢，你发现，万恶之源都始于那个MessageBox函数，正是这个函数，让我们顺藤摸瓜找到了注册码判断代码，时至今日，仍然有非常非常大的一部分软件使用着这个二三十年前就在用的保护手段，每年死于MessageBox被破解的软件，围起来可以绕地球三圈。也就是这个保护机制，成就了所谓软件发布后十分钟就被破解的悲惨结局。<br/><br/><img src="http://www.mzwu.com/pic/202004/134.jpg" border="0" alt=""/><br/><br/>这个时候，你痛定思痛，mmp，有内鬼，既然MessageBox不好用，那我不用就是了，于是你把代码改成下面这样：<br/><br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code51292);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.mzwu.com/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code51292>#include &#34;stdio.h&#34;<br/>#include &#34;string.h&#34;<br/>#include &#34;windows.h&#34;<br/>#include &#34;math.h&#34;<br/><br/>int main()<br/>{<br/>&#160;&#160;&#160;&#160;char iKey[32];<br/>&#160;&#160;&#160;&#160;char Key[32];<br/>&#160;&#160;&#160;&#160;char ID[32];<br/>&#160;&#160;&#160;&#160;int iID=0xabc1d3f;<br/>&#160;&#160;&#160;&#160;sprintf(Key,&#34;%x&#34;,iID*8+123456);<br/>&#160;&#160;&#160;&#160;printf(&#34;你的机器码是%x\n&#34;,iID);<br/>&#160;&#160;&#160;&#160;printf(&#34;请输入注册码:&#34;);<br/>&#160;&#160;&#160;&#160;gets(iKey);<br/>&#160;&#160;&#160;&#160;if (strcmp(Key,iKey)==0)<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;printf(&#34;注册成功&#34;);<br/>&#160;&#160;&#160;&#160;else<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;exit(0);<br/>}</div></div><br/>你看，啧。只要你注册码没输对，我直接把软件退出(或者跳到别的地方)，看你怎么办。<br/><br/>可惜，内鬼年年有，&#34;注册成功&#34;几个字还是出卖了你，打开ollydbg，查找字符串参考，然后双击：<br/><br/><img width="630" height="456" src="http://www.mzwu.com/pic/202004/135.jpg" border="0" alt=""/><br/><br/><img width="630" height="371" src="http://www.mzwu.com/pic/202004/136.jpg" border="0" alt=""/><br/><br/>哦豁，完蛋，换汤不换药，还是给逮住了。<br/><br/>你察觉到这样一个地方判断注册码实在不靠谱，所以，你改变了策略，把检查注册码的代码复制了n遍，或者逐字符检查注册码的准确性，还有人将注册成功等字样进行加密或混淆，等到要用的时候再取出来：<br/><br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code24993);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.mzwu.com/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code24993>#include &#34;stdio.h&#34;<br/>#include &#34;string.h&#34;<br/>#include &#34;windows.h&#34;<br/>#include &#34;math.h&#34;<br/><br/>int main()<br/>{<br/>&#160;&#160;&#160;&#160;char iKey[32];<br/>&#160;&#160;&#160;&#160;char Key[32];<br/>&#160;&#160;&#160;&#160;char ID[32];<br/>&#160;&#160;&#160;&#160;int iID=0xabc1d3f;<br/>&#160;&#160;&#160;&#160;sprintf(Key,&#34;%x&#34;,iID*8+123456);<br/>&#160;&#160;&#160;&#160;printf(&#34;你的机器码是%x\n&#34;,iID);<br/>&#160;&#160;&#160;&#160;printf(&#34;请输入注册码:&#34;);<br/>&#160;&#160;&#160;&#160;gets(iKey);<br/>&#160;&#160;&#160;&#160;if (strcmp(Key,iKey)==0)<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;printf(&#34;注册成功&#34;);<br/>&#160;&#160;&#160;&#160;else<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;exit(0);<br/>if (strcmp(Key,iKey)==0)<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;printf(&#34;注册成功&#34;);<br/>&#160;&#160;&#160;&#160;else<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;exit(0);<br/>if (strcmp(Key,iKey)==0)<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;printf(&#34;注册成功&#34;);<br/>&#160;&#160;&#160;&#160;else<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;exit(0);<br/>if (strcmp(Key,iKey)==0)<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;printf(&#34;注册成功&#34;);<br/>&#160;&#160;&#160;&#160;else<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;exit(0);<br/>if (strcmp(Key,iKey)==0)<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;printf(&#34;注册成功&#34;);<br/>&#160;&#160;&#160;&#160;else<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;exit(0);<br/>if (strcmp(Key,iKey)==0)<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;printf(&#34;注册成功&#34;);<br/>&#160;&#160;&#160;&#160;else<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;exit(0);<br/>if (strcmp(Key,iKey)==0)<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;printf(&#34;注册成功&#34;);<br/>&#160;&#160;&#160;&#160;else<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;exit(0);<br/>if (strcmp(Key,iKey)==0)<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;printf(&#34;注册成功&#34;);<br/>&#160;&#160;&#160;&#160;else<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;exit(0);<br/>}</div></div><br/>你放心，不管你复制多少次，要找出来都是时间问题，吃枣是会被破解的。同时只要你要用到明文字符串你迟早还是要解密的，这种手段类似于加upx压缩壳，只需要等待数据解压完成，所有的东西又都是明文的了。因此比较聪明的做法是，要用时解密，用完后马上把明文抹掉，这样说不定能拖延更长的时间。但这仍然也是时间问题。<br/><br/>你开始发现，与其揪出内鬼，不如主动出击，也就是我们著名的与其解决问题不如解决提出问题的人，终于，你开始对调试器下手了，然后你成功进化到防破解V2.5时代。<br/><br/>这个时候，不得不介绍一个老掉牙的但非常有名的函数：<br/><br/>IsDebugPresent<br/><br/>你可能有点懵，这个函数是干啥子用的?，简单来说，当我们破解一个程序的时候，大部分情况下我们会打开一个叫调试器的东西来对软件进行反编译分析，诶，重点就在这，IsDebugPresent这个函数，就能检测我们的程序有没有被一个调试器附加，你想啊，正常情况我们用软件谁会吃饱撑着附加一个调试器来用，你要是用调试器附加我，你肯定就是想干坏事。<br/><br/>于是，你开始把代码写成这样:<br/><br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code77332);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.mzwu.com/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code77332>#include &#34;stdio.h&#34;<br/>#include &#34;string.h&#34;<br/>#include &#34;windows.h&#34;<br/>#include &#34;math.h&#34;<br/><br/>int main()<br/>{<br/>&#160;&#160;&#160;&#160;char iKey[32];<br/>&#160;&#160;&#160;&#160;char Key[32];<br/>&#160;&#160;&#160;&#160;char ID[32];<br/>&#160;&#160;&#160;&#160;int iID=0xabc1d3f;<br/>&#160;&#160;&#160;&#160;if (IsDebuggerPresent())<br/>&#160;&#160;&#160;&#160;{<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;MessageBoxA(NULL,&#34;小样,就你还破解我的程序,回家喝奶去吧&#34;,&#34;&#34;,MB_OK);<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;return 0;<br/>&#160;&#160;&#160;&#160;}<br/>&#160;&#160;&#160;&#160;sprintf(Key,&#34;%x&#34;,iID*8+123456);<br/>&#160;&#160;&#160;&#160;printf(&#34;你的机器码是%x\n&#34;,iID);<br/>&#160;&#160;&#160;&#160;printf(&#34;请输入注册码:&#34;);<br/>&#160;&#160;&#160;&#160;gets(iKey);<br/>&#160;&#160;&#160;&#160;if (strcmp(Key,iKey)==0)<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;printf(&#34;注册成功&#34;);<br/>&#160;&#160;&#160;&#160;else<br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;exit(0);<br/>}</div></div><br/>于是，当下次再ollydbg加载调试你的程序的时候，就会出现下面的情景：<br/><br/><img width="630" height="407" src="http://www.mzwu.com/pic/202004/137.jpg" border="0" alt=""/><br/><br/>曾经很长一段时间(包括现在)，很多软件或加密壳都会检查是否有调试器正在调试自己，比如tls段会在加载时被执行，如果检查到自己正在被人调试破解，就会设置一个tag让程序跑到没啥用的地方去或者直接退出重新，也有利用变形的PE头让调试器无法加载，总之手段很多。<br/><br/>可惜这还是没什么卵用，比如IsDebugPresent可以通过修改FS寄存器的标志位来让它彻底哑火，同样的手段包括但不限于检查int 3软中断，Raw Call，Query PEB，检查Debug Privilege和父进程等等等等，都有绕过的方式。<br/><br/><img src="http://www.mzwu.com/pic/202004/138.jpg" border="0" alt=""/><br/><br/>暗桩嘛，只要你插，一个一个拔总是拔的完的。<br/><br/>好了，还有啥法子不，放心道高一尺魔高一丈，现在我们来到了现在最流行的，防破解V3.0 VMP时代，<br/><br/>先澄清一下，这里的VMP并不是VMP壳，它全程叫Virtual Machine Protection，简单来说，为啥我们破解软件那么轻车熟路，还不是因为x86 x64 arm的那堆汇编指令集我们太熟悉了呗。要是我们自己发明一套指令集，然后用这个指令集写程序并运行在我们自己的虚拟机上，那么，破解者一进来，看到的不就是一脸懵逼了么<br/><br/>可惜的是，VM的运行机制决定了它可能造成几十倍乃至几百倍的性能损失，所以，VMP必须用于保护那种关键且不是性能瓶颈的代码，否者你的软件跑起来就会像：<br/><br/><img src="http://www.mzwu.com/pic/202004/139.jpg" border="0" alt=""/><br/><br/>那么，VMP保护机制是完美的么，当然不是，VMP说白了，也只能做到延长分析时间，你要是把VMP做的足够复杂，足够让一个Cracker醉生梦死了，但是如果这个时间足够久，你的软件足够的值钱让人有欲望来破解， 他们仍然可以充分地分析你VM机的运行机制，当你的VM机运行机制被摸清了，软件就离沦陷不远了。<br/><br/>不过你可以放心，分析VM机执行机理，可比自己写VM机要头疼多了，毕竟一个是你需要通过代码来揣测别人的思路，而另一个本身是自己的思路转为代码，因此基于这点可以说:<br/><br/>破解软件比制作软件简单，在很多情况下，不存在的!<br/><br/>你可能会问了，为什么现在市面上那么多软件，那么多游戏，购买了那么多听起来那么牛逼的保护软件，结果还是被破解了。而且刚发出来一天就被破解了。<br/><br/>其实很大的问题就出在这个商业保护软件(比如保护壳)上，因为这类保护壳大多都会被卖给一大票的软件开发商，有一句话叫树大招风，就像现在流行的VMP保护机制，之所以能保护，是因为其运行机理破解者不明确，如果你这个软件就给自己用，而且你这软件还不怎么值钱，除非大佬空虚寂寞冷，不然谁会有那闲工夫去分析你的虚拟机是怎么跑的，但商业保护壳不同，不论其采用什么样的保护机制，只要分析过一遍搞清楚了，几乎所有使用这类保护机制的软件都会沦陷，而且在灰色产业上。这种破解甚至还颇有利可图，只要这个保护机制不更新，一次投入，长期回报。于是只有说在第一次分析时会花上很长的时间，之后就都只是玩套路了。<br/><br/>因此，购买商业保护壳，其实其保护效果并没有想象中的那么强，很可能在灰色产业中形同虚设，甚至一个具有反逆向基础的码农自己写的说不定还更有效果。当然一个软件是被破解概率高不高，仍然是我之前提到的那句话:防破解不是让软件无法破解，而是让破解软件的成本远大于购买软件的成本。<br/><br/>毕竟你说你一个软件拿来开源都没人爱用，你还整天琢磨着怎么才不会被破解，寒掺不老铁。<br/><br/>那么你会开始问了，有没有更给力点的防破解技术?好像之前说的说来说去，无非就是拖延时间，诶，这个我们要摆正心态，不论是加密还是破解，其实说白了最终就是拖延时间，你看那些加密算法，依据其数学理论，如果要破解，它的计算量就算你把全世界的计算机加起来一块算，也够你算三个世界末日了。<br/><br/>不过别担心，更给力的方法还是有的，你想啊，为什么我们之前说了那么多软件都被破解了，最最关键的一个原因，是我们能搞到代码，即使这个代码已经是经过编译后的一堆汇编指令，但只要我们有这堆代码，迟早我们还是能搞懂这个程序是怎么回事的，然后我们就可以对症下药干坏事。<br/><br/>这就像给你有一包面粉，而程序就是一个面包机，你把面粉塞进面包机做出了面包，有天你好奇啊，这面包机咋整咋整就出来一块面包了呢，你就动手把面包机拆了，然后你就知道面包机是怎么回事了。<br/><br/>所以有没有办法不让用户知道我们的代码是什么样的呢，就像你把面粉交给了面包师傅做面包，这个面包是怎么做的，你就只能指望看面包师傅有没有这个心情告诉你了。<br/><br/>为此，有请早期一个相当流行且普遍的游戏防破解工具(物理)<br/><br/><img src="http://www.mzwu.com/pic/202004/140.jpg" border="0" alt=""/><br/><br/>你现在可能表情是一脸问号，但我没和你开玩笑，在2000年时代，大部分的游戏运行在光盘CD中，但盗版也容易啊，把光盘里的数据一复制下来，然后就可以复制出一万张盗版光碟，所以游戏厂商们就想办法，想来想去就想到了榔头。<br/><br/>其操作方法很简单，拿榔头和钉子，在光盘上钉几条刮痕出来，造成人工的坏道，然后再将数据烧录到正确的扇区中，这样下来虽然程序还是可以正确运行，但是当光头读盘读到这个坏道的时候，就会读不过去，于是你会发现打开光盘后，没有关键的文件，这样你就没办法将游戏或者说程序拷贝出来了，同时还会对坏道的位置做一个标记，游戏运行时也会检查这个标记，那么想要盗版你就也得拿起榔头在光盘同样的位置上砸出同样的刮痕出来，当然，这几乎是不可能的。<br/><br/>当年这个技术当年又叫防盗环技术，但不管它的名字叫的多高大上，本质上就和榔头钉钉子如出一辙是同样的东西，可惜虚拟光驱出现后，同样有办法复刻光盘的一切数据(包括坏道)，所以，这个技术拿到今天来看并没有什么卵用。不过这仍然给了我们足够的启发。<br/><br/>现在让我们进入防破解V3.x时代，之所以不叫V4.0是因为这类技术很早就有并且比VMP保护流行的时间还早的多，而且它可能是最近接理论上不可破解的防破解手段。<br/><br/>我们先聊的是加密狗或者又叫Ukey保护，就是运行软件你需要插入一个U盘一样的东西到电脑上，实际上这个Ukey是一个微型电脑，软件的一些关键的算法和代码，都在这个UKey的芯片里，当我们PC上的软件运行后，当我们需要执行这类关键算法时，我们会向这个Ukey传递数据，然后UKey将结果计算出来，返回给PC的软件上，这样就避免了用户直接能够逆向取得关键的算法代码，破解也就无从谈起了。这也就是为什么到了今天，Ukey保护仍然非常的流行。<br/><br/>可惜，UKey保护仍然有诸多的限制，首先就是带着一个Ukey贼麻烦，万一UKey丢了补办是一个麻烦事，运行软件插Ukey也是个神烦的事情，同时，UKey的性能决定了它可能不能执行一些过于消耗性能和内存空间的代码，数据交互也因带宽和通讯延迟会造成性能损失，所以它和VMP保护机制一样，同样不是一个省油的灯，同时开发人员的水平不到位，该保护的代码没保护，保护来没啥用的代码塞了一堆，也会给Cracker带来机会，而且只要你的软件够值钱，你是不是太瞧不起我华强北了：<br/><br/><img src="http://www.mzwu.com/pic/202004/141.jpg" border="0" alt=""/><br/><br/>把Ukey拆开来，使用某种&#34;药水&#34;剥开外层找到内部的芯片并接上已经熔断的&#34;读引脚&#34;(有些芯片连这步都省了，直接热风枪一吹接板读ROM) 然后再把芯片的代码给读出来。<br/><br/>于是，UKey保护也宣布沦陷。<br/><br/>你发现，只要是把实体的东西交到用户的手上，迟早会出问题，所以，这个Ukey保护现在大部分情况下变成了带数字证书的网络验证模式，这类的关键代码从Ukey转移到了服务器上，数据交互通过网络来做。其实这种保护机制和Ukey保护原理是一样的并没有什么本质的区别，但同样处于网络带宽也延迟的考虑，同样具有一定的性能损失和设计缺陷。<br/>需要重点提及的是，这类网络保护的手段必须专门设计以保护程序中的一系列关键&#34;功能&#34;代码而不是&#34;防破解&#34;代码(比如代码解密，注册验证)，因为后者几乎没啥卵用仍然能够将&#34;防破解&#34;的代码清除或Dump解密代码或伪造本地服务器实现破解。<br/><br/>所以你指望一堆什么x盾，x宝一键能一劳永逸一键保护程序，程序必须经过专业码农而不是彩笔专门的设计才能起到其应有的保护效果。<br/><br/>但现实情况是，处于用户离线运行和性能延迟瓶颈的考虑，这种网络保护设计的往往都有很大的缺陷，因此，并不是说这东西不好，而是理想很丰满现实很骨干，实在无能为力啊。<br/><br/>原文链接：<a href="https://www.toutiao.com/a6815476340142113283/" target="_blank" rel="external">https://www.toutiao.com/a6815476340142113283/</a>]]></description>
		</item>
		
			<item>
			<link>http://www.mzwu.com/article.asp?id=4615</link>
			<title><![CDATA[SQLite数据库ADO.NET实体数据模型使用示例]]></title>
			<author>service@mzwu.com(dnawo)</author>
			<category><![CDATA[Win编程]]></category>
			<pubDate>Thu,16 Apr 2020 12:38:29 +0800</pubDate>
			<guid>http://www.mzwu.com/default.asp?id=4615</guid>
		<description><![CDATA[<strong>一、安装VS扩展dotConnect ADO.NET Data Provider for SQLite</strong><br/><br/><img width="630" height="437" src="http://www.mzwu.com/pic/202004/108.jpg" border="0" alt=""/><br/><br/><i>说明：dotConnect for SQLite有免费和试用两个版本，必须安装试用版，否则数据源列表不会出现SQLite Database，安装过程出现错误&#34;the specified content does not exist o&#114; is unreadable&#34;不必理会，可以正常使用。</i><br/><br/><img src="http://www.mzwu.com/pic/202004/117.jpg" border="0" alt=""/><br/><br/><strong>二、添加SQLite数据库ADO.NET实体数据模型</strong><br/><br/><img width="630" height="437" src="http://www.mzwu.com/pic/202004/109.jpg" border="0" alt=""/><br/><br/><img src="http://www.mzwu.com/pic/202004/110.jpg" border="0" alt=""/><br/><br/><img src="http://www.mzwu.com/pic/202004/111.jpg" border="0" alt=""/><br/><br/><img src="http://www.mzwu.com/pic/202004/112.jpg" border="0" alt=""/><br/><br/><img src="http://www.mzwu.com/pic/202004/113.jpg" border="0" alt=""/><br/><br/><img src="http://www.mzwu.com/pic/202004/114.jpg" border="0" alt=""/><br/><br/><img src="http://www.mzwu.com/pic/202004/115.jpg" border="0" alt=""/><br/><br/><img src="http://www.mzwu.com/pic/202004/116.jpg" border="0" alt=""/><br/><br/><strong>二、ADO.NET 实体数据模型使用示例</strong><br/><br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code31442);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.mzwu.com/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code31442>using System;<br/>using System.Linq;<br/><br/>namespace ConsoleApp1<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;class Program<br/>&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;static void Main(string[] args)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;using(var db = new mainEntities())<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//Ins&#101;rt<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.UserTB.Add(new UserTB() { Name = &#34;张三&#34;, Age = 20 });<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.UserTB.Add(new UserTB() { Name = &#34;李四&#34;, Age = 30 });<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.SaveChanges();<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//Up&#100;ate<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var user1 = db.UserTB.FirstOrDefault();<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;user1.Name += &#34;new&#34;;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.SaveChanges();<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//Del&#101;te<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var user2 = db.UserTB.OrderByDescending(item =&gt; item.Id).FirstOrDefault(); //不识别方法LastOrDefault<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.UserTB.Remove(user2);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;db.SaveChanges();<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//Sel&#101;ct<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var data = db.UserTB.ToList();<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foreach(var item in data)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine(&#34;{0},{1},{2}&#34;, item.Id, item.Name, item.Age);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.ReadLine();<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br/>&nbsp;&nbsp;&nbsp;&nbsp;}<br/>}</div></div>]]></description>
		</item>
		
			<item>
			<link>http://www.mzwu.com/article.asp?id=4614</link>
			<title><![CDATA[一键卸载NuGet程序包及其依赖项示例]]></title>
			<author>service@mzwu.com(dnawo)</author>
			<category><![CDATA[Win编程]]></category>
			<pubDate>Thu,16 Apr 2020 09:45:10 +0800</pubDate>
			<guid>http://www.mzwu.com/default.asp?id=4614</guid>
		<description><![CDATA[有时引用的NuGet程序包有好几个依赖项，卸载的时候一个个卸载花时间不说，还要注意先后顺序很麻烦。<br/><br/>例如我们引用System.Data.SQLite，它的依赖项就有4个：<br/><div class="UBBPanel quotePanel"><div class="UBBTitle"><img src="http://www.mzwu.com/images/quote.gif" style="margin:0px 2px -3px 0px" alt="引用内容"/> 引用内容</div><div class="UBBContent"><i>EntityFramework<br/>System.Data.SQLite.Core<br/>System.Data.SQLite.EF6<br/>System.Data.SQLite.Linq</i></div></div><br/><img src="http://www.mzwu.com/pic/202004/107.jpg" border="0" alt=""/><br/><br/>有没有办法一键就能卸载NuGet程序包及其依赖项呢？有的，在程序包管理控制台使用Uninstall-Package命令及其参数RemoveDependencies就能实现：<br/><br/><div class="UBBPanel codePanel"><div class="UBBTitle"><a onClick="copycode(code82162);" style="float:right;cursor: pointer;font-weight: normal; font-style: normal">复制内容到剪贴板</a><img src="http://www.mzwu.com/images/code.gif" style="margin:0px 2px -3px 0px;" alt="程序代码"/> 程序代码</div><div class="UBBContent" id=code82162><i>PM&gt; Uninstall-Package System.Data.SQLite -RemoveDependencies<br/><br/>正在尝试收集与目标为“.NETFramework,Version=v4.5”的项目“ConsoleApp1”有关的包“System.Data.SQLite.1.0.112”的依赖项信息<br/>正在解析操作以卸载程序包“System.Data.SQLite.1.0.112”<br/>已解析操作以卸载程序包“System.Data.SQLite.1.0.112”<br/>已从“packages.config”中删除程序包“System.Data.SQLite.1.0.112”<br/>已从 ConsoleApp1 成功卸载“System.Data.SQLite.1.0.112”<br/>已从“packages.config”中删除程序包“System.Data.SQLite.Core.1.0.112”<br/>已从 ConsoleApp1 成功卸载“System.Data.SQLite.Core.1.0.112”<br/>已从“packages.config”中删除程序包“System.Data.SQLite.Linq.1.0.112”<br/>已从 ConsoleApp1 成功卸载“System.Data.SQLite.Linq.1.0.112”<br/>已从“packages.config”中删除程序包“System.Data.SQLite.EF6.1.0.112”<br/>已从 ConsoleApp1 成功卸载“System.Data.SQLite.EF6.1.0.112”<br/>已从“packages.config”中删除程序包“EntityFramework.6.3.0”<br/>已从 ConsoleApp1 成功卸载“EntityFramework.6.3.0”<br/>正在从文件夹“E:\Demo\ConsoleApp1\packages”中删除程序包“System.Data.SQLite.1.0.112”<br/>已从文件夹“E:\Demo\ConsoleApp1\packages”中删除程序包“System.Data.SQLite.1.0.112”<br/>正在从文件夹“E:\Demo\ConsoleApp1\packages”中删除程序包“System.Data.SQLite.Core.1.0.112”<br/>已从文件夹“E:\Demo\ConsoleApp1\packages”中删除程序包“System.Data.SQLite.Core.1.0.112”<br/>正在从文件夹“E:\Demo\ConsoleApp1\packages”中删除程序包“System.Data.SQLite.Linq.1.0.112”<br/>已从文件夹“E:\Demo\ConsoleApp1\packages”中删除程序包“System.Data.SQLite.Linq.1.0.112”<br/>正在从文件夹“E:\Demo\ConsoleApp1\packages”中删除程序包“System.Data.SQLite.EF6.1.0.112”<br/>已从文件夹“E:\Demo\ConsoleApp1\packages”中删除程序包“System.Data.SQLite.EF6.1.0.112”<br/>正在从文件夹“E:\Demo\ConsoleApp1\packages”中删除程序包“EntityFramework.6.3.0”<br/>已从文件夹“E:\Demo\ConsoleApp1\packages”中删除程序包“EntityFramework.6.3.0”<br/>执行 nuget 操作花费时间 8.57 sec<br/>已用时间: 00:00:08.6607601</i></div></div>]]></description>
		</item>
		
			<item>
			<link>http://www.mzwu.com/article.asp?id=4596</link>
			<title><![CDATA[WinForm未能加载文件或程序集AxInterop.WMPLib：生成此程序集的运行时比当前加载的运行时新解决方法]]></title>
			<author>service@mzwu.com(dnawo)</author>
			<category><![CDATA[Win编程]]></category>
			<pubDate>Tue,31 Mar 2020 16:41:22 +0800</pubDate>
			<guid>http://www.mzwu.com/default.asp?id=4596</guid>
		<description><![CDATA[前几年写的一个WinForm应用程序，引用了COM组件Windows Media Player用于播放音频文件，今天用VS2019编辑生成后运行出错，提示：<br/><br/><div class="UBBPanel quotePanel"><div class="UBBTitle"><img src="http://www.mzwu.com/images/quote.gif" style="margin:0px 2px -3px 0px" alt="引用内容"/> 引用内容</div><div class="UBBContent">System.BadImageFormatException: 未能加载文件或程序集“AxInterop.WMPLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null”或它的某一个依赖项。生成此程序集的运行时比当前加载的运行时新，无法加载此程序集。</div></div><br/><br/><img src="http://www.mzwu.com/pic/202003/208.jpg" border="0" alt=""/><br/><br/>运行ildasm工具，载入AxInterop.WMPLib.dll，双击MANIFEST查看程序集清单：<br/><br/><img src="http://www.mzwu.com/pic/202003/209.jpg" border="0" alt=""/><br/><br/>明白了，编辑后自动引用了新版本AxInterop.WMPLib.dll（操作系统Windows 10），它依赖于.NET Framework 4.0，而WinForm应用程序前几年创建的使用的框架为.NET Framework 2.0，将框架版本更改为.NET Framework 4.0，问题解决。<br/><br/>最后，找了下先前版本中引用的AxInterop.WMPLib.dll，同样看下程序集清单：<br/><br/><img src="http://www.mzwu.com/pic/202003/210.jpg" border="0" alt=""/>]]></description>
		</item>
		
</channel>
</rss>
