<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>先生请出山</title>
  
  
  <link href="https://sirtech.cc/atom.xml" rel="self"/>
  
  <link href="https://sirtech.cc/"/>
  <updated>2024-10-17T23:44:25.000Z</updated>
  <id>https://sirtech.cc/</id>
  
  <author>
    <name>先生请出山</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>搭建cloudflare worker实现全速下载huggingface大模型</title>
    <link href="https://sirtech.cc/2024/10/17/da-jian-cloudflare-worker-shi-xian-zi-you-xia-zai-huggingface-da-mo-xing/"/>
    <id>https://sirtech.cc/2024/10/17/da-jian-cloudflare-worker-shi-xian-zi-you-xia-zai-huggingface-da-mo-xing/</id>
    <published>2024-10-17T23:44:25.000Z</published>
    <updated>2024-10-17T23:44:25.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="序"><a href="#序" class="headerlink" title="序"></a>序</h2><p>最近在玩ComfyUI的时候受到了下载模型的强烈痛苦，网上找了一圈也没有找到称心如意的工具，直接用代理下载大模型的话，流量很快就会告急…，而<code>huggingface-cli</code>和<code>ht-transfer</code>也各有各的问题。最后自己想了个办法，通过aria2可以多源下载的特点，在多个开源脚本的基础上自己糊了一个脚本，实现了满速下载大模型，具体细节请看<a href="https://github.com/bughoho/hfdownloader">这里</a>。这里主要记录一下<code>cloudflare woker</code>脚本的部署方法。</p><h2 id="需要准备的东西"><a href="#需要准备的东西" class="headerlink" title="需要准备的东西"></a>需要准备的东西</h2><ol><li>注册一个cloudflare账号</li><li>白嫖或者买一个域名，因为cloudflare的域名DNS污染很严重，最好是用自己的域名，再说现在域名也不贵。</li><li>如果域名不是在cloudflare上购买的，就需要从其他域名服务商转移到cloudflare，让cloudflare来托管域名。cloudflare的DNS修改是真的快，用了之后再也回不去了。</li></ol><h2 id="开始"><a href="#开始" class="headerlink" title="开始"></a>开始</h2><p>首先要先登录<a href="https://www.cloudflare.com/">cloudflare</a>，进入cloudflare的<a href="https://dash.cloudflare.com/">dashboard面板</a>,选择<code>Workers和Pages</code>：</p><p><img src="https://assets.sirtech.cc/img/cloudflare.webp" alt="dashboard.webp"></p><p>在<code>概述</code>页面点击<code>创建</code>：</p><p><img src="https://assets.sirtech.cc/img/202410180005880.webp" alt="dashboard2"></p><p>点击<code>创建worker</code>：</p><p><img src="https://assets.sirtech.cc/img/202410180014912.webp" alt="dashboard3"></p><p>这里名字可以随便填，如果要创建多个就<code>r1</code>，<code>r2</code>这样的名字即可，填了之后你就会获得一个worker.dev的三级域名，不过因为我们要用自己的域名，所以无所谓。</p><p><img src="https://assets.sirtech.cc/img/202410180017858.webp" alt="dashboard4"></p><p>填了名字后直接点击<code>部署</code>，<code>cloudflare</code>会先创建一个默认的<code>hello world</code>脚本。</p><p>创建好后会进入woker详情页面，此时选择<code>编辑代码</code>进入脚本编辑器：</p><p><img src="https://assets.sirtech.cc/img/202410180021792.webp" alt="dashboard5"></p><p><img src="https://assets.sirtech.cc/img/202410180025823.webp" alt="dashboard6"></p><p>现在到去<a href="https://github.com/bughoho/hfdownloader">这里</a>下载<code>worker.js</code>，把其中的内容复制出来，粘贴到编辑器中，或者直接将下面的内容复制进去：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Welcome to Cloudflare Workers! This is your first worker.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * - Run &quot;npm run dev&quot; in your terminal to start a development server</span></span><br><span class="line"><span class="comment"> * - Open a browser tab at http://localhost:8787/ to see your worker in action</span></span><br><span class="line"><span class="comment"> * - Run &quot;npm run deploy&quot; to publish your worker</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Learn more at https://developers.cloudflare.com/workers/</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="title function_">addEventListener</span>(<span class="string">&#x27;fetch&#x27;</span>, <span class="function"><span class="params">event</span> =&gt;</span> &#123;</span><br><span class="line">  event.<span class="title function_">respondWith</span>(<span class="title function_">handleRequest</span>(event.<span class="property">request</span>))</span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">const</span> specialCases = &#123;</span><br><span class="line">  <span class="string">&quot;*&quot;</span>: &#123;</span><br><span class="line">    <span class="string">&quot;Origin&quot;</span>: <span class="string">&quot;DELETE&quot;</span>,</span><br><span class="line">    <span class="string">&quot;Referer&quot;</span>: <span class="string">&quot;DELETE&quot;</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">handleSpecialCases</span>(<span class="params">request</span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> url = <span class="keyword">new</span> <span class="title function_">URL</span>(request.<span class="property">url</span>);</span><br><span class="line">  <span class="keyword">const</span> rules = specialCases[url.<span class="property">hostname</span>] || specialCases[<span class="string">&quot;*&quot;</span>];</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">const</span> [key, value] <span class="keyword">of</span> <span class="title class_">Object</span>.<span class="title function_">entries</span>(rules)) &#123;</span><br><span class="line">    <span class="keyword">switch</span> (value) &#123;</span><br><span class="line">      <span class="keyword">case</span> <span class="string">&quot;KEEP&quot;</span>:</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">      <span class="keyword">case</span> <span class="string">&quot;DELETE&quot;</span>:</span><br><span class="line">        request.<span class="property">headers</span>.<span class="title function_">delete</span>(key);</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">      <span class="attr">default</span>:</span><br><span class="line">        request.<span class="property">headers</span>.<span class="title function_">set</span>(key, value);</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">handleRequest</span>(<span class="params">request</span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> url = <span class="keyword">new</span> <span class="title function_">URL</span>(request.<span class="property">url</span>);</span><br><span class="line">  <span class="keyword">if</span> (url.<span class="property">pathname</span> === <span class="string">&quot;/&quot;</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Response</span>(<span class="string">&quot;Please enter the link after the /&quot;</span>)</span><br><span class="line">  &#125;;</span><br><span class="line">  <span class="keyword">const</span> actualUrlStr = url.<span class="property">pathname</span>.<span class="title function_">replace</span>(<span class="string">&quot;/&quot;</span>, <span class="string">&quot;&quot;</span>) + url.<span class="property">search</span> + url.<span class="property">hash</span>;</span><br><span class="line">  <span class="keyword">const</span> actualUrl = <span class="keyword">new</span> <span class="title function_">URL</span>(actualUrlStr);</span><br><span class="line">  <span class="keyword">const</span> modifiedRequest = <span class="keyword">new</span> <span class="title class_">Request</span>(actualUrl, &#123;</span><br><span class="line">    <span class="attr">headers</span>: request.<span class="property">headers</span>,</span><br><span class="line">    <span class="attr">method</span>: request.<span class="property">method</span>,</span><br><span class="line">    <span class="attr">body</span>: request.<span class="property">body</span>,</span><br><span class="line">    <span class="attr">redirect</span>: <span class="string">&#x27;follow&#x27;</span></span><br><span class="line">  &#125;);</span><br><span class="line">  <span class="title function_">handleSpecialCases</span>(modifiedRequest);</span><br><span class="line">  <span class="keyword">const</span> response = <span class="keyword">await</span> <span class="title function_">fetch</span>(modifiedRequest);</span><br><span class="line">  <span class="keyword">const</span> modifiedResponse = <span class="keyword">new</span> <span class="title class_">Response</span>(response.<span class="property">body</span>, response);</span><br><span class="line">  modifiedResponse.<span class="property">headers</span>.<span class="title function_">set</span>(<span class="string">&#x27;Access-Control-Allow-Origin&#x27;</span>, <span class="string">&#x27;*&#x27;</span>);</span><br><span class="line">  <span class="keyword">return</span> modifiedResponse;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="https://assets.sirtech.cc/img/202410180028706.webp" alt="dashboard8"></p><p>然后点击右上角<code>部署</code>。</p><p>部署成功后点击左上角<code>r5</code>(你刚刚填的名字)返回上一页，选择<code>设置</code>栏，在<code>域和路由</code>处点击<code>添加</code>：</p><p><img src="https://assets.sirtech.cc/img/202410180033304.webp" alt="dashboard9"></p><p>在弹出的侧边栏选择<code>自定义域</code>，填写你托管在<code>cloudflare</code>上的域名，起一个二级域名的名字，比如<code>r5.yourdomain.com</code>。</p><p><img src="https://assets.sirtech.cc/img/202410180038826.webp" alt="dashboard10"></p><h2 id="结束"><a href="#结束" class="headerlink" title="结束"></a>结束</h2><p>此时你的代理域名就搭建好了，你可以这样使用：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">https://r5.yourdomain.com/https://xxx.com/file.zip</span><br></pre></td></tr></table></figure><p>下载速度还可以，至少有好几Mb&#x2F;s。</p><p>如果只使用一个代理服务器的速度肯定还是很慢，如何使用aria2实现多个源服务器并行下载来榨干下行带宽，请参考我<code>糊</code>的<a href="https://github.com/bughoho/hfdownloader">这个脚本</a>。</p><p>更多内容请关注<a href="https://sirtech.cc/">我的博客</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;序&quot;&gt;&lt;a href=&quot;#序&quot; class=&quot;headerlink&quot; title=&quot;序&quot;&gt;&lt;/a&gt;序&lt;/h2&gt;&lt;p&gt;最近在玩ComfyUI的时候受到了下载模型的强烈痛苦，网上找了一圈也没有找到称心如意的工具，直接用代理下载大模型的话，流量很快就会告急…，而&lt;cod</summary>
      
    
    
    
    
    <category term="cloudflare" scheme="https://sirtech.cc/tags/cloudflare/"/>
    
    <category term="使用教程" scheme="https://sirtech.cc/tags/%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/"/>
    
  </entry>
  
  <entry>
    <title>一条命令备份容器中的数据卷</title>
    <link href="https://sirtech.cc/2024/10/15/yi-xing-ming-ling-bei-fen-rong-qi-zhong-de-shu-ju-juan/"/>
    <id>https://sirtech.cc/2024/10/15/yi-xing-ming-ling-bei-fen-rong-qi-zhong-de-shu-ju-juan/</id>
    <published>2024-10-15T14:14:40.000Z</published>
    <updated>2024-10-15T00:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="一行命令备份容器中的数据卷"><a href="#一行命令备份容器中的数据卷" class="headerlink" title="一行命令备份容器中的数据卷"></a>一行命令备份容器中的数据卷</h2><h3 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h3><p>  之前在创建miniflux容器时使用了官方的docker-compose.yml配置：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">miniflux:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">miniflux/miniflux:latest</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;80:8080&quot;</span></span><br><span class="line">    <span class="attr">depends_on:</span></span><br><span class="line">      <span class="attr">db:</span></span><br><span class="line">        <span class="attr">condition:</span> <span class="string">service_healthy</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">DATABASE_URL=postgres://miniflux:secret@db/miniflux?sslmode=disable</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">RUN_MIGRATIONS=1</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">CREATE_ADMIN=1</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">ADMIN_USERNAME=admin</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">ADMIN_PASSWORD=test123</span></span><br><span class="line">  <span class="attr">db:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">postgres:15</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">POSTGRES_USER=miniflux</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">POSTGRES_PASSWORD=secret</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">POSTGRES_DB=miniflux</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">miniflux-db:/var/lib/postgresql/data</span></span><br><span class="line">    <span class="attr">healthcheck:</span></span><br><span class="line">      <span class="attr">test:</span> [<span class="string">&quot;CMD&quot;</span>, <span class="string">&quot;pg_isready&quot;</span>, <span class="string">&quot;-U&quot;</span>, <span class="string">&quot;miniflux&quot;</span>]</span><br><span class="line">      <span class="attr">interval:</span> <span class="string">10s</span></span><br><span class="line">      <span class="attr">start_period:</span> <span class="string">30s</span></span><br><span class="line"><span class="attr">volumes:</span></span><br><span class="line">  <span class="attr">miniflux-db:</span></span><br></pre></td></tr></table></figure><p>  后来注意到官方配置用到了命名数据卷<code>miniflux-db</code>，这样做的好处是可以在多个容器之间共享数据库目录，而实际上并共享读取数据库目录的需求，并且这样做的缺点是如果系统出问题时很可能来不及备份docker的数据卷，或者干脆就忘了。而数据库中有长期订阅积攒下来的大量rss链接和文章，这是一份宝贵的数据，完全可以拿来做知识库什么的，如果丢失了就得不偿失了。</p><p>  然后在网上找了一下资料，翻了几页，方法千篇一律都是创建临时容器、挂载目录、tar压缩打包，然后再用容器解包。后来自己看了下docker命令，发现一条命令就能解决：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker <span class="built_in">cp</span> miniflux-db-1:/var/lib/postgresql/data $(<span class="built_in">pwd</span>)/miniflux-db/</span><br></pre></td></tr></table></figure><p>在docker-compose.yml所在目录下创建一个<code>miniflux-db</code>作为<code>docker ps</code>命令的复制目的目录，<code>miniflux-db-1</code>是miniflux数据库的容器名，执行后会复制到当前目录下的<code>miniflux-db</code>目录。</p><p>这时修改docker-compose.yml中的条目：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">db:</span></span><br><span class="line">  <span class="attr">volumes:</span></span><br><span class="line">    <span class="comment"># - miniflux-db:/var/lib/postgresql/data</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">./miniflux-db:/var/lib/postgresql/data</span></span><br></pre></td></tr></table></figure><p>然后可以删除配置中数据卷的定义（用不上了）：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">volumes:</span></span><br><span class="line">  <span class="attr">miniflux-db:</span></span><br></pre></td></tr></table></figure><p>更多内容请关注<a href="https://sirtech.cc/">我的博客</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;一行命令备份容器中的数据卷&quot;&gt;&lt;a href=&quot;#一行命令备份容器中的数据卷&quot; class=&quot;headerlink&quot; title=&quot;一行命令备份容器中的数据卷&quot;&gt;&lt;/a&gt;一行命令备份容器中的数据卷&lt;/h2&gt;&lt;h3 id=&quot;前言&quot;&gt;&lt;a href=&quot;#前言&quot; cla</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>微信公众号转换为RSS的方法</title>
    <link href="https://sirtech.cc/2024/10/07/wei-xin-gong-zhong-hao-zhuan-huan-wei-rss-de-fang-fa/"/>
    <id>https://sirtech.cc/2024/10/07/wei-xin-gong-zhong-hao-zhuan-huan-wei-rss-de-fang-fa/</id>
    <published>2024-10-07T00:00:00.000Z</published>
    <updated>2024-10-07T00:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<h3 id="1-在PC微信上搜索公众号"><a href="#1-在PC微信上搜索公众号" class="headerlink" title="1.在PC微信上搜索公众号"></a>1.在PC微信上搜索公众号</h3><p><img src="https://assets.sirtech.cc/img/202410071812239.png" alt="Alt"></p><h3 id="2-随便点一个标签，将会从浏览器打开一个网页"><a href="#2-随便点一个标签，将会从浏览器打开一个网页" class="headerlink" title="2.随便点一个标签，将会从浏览器打开一个网页"></a>2.随便点一个标签，将会从浏览器打开一个网页</h3><p><img src="https://assets.sirtech.cc/img/202410071826951.png" alt="202410071826951.png"></p><h3 id="3-从浏览器地址栏复制这个页面"><a href="#3-从浏览器地址栏复制这个页面" class="headerlink" title="3.从浏览器地址栏复制这个页面"></a>3.从浏览器地址栏复制这个页面</h3><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzA5MTIxNTY4MQ==&amp;action=getalbum&amp;album_id=2959126655292211206&amp;scene=126#wechat_redirect</span><br></pre></td></tr></table></figure><h3 id="4-将微信参数-biz和album-id提取出来组成"><a href="#4-将微信参数-biz和album-id提取出来组成" class="headerlink" title="4.将微信参数__biz和album_id提取出来组成"></a>4.将微信参数__biz和album_id提取出来组成</h3><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">MzA5MTIxNTY4MQ==/2959126655292211206</span><br></pre></td></tr></table></figure><p>转换成如下格式：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">http://192.168.1.xxx:1200/wechat/mp/msgalbum/MzA5MTIxNTY4MQ==/2959126655292211206</span><br></pre></td></tr></table></figure><p>即可得到微信公众号的rss</p><h3 id="说明"><a href="#说明" class="headerlink" title="说明"></a>说明</h3><p>其中 <code>http://192.168.1.xxx:1200</code> 是自建的rsshub服务和端口号，<code>/wechat/mp/msgalbum/</code> 是rsshub的微信路由。</p><h3 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h3><p>这个方法有个问题，如果有的公众号上面没有显示<code>#标签</code>，就无法获取到album_id，而且这个album_id只是公众号的一个tag，只能获取到部分内容，还是有一定局限性。后面再研究看看有没有其他办法。</p><p>更多内容请关注<a href="https://sirtech.cc/">我的博客</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;1-在PC微信上搜索公众号&quot;&gt;&lt;a href=&quot;#1-在PC微信上搜索公众号&quot; class=&quot;headerlink&quot; title=&quot;1.在PC微信上搜索公众号&quot;&gt;&lt;/a&gt;1.在PC微信上搜索公众号&lt;/h3&gt;&lt;p&gt;&lt;img src=&quot;https://assets.s</summary>
      
    
    
    
    <category term="技巧" scheme="https://sirtech.cc/categories/%E6%8A%80%E5%B7%A7/"/>
    
    
    <category term="技巧" scheme="https://sirtech.cc/tags/%E6%8A%80%E5%B7%A7/"/>
    
  </entry>
  
  <entry>
    <title>使用usb-ip将USB重定向到远程主机</title>
    <link href="https://sirtech.cc/2024/06/06/shi-yong-usb-ip-jiang-usb-chong-ding-xiang-dao-yuan-cheng-zhu-ji/"/>
    <id>https://sirtech.cc/2024/06/06/shi-yong-usb-ip-jiang-usb-chong-ding-xiang-dao-yuan-cheng-zhu-ji/</id>
    <published>2024-06-06T00:00:00.000Z</published>
    <updated>2024-06-06T00:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="服务端（小主机）"><a href="#服务端（小主机）" class="headerlink" title="服务端（小主机）"></a>服务端（小主机）</h2><p>linux小主机安装usbip：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">sudo apt install linux-tools-`uname -r`</span><br><span class="line">sudo modprobe usbip-core</span><br><span class="line">sudo modprobe vhci-hcd</span><br><span class="line">sudo modprobe usbip-vudc</span><br><span class="line">sudo modprobe usbip-host</span><br></pre></td></tr></table></figure><p>启动守护程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo usbipd -D</span><br></pre></td></tr></table></figure><p>可以将加载模块部分写入<code>/etc/rc.local</code>以达到开机自动加载的目的.</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">/sbin/modprobe usbip-core</span><br><span class="line">/sbin/modprobe vhci-hcd</span><br><span class="line">/sbin/modprobe usbip-vudc</span><br><span class="line">/sbin/modprobe usbip-host</span><br><span class="line">sudo usbipd -D</span><br></pre></td></tr></table></figure><p>端口放行：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo ufw allow 3240</span><br></pre></td></tr></table></figure><p>用lsusb命令查看当前系统下的USB端口详细信息：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">lsusb</span></span><br><span class="line">Bus 006 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub</span><br><span class="line">Bus 005 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub</span><br><span class="line">Bus 001 Device 004: ID 203a:fffa Parallels Virtual Printer (EPSON L8160 Series)</span><br><span class="line">Bus 001 Device 003: ID 203a:fffa Parallels Virtual Printer (Print to PDF (Mac Desktop))</span><br><span class="line">Bus 001 Device 002: ID 203a:fffc Parallels Virtual Mouse</span><br><span class="line">Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub</span><br><span class="line">Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub</span><br><span class="line">Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub</span><br><span class="line">Bus 002 Device 005: ID 248a:8327 Maxxter </span><br><span class="line">Bus 002 Device 003: ID 2dc8:3109 Parallels Virtual USB1.1 HUB</span><br><span class="line">Bus 002 Device 002: ID 203a:fffe Parallels Virtual USB1.1 HUB</span><br><span class="line">Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub</span><br></pre></td></tr></table></figure><p>不认识USB的话可以通过拔插USB接口来确定。<br>我这里的Maxxter是键鼠接收器<br>通过248a:8327这个ID用<code>usbip list</code>命令查找bus id：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">sudo usbip list -l</span><br><span class="line"> - busid 2-2.2 (2dc8:3109)</span><br><span class="line">   unknown vendor : unknown product (2dc8:3109)</span><br><span class="line"></span><br><span class="line"> - busid 2-2.3 (248a:8327)</span><br><span class="line">   Maxxter : unknown product (248a:8327)</span><br><span class="line"></span><br><span class="line"> - busid 1-1 (203a:fffc)</span><br><span class="line">   unknown vendor : unknown product (203a:fffc)</span><br><span class="line"></span><br><span class="line"> - busid 1-2 (203a:fffa)</span><br><span class="line">   unknown vendor : unknown product (203a:fffa)</span><br><span class="line"></span><br><span class="line"> - busid 1-3 (203a:fffa)</span><br><span class="line">   unknown vendor : unknown product (203a:fffa)</span><br></pre></td></tr></table></figure><p>分享设备：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">sudo usbip bind -b 2-2.3</span><br><span class="line">usbip: info: bind device on busid 2-2.3: complete</span><br></pre></td></tr></table></figure><p>成功后设备将无法再在本机使用。</p><h2 id="客户端（要重定向的电脑）"><a href="#客户端（要重定向的电脑）" class="headerlink" title="客户端（要重定向的电脑）"></a>客户端（要重定向的电脑）</h2><p>最开始使用的是开源项目<code>usbip-win</code>(<a href="https://github.com/cezanne/usbip-win)%EF%BC%8C%E4%BD%86%E6%98%AF%E4%BC%9A%E8%93%9D%E5%B1%8F%EF%BC%8C%E6%94%B9%E4%B8%BA%E4%BA%86%E5%8F%A6%E5%A4%96%E4%B8%80%E4%B8%AA%E9%A1%B9%E7%9B%AE(https://github.com/vadimgrn/usbip-win2),%E5%B8%A6GUI%E7%9A%84%EF%BC%8Cattach%E6%AF%94%E8%BE%83%E6%96%B9%E4%BE%BF%E3%80%82">https://github.com/cezanne/usbip-win)，但是会蓝屏，改为了另外一个项目(https://github.com/vadimgrn/usbip-win2),带GUI的，attach比较方便。</a></p><p>更多内容请关注<a href="https://sirtech.cc/">我的博客</a></p>]]></content>
    
    
    <summary type="html">使用usb-ip将USB重定向到远程主机</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>携趣自动设置IP白名单</title>
    <link href="https://sirtech.cc/2024/06/02/xi-qu-zi-dong-she-zhi-ip-bai-ming-dan/"/>
    <id>https://sirtech.cc/2024/06/02/xi-qu-zi-dong-she-zhi-ip-bai-ming-dan/</id>
    <published>2024-06-02T00:00:00.000Z</published>
    <updated>2024-06-02T00:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>直接上代码,注意替换URL中的uid和ukey：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> requests</span><br><span class="line"><span class="keyword">import</span> logging</span><br><span class="line"><span class="keyword">import</span> os</span><br><span class="line"></span><br><span class="line">WHITELIST_DEBUG_MODE = <span class="number">0</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> <span class="string">&quot;WHITELIST_DEBUG&quot;</span> <span class="keyword">in</span> os.environ <span class="keyword">or</span> WHITELIST_DEBUG_MODE:  <span class="comment"># 判断调试模式变量</span></span><br><span class="line">    logging.basicConfig(level=logging.DEBUG, <span class="built_in">format</span>=<span class="string">&#x27;%(message)s&#x27;</span>)  <span class="comment"># 设置日志为 Debug等级输出</span></span><br><span class="line">    logger = logging.getLogger(__name__)  <span class="comment"># 主模块</span></span><br><span class="line">    logger.debug(<span class="string">&quot;\nDEBUG模式开启!\n&quot;</span>)  <span class="comment"># 消息输出</span></span><br><span class="line"><span class="keyword">else</span>:</span><br><span class="line">    logging.basicConfig(level=logging.INFO, <span class="built_in">format</span>=<span class="string">&#x27;%(message)s&#x27;</span>)  <span class="comment"># Info级日志</span></span><br><span class="line">    logger = logging.getLogger(__name__)  <span class="comment"># 主模块</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 自定义请求标头</span></span><br><span class="line">headers = &#123;</span><br><span class="line">    <span class="string">&#x27;Accept&#x27;</span>: <span class="string">&#x27;text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7&#x27;</span>,</span><br><span class="line">    <span class="string">&#x27;Accept-Encoding&#x27;</span>: <span class="string">&#x27;gzip, deflate, br, zstd&#x27;</span>,</span><br><span class="line">    <span class="string">&#x27;Accept-Language&#x27;</span>: <span class="string">&#x27;zh-CN,zh;q=0.9&#x27;</span>,</span><br><span class="line">    <span class="string">&#x27;Cache-Control&#x27;</span>: <span class="string">&#x27;max-age=0&#x27;</span>,</span><br><span class="line">    <span class="string">&#x27;Connection&#x27;</span>: <span class="string">&#x27;keep-alive&#x27;</span>,</span><br><span class="line">    <span class="string">&#x27;Host&#x27;</span>: <span class="string">&#x27;2024.ipchaxun.com&#x27;</span>,</span><br><span class="line">    <span class="string">&#x27;Sec-Fetch-Dest&#x27;</span>: <span class="string">&#x27;document&#x27;</span>,</span><br><span class="line">    <span class="string">&#x27;Sec-Fetch-Mode&#x27;</span>: <span class="string">&#x27;navigate&#x27;</span>,</span><br><span class="line">    <span class="string">&#x27;Sec-Fetch-Site&#x27;</span>: <span class="string">&#x27;none&#x27;</span>,</span><br><span class="line">    <span class="string">&#x27;Sec-Fetch-User&#x27;</span>: <span class="string">&#x27;?1&#x27;</span>,</span><br><span class="line">    <span class="string">&#x27;Upgrade-Insecure-Requests&#x27;</span>: <span class="string">&#x27;1&#x27;</span>,</span><br><span class="line">    <span class="string">&#x27;User-Agent&#x27;</span>: <span class="string">&#x27;Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36&#x27;</span>,</span><br><span class="line">    <span class="string">&#x27;sec-ch-ua&#x27;</span>: <span class="string">&#x27;&quot;Google Chrome&quot;;v=&quot;125&quot;, &quot;Chromium&quot;;v=&quot;125&quot;, &quot;Not.A/Brand&quot;;v=&quot;24&quot;&#x27;</span>,</span><br><span class="line">    <span class="string">&#x27;sec-ch-ua-mobile&#x27;</span>: <span class="string">&#x27;?0&#x27;</span>,</span><br><span class="line">    <span class="string">&#x27;sec-ch-ua-platform&#x27;</span>: <span class="string">&#x27;&quot;macOS&quot;&#x27;</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 获取当前IP地址</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_external_ip</span>():</span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        response = requests.get(<span class="string">&#x27;https://2024.ipchaxun.com/&#x27;</span>, headers=headers)</span><br><span class="line">        response.raise_for_status()</span><br><span class="line">        data = response.json()</span><br><span class="line">        <span class="keyword">if</span> data.get(<span class="string">&#x27;ret&#x27;</span>) == <span class="string">&#x27;ok&#x27;</span>:</span><br><span class="line">            <span class="keyword">return</span> data.get(<span class="string">&#x27;ip&#x27;</span>)</span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            logger.info(<span class="string">f&quot;获取IP地址失败，返回内容: <span class="subst">&#123;data&#125;</span>&quot;</span>)</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">None</span></span><br><span class="line">    <span class="keyword">except</span> requests.RequestException <span class="keyword">as</span> e:</span><br><span class="line">        logger.info(<span class="string">f&quot;获取外部IP时出错: <span class="subst">&#123;e&#125;</span>&quot;</span>)</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">None</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 获取白名单IP</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_whitelist_ips</span>():</span><br><span class="line">    <span class="comment"># uid和ukey换成自己的</span></span><br><span class="line">    url = <span class="string">&#x27;http://op.xiequ.cn/IpWhiteList.aspx?uid=xxxxx&amp;ukey=yyyyy&amp;act=get&#x27;</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        response = requests.get(url)</span><br><span class="line">        response.raise_for_status()</span><br><span class="line">        ips = response.text.split(<span class="string">&#x27;,&#x27;</span>)</span><br><span class="line">        <span class="keyword">return</span> [ip.strip() <span class="keyword">for</span> ip <span class="keyword">in</span> ips]</span><br><span class="line">    <span class="keyword">except</span> requests.RequestException <span class="keyword">as</span> e:</span><br><span class="line">        logger.info(<span class="string">f&quot;获取白名单IP时出错: <span class="subst">&#123;e&#125;</span>&quot;</span>)</span><br><span class="line">        <span class="keyword">return</span> []</span><br><span class="line"></span><br><span class="line"><span class="comment"># 删除所有白名单记录</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">delete_all_whitelist</span>():</span><br><span class="line">    <span class="comment"># uid和ukey换成自己的</span></span><br><span class="line">    url = <span class="string">&#x27;http://op.xiequ.cn/IpWhiteList.aspx?uid=xxxxx&amp;ukey=yyyyy&amp;act=del&amp;ip=all&#x27;</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        response = requests.get(url)</span><br><span class="line">        response.raise_for_status()</span><br><span class="line">        logger.info(<span class="string">&quot;已成功删除所有白名单记录。&quot;</span>)</span><br><span class="line">    <span class="keyword">except</span> requests.RequestException <span class="keyword">as</span> e:</span><br><span class="line">        logger.info(<span class="string">f&quot;删除白名单记录时出错: <span class="subst">&#123;e&#125;</span>&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 添加IP到白名单</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">add_ip_to_whitelist</span>(<span class="params">ip</span>):</span><br><span class="line">    <span class="keyword">if</span> ip <span class="keyword">is</span> <span class="literal">None</span>:</span><br><span class="line">        logger.info(<span class="string">&quot;没有IP地址可添加。&quot;</span>)</span><br><span class="line">        <span class="keyword">return</span></span><br><span class="line">    <span class="comment"># uid和ukey换成自己的</span></span><br><span class="line">    url = <span class="string">f&#x27;http://op.xiequ.cn/IpWhiteList.aspx?uid=xxxxx&amp;ukey=yyyyy&amp;act=add&amp;ip=<span class="subst">&#123;ip&#125;</span>&#x27;</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        response = requests.get(url)</span><br><span class="line">        response.raise_for_status()</span><br><span class="line">        <span class="keyword">if</span> <span class="string">&#x27;success&#x27;</span> <span class="keyword">in</span> response.text.lower():</span><br><span class="line">            logger.info(<span class="string">&quot;IP地址已成功添加到白名单。&quot;</span>)</span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            logger.info(<span class="string">f&quot;添加IP地址失败: <span class="subst">&#123;response.text&#125;</span>&quot;</span>)</span><br><span class="line">    <span class="keyword">except</span> requests.RequestException <span class="keyword">as</span> e:</span><br><span class="line">        logger.info(<span class="string">f&quot;添加IP到白名单时出错: <span class="subst">&#123;e&#125;</span>&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">&quot;__main__&quot;</span>:</span><br><span class="line">    logger.info(<span class="string">&quot;正在获取外部IP&quot;</span>)</span><br><span class="line">    ip = get_external_ip()</span><br><span class="line">    logger.info(<span class="string">f&quot;外部IP: <span class="subst">&#123;ip&#125;</span>&quot;</span>)</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">if</span> ip:</span><br><span class="line">        whitelist_ips = get_whitelist_ips()</span><br><span class="line">        logger.info(<span class="string">f&quot;当前白名单IP: <span class="subst">&#123;whitelist_ips&#125;</span>&quot;</span>)</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">if</span> ip <span class="keyword">not</span> <span class="keyword">in</span> whitelist_ips:</span><br><span class="line">            delete_all_whitelist()</span><br><span class="line">            add_ip_to_whitelist(ip)</span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            logger.info(<span class="string">&quot;当前IP已在白名单中。&quot;</span>)</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>更多内容请关注<a href="https://sirtech.cc/">我的博客</a></p>]]></content>
    
    
    <summary type="html">直接上代码：</summary>
    
    
    
    
    <category term="python" scheme="https://sirtech.cc/tags/python/"/>
    
    <category term="青龙" scheme="https://sirtech.cc/tags/%E9%9D%92%E9%BE%99/"/>
    
  </entry>
  
  <entry>
    <title>实现了一个某继续教育平台的自动学习的脚本</title>
    <link href="https://sirtech.cc/2024/05/19/shi-xian-liao-yi-ge-mou-ji-xu-jiao-yu-ping-tai-de-zi-dong-xue-xi-de-jiao-ben/"/>
    <id>https://sirtech.cc/2024/05/19/shi-xian-liao-yi-ge-mou-ji-xu-jiao-yu-ping-tai-de-zi-dong-xue-xi-de-jiao-ben/</id>
    <published>2024-05-19T00:00:00.000Z</published>
    <updated>2024-05-19T00:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>直接上代码：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// ==UserScript==</span></span><br><span class="line"><span class="comment">// @name         New Userscript</span></span><br><span class="line"><span class="comment">// @namespace    http://tampermonkey.net/</span></span><br><span class="line"><span class="comment">// @version      2024-05-19</span></span><br><span class="line"><span class="comment">// @description  try to take over the world!</span></span><br><span class="line"><span class="comment">// @author       You</span></span><br><span class="line"><span class="comment">// @match        https://player.cnzx.info/KeCheng/*</span></span><br><span class="line"><span class="comment">// @icon         https://www.google.com/s2/favicons?sz=64&amp;domain=cnzx.info</span></span><br><span class="line"><span class="comment">// @grant        none</span></span><br><span class="line"><span class="comment">// ==/UserScript==</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">(<span class="keyword">function</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="string">&#x27;use strict&#x27;</span>;</span><br><span class="line">  <span class="keyword">var</span> errcount = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">var</span> listening = <span class="literal">false</span>;</span><br><span class="line">  <span class="keyword">var</span> currentPageURL = <span class="variable language_">document</span>.<span class="property">location</span>.<span class="property">href</span>;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;当前脚本所注入的页面 URL:&quot;</span>, currentPageURL);</span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="title function_">nextcourse</span>(<span class="params"></span>)&#123;</span><br><span class="line">      <span class="comment">// 这里是要执行的代码</span></span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;寻找可播放列表&#x27;</span>);</span><br><span class="line">      <span class="comment">// 获取包含章节列表的父元素</span></span><br><span class="line">      <span class="keyword">var</span> chapterList = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&#x27;.m-chapterList&#x27;</span>);</span><br><span class="line"></span><br><span class="line">      <span class="comment">// 获取所有没有展开的章节</span></span><br><span class="line">      <span class="keyword">var</span> chapterItems = chapterList.<span class="title function_">querySelectorAll</span>(<span class="string">&#x27;.chapter:not(.ant-menu-submenu-open)&#x27;</span>);</span><br><span class="line"></span><br><span class="line">      <span class="comment">// 展开所有章节</span></span><br><span class="line">      chapterItems.<span class="title function_">forEach</span>(<span class="keyword">function</span>(<span class="params">item</span>) &#123;</span><br><span class="line">          item.<span class="title function_">click</span>();</span><br><span class="line">      &#125;);</span><br><span class="line"></span><br><span class="line">      <span class="comment">// 遍历所有课时，读取课程名称和有没有学过</span></span><br><span class="line">      <span class="keyword">var</span> sections = chapterList.<span class="title function_">querySelectorAll</span>(<span class="string">&#x27;.section&#x27;</span>);</span><br><span class="line"></span><br><span class="line">      <span class="comment">// 遍历每个 section</span></span><br><span class="line">      <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; sections.<span class="property">length</span>; i++) &#123;</span><br><span class="line">        <span class="keyword">var</span> section = sections[i];</span><br><span class="line"></span><br><span class="line">        <span class="keyword">var</span> courseName = section.<span class="title function_">querySelector</span>(<span class="string">&#x27;.ksname&#x27;</span>).<span class="property">textContent</span>;</span><br><span class="line">        <span class="keyword">var</span> zhuangtai = section.<span class="title function_">querySelector</span>(<span class="string">&#x27;.u-clicon.ksicon&#x27;</span>).<span class="property">title</span>;</span><br><span class="line"></span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;课程名称:&#x27;</span>, courseName);</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;是否学过:&#x27;</span>, zhuangtai);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (zhuangtai == <span class="string">&#x27;未完成&#x27;</span>) &#123;</span><br><span class="line">          section.<span class="title function_">click</span>();</span><br><span class="line">          <span class="keyword">break</span>; <span class="comment">// 停止继续遍历</span></span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">  &#125;;</span><br><span class="line">  <span class="keyword">var</span> timerId = <span class="built_in">setInterval</span>(<span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      <span class="keyword">var</span> playerElement = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&#x27;chinaHcmPlayer&#x27;</span>);</span><br><span class="line"></span><br><span class="line">      <span class="keyword">if</span> (playerElement === <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;playerElement is null&#x27;</span>);</span><br><span class="line">        <span class="keyword">if</span>(errcount &gt; <span class="number">100</span>)&#123;</span><br><span class="line">            <span class="built_in">clearInterval</span>(timerId); <span class="comment">// 停止定时器</span></span><br><span class="line">        &#125;</span><br><span class="line">        errcount++;</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">if</span>(!listening)&#123;</span><br><span class="line">        playerElement.<span class="title function_">addEventListener</span>(<span class="string">&quot;ended&quot;</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">          <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;播放完毕,开始寻找可播放列表&#x27;</span>);</span><br><span class="line">          <span class="built_in">setTimeout</span>(<span class="keyword">function</span>(<span class="params"></span>) &#123;</span><br><span class="line">            <span class="title function_">nextcourse</span>();<span class="comment">//学下一课</span></span><br><span class="line">          &#125;, <span class="number">1000</span>);</span><br><span class="line">        &#125;);</span><br><span class="line">        listening = <span class="literal">true</span>;</span><br><span class="line">      &#125;</span><br><span class="line">      </span><br><span class="line">      <span class="keyword">var</span> <span class="title class_">XueXiZhuangTai</span> = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&#x27;XueXiZhuangTai&#x27;</span>);</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">XueXiZhuangTai</span>.<span class="property">title</span>);</span><br><span class="line">      <span class="keyword">if</span>(<span class="title class_">XueXiZhuangTai</span>.<span class="property">title</span> == <span class="string">&#x27;未学习&#x27;</span>) &#123;</span><br><span class="line">        playerElement.<span class="property">muted</span> = <span class="literal">true</span>;<span class="comment">//必须要加这一句才能在脚本中执行play()，可能是浏览器的安全策略</span></span><br><span class="line">        playerElement.<span class="title function_">play</span>();<span class="comment">//按播放直接开始</span></span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">      &#125;<span class="keyword">else</span> <span class="keyword">if</span>(<span class="title class_">XueXiZhuangTai</span>.<span class="property">title</span> == <span class="string">&#x27;学过了&#x27;</span>)&#123;</span><br><span class="line">        <span class="title function_">nextcourse</span>();<span class="comment">//学下一课</span></span><br><span class="line">      &#125;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (error) &#123;</span><br><span class="line">      <span class="comment">// 处理异常情况</span></span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;发生错误:&quot;</span>, error);</span><br><span class="line">      <span class="built_in">clearInterval</span>(timerId); <span class="comment">// 停止定时器</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;, <span class="number">2000</span>)</span><br><span class="line">&#125;)();</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>更多内容请关注<a href="https://sirtech.cc/">我的博客</a></p>]]></content>
    
    
    <summary type="html">直接上代码：</summary>
    
    
    
    
    <category term="javascript" scheme="https://sirtech.cc/tags/javascript/"/>
    
  </entry>
  
  <entry>
    <title>解锁硬盘限制！50块钱的中兴CT321G2小主机用ipxe无盘启动windows</title>
    <link href="https://sirtech.cc/2024/04/23/jie-suo-ying-pan-xian-zhi-50-kuai-qian-de-zhong-xing-ct321g2-xiao-zhu-ji-yong-ipxe-wu-pan-qi-dong-windows/"/>
    <id>https://sirtech.cc/2024/04/23/jie-suo-ying-pan-xian-zhi-50-kuai-qian-de-zhong-xing-ct321g2-xiao-zhu-ji-yong-ipxe-wu-pan-qi-dong-windows/</id>
    <published>2024-04-23T00:00:00.000Z</published>
    <updated>2024-04-23T00:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>先说原因，在家里用apple tv串流到电脑上玩游戏，发现蓝牙连接手柄没有震动功能，手柄直连电脑是可以震动功能的，玩地平线时试过那个手柄震动功能之后，就再也回不去了，于是想找个便宜的方案曲线救国，海鲜市场50块钱淘了这个小主机，x86&#x2F;64构架，只有2g内存和4g硬盘，可玩性不高，但是cpu跟j1900差不多，usb口也很丰富，4个USB2.0+2个USB3.0接口，完全可以做书房电脑主机的usb延伸，顺便还可以跑点小程序也是没问题的。<br><img src="https://assets.sirtech.cc/img/202404291558568.png" alt="image.png"></p><p><img src="https://assets.sirtech.cc/img/202404291559240.png" alt="image.png"></p><p>找了个usb串流软件只能在windows下用，所以我准备装一个windows，但是4G硬盘存储太拉跨，装windows是完全不够用，也考虑过windows to go安装到u盘里，而windows to go对u盘的要求挺高，最便宜的价格都要100多了，已经超出了小主机的价格，完全无法接受，所以想到了用iscsi无盘启动的方式，经过几天的折腾，最终完美启动。</p><h1 id="要准备的文件"><a href="#要准备的文件" class="headerlink" title="要准备的文件"></a>要准备的文件</h1><ul><li>wimboot:用来启动windows pe</li><li>ipxe:这个要自己编译，因为要嵌入自己的脚本</li><li>windows镜像</li><li>u盘：用rufus等工具把windows镜像写入u盘。如果不想用u盘也可以把镜像挂载到群晖共享文件夹，在windowspe里用net use命令挂载镜像所在的文件夹，执行setup.exe启动，这里为了省事直接用了u盘。<br>需要的文件可以自己下载编译，也可以用我编译好的版本和镜像，但是注意6111端口号要和我的一样。</li></ul><p>（wimboot、编译好的ipxe、windows镜像、我写的ipxe启动脚本）的下载链接:<br><a href="https://pan.baidu.com/s/1Lb69OU13pGFt-ff78TSGpA?pwd=1234">https://pan.baidu.com/s/1Lb69OU13pGFt-ff78TSGpA?pwd=1234</a> 提取码: 1234<br><a href="https://url95.ctfile.com/d/44827295-61067476-560716?p=4681">https://url95.ctfile.com/d/44827295-61067476-560716?p=4681</a> (访问密码: 4681)</p><h1 id="0-遇到的坑"><a href="#0-遇到的坑" class="headerlink" title="0 遇到的坑"></a>0 遇到的坑</h1><h2 id="0-0-windows的版本"><a href="#0-0-windows的版本" class="headerlink" title="0.0 windows的版本"></a>0.0 windows的版本</h2><p>唯一能成功安装的windows版本是windows 1607，在这之前之后的版本都不行，不要问我怎么知道的😭。<br>本来想讨巧在其他电脑上直接把windows装到iscsi硬盘直接给小主机使用，但是发现用DISM命令直接从windows镜像提取文件再写入iscsi硬盘的方式在网启的时候会报错（ inaccessible boot device）。<br>后来直接用U盘安装发现错误一样，最终确定是镜像的问题，下次折腾再试试DISM命令直接写入ISCSI硬盘。</p><h3 id="0-1-群晖的iscsi格式"><a href="#0-1-群晖的iscsi格式" class="headerlink" title="0.1 群晖的iscsi格式"></a>0.1 群晖的iscsi格式</h3><p>我在群晖部署的iscsi硬盘是一个target映射一个lun：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sanboot iscsi:192.168.1.225::::iqn.2000-01.com.synology:diskstation.Target-win10</span><br></pre></td></tr></table></figure><p>这种死活连接不上，这种::::冒号之间不填都是默认值，第三个冒号后面是LUN的编号，看网上的文章在使用sanboot命令时都是用的默认值，但是经过我的试验使用把LUN的编号改成1才启动成功</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sanboot iscsi:192.168.1.225:::1:iqn.2000-01.com.synology:diskstation.Target-win10</span><br></pre></td></tr></table></figure><p>这里第三个冒号后面的是LUN ID，如果不填默认是0，看来群晖的LUN映射编号是从1开始的。</p><h3 id="0-2-群晖iscsi初次登录的权限问题"><a href="#0-2-群晖iscsi初次登录的权限问题" class="headerlink" title="0.2 群晖iscsi初次登录的权限问题"></a>0.2 群晖iscsi初次登录的权限问题</h3><p>如果群晖的iscsi target设置了权限的话，在第一次执行sanboot时会连接失败（can not open SAN device）,这个要在群晖SAN管理器中的iscsi target页面等待小主机执行sanboot，执行sanboot后在群晖的san manager的iscsi页面会看到连接过来的客户端IP，这个时候点括号里的create new host，然后给这个客户端设置LUN的可读写权限，再次重启小主机进行引导就能连接成功了。<br><img src="https://assets.sirtech.cc/img/202404251520568.png" alt="image.png"></p><h3 id="0-3-ipxe的编译"><a href="#0-3-ipxe的编译" class="headerlink" title="0.3 ipxe的编译"></a>0.3 ipxe的编译</h3><p>如果使用我编译好的ipxe就不用看了，要自己编译的话，首先要开个ubuntu虚拟机或者ubuntu docker环境来编译，在macos、windows下是编译不了的，或者说要配置复杂的交叉编译命令，最好还是开个虚拟机方便一点。关于编译命令，官网上说的编译依赖有点过时，经过试验我安装了如下依赖：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> apt install git  </span><br><span class="line"><span class="built_in">sudo</span> apt install git-core   <span class="comment">#不装这个编译时会出现文件找不到  </span></span><br><span class="line"><span class="built_in">sudo</span> apt install liblzma-dev <span class="comment">#不装会出现lzma.h错误   </span></span><br><span class="line"><span class="built_in">sudo</span> apt install gcc</span><br><span class="line"><span class="built_in">sudo</span> apt install make  </span><br><span class="line"><span class="built_in">sudo</span> apt install mtools  <span class="comment">#DOS命令模拟器</span></span><br><span class="line"><span class="built_in">sudo</span> apt install mkisofs <span class="comment">#不生成ISO不需要  </span></span><br><span class="line"><span class="built_in">sudo</span> apt install syslinux <span class="comment">#不生成ISO不需要</span></span><br></pre></td></tr></table></figure><p>在src目录下建立一个链式脚本chain.ipxe，内容如下：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!ipxe</span></span><br><span class="line">dhcp</span><br><span class="line">chain http://<span class="variable">$&#123;next-server&#125;</span>:6111/boot.ipxe</span><br></pre></td></tr></table></figure><p><code>$&#123;next-server&#125;:6111</code>是我在群晖webstation上放的更完整的引导脚本，<code>$&#123;next-server&#125;</code>变量是dhcp服务器返回的下一个服务器的地址，这个在 配置软路由 章节会提到如何设置，现在开始编译：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> src</span><br><span class="line">make clean</span><br><span class="line">make bin-x86_64-efi/ipxe.efi EMBED=chain.ipxe</span><br><span class="line"><span class="built_in">mkdir</span> -p myipxe/64</span><br><span class="line"><span class="built_in">cp</span> bin-x86_64-efi/ipxe.efi myipxe/64</span><br></pre></td></tr></table></figure><p>到<code>src/myipxe/64</code>目录下找到<code>ipxe.efi</code>,拷贝到群晖websation的目录下，用浏览器确保<code>http://192.168.1.225:6111/ipxe.efi</code>可以正常访问。</p><p>这个时候小主机使用网络引导时就可以使用ipxe执行<code>http://$&#123;next-server&#125;:61111/boot.ipxe</code>中的命令了。</p><h3 id="0-4-网口问题"><a href="#0-4-网口问题" class="headerlink" title="0.4 网口问题"></a>0.4 网口问题</h3><p>这个主机的网卡是realtek 8168，速率是10&#x2F;100&#x2F;1000Mbps自适应的，进入系统后网络接口显示的是100Mbps，折腾后发现是网线问题，换了根网线后，协商速率变成1000Mbps了，不过内网librespeed跑了下，最大只能跑满500Mbps左右，只能跑一半的速度，一般来说也够了。<br><img src="https://assets.sirtech.cc/img/202404281104219.png" alt="image.png"></p><h1 id="1-安装步骤"><a href="#1-安装步骤" class="headerlink" title="1 安装步骤"></a>1 安装步骤</h1><h2 id="1-0-网络引导流程图"><a href="#1-0-网络引导流程图" class="headerlink" title="1.0 网络引导流程图"></a>1.0 网络引导流程图</h2><p>先看完整pxe网络引导流程图：</p><p>![[ipxe引导示意图.excalidraw.svg]]</p><h3 id="1-0-BIOS选项设置"><a href="#1-0-BIOS选项设置" class="headerlink" title="1.0 BIOS选项设置"></a>1.0 BIOS选项设置</h3><ul><li>BIOS的密码：zte-ct  </li><li>BIOS启动顺序改为网络优先  </li><li>IDE配置修改为IDE-&gt;AHCI,原先是AMDAHCI  </li><li>启动类型改为uefi启动或者dual boot type  </li><li>pxe boot capability改为uefi:ipv4</li></ul><p>ps:如果bios改坏了变砖，可以把机子拆开把电池扣下来放电就还原回去了～</p><h3 id="1-1-配置软路由"><a href="#1-1-配置软路由" class="headerlink" title="1.1 配置软路由"></a>1.1 配置软路由</h3><p>首先要配置软路由的dhcp服务器，让dhcp服务器告诉网卡tftp服务器的地址和要获取的引导文件名字，我的软路由系统是iStoreOS（基于openwrt），在网络-&gt;DHCP&#x2F;DNS-&gt;PXE&#x2F;TFTP设置，添加ipxe的信息：<br><img src="https://assets.sirtech.cc/img/202404250309851.png" alt="image.png"></p><p>填入群晖的ip地址，名称，和引导固件的文件名：<br><img src="https://assets.sirtech.cc/img/202404250315888.png" alt="image.png"></p><p>填这个的目的是让dhcp服务器告诉网卡下一步到哪里里去下载引导文件。</p><p>其他软路由类似，一些硬路由也有这个功能，如果没有的话，替代方案是关闭路由器上的DHCP服务，并打开群晖的DHCP服务，用群晖来实现给内网提供ip地址服务。<br>注意如果要用群晖的dhcp服务，就必须关闭路由器上的dhcp服务，因为整个内网只能有一个dhcp服务器，如果有多个dhcp服务会造成内网ip地址混乱。</p><h3 id="1-2-在群晖上配置tftp服务"><a href="#1-2-在群晖上配置tftp服务" class="headerlink" title="1.2 在群晖上配置tftp服务"></a>1.2 在群晖上配置tftp服务</h3><p>如果软路由支持开启tftp服务也可以将引导固件放在软路由上，但是为了方便我将文件都统一存放在群晖上方便管理。</p><p>打开群晖页面，在控制面板-&gt;文件服务-&gt;高级设置-&gt;tftp，勾上启用tftp服务，并设置根文件夹：<br><img src="https://assets.sirtech.cc/img/202404250321900.png" alt="image.png"></p><p>然后把<code>ipxe.efi</code>放到<code>/web/tftp</code>目录下（见前面的编译方法）。<br>前面提到ipxe.efi内嵌了自己写的脚本，脚本中用chain命令链式启动了一个新的脚本：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">chain http://$&#123;next-server&#125;:6111/boot.ipxe</span><br></pre></td></tr></table></figure><p>为什么要这样做呢？因为将引导脚本内嵌到ipxe.efi中的，不方便修改，所以内嵌脚本中直接链式启动一个新的脚本灵活一点。另外前面有提到我发现ipxe.efi启动时似乎会隐式执行<code>autoexec.ipxe</code>脚本，但是我在官网上没有找到使用说明，就没继续折腾了，后面的朋友可以试试这个方法，如果行得通可以省去ipxe.efi的编译过程，直接使用官网release原版。</p><h3 id="1-3-在群晖web-station服务上建立一个http服务，端口号设置为脚本里的6111"><a href="#1-3-在群晖web-station服务上建立一个http服务，端口号设置为脚本里的6111" class="headerlink" title="1.3 在群晖web station服务上建立一个http服务，端口号设置为脚本里的6111"></a>1.3 在群晖web station服务上建立一个http服务，端口号设置为脚本里的6111</h3><p>群晖上打开Web Station-&gt;网页服务，选择本机脚本语言网站:<br><img src="https://assets.sirtech.cc/img/202404281736498.png" alt="image.png"></p><p>名称描述随便填，目录选择web&#x2F;www，自己要在相应位置创建目录：<br><img src="https://assets.sirtech.cc/img/202404281731725.png" alt="image.png"></p><p><img src="https://assets.sirtech.cc/img/202404281737360.png" alt="image.png"></p><p>然后在网络门户新增一个门户：<br><img src="https://assets.sirtech.cc/img/202404281739400.png" alt="image.png"><br>在web&#x2F;www&#x2F;目录下随便放个文件用http协议访问下，能读取到就没问题了。</p><h3 id="1-4-制作windows-pe-windows预执行环境"><a href="#1-4-制作windows-pe-windows预执行环境" class="headerlink" title="1.4 制作windows pe(windows预执行环境)"></a>1.4 制作windows pe(windows预执行环境)</h3><p>这一步的目的是为了能进入windows安装程序的命令行界面启动U盘上的windows镜像，但不是真的要使用这些文件来安装windows。所以我做了个最简单的windows pe。<br>挂载windows镜像，把以下文件按对应目录的方式拷贝到群晖的6111端口的web服务根目录中：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">boot/bcd</span><br><span class="line">boot/bcd.sdi</span><br><span class="line">sources/boot.wim</span><br></pre></td></tr></table></figure><p>在把前面下载的wimboot也放到目录中，最终web服务根目录如下：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">wimboot</span><br><span class="line">boot/bcd</span><br><span class="line">boot/bcd.sdi</span><br><span class="line">sources/boot.wim</span><br></pre></td></tr></table></figure><p>到这里一个最最最简单的可以用ipxe启动的pe预安装环境就配置好了。</p><h5 id="1-5-boot-ipxe启动脚本"><a href="#1-5-boot-ipxe启动脚本" class="headerlink" title="1.5 boot.ipxe启动脚本"></a>1.5 boot.ipxe启动脚本</h5><p>我从网上找了些脚本，做了修改，只实现了两个功能，从iscsi磁盘引导，和进入前面制作好的windows pe环境，内容如下：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line">#!ipxe</span><br><span class="line">#下面这个3000是菜单等待时间代表3秒，</span><br><span class="line">   set menu-timeout 3000</span><br><span class="line">   set menu-default WINDOWS</span><br><span class="line">   isset $&#123;ip&#125; || dhcp</span><br><span class="line">set initiator-iqn iqn.$&#123;product&#125;:$&#123;mac:hexhyp&#125;</span><br><span class="line"></span><br><span class="line">:start</span><br><span class="line">  menu iPXE Boot Menu</span><br><span class="line">  item --gap --             --------------------------------- WIN --------------------------------</span><br><span class="line">  item WINDOWS                 BOOT WINDOWS(ISCSI)</span><br><span class="line">  item --gap --             ---------------------------- Advanced options ------------------------</span><br><span class="line">  item --key p pe              PE system                                                     -- p</span><br><span class="line">  item --key s shell           shell                                                         -- s</span><br><span class="line">  item --key r reboot          reboot computer                                               -- r</span><br><span class="line">  item --key x exit            Exit iPXE and continue BIOS boot                              -- x</span><br><span class="line">  item --gap --  </span><br><span class="line">  item --gap --             ------------------------------- systeminfo ---------------------------</span><br><span class="line">  item --gap --             DHCP Server: $&#123;dhcp-server&#125;</span><br><span class="line">  item --gap --             IP: $&#123;ip&#125;</span><br><span class="line">  item --gap --             MAC: $&#123;mac&#125;</span><br><span class="line">  item --gap --             netmask: $&#123;netmask&#125;</span><br><span class="line">  item --gap --             Gateway: $&#123;gateway&#125;</span><br><span class="line">  item --gap --             DNS: $&#123;dns&#125;</span><br><span class="line">  item --gap --             UUID: $&#123;uuid&#125;</span><br><span class="line">  item --gap --             initiator-iqn: $&#123;initiator-iqn&#125;</span><br><span class="line">  choose --timeout $&#123;menu-timeout&#125; --default $&#123;menu-default&#125; selected</span><br><span class="line">  goto $&#123;selected&#125;</span><br><span class="line"></span><br><span class="line">:reboot</span><br><span class="line">  reboot</span><br><span class="line"></span><br><span class="line">:exit</span><br><span class="line">  exit</span><br><span class="line"></span><br><span class="line">:shell</span><br><span class="line">  shell</span><br><span class="line">goto start</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">:WINDOWS </span><br><span class="line">  chain /mac/$&#123;mac:hexhyp&#125; || goto install</span><br><span class="line"></span><br><span class="line">:pe</span><br><span class="line">  sanhook iscsi:$&#123;next-server&#125;:::1:iqn.2000-01.com.synology:diskstation.Target-win10 || goto shell</span><br><span class="line">  kernel wimboot</span><br><span class="line">  initrd http://$&#123;next-server&#125;:6111/boot/bcd         BCD</span><br><span class="line">  initrd http://$&#123;next-server&#125;:6111/boot/boot.sdi    boot.sdi</span><br><span class="line">  initrd http://$&#123;next-server&#125;:6111/sources/boot.wim boot.wim</span><br><span class="line">  boot</span><br></pre></td></tr></table></figure><p>把boot.ipxe放到web根目录下，然后就小主机就可以开机了。</p><h5 id="1-6-安装windows"><a href="#1-6-安装windows" class="headerlink" title="1.6 安装windows"></a>1.6 安装windows</h5><p>先把安装u盘插到usb口，开机后最终会执行boot.ipxe，就可以看到一个菜单项，第一次要选择第二项：PE System菜单<br>进入pe环境，注意这个pe环境不像网上的windows pe系统那么完整，它本质上只能进入windows安装界面的第一步，如果真的点install会失败（因为文件不全），我只是用它来进入命令行界面（选择repair computer-&gt;trouble shooting，找到命令行选项）：<br><img src="https://assets.sirtech.cc/img/202404281750489.png" alt="image.png"></p><p>把前面提到的windows镜像用rufus写到u盘里后插入u盘，在命令行中用dir的方式切换到u盘的目录，dir c:,dir d:这样一个一个的试，然后cd &#x2F;d c:\ 切换过去，执行setup.exe就可以直接启动u盘上的安装程序了。</p><h5 id="1-7-直接启动iscsi磁盘上的windows"><a href="#1-7-直接启动iscsi磁盘上的windows" class="headerlink" title="1.7 直接启动iscsi磁盘上的windows"></a>1.7 直接启动iscsi磁盘上的windows</h5><p>我的boot.ipxe脚本启动windows是按照mac地址来启动不同的iscsi磁盘，<br>要在web根目录下的创建一个文件&#x2F;mac&#x2F;xx-xx-xx-xx-xx-xx这也是一个引导脚本，内容如下：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">#!ipxe</span><br><span class="line">set keep-san 1</span><br><span class="line">sanboot iscsi:$&#123;next-server&#125;:::1:iqn.2000-01.com.synology:diskstation.Target-win10</span><br><span class="line">boot</span><br></pre></td></tr></table></figure><p>我是为了方便一个脚本引导多台主机这样写的，如果不需要网络引导多台电脑的话，可以把这几行代码直接写到boot.ipxe中，修改如下：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">:WINDOWS </span><br><span class="line">  set keep-san 1</span><br><span class="line">  sanboot iscsi:$&#123;next-server&#125;:::1:iqn.2000-01.com.synology:diskstation.Target-win10</span><br><span class="line">  boot</span><br></pre></td></tr></table></figure><p>到这里，启动的时候选择BOOT WINDOWS(ISCSI)菜单，就可以直接进入windows界面了。</p><h4 id="最终效果图"><a href="#最终效果图" class="headerlink" title="最终效果图"></a>最终效果图</h4><p>刚安装完成时CPU几乎满载，原版windows装好后会运行一堆有得没得的程序，等一段时间后自然会降下来，最好还是找几个windows优化工具关闭一些不需要的服务。<br><img src="https://assets.sirtech.cc/img/202404241310661.png" alt="image.png"></p><p>装好后马上关闭系统的虚拟内存，因为如果通过无盘启动windows的话，虚拟内存的页面文件是建立群晖iscsi硬盘上的，多多少少会影响运行速度。<br><img src="https://assets.sirtech.cc/img/202404241319664.png" alt="image.png"></p><p>这小主机能装windows，50块钱的价格就值回来了，你也可以装个linux跑点小服务啥的，其他玩法大家就自由发挥了～</p><p>更多内容请关注<a href="https://sirtech.cc/">我的博客</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;先说原因，在家里用apple tv串流到电脑上玩游戏，发现蓝牙连接手柄没有震动功能，手柄直连电脑是可以震动功能的，玩地平线时试过那个手柄震动功能之后，就再也回不去了，于是想找个便宜的方案曲线救国，海鲜市场50块钱淘了这个小主机，x86&amp;#x2F;64构架，只有2g内存和4g</summary>
      
    
    
    
    <category term="hardware" scheme="https://sirtech.cc/categories/hardware/"/>
    
    
    <category term="群晖" scheme="https://sirtech.cc/tags/%E7%BE%A4%E6%99%96/"/>
    
    <category term="IPXE" scheme="https://sirtech.cc/tags/IPXE/"/>
    
    <category term="windows" scheme="https://sirtech.cc/tags/windows/"/>
    
    <category term="nas" scheme="https://sirtech.cc/tags/nas/"/>
    
  </entry>
  
  <entry>
    <title>使用 VSCode Remote SSH 连接到群晖 DSM</title>
    <link href="https://sirtech.cc/2024/04/04/shi-yong-vscode-remote-ssh-lian-jie-dao-qun-hui-dsm/"/>
    <id>https://sirtech.cc/2024/04/04/shi-yong-vscode-remote-ssh-lian-jie-dao-qun-hui-dsm/</id>
    <published>2024-04-04T00:00:00.000Z</published>
    <updated>2024-04-04T00:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>使用 VSCode Remote SSH 连接到群晖 DSM</p><h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><p>vscode直接ssh进入群晖时会出现：</p><blockquote><p>The remote host may not meet VS Code Server’s prerequisites for glibc and libstdc++</p></blockquote><p><a href="https://community.synology.com/enu/forum/10/post/153781">https://community.synology.com/enu/forum/10/post/153781</a></p><p>解决办法如下：</p><h3 id="ssh命令行进入群晖"><a href="#ssh命令行进入群晖" class="headerlink" title="ssh命令行进入群晖"></a>ssh命令行进入群晖</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ssh yourname@192.168.1.x</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> vim /usr/bin/ldd</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#/bin/sh </span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;ldd 2.20&quot;</span></span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">chmod</span> 755 /usr/bin/ldd</span><br></pre></td></tr></table></figure><h3 id="开启端口转发"><a href="#开启端口转发" class="headerlink" title="开启端口转发"></a>开启端口转发</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> <span class="built_in">cp</span> sshd_config sshd_config.bck</span><br><span class="line"><span class="built_in">cd</span> /etc/ssh/</span><br><span class="line">/etc/ssh$ <span class="built_in">sudo</span> vim sshd_config</span><br></pre></td></tr></table></figure><p>修改配置</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">AllowAgentForwarding yes </span><br><span class="line">AllowTcpForwarding yes</span><br></pre></td></tr></table></figure><p><img src="https://assets.sirtech.cc/img/202404041818570.png" alt="alt"><br>注意一共有两处，文件起始处的参数去掉#注释，另外一处在文档末尾<br><img src="https://assets.sirtech.cc/img/202404041820949.png" alt="image.png"></p><p>建议root和admin等账户不要改，在末尾加一项自己的用户名配置，username是你自己的DSM账户名：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Match User username</span><br><span class="line">    AllowAgentForwarding yes</span><br><span class="line">    AllowTcpForwarding yes</span><br></pre></td></tr></table></figure><h4 id="重启sshd"><a href="#重启sshd" class="headerlink" title="重启sshd"></a>重启sshd</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> systemctl restart sshd </span><br><span class="line"><span class="built_in">rm</span> -rf ~/.vscode-server/</span><br></pre></td></tr></table></figure><p>引用自：<a href="https://github.com/microsoft/vscode-remote-release/issues/8132#issuecomment-1515989319">microsoft&#x2F;vscode-remote-release#8132 (comment)</a></p><p>更多内容请关注<a href="https://sirtech.cc/">我的博客</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;使用 VSCode Remote SSH 连接到群晖 DSM&lt;/p&gt;
&lt;h2 id=&quot;Quick-Start&quot;&gt;&lt;a href=&quot;#Quick-Start&quot; class=&quot;headerlink&quot; title=&quot;Quick Start&quot;&gt;&lt;/a&gt;Quick Start&lt;/h2</summary>
      
    
    
    
    
    <category term="群晖" scheme="https://sirtech.cc/tags/%E7%BE%A4%E6%99%96/"/>
    
    <category term="Synology" scheme="https://sirtech.cc/tags/Synology/"/>
    
  </entry>
  
  <entry>
    <title>各种开源汇编、反汇编引擎的非专业比较</title>
    <link href="https://sirtech.cc/2015/11/08/ge-chong-kai-yuan-hui-bian-fan-hui-bian-yin-qing-de-fei-zhuan-ye-bi-jiao/"/>
    <id>https://sirtech.cc/2015/11/08/ge-chong-kai-yuan-hui-bian-fan-hui-bian-yin-qing-de-fei-zhuan-ye-bi-jiao/</id>
    <published>2015-11-08T00:00:00.000Z</published>
    <updated>2015-11-08T00:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>　　由于平时业余兴趣和工作需要，研究过并使用过时下流行的各种开源的x86&#x2F;64汇编和反汇编引擎。如果要对汇编指令进行分析和操作，要么自己研究Intel指令集<br>写一个，要么就用现成的开源引擎。自己写太浪费时间，又是苦力活，还容易出错，所以还是使用现成的好一点。  </p><p>这里对我曾使用过的比较流行的反汇编引擎做个比较，我使用过的反汇编引擎有：  </p><p>##1. Ollydbg的ODDisassm<br>　　Ollydbg的<a href="http://www.ollydbg.de/">ODDisassm</a>，这是我最早使用的一个开源的反汇编引擎，07年在<a href="http://bbs.pediy.com/showthread.php?t=66210">《加密解密》（三）</a><br>中我写的一个很简单的虚拟机就是使用的这个库，因为那个时候还没有那么多可选择。不过多亏有这样一个基础库，整个虚拟机从设计到开发完成只用了两个星期便开发完成<br>（当时对反汇编库的要求不高，只要求能用字符串文本做中间表示进行编码&#x2F;解码）。<br>　　这个反汇编库的优点是含有汇编接口（即文本解析，将文本字符串解析并编码成二进制），就拿这个特性来说在当时也算是独树一帜的了，到目前为止开源界在做这个工作的人也很少，<br>不过近年出现的调试器新秀x64dbg，也附带开发了开源的汇编库XEDParse，功能与OD的文本解析功能相似，并且支持的指令集更加完整，BUG更少，同时还支持X64，维护一直很强劲。<br>但是ODDisassm的缺点也很多，比如：<br>　　1. 指令集支持不全，由于Ollydbg年久失修，现在甚至连对MMX指令集都不全，而现在的INTEL&#x2F;AMD的扩展指令集标准又更新了多个版本，什么SSE5&#x2F;AVX&#x2F;AES&#x2F;XOP就更别提了，完全无法解析。<br>　　2. 解码出来的结构不详细，比如指令前缀支持不够友好，这点从Ollydbg的反汇编窗口可以看出，除了movs&#x2F;cmps等指令以外，repcc与其他指令组合时都是单独分开的；<br>    再比如寄存器无法表示<code>ah\bh\ch\dh</code>这种高8位寄存器。<br>　　3. 作者一次性开源后便不再维护开源版本，对于反汇编上的BUG很难即时修复。  </p><p>　　不过这些也可以理解，因为在当时作者的开发目的是进行文本汇编\反汇编，所以没有为解码出的信息建立结构体以及接口。总的来说，如今再使用这个反汇编引擎，<br>已经落后于时代了。  </p><p>##2. BeaEngine<br>　　<a href="https://github.com/BeaEngine/beaengine">BeaEngine</a>是我用的第二个库，当时使用OD库已经不能满足我的需求了。<br>在做反编译器的时候，需要一个能够解码信息越多越好的库，于是我找到了<code>BeaEngine</code>，这个库我记得以前的版本不支持高8位寄存器识别，现在的版本也支持了。<br>在使用过程中基本上没有发现什么明显的缺点，不常用的新的扩展指令集也实现了不少。<br>　　目前实现的扩展指令集有：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">FPU, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, VMX, CLMUL, AES, MPX</span><br></pre></td></tr></table></figure><p>　　同时它也给不同种类的指令进行了分类，这在判断不同指令时很方便。它还有一个特点是可以解码出每一条指令所使用到和影响到的寄存器，<br>包括标志位寄存器，甚至精确到标志位寄存器的每一个位置。<br>这个功能用来做优化器与混淆器再好不过了。<br>　　但是个人认为<code>BeaEngine</code>的编码风格实在是不咋地，各种变量强制转换，各种命名风格，给人一种乱乱的感觉。<br>对我这种对编码有洁癖的人来说，实在是无法忍受，所以后来又换了其他的库。如果你不在意这些，BeaEngine的性能还是比较不错的。<br>还有一点，BeaEngine经常性的爆出一些BUG，所以使用它时要有心理准备。  </p><p>##3. udis86<br>　　<a href="https://github.com/vmt/udis86"><code>udis86</code></a>应该是我最喜爱的反汇编引擎了。<br>udis86支持的X86扩展指令集有：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">MMX, FPU (x87), AMD 3DNow, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AES, AMD-V, INTEL-VMX, SMX</span><br></pre></td></tr></table></figure><p>　　udis86的代码风格十分简洁，功能函数短小，变量命名清楚又简洁，接口干净意思明白，操作灵活，如果你自己有需求维护一个自己的分支，花不了几十分钟的时间就能熟悉整个代码构架。<br>　　说了这么多溢美之词，它到底有什么优点呢？<br>　　udis86的优点就是接口很灵活，你可以选择对一条指令使用<code>ud_decode</code>只进行解码，再对解码后的结构使用<code>ud_translate_intel</code>转换成文本格式，<br>或者你也可以直接使用<code>ud_disassemble</code>一次性完成整个操作。而且这些接口都只需要一行就能搞定。<br>由于udis86的这种组合模式设计理念，他可以适应各种场景，如果你要开发一个IDA那样的反汇编器，它能做；<br>你要开发一个指令模拟器、分析器、优化器、混淆器，它也能做。<br>　　这种理念直接使udis86在拥有了强大的适应能力的同时还兼顾了性能，我做过性能测试，<br>udis86是我用过的<font color='red'>解码细节能力相近</font>的情况下，解码速度最快的引擎了。<br>　　至于缺点的话，目前还没发现，不过，udis86不支持BeaEngine那种的寄存器分析，算是点小遗憾。</p><p>##4. Capstone<br>　　<a href="https://github.com/aquynh/capstone"><code>capstone</code></a>应该算是所有反汇编引擎中集大成者了，对于它我要多费点口水，因为我对他是又爱又恨。<br>capstone是基于<code>LLVM</code>框架中的MC组件部分移植过来，所以<code>LLVM</code>支持的<code>CPU</code>构架，capstone也都支持。<br>　　它支持的CPU构架有:<code>Arm, Arm64 (Armv8), M68K, Mips, PowerPC, Sparc, SystemZ, XCore &amp; X86 (include X86_64)</code>。<br>　　而且Capstone对X86构架的指令集支持是最全的，这一点是其他引擎都比不上的，其支持的X86扩展指令集有：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">3dnow, 3dnowa, x86_64, adx, aes, atom, avx, avx2, avx512cd, avx512er, avx512f, avx512pf, bmi, bmi2, fma, fma4, fsgsbase, lzcnt, mmx, sha, slm, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, xop.</span><br></pre></td></tr></table></figure><p>　　很强吧？<br>　　在目前移动端如此火热的背景下，支持ARM的反汇编库还是非常少的，如果要同时进行X86与ARM下的编译器方面的开发，能使用一个统一的接口那自然是更好。<br>另外capstone的<code>next</code>分支（<code>master</code>分支没有这个接口）中也支持BeaEngine那种解码时分析指令使用和影响到的寄存器这种炫酷的特技，有这样的基础库存在真的可以偷不少的懒。<br>　　仅从X86&#x2F;64平台来看，无论是从解码能力还是指令集支持，<code>Capstone</code>可以称得上是一个完全超越了<code>BeaEngine</code>的存在。<br>　　老套路，说完了好话，又该说缺点了。<br>　　由于<code>capstone</code>是从<code>LLVM</code>移植过来，<code>capstone</code>是<code>C</code>语言的项目，而<code>LLVM</code>是<code>C++</code>项目，所以在移植过程中做了很多适配工作，显得很臃肿。<br>　　举个栗子，<code>LLVM</code>中的<code>MCInst</code>是一个单条底层机制指令的描述类，由于<code>capstone</code>是C项目，<br>    移植时将这些类变成了结构，把成员函数变成了独立的C函数，比如<code>MCInst_Init</code>，<code>MCInst_setOpcode</code>等等。并且由于<code>LLVM</code>框架的复杂性和高度兼容性，<br>里面的所有的概念都做了高度抽象，并且Capstone又做了适配接口将其转换到自己的构架中，这会造成解码时中间层过多，性能下降。一条指令的解码过程用到的重要的中间层结构顺序是这样的：  </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">MCInst =&gt; InternalInstruction =&gt; cs_insn</span><br></pre></td></tr></table></figure><p>　　最基础的解码工作依靠LLVM的构架解码到Capstone的<code>InternalInstruction</code>，它是一个包含了解码过程中的所有细节的内部结构，<br>解码完成后再调用<code>update_pub_insn</code>将认为需要公开暴露出来的内容复制到<code>cs_insn</code>中。而其他反汇编引擎都是一次性解码到目标结构中的。<br>　　Capstone的解码过程如此复杂，自然会对性能造成影响，我做过一个不太严格的性能测试，Capstone的性能消耗时间大概是udis86的5、6倍<br>（顺便吹一下，这里我给Capstone提交了一个小小的Pull Request,分别在<a href="https://github.com/aquynh/capstone/pull/484">这里</a>和<a href="https://github.com/aquynh/capstone/pull/505">这里</a>，<br>PR中附带了一个benchmark，经过测试性能提高了将近有20%），如果换种方式测试，udis86只使用<code>ud_decode</code>进行解码，而Capstone没有独立的解码接口，<br>需要做一些Hack，也让它不生成汇编文本，那么Capstone的消耗时间大概是udis86的2倍多，<br>由此可见Capstone的文本操作又比udis86慢更多。<br>　　其次，Capstone的内存消耗很大，解码一条指令时你传入的指令结构<code>cs_insn</code>必须由动态分配函数来分配，并且还要分配两次，一次是cs_insn，一次是cs_detail。<br>这会造成巨量的内存碎片，另外，每一条指令的结构体都很大，有多大我不记得了，<code>sizeof(cs_insn)</code>+<code>sizeof(cs_detail)</code>好像至少在2K以上。<br>必须使用<font color='red'>动态内存</font>这一点是Capstone与其他反汇编引擎不一样的地方。<br>如果要使用Capstone做大量指令分析的话，那么得给它配一个固定对象内存分配器才行，那样能稍微缓解一下内存碎片情况，也能提高一点性能。<br>　　可能是基于以上理由，x64dbg社区本来最开始是使用BeaEngine作为支撑基础的，但是BeaEngine总是爆出不少BUG，所以后来选择由Capstone替换，<br>但是也仅用Capstone来做GUI的文本反汇编，因为它解码速度虽然不行，但是BUG很少（毕竟LLVM有苹果那么大个公司做支撑），<br>而流图和指令分析（还不完善）目前仍然使用的BeaEngine，这也是没办法的事，毕竟性能也很重要。<br>　　还有一个问题，如果你需要的是解码能力强的反汇编引擎，那么建议你在选择前先对比一下各引擎的解码结构，有没有你需要或者必须有的字段。<br>　　因为Capstone有一个坑爹的地方，虽然其本身的解码能力其实很强的，但是Capstone把中间层封装了一遍，只暴露其认为需要暴露的字段，<br>并且其主要维护者有点固执（也可以说严谨），他坚持认为不太常用的字段没必要暴露出来，而接口是越简洁越好。<br>　　比如说指令中立即数Immediate所在的偏移，内存操作数中Displacement所在的偏移，在内部结构<code>InternalInstruction</code>中本来是有的，但是复制到公开结构<code>cs_insn</code>结构中就丢弃了。<br>还有<code>REP</code>与<code>REPE</code>前缀，虽然都是同一个常量表示，但是配上不同指令功能还是不一样的，对于这个，capstone内部有一个<code>valid_repe</code>函数可以区别，<br>但是也没有暴露到公开结构中，都当做<code>REP</code>来识别。虽然这些都很冷门，但是做指令分析和变形，这些还是很有用处的。<br>　　我个人认为capstone的接口用起来实在让人不爽，但是它的功能又实在太强大，如果研究下其源码的内部构造，会发现很多接口没提供，但是内部却有的好东西，<br>所以我自己维护了一个<a href="https://github.com/bughoho/capstone">分支</a>，痛并快乐着的使用着。</p><p>##其他<br>　　其实还有XDE，不过我没使用过，就不做评论了。<br>　　另外，<a href="https://github.com/DarthTon/Blackbone">blackbone</a>中含有一个长度反汇编引擎也值得一提，名字叫<code>ldasm</code>，其实它也算不上一个引擎，因为它只有一个函数，<br>作用只是计算一条指令的长度，在hook的时候重定位跳转指令时很有用处。<a href="https://github.com/DarthTon/Blackbone/blob/master/src/BlackBone/Asm/LDasm.c">代码传送门</a></p><p>##总结<br>　　这几款反汇编引擎各有长处（OD除外。。），但是又各自有那么一丁点儿的缺陷，这世上没有完美的事情，人家都开源了，有的用就不错了，自己总要做些事情不是？<br>挑一款好用的库，使用过程中发现BUG，给社区提交个Issue，或者做个解决方案再发个Pull Request，也算付了使用费了。  </p><table><thead><tr><th align="center">特　性</th><th align="left">比较</th></tr></thead><tbody><tr><td align="center">性能</td><td align="left">udis86 &gt; BeaEngine &gt; capstone</td></tr><tr><td align="center">解码能力</td><td align="left">capstone &gt; BeaEngine &gt; udis86 (udis86不支持寄存器分析,其余解码能力是相近的)</td></tr><tr><td align="center">平台支持</td><td align="left">capstone &gt; (udis86 &#x3D; BeaEngine)</td></tr><tr><td align="center">X86扩展指令集</td><td align="left">capstone &gt; (udis86 ≈BeaEngine)</td></tr></tbody></table><p>　　如果你需要的是一个X86&#x2F;64下的性能又好同时解码能力又强的反汇编引擎，并且不需要寄存器分析这种特技的话，那么udis86合适你；<br>如果你还需要带寄存器分析功能的话，那么BeaEngine与capstone合适你；如果你还需要ARM构架支持的话，capstone应该会更适合你。<br>　　每一款引擎各有优劣，使用起来仁者见仁智者见智，鞋子合不合适只有自己的脚才知道了。</p><p>更多内容请关注<a href="https://sirtech.cc/">我的博客</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;　　由于平时业余兴趣和工作需要，研究过并使用过时下流行的各种开源的x86&amp;#x2F;64汇编和反汇编引擎。如果要对汇编指令进行分析和操作，要么自己研究Intel指令集&lt;br&gt;写一个，要么就用现成的开源引擎。自己写太浪费时间，又是苦力活，还容易出错，所以还是使用现成的好一点。</summary>
      
    
    
    
    <category term="disassembly" scheme="https://sirtech.cc/categories/disassembly/"/>
    
    
  </entry>
  
  <entry>
    <title>YY 2015 逆向分析(一) 底层通讯机制</title>
    <link href="https://sirtech.cc/2015/11/04/yy-2015-ni-xiang-fen-xi-yi-di-ceng-tong-xun-ji-zhi/"/>
    <id>https://sirtech.cc/2015/11/04/yy-2015-ni-xiang-fen-xi-yi-di-ceng-tong-xun-ji-zhi/</id>
    <published>2015-11-04T00:00:00.000Z</published>
    <updated>2015-11-04T00:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>YY 2015 逆向分析(一) 底层通讯机制</p><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>　　之前研究过YY 6.2版本的协议，今天有没事又看了一次，发现现在的版本8.3.0.0版本较之前又有了翻天覆地的变化，<br>密钥交互时不再使用<code>ZLIB</code>压缩解压缩，并且所有的命令字是１００％的全部更新了，但是通讯算法还是没变，仍然是<code>RSA</code> + <code>RC4</code>。</p><h2 id="底层通讯过程"><a href="#底层通讯过程" class="headerlink" title="底层通讯过程"></a>底层通讯过程</h2><ol start="0"><li><p>YY的封包结构是4字节长度，4字节命令字，剩下的就是数据了，也就是说，根据首4字节就可以将包分割开。但是也有一些其他情况，<br>比如嵌套包，一个命令字包中又包含了一个或者多个子命令包，这些子命令包有时是独立处理，有时需要用到父包的数据。</p></li><li><p>首先,客户端先给几个(我这里是4个)服务器发送<code>UDP</code>包,请求IP地址,服务器会根据收到的版本号下发对应的支持此版本号的服务器和列表。</p></li></ol><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">61 00 00 00 1E 73 00 00 C8 00 FF FF FF FF FF FF   a....s..?.......</span><br><span class="line">FF FF 03 01 00 00 00 00 00 00 20 00 35 34 64 37     ........ .54d7</span><br><span class="line">63 62 39 31 35 38 31 38 32 30 39 38 65 38 36 32   cb9158182098e862</span><br><span class="line">66 66 38 39 30 64 62 66 61 33 63 30 00 00 30 80   ff890dbfa3c0..0.</span><br><span class="line">07 00 38 2E 33 2E 30 2E 30 02 00 79 79 00 00 00   ..8.3.0.0..yy...</span><br><span class="line">00 00 00 00 00 00 00 04 08 00 00 00 00 00 00 00   ................</span><br><span class="line">00††††††††††††††††††††††    .</span><br></pre></td></tr></table></figure><p>然后其中一个会返回<code>0x741E</code>,返回请求到的IP列表(其他服务器可能也返回了,但是这时客户端收到一个就不再继续接收了)。<br>注意这里每个包的+4处是命令字（下同），比如这里是0x731E。</p><ol><li>客户端从收到的ＩＰ列表中随机选几个（我这里是６个）发送登陆请求，其中５个是<code>UDP</code>，１个<code>TCP</code>。包的数据都是一样的。</li></ol><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">34 00 00 00 01 14 00 00 C8 00 00 00 00 00 30 80   4.......?.....0.</span><br><span class="line">FF FF FF FF 08 00 62 75 67 73 74 65 73 74 00 00   ..bugstest..</span><br><span class="line">04 08 00 00 01 00 00 00 00 00 00 00 00 00 00 00   ................</span><br><span class="line">00 00 00 00††††††††††††††††††   ....</span><br></pre></td></tr></table></figure><ol start="3"><li>响应最快的那个服务器返回<code>0x1501</code>命令，+0C处是反馈结果，当为<code>0xC8</code>时表示一切正常，后面的数据就是真正要登陆的服务器<br>的<code>IP</code>和<code>Port</code>了；如果为其他值（比如<code>97 01 00 00</code>），表示版本过低，需要升级。</li></ol><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">54 00 00 00 01 15 00 00 C8 00 00 00 C8 00 00 00   T.......?...?...</span><br><span class="line">02 00 00 00 70 75 DC EB DA 85 3B 14 00 00 03 00   ....pu????;.....</span><br><span class="line">00 00 91 1F 39 04 51 00 6F B2 91 8A 4D E6 3B 14   ..?9.Q.o???M?;.</span><br><span class="line">00 00 03 00 00 00 94 1F 39 04 54 00 00 00 00 00   ......?9.T.....</span><br><span class="line">01 00 11 00 AB 5B 54 76 00 00 00 00 00 00 00 00   ....?[Tv........</span><br><span class="line">F4 01 00 00††††††††††††††††††   ?...</span><br></pre></td></tr></table></figure><ol start="4"><li>此时才是真正的登陆过程，一切从这里开始。客户端根据收到的登陆用的IP列表，随机选择一个建立连接，连接成功后，客户端主动给服务器发送一条密钥交互包，命令字是<code>0x1104</code>或者<code>0x3204</code>（因为登陆时会连接多个服务器，比如验证服务器＼频道服务器＼好友服务器，<br>命令字根据类型的不同是不一样的）</li></ol><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">53 00 00 00 04 11 00 00 C8 00 40 00 E9 03 40 F2   S.....?@.?@?</span><br><span class="line">4D ED C4 86 32 9B 25 F1 7A D8 94 70 D5 E2 20 6C   M砟??駔財p这 l</span><br><span class="line">F0 B7 AF FD 5A DD A4 A6 F3 CA F5 8C CE 7B 9B CB   鸱Z荬术屛&#123;浰</span><br><span class="line">2D AB 49 45 04 61 93 9C 4F 7D 40 DE E1 E4 8B 19   -獻Ea摐O&#125;@掎鋴</span><br><span class="line">BC 89 C2 E0 76 29 58 2E 2F BB A6 51 01 00 03 00   級锣v)X./沪Q..</span><br><span class="line">00 00 00                                          ...</span><br></pre></td></tr></table></figure><p>或者</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">66 00 00 00 04 32 00 00 C8 00 40 00 E9 03 40 F2  f...2..?@.?@?</span><br><span class="line">4D ED C4 86 32 9B 25 F1 7A D8 94 70 D5 E2 20 6C  M砟??駔財p这 l</span><br><span class="line">F0 B7 AF FD 5A DD A4 A6 F3 CA F5 8C CE 7B 9B CB  鸱Z荬术屛&#123;浰</span><br><span class="line">2D AB 49 45 04 61 93 9C 4F 7D 40 DE E1 E4 8B 19  -獻Ea摐O&#125;@掎鋴</span><br><span class="line">BC 89 C2 E0 76 29 58 2E 2F BB A6 51 01 00 03 13  級锣v)X./沪Q.</span><br><span class="line">00 00 00 13 00 00 00 04 E8 0B 00 C8 00 00 00 05  ......?.?..</span><br><span class="line">00 6C 6F 67 69 6E                                .login</span><br></pre></td></tr></table></figure><p>+4处的0x40字节是客户端生成的公钥，即<code>RSA</code>的<code>N</code>；+0x4E处一字节是<code>RSA</code>的<code>E</code>。这个包的作用是通知服务端，下发的<code>RC4</code>密钥使用这个RSA密钥进行加密，</p><ol start="5"><li>服务器收到客户端的密钥后，返回0x3304\0x1504，以前这个包的key是经过zlib压缩的，现在取消掉了，估计服务器吃不消给优化掉了。</li></ol><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">50 00 00 00 04 15 00 00 C8 00 40 00 7B 89 12 1B  P.........@.&#123;...</span><br><span class="line">FE 8F AC 7A BF 02 D4 34 42 D9 52 29 21 EA 0D 13  ...z...4B.R)!...</span><br><span class="line">27 EC C0 11 BB 59 A8 7F 9C 95 AE B7 9C 09 5A 3C  &#x27;....Y........Z&lt;</span><br><span class="line">43 A1 55 8E DA A0 2D F6 CA E9 EB F4 DC D3 DC C5  C.U...-.........</span><br><span class="line">64 8E 75 91 AE 32 A4 28 04 88 CA 79 00 00 00 00  d.u..2.(...y....</span><br></pre></td></tr></table></figure><p>或者</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">18 09 00 00 04 33 00 00  C8 00 40 00 22 79 01 D6 .....3....@.&quot;y..</span><br><span class="line">58 E0 86 9C A2 57 37 21  89 4B BF 7F C2 F2 BE 64 X....W7!.K.....d</span><br><span class="line">48 00 8B E6 14 82 C3 0E  D0 FF 80 3C 2C 60 F2 DD H..........&lt;,`..</span><br><span class="line">7F BA A4 67 17 C1 DA CA  F4 D6 C0 4E B2 EE A7 90 ...g.......N....</span><br><span class="line">23 3E 46 1D D4 A4 B4 E5  91 14 FE F5 C8 08 00 00 #&gt;F.............</span><br><span class="line">C8 08 00 00 04 E9 0B 00  C8 00 00 00 BA 08 B6 08 ................</span><br><span class="line">00 00 06 00 04 00 00 00  FF FF 00 00 17 27 54 08 .............&#x27;T.</span><br><span class="line">00 00 78 DA 8D 57 4D 6C  1B C7 15 7E 43 AD 4D 49 ..x..WMl...~C.MI</span><br><span class="line">D6 8F AD C6 86 64 BB 8E  9A BA 46 0E 75 10 5B 76 .....d....F.u.[v</span><br><span class="line">E5 9C 32 4B 8A 22 F5 47  D2 22 25 45 69 22 7B 45 ..2K.&quot;.G.&quot;%Ei&quot;&#123;E</span><br><span class="line">...后面省略</span><br></pre></td></tr></table></figure><p>顺便一提，<code>3304</code>这个包除了密钥外还下发了一个字节码模块，交给客户端初始化动态环境，这样的数据包后面还有很多，都是服务端下发的动态检测代码。</p><p>这两个包的<code>0C</code>处开始的<code>0x40</code>字节便是下发的经过<code>RSA</code>加密过的<code>RC4</code>密钥了，经过<code>RSA</code>解密后的RC4密钥复制成两份，一份是专门用来加密，一份专门用来解密。<br>到这一步，YY密钥协商过程完成，后面发送的数据都是加密数据了。</p><p>至于算法的实现在<code>dwUtility.dll</code>中的导出函数，这里挑出几个用得到的翻译一下功能：</p><table><thead><tr><th>导出函数名称</th><th align="center">功能</th></tr></thead><tbody><tr><td>DwUtility::dwBaseFunc::dwUtilityrgk</td><td align="center">初始化RSA结构</td></tr><tr><td>DwUtility::dwBaseFunc::dwUtilityrpd</td><td align="center">RSA解密算法</td></tr><tr><td>DwUtility::dwBaseFunc::dwUtilitybb</td><td align="center">将大数转换为二进制</td></tr><tr><td>DwUtility::dwBaseFunc::dwUtilityrsk</td><td align="center">初始化RC4结构</td></tr><tr><td>DwUtility::dwBaseFunc::dwUtilityr</td><td align="center">RC4加\解密算法</td></tr></tbody></table><p>以上就是几个关键的算法了，这个DLL中还有很多其他基础的功能，有兴趣的可以自己去研究，这里就不一一列举了。</p><p>由于收发数据有的加密有的不加密，并且连接的SOCKET太多，只用OD分析实在不方便，为此我写了一个现实加密前和解密后的封包分析工具，<br>加上了每个原始包对应的SOCKET加以区分。show一下：）</p><p><code>图片丢失</code></p><h2 id="结束"><a href="#结束" class="headerlink" title="结束"></a>结束</h2><p>YY在登陆时是一次性给N个服务器发送请求，谁快用谁，这对登陆服务器集群的性能要求特别高，因为这样<br>每个服务器处理所需要的资源成倍提高。通过建立密钥这个过程可以看出YY把负载均衡真的是做到了极致。</p><p>这一章就到此结束，下次有空写下一章YY登陆的封包实际内容分析。</p><p>PS:研究仅为学习，没有任何不纯目的：）</p><p>如有任何疑问请联系:bughoho[at]gmail.com，欢迎指出错误。</p><p>更多内容请关注<a href="https://sirtech.cc/">我的博客</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;YY 2015 逆向分析(一) 底层通讯机制&lt;/p&gt;
&lt;h2 id=&quot;前言&quot;&gt;&lt;a href=&quot;#前言&quot; class=&quot;headerlink&quot; title=&quot;前言&quot;&gt;&lt;/a&gt;前言&lt;/h2&gt;&lt;p&gt;　　之前研究过YY 6.2版本的协议，今天有没事又看了一次，发现现在的版本8.3</summary>
      
    
    
    
    <category term="Revese Engineering" scheme="https://sirtech.cc/categories/Revese-Engineering/"/>
    
    
    <category term="yy" scheme="https://sirtech.cc/tags/yy/"/>
    
    <category term="ReveseEngineering" scheme="https://sirtech.cc/tags/ReveseEngineering/"/>
    
    <category term="network" scheme="https://sirtech.cc/tags/network/"/>
    
  </entry>
  
</feed>
